diff options
author | rdivacky <rdivacky@FreeBSD.org> | 2010-02-16 09:31:36 +0000 |
---|---|---|
committer | rdivacky <rdivacky@FreeBSD.org> | 2010-02-16 09:31:36 +0000 |
commit | fd035e6496665b1f1197868e21cb0a4594e8db6e (patch) | |
tree | 53010172e19c77ea447bcd89e117cda052ab52e0 /lib/AST | |
parent | 2fce988e86bc01829142e4362d4eff1af0925147 (diff) | |
download | FreeBSD-src-fd035e6496665b1f1197868e21cb0a4594e8db6e.zip FreeBSD-src-fd035e6496665b1f1197868e21cb0a4594e8db6e.tar.gz |
Update clang to r96341.
Diffstat (limited to 'lib/AST')
-rw-r--r-- | lib/AST/ASTContext.cpp | 247 | ||||
-rw-r--r-- | lib/AST/ASTDiagnostic.cpp | 266 | ||||
-rw-r--r-- | lib/AST/ASTImporter.cpp | 2394 | ||||
-rw-r--r-- | lib/AST/AttrImpl.cpp | 65 | ||||
-rw-r--r-- | lib/AST/CMakeLists.txt | 2 | ||||
-rw-r--r-- | lib/AST/CXXInheritance.cpp | 14 | ||||
-rw-r--r-- | lib/AST/Decl.cpp | 734 | ||||
-rw-r--r-- | lib/AST/DeclBase.cpp | 35 | ||||
-rw-r--r-- | lib/AST/DeclCXX.cpp | 123 | ||||
-rw-r--r-- | lib/AST/DeclObjC.cpp | 14 | ||||
-rw-r--r-- | lib/AST/DeclPrinter.cpp | 62 | ||||
-rw-r--r-- | lib/AST/DeclTemplate.cpp | 3 | ||||
-rw-r--r-- | lib/AST/DeclarationName.cpp | 47 | ||||
-rw-r--r-- | lib/AST/Expr.cpp | 134 | ||||
-rw-r--r-- | lib/AST/ExprCXX.cpp | 100 | ||||
-rw-r--r-- | lib/AST/ExprConstant.cpp | 39 | ||||
-rw-r--r-- | lib/AST/Makefile | 1 | ||||
-rw-r--r-- | lib/AST/RecordLayoutBuilder.cpp | 9 | ||||
-rw-r--r-- | lib/AST/Stmt.cpp | 148 | ||||
-rw-r--r-- | lib/AST/StmtDumper.cpp | 2 | ||||
-rw-r--r-- | lib/AST/StmtPrinter.cpp | 4 | ||||
-rw-r--r-- | lib/AST/StmtProfile.cpp | 4 | ||||
-rw-r--r-- | lib/AST/Type.cpp | 154 | ||||
-rw-r--r-- | lib/AST/TypePrinter.cpp | 40 |
24 files changed, 3976 insertions, 665 deletions
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index c1bc709..c23babb 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -56,6 +56,10 @@ ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM, } ASTContext::~ASTContext() { + // Release the DenseMaps associated with DeclContext objects. + // FIXME: Is this the ideal solution? + ReleaseDeclContextMaps(); + if (FreeMemory) { // Deallocate all the types. while (!Types.empty()) { @@ -533,12 +537,12 @@ const llvm::fltSemantics &ASTContext::getFloatTypeSemantics(QualType T) const { } } -/// getDeclAlignInBytes - Return a conservative estimate of the alignment of the +/// getDeclAlign - Return a conservative estimate of the alignment of the /// specified decl. Note that bitfields do not have a valid alignment, so /// this method will assert on them. /// If @p RefAsPointee, references are treated like their underlying type /// (for alignof), else they're treated like pointers (for CodeGen). -unsigned ASTContext::getDeclAlignInBytes(const Decl *D, bool RefAsPointee) { +CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) { unsigned Align = Target.getCharWidth(); if (const AlignedAttr* AA = D->getAttr<AlignedAttr>()) @@ -561,7 +565,7 @@ unsigned ASTContext::getDeclAlignInBytes(const Decl *D, bool RefAsPointee) { } } - return Align / Target.getCharWidth(); + return CharUnits::fromQuantity(Align / Target.getCharWidth()); } /// getTypeSize - Return the size of the specified type, in bits. This method @@ -820,6 +824,15 @@ CharUnits ASTContext::getTypeSizeInChars(const Type *T) { return CharUnits::fromQuantity(getTypeSize(T) / getCharWidth()); } +/// getTypeAlignInChars - Return the ABI-specified alignment of a type, in +/// characters. This method does not work on incomplete types. +CharUnits ASTContext::getTypeAlignInChars(QualType T) { + return CharUnits::fromQuantity(getTypeAlign(T) / getCharWidth()); +} +CharUnits ASTContext::getTypeAlignInChars(const Type *T) { + return CharUnits::fromQuantity(getTypeAlign(T) / getCharWidth()); +} + /// getPreferredTypeAlign - Return the "preferred" alignment of the specified /// type for the current target in bits. This can be different than the ABI /// alignment in cases where it is beneficial for performance to overalign @@ -904,12 +917,12 @@ void ASTContext::CollectSynthesizedIvars(const ObjCInterfaceDecl *OI, /// CollectInheritedProtocols - Collect all protocols in current class and /// those inherited by it. void ASTContext::CollectInheritedProtocols(const Decl *CDecl, - llvm::SmallVectorImpl<ObjCProtocolDecl*> &Protocols) { + llvm::SmallPtrSet<ObjCProtocolDecl*, 8> &Protocols) { if (const ObjCInterfaceDecl *OI = dyn_cast<ObjCInterfaceDecl>(CDecl)) { for (ObjCInterfaceDecl::protocol_iterator P = OI->protocol_begin(), PE = OI->protocol_end(); P != PE; ++P) { ObjCProtocolDecl *Proto = (*P); - Protocols.push_back(Proto); + Protocols.insert(Proto); for (ObjCProtocolDecl::protocol_iterator P = Proto->protocol_begin(), PE = Proto->protocol_end(); P != PE; ++P) CollectInheritedProtocols(*P, Protocols); @@ -930,7 +943,7 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl, for (ObjCInterfaceDecl::protocol_iterator P = OC->protocol_begin(), PE = OC->protocol_end(); P != PE; ++P) { ObjCProtocolDecl *Proto = (*P); - Protocols.push_back(Proto); + Protocols.insert(Proto); for (ObjCProtocolDecl::protocol_iterator P = Proto->protocol_begin(), PE = Proto->protocol_end(); P != PE; ++P) CollectInheritedProtocols(*P, Protocols); @@ -941,7 +954,7 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl, for (ObjCProtocolDecl::protocol_iterator P = OP->protocol_begin(), PE = OP->protocol_end(); P != PE; ++P) { ObjCProtocolDecl *Proto = (*P); - Protocols.push_back(Proto); + Protocols.insert(Proto); for (ObjCProtocolDecl::protocol_iterator P = Proto->protocol_begin(), PE = Proto->protocol_end(); P != PE; ++P) CollectInheritedProtocols(*P, Protocols); @@ -1088,7 +1101,7 @@ ASTContext::getASTObjCImplementationLayout(const ObjCImplementationDecl *D) { /// specified record (struct/union/class), which indicates its size and field /// position information. const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) { - D = D->getDefinition(*this); + D = D->getDefinition(); assert(D && "Cannot get layout of forward declarations!"); // Look up this layout, if already laid out, return what we have. @@ -1105,7 +1118,7 @@ const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) { } const CXXMethodDecl *ASTContext::getKeyFunction(const CXXRecordDecl *RD) { - RD = cast<CXXRecordDecl>(RD->getDefinition(*this)); + RD = cast<CXXRecordDecl>(RD->getDefinition()); assert(RD && "Cannot get key function for forward declarations!"); const CXXMethodDecl *&Entry = KeyFunctions[RD]; @@ -1519,12 +1532,12 @@ QualType ASTContext::getDependentSizedArrayType(QualType EltTy, void *InsertPos = 0; DependentSizedArrayType *Canon = 0; + llvm::FoldingSetNodeID ID; if (NumElts) { // Dependently-sized array types that do not have a specified // number of elements will have their sizes deduced from an // initializer. - llvm::FoldingSetNodeID ID; DependentSizedArrayType::Profile(ID, *this, getCanonicalType(EltTy), ASM, EltTypeQuals, NumElts); @@ -1545,8 +1558,13 @@ QualType ASTContext::getDependentSizedArrayType(QualType EltTy, DependentSizedArrayType(*this, EltTy, QualType(), NumElts, ASM, EltTypeQuals, Brackets); - if (NumElts) + if (NumElts) { + DependentSizedArrayType *CanonCheck + = DependentSizedArrayTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(!CanonCheck && "Dependent-sized canonical array type broken"); + (void)CanonCheck; DependentSizedArrayTypes.InsertNode(New, InsertPos); + } } else { QualType Canon = getDependentSizedArrayType(CanonEltTy, NumElts, ASM, EltTypeQuals, @@ -1596,7 +1614,8 @@ QualType ASTContext::getIncompleteArrayType(QualType EltTy, /// getVectorType - Return the unique reference to a vector type of /// the specified element type and size. VectorType must be a built-in type. -QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts) { +QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts, + bool IsAltiVec, bool IsPixel) { BuiltinType *baseType; baseType = dyn_cast<BuiltinType>(getCanonicalType(vecType).getTypePtr()); @@ -1604,7 +1623,8 @@ QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts) { // Check if we've already instantiated a vector of this type. llvm::FoldingSetNodeID ID; - VectorType::Profile(ID, vecType, NumElts, Type::Vector); + VectorType::Profile(ID, vecType, NumElts, Type::Vector, + IsAltiVec, IsPixel); void *InsertPos = 0; if (VectorType *VTP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(VTP, 0); @@ -1612,15 +1632,16 @@ 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()) { - Canonical = getVectorType(getCanonicalType(vecType), NumElts); + if (!vecType.isCanonical() || IsAltiVec || IsPixel) { + Canonical = getVectorType(getCanonicalType(vecType), + NumElts, false, false); // Get the new insert position for the node we care about. VectorType *NewIP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos); assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; } VectorType *New = new (*this, TypeAlignment) - VectorType(vecType, NumElts, Canonical); + VectorType(vecType, NumElts, Canonical, IsAltiVec, IsPixel); VectorTypes.InsertNode(New, InsertPos); Types.push_back(New); return QualType(New, 0); @@ -1636,7 +1657,7 @@ QualType ASTContext::getExtVectorType(QualType vecType, unsigned NumElts) { // Check if we've already instantiated a vector of this type. llvm::FoldingSetNodeID ID; - VectorType::Profile(ID, vecType, NumElts, Type::ExtVector); + VectorType::Profile(ID, vecType, NumElts, Type::ExtVector, false, false); void *InsertPos = 0; if (VectorType *VTP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(VTP, 0); @@ -1681,6 +1702,11 @@ QualType ASTContext::getDependentSizedExtVectorType(QualType vecType, New = new (*this, TypeAlignment) DependentSizedExtVectorType(*this, vecType, QualType(), SizeExpr, AttrLoc); + + DependentSizedExtVectorType *CanonCheck + = DependentSizedExtVectorTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(!CanonCheck && "Dependent-sized ext_vector canonical type broken"); + (void)CanonCheck; DependentSizedExtVectorTypes.InsertNode(New, InsertPos); } else { QualType Canon = getDependentSizedExtVectorType(CanonVecTy, SizeExpr, @@ -1694,12 +1720,6 @@ QualType ASTContext::getDependentSizedExtVectorType(QualType vecType, return QualType(New, 0); } -static CallingConv getCanonicalCallingConv(CallingConv CC) { - if (CC == CC_C) - return CC_Default; - return CC; -} - /// getFunctionNoProtoType - Return a K&R style C function type like 'int()'. /// QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn, @@ -1707,7 +1727,7 @@ QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn, // Unique functions, to guarantee there is only one function of a particular // structure. llvm::FoldingSetNodeID ID; - FunctionNoProtoType::Profile(ID, ResultTy, NoReturn); + FunctionNoProtoType::Profile(ID, ResultTy, NoReturn, CallConv); void *InsertPos = 0; if (FunctionNoProtoType *FT = @@ -1716,9 +1736,9 @@ QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn, QualType Canonical; if (!ResultTy.isCanonical() || - getCanonicalCallingConv(CallConv) != CallConv) { + getCanonicalCallConv(CallConv) != CallConv) { Canonical = getFunctionNoProtoType(getCanonicalType(ResultTy), NoReturn, - getCanonicalCallingConv(CallConv)); + getCanonicalCallConv(CallConv)); // Get the new insert position for the node we care about. FunctionNoProtoType *NewIP = @@ -1727,7 +1747,7 @@ QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn, } FunctionNoProtoType *New = new (*this, TypeAlignment) - FunctionNoProtoType(ResultTy, Canonical, NoReturn); + FunctionNoProtoType(ResultTy, Canonical, NoReturn, CallConv); Types.push_back(New); FunctionNoProtoTypes.InsertNode(New, InsertPos); return QualType(New, 0); @@ -1746,7 +1766,7 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray, llvm::FoldingSetNodeID ID; FunctionProtoType::Profile(ID, ResultTy, ArgArray, NumArgs, isVariadic, TypeQuals, hasExceptionSpec, hasAnyExceptionSpec, - NumExs, ExArray, NoReturn); + NumExs, ExArray, NoReturn, CallConv); void *InsertPos = 0; if (FunctionProtoType *FTP = @@ -1762,7 +1782,7 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray, // If this type isn't canonical, get the canonical version of it. // The exception spec is not part of the canonical type. QualType Canonical; - if (!isCanonical || getCanonicalCallingConv(CallConv) != CallConv) { + if (!isCanonical || getCanonicalCallConv(CallConv) != CallConv) { llvm::SmallVector<QualType, 16> CanonicalArgs; CanonicalArgs.reserve(NumArgs); for (unsigned i = 0; i != NumArgs; ++i) @@ -1772,7 +1792,7 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray, CanonicalArgs.data(), NumArgs, isVariadic, TypeQuals, false, false, 0, 0, NoReturn, - getCanonicalCallingConv(CallConv)); + getCanonicalCallConv(CallConv)); // Get the new insert position for the node we care about. FunctionProtoType *NewIP = @@ -1797,29 +1817,30 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray, /// getTypeDeclType - Return the unique reference to the type for the /// specified type declaration. -QualType ASTContext::getTypeDeclType(TypeDecl *Decl, TypeDecl* PrevDecl) { +QualType ASTContext::getTypeDeclType(const TypeDecl *Decl, + const TypeDecl* PrevDecl) { assert(Decl && "Passed null for Decl param"); if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0); - if (TypedefDecl *Typedef = dyn_cast<TypedefDecl>(Decl)) + if (const TypedefDecl *Typedef = dyn_cast<TypedefDecl>(Decl)) return getTypedefType(Typedef); else if (isa<TemplateTypeParmDecl>(Decl)) { assert(false && "Template type parameter types are always available."); - } else if (ObjCInterfaceDecl *ObjCInterface + } else if (const ObjCInterfaceDecl *ObjCInterface = dyn_cast<ObjCInterfaceDecl>(Decl)) return getObjCInterfaceType(ObjCInterface); - if (RecordDecl *Record = dyn_cast<RecordDecl>(Decl)) { + if (const RecordDecl *Record = dyn_cast<RecordDecl>(Decl)) { if (PrevDecl) Decl->TypeForDecl = PrevDecl->TypeForDecl; else Decl->TypeForDecl = new (*this, TypeAlignment) RecordType(Record); - } else if (EnumDecl *Enum = dyn_cast<EnumDecl>(Decl)) { + } else if (const EnumDecl *Enum = dyn_cast<EnumDecl>(Decl)) { if (PrevDecl) Decl->TypeForDecl = PrevDecl->TypeForDecl; else Decl->TypeForDecl = new (*this, TypeAlignment) EnumType(Enum); - } else if (UnresolvedUsingTypenameDecl *Using = + } else if (const UnresolvedUsingTypenameDecl *Using = dyn_cast<UnresolvedUsingTypenameDecl>(Decl)) { Decl->TypeForDecl = new (*this, TypeAlignment) UnresolvedUsingType(Using); } else @@ -1831,7 +1852,7 @@ QualType ASTContext::getTypeDeclType(TypeDecl *Decl, TypeDecl* PrevDecl) { /// getTypedefType - Return the unique reference to the type for the /// specified typename decl. -QualType ASTContext::getTypedefType(TypedefDecl *Decl) { +QualType ASTContext::getTypedefType(const TypedefDecl *Decl) { if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0); QualType Canonical = getCanonicalType(Decl->getUnderlyingType()); @@ -1883,6 +1904,11 @@ QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index, QualType Canon = getTemplateTypeParmType(Depth, Index, ParameterPack); TypeParm = new (*this, TypeAlignment) TemplateTypeParmType(Depth, Index, ParameterPack, Name, Canon); + + TemplateTypeParmType *TypeCheck + = TemplateTypeParmTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(!TypeCheck && "Template type parameter canonical type broken"); + (void)TypeCheck; } else TypeParm = new (*this, TypeAlignment) TemplateTypeParmType(Depth, Index, ParameterPack); @@ -1976,8 +2002,16 @@ ASTContext::getQualifiedNameType(NestedNameSpecifier *NNS, if (T) return QualType(T, 0); - T = new (*this) QualifiedNameType(NNS, NamedType, - getCanonicalType(NamedType)); + QualType Canon = NamedType; + if (!Canon.isCanonical()) { + Canon = getCanonicalType(NamedType); + QualifiedNameType *CheckT + = QualifiedNameTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(!CheckT && "Qualified name canonical type broken"); + (void)CheckT; + } + + T = new (*this) QualifiedNameType(NNS, NamedType, Canon); Types.push_back(T); QualifiedNameTypes.InsertNode(T, InsertPos); return QualType(T, 0); @@ -2015,6 +2049,15 @@ ASTContext::getTypenameType(NestedNameSpecifier *NNS, QualType Canon) { assert(NNS->isDependent() && "nested-name-specifier must be dependent"); + llvm::FoldingSetNodeID ID; + TypenameType::Profile(ID, NNS, TemplateId); + + void *InsertPos = 0; + TypenameType *T + = TypenameTypes.FindNodeOrInsertPos(ID, InsertPos); + if (T) + return QualType(T, 0); + if (Canon.isNull()) { NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS); QualType CanonType = getCanonicalType(QualType(TemplateId, 0)); @@ -2025,16 +2068,11 @@ ASTContext::getTypenameType(NestedNameSpecifier *NNS, "Canonical type must also be a template specialization type"); Canon = getTypenameType(CanonNNS, CanonTemplateId); } - } - llvm::FoldingSetNodeID ID; - TypenameType::Profile(ID, NNS, TemplateId); - - void *InsertPos = 0; - TypenameType *T - = TypenameTypes.FindNodeOrInsertPos(ID, InsertPos); - if (T) - return QualType(T, 0); + TypenameType *CheckT + = TypenameTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(!CheckT && "Typename canonical type is broken"); (void)CheckT; + } T = new (*this) TypenameType(NNS, TemplateId, Canon); Types.push_back(T); @@ -2053,7 +2091,12 @@ ASTContext::getElaboratedType(QualType UnderlyingType, if (T) return QualType(T, 0); - QualType Canon = getCanonicalType(UnderlyingType); + QualType Canon = UnderlyingType; + if (!Canon.isCanonical()) { + Canon = getCanonicalType(Canon); + ElaboratedType *CheckT = ElaboratedTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(!CheckT && "Elaborated canonical type is broken"); (void)CheckT; + } T = new (*this) ElaboratedType(UnderlyingType, Tag, Canon); Types.push_back(T); @@ -2125,10 +2168,14 @@ QualType ASTContext::getObjCObjectPointerType(QualType InterfaceT, ObjCObjectPointerTypes.FindNodeOrInsertPos(ID, InsertPos); } - // No Match; - ObjCObjectPointerType *QType = new (*this, TypeAlignment) - ObjCObjectPointerType(*this, Canonical, InterfaceT, Protocols, - NumProtocols); + // No match. + unsigned Size = sizeof(ObjCObjectPointerType) + + NumProtocols * sizeof(ObjCProtocolDecl *); + void *Mem = Allocate(Size, TypeAlignment); + ObjCObjectPointerType *QType = new (Mem) ObjCObjectPointerType(Canonical, + InterfaceT, + Protocols, + NumProtocols); Types.push_back(QType); ObjCObjectPointerTypes.InsertNode(QType, InsertPos); @@ -2161,9 +2208,13 @@ QualType ASTContext::getObjCInterfaceType(const ObjCInterfaceDecl *Decl, ObjCInterfaceTypes.FindNodeOrInsertPos(ID, InsertPos); } - ObjCInterfaceType *QType = new (*this, TypeAlignment) - ObjCInterfaceType(*this, Canonical, const_cast<ObjCInterfaceDecl*>(Decl), - Protocols, NumProtocols); + unsigned Size = sizeof(ObjCInterfaceType) + + NumProtocols * sizeof(ObjCProtocolDecl *); + void *Mem = Allocate(Size, TypeAlignment); + ObjCInterfaceType *QType = new (Mem) ObjCInterfaceType(Canonical, + const_cast<ObjCInterfaceDecl*>(Decl), + Protocols, + NumProtocols); Types.push_back(QType); ObjCInterfaceTypes.InsertNode(QType, InsertPos); @@ -2858,6 +2909,7 @@ QualType ASTContext::getCFConstantStringType() { CFConstantStringTypeDecl = CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), &Idents.get("NSConstantString")); + CFConstantStringTypeDecl->startDefinition(); QualType FieldTypes[4]; @@ -2880,7 +2932,7 @@ QualType ASTContext::getCFConstantStringType() { CFConstantStringTypeDecl->addDecl(Field); } - CFConstantStringTypeDecl->completeDefinition(*this); + CFConstantStringTypeDecl->completeDefinition(); } return getTagDeclType(CFConstantStringTypeDecl); @@ -2897,6 +2949,7 @@ QualType ASTContext::getObjCFastEnumerationStateType() { ObjCFastEnumerationStateTypeDecl = CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), &Idents.get("__objcFastEnumerationState")); + ObjCFastEnumerationStateTypeDecl->startDefinition(); QualType FieldTypes[] = { UnsignedLongTy, @@ -2916,7 +2969,7 @@ QualType ASTContext::getObjCFastEnumerationStateType() { ObjCFastEnumerationStateTypeDecl->addDecl(Field); } - ObjCFastEnumerationStateTypeDecl->completeDefinition(*this); + ObjCFastEnumerationStateTypeDecl->completeDefinition(); } return getTagDeclType(ObjCFastEnumerationStateTypeDecl); @@ -2930,6 +2983,7 @@ QualType ASTContext::getBlockDescriptorType() { // FIXME: Needs the FlagAppleBlock bit. T = CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), &Idents.get("__block_descriptor")); + T->startDefinition(); QualType FieldTypes[] = { UnsignedLongTy, @@ -2952,7 +3006,7 @@ QualType ASTContext::getBlockDescriptorType() { T->addDecl(Field); } - T->completeDefinition(*this); + T->completeDefinition(); BlockDescriptorType = T; @@ -2973,6 +3027,7 @@ QualType ASTContext::getBlockDescriptorExtendedType() { // FIXME: Needs the FlagAppleBlock bit. T = CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), &Idents.get("__block_descriptor_withcopydispose")); + T->startDefinition(); QualType FieldTypes[] = { UnsignedLongTy, @@ -2999,7 +3054,7 @@ QualType ASTContext::getBlockDescriptorExtendedType() { T->addDecl(Field); } - T->completeDefinition(*this); + T->completeDefinition(); BlockDescriptorExtendedType = T; @@ -3076,7 +3131,7 @@ QualType ASTContext::BuildByRefType(const char *DeclName, QualType Ty) { T->addDecl(Field); } - T->completeDefinition(*this); + T->completeDefinition(); return getPointerType(getTagDeclType(T)); } @@ -3093,6 +3148,7 @@ QualType ASTContext::getBlockParmType( RecordDecl *T; T = CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), &Idents.get(Name.str())); + T->startDefinition(); QualType FieldTypes[] = { getPointerType(VoidPtrTy), IntTy, @@ -3139,7 +3195,7 @@ QualType ASTContext::getBlockParmType( T->addDecl(Field); } - T->completeDefinition(*this); + T->completeDefinition(); return getPointerType(getTagDeclType(T)); } @@ -3786,6 +3842,7 @@ TemplateName ASTContext::getOverloadedTemplateName(UnresolvedSetIterator Begin, TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS, bool TemplateKeyword, TemplateDecl *Template) { + // FIXME: Canonicalization? llvm::FoldingSetNodeID ID; QualifiedTemplateName::Profile(ID, NNS, TemplateKeyword, Template); @@ -3823,6 +3880,10 @@ TemplateName ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS, } else { TemplateName Canon = getDependentTemplateName(CanonNNS, Name); QTN = new (*this,4) DependentTemplateName(NNS, Name, Canon); + DependentTemplateName *CheckQTN = + DependentTemplateNames.FindNodeOrInsertPos(ID, InsertPos); + assert(!CheckQTN && "Dependent type name canonicalization broken"); + (void)CheckQTN; } DependentTemplateNames.InsertNode(QTN, InsertPos); @@ -3841,8 +3902,8 @@ ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS, DependentTemplateName::Profile(ID, NNS, Operator); void *InsertPos = 0; - DependentTemplateName *QTN = - DependentTemplateNames.FindNodeOrInsertPos(ID, InsertPos); + DependentTemplateName *QTN + = DependentTemplateNames.FindNodeOrInsertPos(ID, InsertPos); if (QTN) return TemplateName(QTN); @@ -3853,6 +3914,11 @@ ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS, } else { TemplateName Canon = getDependentTemplateName(CanonNNS, Operator); QTN = new (*this,4) DependentTemplateName(NNS, Operator, Canon); + + DependentTemplateName *CheckQTN + = DependentTemplateNames.FindNodeOrInsertPos(ID, InsertPos); + assert(!CheckQTN && "Dependent template name canonicalization broken"); + (void)CheckQTN; } DependentTemplateNames.InsertNode(QTN, InsertPos); @@ -4123,8 +4189,8 @@ void getIntersectionOfProtocols(ASTContext &Context, if (LHSNumProtocols > 0) InheritedProtocolSet.insert(LHS->qual_begin(), LHS->qual_end()); else { - llvm::SmallVector<ObjCProtocolDecl *, 8> LHSInheritedProtocols; - Context.CollectInheritedProtocols(LHS->getDecl(), LHSInheritedProtocols); + llvm::SmallPtrSet<ObjCProtocolDecl *, 8> LHSInheritedProtocols; + Context.CollectInheritedProtocols(LHS->getDecl(), LHSInheritedProtocols); InheritedProtocolSet.insert(LHSInheritedProtocols.begin(), LHSInheritedProtocols.end()); } @@ -4137,13 +4203,13 @@ void getIntersectionOfProtocols(ASTContext &Context, IntersectionOfProtocols.push_back(RHSProtocols[i]); } else { - llvm::SmallVector<ObjCProtocolDecl *, 8> RHSInheritedProtocols; + llvm::SmallPtrSet<ObjCProtocolDecl *, 8> RHSInheritedProtocols; Context.CollectInheritedProtocols(RHS->getDecl(), RHSInheritedProtocols); - // FIXME. This may cause duplication of protocols in the list, but should - // be harmless. - for (unsigned i = 0, len = RHSInheritedProtocols.size(); i < len; ++i) - if (InheritedProtocolSet.count(RHSInheritedProtocols[i])) - IntersectionOfProtocols.push_back(RHSInheritedProtocols[i]); + for (llvm::SmallPtrSet<ObjCProtocolDecl*,8>::iterator I = + RHSInheritedProtocols.begin(), + E = RHSInheritedProtocols.end(); I != E; ++I) + if (InheritedProtocolSet.count((*I))) + IntersectionOfProtocols.push_back((*I)); } } @@ -4235,13 +4301,12 @@ bool ASTContext::areComparableObjCPointerTypes(QualType LHS, QualType RHS) { /// C99 6.2.7p1: Two types have compatible types if their types are the /// same. See 6.7.[2,3,5] for additional rules. bool ASTContext::typesAreCompatible(QualType LHS, QualType RHS) { + if (getLangOptions().CPlusPlus) + return hasSameType(LHS, RHS); + return !mergeTypes(LHS, RHS).isNull(); } -static bool isSameCallingConvention(CallingConv lcc, CallingConv rcc) { - return (getCanonicalCallingConv(lcc) == getCanonicalCallingConv(rcc)); -} - QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) { const FunctionType *lbase = lhs->getAs<FunctionType>(); const FunctionType *rbase = rhs->getAs<FunctionType>(); @@ -4266,7 +4331,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) { CallingConv lcc = lbase->getCallConv(); CallingConv rcc = rbase->getCallConv(); // Compatible functions must have compatible calling conventions - if (!isSameCallingConvention(lcc, rcc)) + if (!isSameCallConv(lcc, rcc)) return QualType(); if (lproto && rproto) { // two C99 style function prototypes @@ -4303,7 +4368,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) { if (allRTypes) return rhs; return getFunctionType(retType, types.begin(), types.size(), lproto->isVariadic(), lproto->getTypeQuals(), - NoReturn, lcc); + false, false, 0, 0, NoReturn, lcc); } if (lproto) allRTypes = false; @@ -4321,6 +4386,12 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) { unsigned proto_nargs = proto->getNumArgs(); for (unsigned i = 0; i < proto_nargs; ++i) { QualType argTy = proto->getArgType(i); + + // Look at the promotion type of enum types, since that is the type used + // to pass enum values. + if (const EnumType *Enum = argTy->getAs<EnumType>()) + argTy = Enum->getDecl()->getPromotionType(); + if (argTy->isPromotableIntegerType() || getCanonicalType(argTy).getUnqualifiedType() == FloatTy) return QualType(); @@ -4344,15 +4415,9 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) { // designates the object or function denoted by the reference, and the // expression is an lvalue unless the reference is an rvalue reference and // the expression is a function call (possibly inside parentheses). - // FIXME: C++ shouldn't be going through here! The rules are different - // enough that they should be handled separately. - // FIXME: Merging of lvalue and rvalue references is incorrect. C++ *really* - // shouldn't be going through here! - if (const ReferenceType *RT = LHS->getAs<ReferenceType>()) - LHS = RT->getPointeeType(); - if (const ReferenceType *RT = RHS->getAs<ReferenceType>()) - RHS = RT->getPointeeType(); - + assert(!LHS->getAs<ReferenceType>() && "LHS is a reference type?"); + assert(!RHS->getAs<ReferenceType>() && "RHS is a reference type?"); + QualType LHSCan = getCanonicalType(LHS), RHSCan = getCanonicalType(RHS); @@ -4582,7 +4647,7 @@ QualType ASTContext::getCorrespondingUnsignedType(QualType T) { // Turn <4 x signed int> -> <4 x unsigned int> if (const VectorType *VTy = T->getAs<VectorType>()) return getVectorType(getCorrespondingUnsignedType(VTy->getElementType()), - VTy->getNumElements()); + VTy->getNumElements(), VTy->isAltiVec(), VTy->isPixel()); // For enums, we return the unsigned version of the base type. if (const EnumType *ETy = T->getAs<EnumType>()) @@ -4739,7 +4804,8 @@ static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context, Str = End; QualType ElementType = DecodeTypeFromStr(Str, Context, Error, false); - Type = Context.getVectorType(ElementType, NumElements); + // FIXME: Don't know what to do about AltiVec. + Type = Context.getVectorType(ElementType, NumElements, false, false); break; } case 'X': { @@ -4784,6 +4850,9 @@ static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context, case 'C': Type = Type.withConst(); break; + case 'D': + Type = Context.getVolatileType(Type); + break; } } diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp new file mode 100644 index 0000000..7402b7d --- /dev/null +++ b/lib/AST/ASTDiagnostic.cpp @@ -0,0 +1,266 @@ +//===--- ASTDiagnostic.cpp - Diagnostic Printing Hooks for AST Nodes ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements a diagnostic formatting hook for AST elements. +// +//===----------------------------------------------------------------------===// +#include "clang/AST/ASTDiagnostic.h" + +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/Type.h" +#include "llvm/Support/raw_ostream.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; + + // Don't desugar through the primary typedef of an anonymous type. + if (isa<TagType>(Underlying) && isa<TypedefType>(QT)) + if (cast<TagType>(Underlying)->getDecl()->getTypedefForAnonDecl() == + cast<TypedefType>(QT)->getDecl()) + 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, + const Diagnostic::ArgumentValue *PrevArgs, + unsigned NumPrevArgs) { + // FIXME: Playing with std::string is really slow. + std::string S = Ty.getAsString(Context.PrintingPolicy); + + // 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 += "')"; + return S; + } + + S = "'" + S + "'"; + return S; +} + +void clang::FormatASTNodeDiagnosticArgument(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; + + 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, PrevArgs, NumPrevArgs); + NeedQuotes = false; + break; + } + case Diagnostic::ak_declarationname: { + DeclarationName N = DeclarationName::getFromOpaqueInteger(Val); + S = N.getAsString(); + + if (ModLen == 9 && !memcmp(Modifier, "objcclass", 9) && ArgLen == 0) + S = '+' + S; + else if (ModLen == 12 && !memcmp(Modifier, "objcinstance", 12) + && ArgLen==0) + S = '-' + S; + else + assert(ModLen == 0 && ArgLen == 0 && + "Invalid modifier for DeclarationName argument"); + break; + } + case Diagnostic::ak_nameddecl: { + bool Qualified; + if (ModLen == 1 && Modifier[0] == 'q' && ArgLen == 0) + Qualified = true; + else { + assert(ModLen == 0 && ArgLen == 0 && + "Invalid modifier for NamedDecl* argument"); + Qualified = false; + } + 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); + NeedQuotes = false; + break; + } + case Diagnostic::ak_declcontext: { + DeclContext *DC = reinterpret_cast<DeclContext *> (Val); + 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), + PrevArgs, NumPrevArgs); + } else { + // FIXME: Get these strings from some localized place + NamedDecl *ND = cast<NamedDecl>(DC); + if (isa<NamespaceDecl>(ND)) + S += "namespace "; + else if (isa<ObjCMethodDecl>(ND)) + S += "method "; + else if (isa<FunctionDecl>(ND)) + S += "function "; + + S += "'"; + ND->getNameForDiagnostic(S, Context.PrintingPolicy, true); + S += "'"; + } + NeedQuotes = false; + break; + } + } + + if (NeedQuotes) + Output.push_back('\''); + + Output.append(S.begin(), S.end()); + + if (NeedQuotes) + Output.push_back('\''); +} diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp new file mode 100644 index 0000000..dee0d2b --- /dev/null +++ b/lib/AST/ASTImporter.cpp @@ -0,0 +1,2394 @@ +//===--- ASTImporter.cpp - Importing ASTs from other Contexts ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ASTImporter class which imports AST nodes from one +// context into another context. +// +//===----------------------------------------------------------------------===// +#include "clang/AST/ASTImporter.h" + +#include "clang/AST/ASTContext.h" +#include "clang/AST/ASTDiagnostic.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclVisitor.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/AST/TypeLoc.h" +#include "clang/AST/TypeVisitor.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/Support/MemoryBuffer.h" +#include <deque> + +using namespace clang; + +namespace { + class ASTNodeImporter : public TypeVisitor<ASTNodeImporter, QualType>, + public DeclVisitor<ASTNodeImporter, Decl *>, + public StmtVisitor<ASTNodeImporter, Stmt *> { + ASTImporter &Importer; + + public: + explicit ASTNodeImporter(ASTImporter &Importer) : Importer(Importer) { } + + using TypeVisitor<ASTNodeImporter, QualType>::Visit; + using DeclVisitor<ASTNodeImporter, Decl *>::Visit; + using StmtVisitor<ASTNodeImporter, Stmt *>::Visit; + + // Importing types + QualType VisitType(Type *T); + QualType VisitBuiltinType(BuiltinType *T); + QualType VisitComplexType(ComplexType *T); + QualType VisitPointerType(PointerType *T); + QualType VisitBlockPointerType(BlockPointerType *T); + QualType VisitLValueReferenceType(LValueReferenceType *T); + QualType VisitRValueReferenceType(RValueReferenceType *T); + QualType VisitMemberPointerType(MemberPointerType *T); + QualType VisitConstantArrayType(ConstantArrayType *T); + QualType VisitIncompleteArrayType(IncompleteArrayType *T); + QualType VisitVariableArrayType(VariableArrayType *T); + // FIXME: DependentSizedArrayType + // FIXME: DependentSizedExtVectorType + QualType VisitVectorType(VectorType *T); + QualType VisitExtVectorType(ExtVectorType *T); + QualType VisitFunctionNoProtoType(FunctionNoProtoType *T); + QualType VisitFunctionProtoType(FunctionProtoType *T); + // FIXME: UnresolvedUsingType + QualType VisitTypedefType(TypedefType *T); + QualType VisitTypeOfExprType(TypeOfExprType *T); + // FIXME: DependentTypeOfExprType + QualType VisitTypeOfType(TypeOfType *T); + QualType VisitDecltypeType(DecltypeType *T); + // FIXME: DependentDecltypeType + QualType VisitRecordType(RecordType *T); + QualType VisitEnumType(EnumType *T); + QualType VisitElaboratedType(ElaboratedType *T); + // FIXME: TemplateTypeParmType + // FIXME: SubstTemplateTypeParmType + // FIXME: TemplateSpecializationType + QualType VisitQualifiedNameType(QualifiedNameType *T); + // FIXME: TypenameType + QualType VisitObjCInterfaceType(ObjCInterfaceType *T); + QualType VisitObjCObjectPointerType(ObjCObjectPointerType *T); + + // Importing declarations + bool ImportDeclParts(NamedDecl *D, DeclContext *&DC, + DeclContext *&LexicalDC, DeclarationName &Name, + SourceLocation &Loc); + bool IsStructuralMatch(RecordDecl *FromRecord, RecordDecl *ToRecord); + bool IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToRecord); + Decl *VisitDecl(Decl *D); + Decl *VisitTypedefDecl(TypedefDecl *D); + Decl *VisitEnumDecl(EnumDecl *D); + Decl *VisitRecordDecl(RecordDecl *D); + Decl *VisitEnumConstantDecl(EnumConstantDecl *D); + Decl *VisitFunctionDecl(FunctionDecl *D); + Decl *VisitFieldDecl(FieldDecl *D); + Decl *VisitVarDecl(VarDecl *D); + Decl *VisitParmVarDecl(ParmVarDecl *D); + Decl *VisitObjCInterfaceDecl(ObjCInterfaceDecl *D); + + // Importing statements + Stmt *VisitStmt(Stmt *S); + + // Importing expressions + Expr *VisitExpr(Expr *E); + Expr *VisitIntegerLiteral(IntegerLiteral *E); + Expr *VisitImplicitCastExpr(ImplicitCastExpr *E); + }; +} + +//---------------------------------------------------------------------------- +// Structural Equivalence +//---------------------------------------------------------------------------- + +namespace { + struct StructuralEquivalenceContext { + /// \brief AST contexts for which we are checking structural equivalence. + ASTContext &C1, &C2; + + /// \brief Diagnostic object used to emit diagnostics. + Diagnostic &Diags; + + /// \brief The set of "tentative" equivalences between two canonical + /// declarations, mapping from a declaration in the first context to the + /// declaration in the second context that we believe to be equivalent. + llvm::DenseMap<Decl *, Decl *> TentativeEquivalences; + + /// \brief Queue of declarations in the first context whose equivalence + /// with a declaration in the second context still needs to be verified. + std::deque<Decl *> DeclsToCheck; + + /// \brief Declaration (from, to) pairs that are known not to be equivalent + /// (which we have already complained about). + llvm::DenseSet<std::pair<Decl *, Decl *> > &NonEquivalentDecls; + + /// \brief Whether we're being strict about the spelling of types when + /// unifying two types. + bool StrictTypeSpelling; + + StructuralEquivalenceContext(ASTContext &C1, ASTContext &C2, + Diagnostic &Diags, + llvm::DenseSet<std::pair<Decl *, Decl *> > &NonEquivalentDecls, + bool StrictTypeSpelling = false) + : C1(C1), C2(C2), Diags(Diags), NonEquivalentDecls(NonEquivalentDecls), + StrictTypeSpelling(StrictTypeSpelling) { } + + /// \brief Determine whether the two declarations are structurally + /// equivalent. + bool IsStructurallyEquivalent(Decl *D1, Decl *D2); + + /// \brief Determine whether the two types are structurally equivalent. + bool IsStructurallyEquivalent(QualType T1, QualType T2); + + private: + /// \brief Finish checking all of the structural equivalences. + /// + /// \returns true if an error occurred, false otherwise. + bool Finish(); + + public: + DiagnosticBuilder Diag1(SourceLocation Loc, unsigned DiagID) { + return Diags.Report(FullSourceLoc(Loc, C1.getSourceManager()), DiagID); + } + + DiagnosticBuilder Diag2(SourceLocation Loc, unsigned DiagID) { + return Diags.Report(FullSourceLoc(Loc, C2.getSourceManager()), DiagID); + } + }; +} + +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + QualType T1, QualType T2); +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + Decl *D1, Decl *D2); + +/// \brief Determine if two APInts have the same value, after zero-extending +/// one of them (if needed!) to ensure that the bit-widths match. +static bool IsSameValue(const llvm::APInt &I1, const llvm::APInt &I2) { + if (I1.getBitWidth() == I2.getBitWidth()) + return I1 == I2; + + if (I1.getBitWidth() > I2.getBitWidth()) + return I1 == llvm::APInt(I2).zext(I1.getBitWidth()); + + return llvm::APInt(I1).zext(I2.getBitWidth()) == I2; +} + +/// \brief Determine if two APSInts have the same value, zero- or sign-extending +/// as needed. +static bool IsSameValue(const llvm::APSInt &I1, const llvm::APSInt &I2) { + if (I1.getBitWidth() == I2.getBitWidth() && I1.isSigned() == I2.isSigned()) + return I1 == I2; + + // Check for a bit-width mismatch. + if (I1.getBitWidth() > I2.getBitWidth()) + return IsSameValue(I1, llvm::APSInt(I2).extend(I1.getBitWidth())); + else if (I2.getBitWidth() > I1.getBitWidth()) + return IsSameValue(llvm::APSInt(I1).extend(I2.getBitWidth()), I2); + + // We have a signedness mismatch. Turn the signed value into an unsigned + // value. + if (I1.isSigned()) { + if (I1.isNegative()) + return false; + + return llvm::APSInt(I1, true) == I2; + } + + if (I2.isNegative()) + return false; + + return I1 == llvm::APSInt(I2, true); +} + +/// \brief Determine structural equivalence of two expressions. +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + Expr *E1, Expr *E2) { + if (!E1 || !E2) + return E1 == E2; + + // FIXME: Actually perform a structural comparison! + return true; +} + +/// \brief Determine whether two identifiers are equivalent. +static bool IsStructurallyEquivalent(const IdentifierInfo *Name1, + const IdentifierInfo *Name2) { + if (!Name1 || !Name2) + return Name1 == Name2; + + return Name1->getName() == Name2->getName(); +} + +/// \brief Determine whether two nested-name-specifiers are equivalent. +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + NestedNameSpecifier *NNS1, + NestedNameSpecifier *NNS2) { + // FIXME: Implement! + return true; +} + +/// \brief Determine whether two template arguments are equivalent. +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + const TemplateArgument &Arg1, + const TemplateArgument &Arg2) { + // FIXME: Implement! + return true; +} + +/// \brief Determine structural equivalence for the common part of array +/// types. +static bool IsArrayStructurallyEquivalent(StructuralEquivalenceContext &Context, + const ArrayType *Array1, + const ArrayType *Array2) { + if (!IsStructurallyEquivalent(Context, + Array1->getElementType(), + Array2->getElementType())) + return false; + if (Array1->getSizeModifier() != Array2->getSizeModifier()) + return false; + if (Array1->getIndexTypeQualifiers() != Array2->getIndexTypeQualifiers()) + return false; + + return true; +} + +/// \brief Determine structural equivalence of two types. +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + QualType T1, QualType T2) { + if (T1.isNull() || T2.isNull()) + return T1.isNull() && T2.isNull(); + + if (!Context.StrictTypeSpelling) { + // We aren't being strict about token-to-token equivalence of types, + // so map down to the canonical type. + T1 = Context.C1.getCanonicalType(T1); + T2 = Context.C2.getCanonicalType(T2); + } + + if (T1.getQualifiers() != T2.getQualifiers()) + return false; + + Type::TypeClass TC = T1->getTypeClass(); + + if (T1->getTypeClass() != T2->getTypeClass()) { + // Compare function types with prototypes vs. without prototypes as if + // both did not have prototypes. + if (T1->getTypeClass() == Type::FunctionProto && + T2->getTypeClass() == Type::FunctionNoProto) + TC = Type::FunctionNoProto; + else if (T1->getTypeClass() == Type::FunctionNoProto && + T2->getTypeClass() == Type::FunctionProto) + TC = Type::FunctionNoProto; + else + return false; + } + + switch (TC) { + case Type::Builtin: + // FIXME: Deal with Char_S/Char_U. + if (cast<BuiltinType>(T1)->getKind() != cast<BuiltinType>(T2)->getKind()) + return false; + break; + + case Type::Complex: + if (!IsStructurallyEquivalent(Context, + cast<ComplexType>(T1)->getElementType(), + cast<ComplexType>(T2)->getElementType())) + return false; + break; + + case Type::Pointer: + if (!IsStructurallyEquivalent(Context, + cast<PointerType>(T1)->getPointeeType(), + cast<PointerType>(T2)->getPointeeType())) + return false; + break; + + case Type::BlockPointer: + if (!IsStructurallyEquivalent(Context, + cast<BlockPointerType>(T1)->getPointeeType(), + cast<BlockPointerType>(T2)->getPointeeType())) + return false; + break; + + case Type::LValueReference: + case Type::RValueReference: { + const ReferenceType *Ref1 = cast<ReferenceType>(T1); + const ReferenceType *Ref2 = cast<ReferenceType>(T2); + if (Ref1->isSpelledAsLValue() != Ref2->isSpelledAsLValue()) + return false; + if (Ref1->isInnerRef() != Ref2->isInnerRef()) + return false; + if (!IsStructurallyEquivalent(Context, + Ref1->getPointeeTypeAsWritten(), + Ref2->getPointeeTypeAsWritten())) + return false; + break; + } + + case Type::MemberPointer: { + const MemberPointerType *MemPtr1 = cast<MemberPointerType>(T1); + const MemberPointerType *MemPtr2 = cast<MemberPointerType>(T2); + if (!IsStructurallyEquivalent(Context, + MemPtr1->getPointeeType(), + MemPtr2->getPointeeType())) + return false; + if (!IsStructurallyEquivalent(Context, + QualType(MemPtr1->getClass(), 0), + QualType(MemPtr2->getClass(), 0))) + return false; + break; + } + + case Type::ConstantArray: { + const ConstantArrayType *Array1 = cast<ConstantArrayType>(T1); + const ConstantArrayType *Array2 = cast<ConstantArrayType>(T2); + if (!IsSameValue(Array1->getSize(), Array2->getSize())) + return false; + + if (!IsArrayStructurallyEquivalent(Context, Array1, Array2)) + return false; + break; + } + + case Type::IncompleteArray: + if (!IsArrayStructurallyEquivalent(Context, + cast<ArrayType>(T1), + cast<ArrayType>(T2))) + return false; + break; + + case Type::VariableArray: { + const VariableArrayType *Array1 = cast<VariableArrayType>(T1); + const VariableArrayType *Array2 = cast<VariableArrayType>(T2); + if (!IsStructurallyEquivalent(Context, + Array1->getSizeExpr(), Array2->getSizeExpr())) + return false; + + if (!IsArrayStructurallyEquivalent(Context, Array1, Array2)) + return false; + + break; + } + + case Type::DependentSizedArray: { + const DependentSizedArrayType *Array1 = cast<DependentSizedArrayType>(T1); + const DependentSizedArrayType *Array2 = cast<DependentSizedArrayType>(T2); + if (!IsStructurallyEquivalent(Context, + Array1->getSizeExpr(), Array2->getSizeExpr())) + return false; + + if (!IsArrayStructurallyEquivalent(Context, Array1, Array2)) + return false; + + break; + } + + case Type::DependentSizedExtVector: { + const DependentSizedExtVectorType *Vec1 + = cast<DependentSizedExtVectorType>(T1); + const DependentSizedExtVectorType *Vec2 + = cast<DependentSizedExtVectorType>(T2); + if (!IsStructurallyEquivalent(Context, + Vec1->getSizeExpr(), Vec2->getSizeExpr())) + return false; + if (!IsStructurallyEquivalent(Context, + Vec1->getElementType(), + Vec2->getElementType())) + return false; + break; + } + + case Type::Vector: + case Type::ExtVector: { + const VectorType *Vec1 = cast<VectorType>(T1); + const VectorType *Vec2 = cast<VectorType>(T2); + if (!IsStructurallyEquivalent(Context, + Vec1->getElementType(), + Vec2->getElementType())) + return false; + if (Vec1->getNumElements() != Vec2->getNumElements()) + return false; + if (Vec1->isAltiVec() != Vec2->isAltiVec()) + return false; + if (Vec1->isPixel() != Vec2->isPixel()) + return false; + } + + case Type::FunctionProto: { + const FunctionProtoType *Proto1 = cast<FunctionProtoType>(T1); + const FunctionProtoType *Proto2 = cast<FunctionProtoType>(T2); + if (Proto1->getNumArgs() != Proto2->getNumArgs()) + return false; + for (unsigned I = 0, N = Proto1->getNumArgs(); I != N; ++I) { + if (!IsStructurallyEquivalent(Context, + Proto1->getArgType(I), + Proto2->getArgType(I))) + return false; + } + if (Proto1->isVariadic() != Proto2->isVariadic()) + return false; + if (Proto1->hasExceptionSpec() != Proto2->hasExceptionSpec()) + return false; + if (Proto1->hasAnyExceptionSpec() != Proto2->hasAnyExceptionSpec()) + return false; + if (Proto1->getNumExceptions() != Proto2->getNumExceptions()) + return false; + for (unsigned I = 0, N = Proto1->getNumExceptions(); I != N; ++I) { + if (!IsStructurallyEquivalent(Context, + Proto1->getExceptionType(I), + Proto2->getExceptionType(I))) + return false; + } + if (Proto1->getTypeQuals() != Proto2->getTypeQuals()) + return false; + + // Fall through to check the bits common with FunctionNoProtoType. + } + + case Type::FunctionNoProto: { + const FunctionType *Function1 = cast<FunctionType>(T1); + const FunctionType *Function2 = cast<FunctionType>(T2); + if (!IsStructurallyEquivalent(Context, + Function1->getResultType(), + Function2->getResultType())) + return false; + if (Function1->getNoReturnAttr() != Function2->getNoReturnAttr()) + return false; + if (Function1->getCallConv() != Function2->getCallConv()) + return false; + break; + } + + case Type::UnresolvedUsing: + if (!IsStructurallyEquivalent(Context, + cast<UnresolvedUsingType>(T1)->getDecl(), + cast<UnresolvedUsingType>(T2)->getDecl())) + return false; + + break; + + case Type::Typedef: + if (!IsStructurallyEquivalent(Context, + cast<TypedefType>(T1)->getDecl(), + cast<TypedefType>(T2)->getDecl())) + return false; + break; + + case Type::TypeOfExpr: + if (!IsStructurallyEquivalent(Context, + cast<TypeOfExprType>(T1)->getUnderlyingExpr(), + cast<TypeOfExprType>(T2)->getUnderlyingExpr())) + return false; + break; + + case Type::TypeOf: + if (!IsStructurallyEquivalent(Context, + cast<TypeOfType>(T1)->getUnderlyingType(), + cast<TypeOfType>(T2)->getUnderlyingType())) + return false; + break; + + case Type::Decltype: + if (!IsStructurallyEquivalent(Context, + cast<DecltypeType>(T1)->getUnderlyingExpr(), + cast<DecltypeType>(T2)->getUnderlyingExpr())) + return false; + break; + + case Type::Record: + case Type::Enum: + if (!IsStructurallyEquivalent(Context, + cast<TagType>(T1)->getDecl(), + cast<TagType>(T2)->getDecl())) + return false; + break; + + case Type::Elaborated: { + const ElaboratedType *Elab1 = cast<ElaboratedType>(T1); + const ElaboratedType *Elab2 = cast<ElaboratedType>(T2); + if (Elab1->getTagKind() != Elab2->getTagKind()) + return false; + if (!IsStructurallyEquivalent(Context, + Elab1->getUnderlyingType(), + Elab2->getUnderlyingType())) + return false; + break; + } + + case Type::TemplateTypeParm: { + const TemplateTypeParmType *Parm1 = cast<TemplateTypeParmType>(T1); + const TemplateTypeParmType *Parm2 = cast<TemplateTypeParmType>(T2); + if (Parm1->getDepth() != Parm2->getDepth()) + return false; + if (Parm1->getIndex() != Parm2->getIndex()) + return false; + if (Parm1->isParameterPack() != Parm2->isParameterPack()) + return false; + + // Names of template type parameters are never significant. + break; + } + + case Type::SubstTemplateTypeParm: { + const SubstTemplateTypeParmType *Subst1 + = cast<SubstTemplateTypeParmType>(T1); + const SubstTemplateTypeParmType *Subst2 + = cast<SubstTemplateTypeParmType>(T2); + if (!IsStructurallyEquivalent(Context, + QualType(Subst1->getReplacedParameter(), 0), + QualType(Subst2->getReplacedParameter(), 0))) + return false; + if (!IsStructurallyEquivalent(Context, + Subst1->getReplacementType(), + Subst2->getReplacementType())) + return false; + break; + } + + case Type::TemplateSpecialization: { + const TemplateSpecializationType *Spec1 + = cast<TemplateSpecializationType>(T1); + const TemplateSpecializationType *Spec2 + = cast<TemplateSpecializationType>(T2); + if (!IsStructurallyEquivalent(Context, + Spec1->getTemplateName(), + Spec2->getTemplateName())) + return false; + if (Spec1->getNumArgs() != Spec2->getNumArgs()) + return false; + for (unsigned I = 0, N = Spec1->getNumArgs(); I != N; ++I) { + if (!IsStructurallyEquivalent(Context, + Spec1->getArg(I), Spec2->getArg(I))) + return false; + } + break; + } + + case Type::QualifiedName: { + const QualifiedNameType *Qual1 = cast<QualifiedNameType>(T1); + const QualifiedNameType *Qual2 = cast<QualifiedNameType>(T2); + if (!IsStructurallyEquivalent(Context, + Qual1->getQualifier(), + Qual2->getQualifier())) + return false; + if (!IsStructurallyEquivalent(Context, + Qual1->getNamedType(), + Qual2->getNamedType())) + return false; + break; + } + + case Type::Typename: { + const TypenameType *Typename1 = cast<TypenameType>(T1); + const TypenameType *Typename2 = cast<TypenameType>(T2); + if (!IsStructurallyEquivalent(Context, + Typename1->getQualifier(), + Typename2->getQualifier())) + return false; + if (!IsStructurallyEquivalent(Typename1->getIdentifier(), + Typename2->getIdentifier())) + return false; + if (!IsStructurallyEquivalent(Context, + QualType(Typename1->getTemplateId(), 0), + QualType(Typename2->getTemplateId(), 0))) + return false; + + break; + } + + case Type::ObjCInterface: { + const ObjCInterfaceType *Iface1 = cast<ObjCInterfaceType>(T1); + const ObjCInterfaceType *Iface2 = cast<ObjCInterfaceType>(T2); + if (!IsStructurallyEquivalent(Context, + Iface1->getDecl(), Iface2->getDecl())) + return false; + if (Iface1->getNumProtocols() != Iface2->getNumProtocols()) + return false; + for (unsigned I = 0, N = Iface1->getNumProtocols(); I != N; ++I) { + if (!IsStructurallyEquivalent(Context, + Iface1->getProtocol(I), + Iface2->getProtocol(I))) + return false; + } + break; + } + + case Type::ObjCObjectPointer: { + const ObjCObjectPointerType *Ptr1 = cast<ObjCObjectPointerType>(T1); + const ObjCObjectPointerType *Ptr2 = cast<ObjCObjectPointerType>(T2); + if (!IsStructurallyEquivalent(Context, + Ptr1->getPointeeType(), + Ptr2->getPointeeType())) + return false; + if (Ptr1->getNumProtocols() != Ptr2->getNumProtocols()) + return false; + for (unsigned I = 0, N = Ptr1->getNumProtocols(); I != N; ++I) { + if (!IsStructurallyEquivalent(Context, + Ptr1->getProtocol(I), + Ptr2->getProtocol(I))) + return false; + } + break; + } + + } // end switch + + return true; +} + +/// \brief Determine structural equivalence of two records. +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + RecordDecl *D1, RecordDecl *D2) { + if (D1->isUnion() != D2->isUnion()) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag1(D1->getLocation(), diag::note_odr_tag_kind_here) + << D1->getDeclName() << (unsigned)D1->getTagKind(); + return false; + } + + // Compare the definitions of these two records. If either or both are + // incomplete, we assume that they are equivalent. + D1 = D1->getDefinition(); + D2 = D2->getDefinition(); + if (!D1 || !D2) + return true; + + if (CXXRecordDecl *D1CXX = dyn_cast<CXXRecordDecl>(D1)) { + if (CXXRecordDecl *D2CXX = dyn_cast<CXXRecordDecl>(D2)) { + if (D1CXX->getNumBases() != D2CXX->getNumBases()) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag2(D2->getLocation(), diag::note_odr_number_of_bases) + << D2CXX->getNumBases(); + Context.Diag1(D1->getLocation(), diag::note_odr_number_of_bases) + << D1CXX->getNumBases(); + return false; + } + + // Check the base classes. + for (CXXRecordDecl::base_class_iterator Base1 = D1CXX->bases_begin(), + BaseEnd1 = D1CXX->bases_end(), + Base2 = D2CXX->bases_begin(); + Base1 != BaseEnd1; + ++Base1, ++Base2) { + if (!IsStructurallyEquivalent(Context, + Base1->getType(), Base2->getType())) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag2(Base2->getSourceRange().getBegin(), diag::note_odr_base) + << Base2->getType() + << Base2->getSourceRange(); + Context.Diag1(Base1->getSourceRange().getBegin(), diag::note_odr_base) + << Base1->getType() + << Base1->getSourceRange(); + return false; + } + + // Check virtual vs. non-virtual inheritance mismatch. + if (Base1->isVirtual() != Base2->isVirtual()) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag2(Base2->getSourceRange().getBegin(), + diag::note_odr_virtual_base) + << Base2->isVirtual() << Base2->getSourceRange(); + Context.Diag1(Base1->getSourceRange().getBegin(), diag::note_odr_base) + << Base1->isVirtual() + << Base1->getSourceRange(); + return false; + } + } + } else if (D1CXX->getNumBases() > 0) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + const CXXBaseSpecifier *Base1 = D1CXX->bases_begin(); + Context.Diag1(Base1->getSourceRange().getBegin(), diag::note_odr_base) + << Base1->getType() + << Base1->getSourceRange(); + Context.Diag2(D2->getLocation(), diag::note_odr_missing_base); + return false; + } + } + + // Check the fields for consistency. + CXXRecordDecl::field_iterator Field2 = D2->field_begin(), + Field2End = D2->field_end(); + for (CXXRecordDecl::field_iterator Field1 = D1->field_begin(), + Field1End = D1->field_end(); + Field1 != Field1End; + ++Field1, ++Field2) { + if (Field2 == Field2End) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag1(Field1->getLocation(), diag::note_odr_field) + << Field1->getDeclName() << Field1->getType(); + Context.Diag2(D2->getLocation(), diag::note_odr_missing_field); + return false; + } + + if (!IsStructurallyEquivalent(Context, + Field1->getType(), Field2->getType())) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag2(Field2->getLocation(), diag::note_odr_field) + << Field2->getDeclName() << Field2->getType(); + Context.Diag1(Field1->getLocation(), diag::note_odr_field) + << Field1->getDeclName() << Field1->getType(); + return false; + } + + if (Field1->isBitField() != Field2->isBitField()) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + if (Field1->isBitField()) { + llvm::APSInt Bits; + Field1->getBitWidth()->isIntegerConstantExpr(Bits, Context.C1); + Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field) + << Field1->getDeclName() << Field1->getType() + << Bits.toString(10, false); + Context.Diag2(Field2->getLocation(), diag::note_odr_not_bit_field) + << Field2->getDeclName(); + } else { + llvm::APSInt Bits; + Field2->getBitWidth()->isIntegerConstantExpr(Bits, Context.C2); + Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field) + << Field2->getDeclName() << Field2->getType() + << Bits.toString(10, false); + Context.Diag1(Field1->getLocation(), + diag::note_odr_not_bit_field) + << Field1->getDeclName(); + } + return false; + } + + if (Field1->isBitField()) { + // Make sure that the bit-fields are the same length. + llvm::APSInt Bits1, Bits2; + if (!Field1->getBitWidth()->isIntegerConstantExpr(Bits1, Context.C1)) + return false; + if (!Field2->getBitWidth()->isIntegerConstantExpr(Bits2, Context.C2)) + return false; + + if (!IsSameValue(Bits1, Bits2)) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field) + << Field2->getDeclName() << Field2->getType() + << Bits2.toString(10, false); + Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field) + << Field1->getDeclName() << Field1->getType() + << Bits1.toString(10, false); + return false; + } + } + } + + if (Field2 != Field2End) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag2(Field2->getLocation(), diag::note_odr_field) + << Field2->getDeclName() << Field2->getType(); + Context.Diag1(D1->getLocation(), diag::note_odr_missing_field); + return false; + } + + return true; +} + +/// \brief Determine structural equivalence of two enums. +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + EnumDecl *D1, EnumDecl *D2) { + EnumDecl::enumerator_iterator EC2 = D2->enumerator_begin(), + EC2End = D2->enumerator_end(); + for (EnumDecl::enumerator_iterator EC1 = D1->enumerator_begin(), + EC1End = D1->enumerator_end(); + EC1 != EC1End; ++EC1, ++EC2) { + if (EC2 == EC2End) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator) + << EC1->getDeclName() + << EC1->getInitVal().toString(10); + Context.Diag2(D2->getLocation(), diag::note_odr_missing_enumerator); + return false; + } + + llvm::APSInt Val1 = EC1->getInitVal(); + llvm::APSInt Val2 = EC2->getInitVal(); + if (!IsSameValue(Val1, Val2) || + !IsStructurallyEquivalent(EC1->getIdentifier(), EC2->getIdentifier())) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator) + << EC2->getDeclName() + << EC2->getInitVal().toString(10); + Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator) + << EC1->getDeclName() + << EC1->getInitVal().toString(10); + return false; + } + } + + if (EC2 != EC2End) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator) + << EC2->getDeclName() + << EC2->getInitVal().toString(10); + Context.Diag1(D1->getLocation(), diag::note_odr_missing_enumerator); + return false; + } + + return true; +} + +/// \brief Determine structural equivalence of two declarations. +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + Decl *D1, Decl *D2) { + // FIXME: Check for known structural equivalences via a callback of some sort. + + // Check whether we already know that these two declarations are not + // structurally equivalent. + if (Context.NonEquivalentDecls.count(std::make_pair(D1->getCanonicalDecl(), + D2->getCanonicalDecl()))) + return false; + + // Determine whether we've already produced a tentative equivalence for D1. + Decl *&EquivToD1 = Context.TentativeEquivalences[D1->getCanonicalDecl()]; + if (EquivToD1) + return EquivToD1 == D2->getCanonicalDecl(); + + // Produce a tentative equivalence D1 <-> D2, which will be checked later. + EquivToD1 = D2->getCanonicalDecl(); + Context.DeclsToCheck.push_back(D1->getCanonicalDecl()); + return true; +} + +bool StructuralEquivalenceContext::IsStructurallyEquivalent(Decl *D1, + Decl *D2) { + if (!::IsStructurallyEquivalent(*this, D1, D2)) + return false; + + return !Finish(); +} + +bool StructuralEquivalenceContext::IsStructurallyEquivalent(QualType T1, + QualType T2) { + if (!::IsStructurallyEquivalent(*this, T1, T2)) + return false; + + return !Finish(); +} + +bool StructuralEquivalenceContext::Finish() { + while (!DeclsToCheck.empty()) { + // Check the next declaration. + Decl *D1 = DeclsToCheck.front(); + DeclsToCheck.pop_front(); + + Decl *D2 = TentativeEquivalences[D1]; + assert(D2 && "Unrecorded tentative equivalence?"); + + bool Equivalent = true; + + // FIXME: Switch on all declaration kinds. For now, we're just going to + // check the obvious ones. + if (RecordDecl *Record1 = dyn_cast<RecordDecl>(D1)) { + if (RecordDecl *Record2 = dyn_cast<RecordDecl>(D2)) { + // Check for equivalent structure names. + IdentifierInfo *Name1 = Record1->getIdentifier(); + if (!Name1 && Record1->getTypedefForAnonDecl()) + Name1 = Record1->getTypedefForAnonDecl()->getIdentifier(); + IdentifierInfo *Name2 = Record2->getIdentifier(); + if (!Name2 && Record2->getTypedefForAnonDecl()) + Name2 = Record2->getTypedefForAnonDecl()->getIdentifier(); + if (!::IsStructurallyEquivalent(Name1, Name2) || + !::IsStructurallyEquivalent(*this, Record1, Record2)) + Equivalent = false; + } else { + // Record/non-record mismatch. + Equivalent = false; + } + } else if (EnumDecl *Enum1 = dyn_cast<EnumDecl>(D1)) { + if (EnumDecl *Enum2 = dyn_cast<EnumDecl>(D2)) { + // Check for equivalent enum names. + IdentifierInfo *Name1 = Enum1->getIdentifier(); + if (!Name1 && Enum1->getTypedefForAnonDecl()) + Name1 = Enum1->getTypedefForAnonDecl()->getIdentifier(); + IdentifierInfo *Name2 = Enum2->getIdentifier(); + if (!Name2 && Enum2->getTypedefForAnonDecl()) + Name2 = Enum2->getTypedefForAnonDecl()->getIdentifier(); + if (!::IsStructurallyEquivalent(Name1, Name2) || + !::IsStructurallyEquivalent(*this, Enum1, Enum2)) + Equivalent = false; + } else { + // Enum/non-enum mismatch + Equivalent = false; + } + } else if (TypedefDecl *Typedef1 = dyn_cast<TypedefDecl>(D1)) { + if (TypedefDecl *Typedef2 = dyn_cast<TypedefDecl>(D2)) { + if (!::IsStructurallyEquivalent(Typedef1->getIdentifier(), + Typedef2->getIdentifier()) || + !::IsStructurallyEquivalent(*this, + Typedef1->getUnderlyingType(), + Typedef2->getUnderlyingType())) + Equivalent = false; + } else { + // Typedef/non-typedef mismatch. + Equivalent = false; + } + } + + if (!Equivalent) { + // Note that these two declarations are not equivalent (and we already + // know about it). + NonEquivalentDecls.insert(std::make_pair(D1->getCanonicalDecl(), + D2->getCanonicalDecl())); + return true; + } + // FIXME: Check other declaration kinds! + } + + return false; +} + +//---------------------------------------------------------------------------- +// Import Types +//---------------------------------------------------------------------------- + +QualType ASTNodeImporter::VisitType(Type *T) { + Importer.FromDiag(SourceLocation(), diag::err_unsupported_ast_node) + << T->getTypeClassName(); + return QualType(); +} + +QualType ASTNodeImporter::VisitBuiltinType(BuiltinType *T) { + switch (T->getKind()) { + case BuiltinType::Void: return Importer.getToContext().VoidTy; + case BuiltinType::Bool: return Importer.getToContext().BoolTy; + + case BuiltinType::Char_U: + // The context we're importing from has an unsigned 'char'. If we're + // importing into a context with a signed 'char', translate to + // 'unsigned char' instead. + if (Importer.getToContext().getLangOptions().CharIsSigned) + return Importer.getToContext().UnsignedCharTy; + + return Importer.getToContext().CharTy; + + case BuiltinType::UChar: return Importer.getToContext().UnsignedCharTy; + + case BuiltinType::Char16: + // FIXME: Make sure that the "to" context supports C++! + return Importer.getToContext().Char16Ty; + + case BuiltinType::Char32: + // FIXME: Make sure that the "to" context supports C++! + return Importer.getToContext().Char32Ty; + + case BuiltinType::UShort: return Importer.getToContext().UnsignedShortTy; + case BuiltinType::UInt: return Importer.getToContext().UnsignedIntTy; + case BuiltinType::ULong: return Importer.getToContext().UnsignedLongTy; + case BuiltinType::ULongLong: + return Importer.getToContext().UnsignedLongLongTy; + case BuiltinType::UInt128: return Importer.getToContext().UnsignedInt128Ty; + + case BuiltinType::Char_S: + // The context we're importing from has an unsigned 'char'. If we're + // importing into a context with a signed 'char', translate to + // 'unsigned char' instead. + if (!Importer.getToContext().getLangOptions().CharIsSigned) + return Importer.getToContext().SignedCharTy; + + return Importer.getToContext().CharTy; + + case BuiltinType::SChar: return Importer.getToContext().SignedCharTy; + case BuiltinType::WChar: + // FIXME: If not in C++, shall we translate to the C equivalent of + // wchar_t? + return Importer.getToContext().WCharTy; + + case BuiltinType::Short : return Importer.getToContext().ShortTy; + case BuiltinType::Int : return Importer.getToContext().IntTy; + case BuiltinType::Long : return Importer.getToContext().LongTy; + case BuiltinType::LongLong : return Importer.getToContext().LongLongTy; + case BuiltinType::Int128 : return Importer.getToContext().Int128Ty; + case BuiltinType::Float: return Importer.getToContext().FloatTy; + case BuiltinType::Double: return Importer.getToContext().DoubleTy; + case BuiltinType::LongDouble: return Importer.getToContext().LongDoubleTy; + + case BuiltinType::NullPtr: + // FIXME: Make sure that the "to" context supports C++0x! + return Importer.getToContext().NullPtrTy; + + case BuiltinType::Overload: return Importer.getToContext().OverloadTy; + case BuiltinType::Dependent: return Importer.getToContext().DependentTy; + case BuiltinType::UndeducedAuto: + // FIXME: Make sure that the "to" context supports C++0x! + return Importer.getToContext().UndeducedAutoTy; + + case BuiltinType::ObjCId: + // FIXME: Make sure that the "to" context supports Objective-C! + return Importer.getToContext().ObjCBuiltinIdTy; + + case BuiltinType::ObjCClass: + return Importer.getToContext().ObjCBuiltinClassTy; + + case BuiltinType::ObjCSel: + return Importer.getToContext().ObjCBuiltinSelTy; + } + + return QualType(); +} + +QualType ASTNodeImporter::VisitComplexType(ComplexType *T) { + QualType ToElementType = Importer.Import(T->getElementType()); + if (ToElementType.isNull()) + return QualType(); + + return Importer.getToContext().getComplexType(ToElementType); +} + +QualType ASTNodeImporter::VisitPointerType(PointerType *T) { + QualType ToPointeeType = Importer.Import(T->getPointeeType()); + if (ToPointeeType.isNull()) + return QualType(); + + return Importer.getToContext().getPointerType(ToPointeeType); +} + +QualType ASTNodeImporter::VisitBlockPointerType(BlockPointerType *T) { + // FIXME: Check for blocks support in "to" context. + QualType ToPointeeType = Importer.Import(T->getPointeeType()); + if (ToPointeeType.isNull()) + return QualType(); + + return Importer.getToContext().getBlockPointerType(ToPointeeType); +} + +QualType ASTNodeImporter::VisitLValueReferenceType(LValueReferenceType *T) { + // FIXME: Check for C++ support in "to" context. + QualType ToPointeeType = Importer.Import(T->getPointeeTypeAsWritten()); + if (ToPointeeType.isNull()) + return QualType(); + + return Importer.getToContext().getLValueReferenceType(ToPointeeType); +} + +QualType ASTNodeImporter::VisitRValueReferenceType(RValueReferenceType *T) { + // FIXME: Check for C++0x support in "to" context. + QualType ToPointeeType = Importer.Import(T->getPointeeTypeAsWritten()); + if (ToPointeeType.isNull()) + return QualType(); + + return Importer.getToContext().getRValueReferenceType(ToPointeeType); +} + +QualType ASTNodeImporter::VisitMemberPointerType(MemberPointerType *T) { + // FIXME: Check for C++ support in "to" context. + QualType ToPointeeType = Importer.Import(T->getPointeeType()); + if (ToPointeeType.isNull()) + return QualType(); + + QualType ClassType = Importer.Import(QualType(T->getClass(), 0)); + return Importer.getToContext().getMemberPointerType(ToPointeeType, + ClassType.getTypePtr()); +} + +QualType ASTNodeImporter::VisitConstantArrayType(ConstantArrayType *T) { + QualType ToElementType = Importer.Import(T->getElementType()); + if (ToElementType.isNull()) + return QualType(); + + return Importer.getToContext().getConstantArrayType(ToElementType, + T->getSize(), + T->getSizeModifier(), + T->getIndexTypeCVRQualifiers()); +} + +QualType ASTNodeImporter::VisitIncompleteArrayType(IncompleteArrayType *T) { + QualType ToElementType = Importer.Import(T->getElementType()); + if (ToElementType.isNull()) + return QualType(); + + return Importer.getToContext().getIncompleteArrayType(ToElementType, + T->getSizeModifier(), + T->getIndexTypeCVRQualifiers()); +} + +QualType ASTNodeImporter::VisitVariableArrayType(VariableArrayType *T) { + QualType ToElementType = Importer.Import(T->getElementType()); + if (ToElementType.isNull()) + return QualType(); + + Expr *Size = Importer.Import(T->getSizeExpr()); + if (!Size) + return QualType(); + + SourceRange Brackets = Importer.Import(T->getBracketsRange()); + return Importer.getToContext().getVariableArrayType(ToElementType, Size, + T->getSizeModifier(), + T->getIndexTypeCVRQualifiers(), + Brackets); +} + +QualType ASTNodeImporter::VisitVectorType(VectorType *T) { + QualType ToElementType = Importer.Import(T->getElementType()); + if (ToElementType.isNull()) + return QualType(); + + return Importer.getToContext().getVectorType(ToElementType, + T->getNumElements(), + T->isAltiVec(), + T->isPixel()); +} + +QualType ASTNodeImporter::VisitExtVectorType(ExtVectorType *T) { + QualType ToElementType = Importer.Import(T->getElementType()); + if (ToElementType.isNull()) + return QualType(); + + return Importer.getToContext().getExtVectorType(ToElementType, + T->getNumElements()); +} + +QualType ASTNodeImporter::VisitFunctionNoProtoType(FunctionNoProtoType *T) { + // FIXME: What happens if we're importing a function without a prototype + // into C++? Should we make it variadic? + QualType ToResultType = Importer.Import(T->getResultType()); + if (ToResultType.isNull()) + return QualType(); + + return Importer.getToContext().getFunctionNoProtoType(ToResultType, + T->getNoReturnAttr(), + T->getCallConv()); +} + +QualType ASTNodeImporter::VisitFunctionProtoType(FunctionProtoType *T) { + QualType ToResultType = Importer.Import(T->getResultType()); + if (ToResultType.isNull()) + return QualType(); + + // Import argument types + llvm::SmallVector<QualType, 4> ArgTypes; + for (FunctionProtoType::arg_type_iterator A = T->arg_type_begin(), + AEnd = T->arg_type_end(); + A != AEnd; ++A) { + QualType ArgType = Importer.Import(*A); + if (ArgType.isNull()) + return QualType(); + ArgTypes.push_back(ArgType); + } + + // Import exception types + llvm::SmallVector<QualType, 4> ExceptionTypes; + for (FunctionProtoType::exception_iterator E = T->exception_begin(), + EEnd = T->exception_end(); + E != EEnd; ++E) { + QualType ExceptionType = Importer.Import(*E); + if (ExceptionType.isNull()) + return QualType(); + ExceptionTypes.push_back(ExceptionType); + } + + return Importer.getToContext().getFunctionType(ToResultType, ArgTypes.data(), + ArgTypes.size(), + T->isVariadic(), + T->getTypeQuals(), + T->hasExceptionSpec(), + T->hasAnyExceptionSpec(), + ExceptionTypes.size(), + ExceptionTypes.data(), + T->getNoReturnAttr(), + T->getCallConv()); +} + +QualType ASTNodeImporter::VisitTypedefType(TypedefType *T) { + TypedefDecl *ToDecl + = dyn_cast_or_null<TypedefDecl>(Importer.Import(T->getDecl())); + if (!ToDecl) + return QualType(); + + return Importer.getToContext().getTypeDeclType(ToDecl); +} + +QualType ASTNodeImporter::VisitTypeOfExprType(TypeOfExprType *T) { + Expr *ToExpr = Importer.Import(T->getUnderlyingExpr()); + if (!ToExpr) + return QualType(); + + return Importer.getToContext().getTypeOfExprType(ToExpr); +} + +QualType ASTNodeImporter::VisitTypeOfType(TypeOfType *T) { + QualType ToUnderlyingType = Importer.Import(T->getUnderlyingType()); + if (ToUnderlyingType.isNull()) + return QualType(); + + return Importer.getToContext().getTypeOfType(ToUnderlyingType); +} + +QualType ASTNodeImporter::VisitDecltypeType(DecltypeType *T) { + Expr *ToExpr = Importer.Import(T->getUnderlyingExpr()); + if (!ToExpr) + return QualType(); + + return Importer.getToContext().getDecltypeType(ToExpr); +} + +QualType ASTNodeImporter::VisitRecordType(RecordType *T) { + RecordDecl *ToDecl + = dyn_cast_or_null<RecordDecl>(Importer.Import(T->getDecl())); + if (!ToDecl) + return QualType(); + + return Importer.getToContext().getTagDeclType(ToDecl); +} + +QualType ASTNodeImporter::VisitEnumType(EnumType *T) { + EnumDecl *ToDecl + = dyn_cast_or_null<EnumDecl>(Importer.Import(T->getDecl())); + if (!ToDecl) + return QualType(); + + return Importer.getToContext().getTagDeclType(ToDecl); +} + +QualType ASTNodeImporter::VisitElaboratedType(ElaboratedType *T) { + QualType ToUnderlyingType = Importer.Import(T->getUnderlyingType()); + if (ToUnderlyingType.isNull()) + return QualType(); + + return Importer.getToContext().getElaboratedType(ToUnderlyingType, + T->getTagKind()); +} + +QualType ASTNodeImporter::VisitQualifiedNameType(QualifiedNameType *T) { + NestedNameSpecifier *ToQualifier = Importer.Import(T->getQualifier()); + if (!ToQualifier) + return QualType(); + + QualType ToNamedType = Importer.Import(T->getNamedType()); + if (ToNamedType.isNull()) + return QualType(); + + return Importer.getToContext().getQualifiedNameType(ToQualifier, ToNamedType); +} + +QualType ASTNodeImporter::VisitObjCInterfaceType(ObjCInterfaceType *T) { + ObjCInterfaceDecl *Class + = dyn_cast_or_null<ObjCInterfaceDecl>(Importer.Import(T->getDecl())); + if (!Class) + return QualType(); + + llvm::SmallVector<ObjCProtocolDecl *, 4> Protocols; + for (ObjCInterfaceType::qual_iterator P = T->qual_begin(), + PEnd = T->qual_end(); + P != PEnd; ++P) { + ObjCProtocolDecl *Protocol + = dyn_cast_or_null<ObjCProtocolDecl>(Importer.Import(*P)); + if (!Protocol) + return QualType(); + Protocols.push_back(Protocol); + } + + return Importer.getToContext().getObjCInterfaceType(Class, + Protocols.data(), + Protocols.size()); +} + +QualType ASTNodeImporter::VisitObjCObjectPointerType(ObjCObjectPointerType *T) { + QualType ToPointeeType = Importer.Import(T->getPointeeType()); + if (ToPointeeType.isNull()) + return QualType(); + + llvm::SmallVector<ObjCProtocolDecl *, 4> Protocols; + for (ObjCObjectPointerType::qual_iterator P = T->qual_begin(), + PEnd = T->qual_end(); + P != PEnd; ++P) { + ObjCProtocolDecl *Protocol + = dyn_cast_or_null<ObjCProtocolDecl>(Importer.Import(*P)); + if (!Protocol) + return QualType(); + Protocols.push_back(Protocol); + } + + return Importer.getToContext().getObjCObjectPointerType(ToPointeeType, + Protocols.data(), + Protocols.size()); +} + +//---------------------------------------------------------------------------- +// Import Declarations +//---------------------------------------------------------------------------- +bool ASTNodeImporter::ImportDeclParts(NamedDecl *D, DeclContext *&DC, + DeclContext *&LexicalDC, + DeclarationName &Name, + SourceLocation &Loc) { + // Import the context of this declaration. + DC = Importer.ImportContext(D->getDeclContext()); + if (!DC) + return true; + + LexicalDC = DC; + if (D->getDeclContext() != D->getLexicalDeclContext()) { + LexicalDC = Importer.ImportContext(D->getLexicalDeclContext()); + if (!LexicalDC) + return true; + } + + // Import the name of this declaration. + Name = Importer.Import(D->getDeclName()); + if (D->getDeclName() && !Name) + return true; + + // Import the location of this declaration. + Loc = Importer.Import(D->getLocation()); + return false; +} + +bool ASTNodeImporter::IsStructuralMatch(RecordDecl *FromRecord, + RecordDecl *ToRecord) { + StructuralEquivalenceContext SEC(Importer.getFromContext(), + Importer.getToContext(), + Importer.getDiags(), + Importer.getNonEquivalentDecls()); + return SEC.IsStructurallyEquivalent(FromRecord, ToRecord); +} + +bool ASTNodeImporter::IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToEnum) { + StructuralEquivalenceContext SEC(Importer.getFromContext(), + Importer.getToContext(), + Importer.getDiags(), + Importer.getNonEquivalentDecls()); + return SEC.IsStructurallyEquivalent(FromEnum, ToEnum); +} + +Decl *ASTNodeImporter::VisitDecl(Decl *D) { + Importer.FromDiag(D->getLocation(), diag::err_unsupported_ast_node) + << D->getDeclKindName(); + return 0; +} + +Decl *ASTNodeImporter::VisitTypedefDecl(TypedefDecl *D) { + // Import the major distinguishing characteristics of this typedef. + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + return 0; + + // If this typedef is not in block scope, determine whether we've + // seen a typedef with the same name (that we can merge with) or any + // other entity by that name (which name lookup could conflict with). + if (!DC->isFunctionOrMethod()) { + llvm::SmallVector<NamedDecl *, 4> ConflictingDecls; + unsigned IDNS = Decl::IDNS_Ordinary; + for (DeclContext::lookup_result Lookup = DC->lookup(Name); + Lookup.first != Lookup.second; + ++Lookup.first) { + if (!(*Lookup.first)->isInIdentifierNamespace(IDNS)) + continue; + if (TypedefDecl *FoundTypedef = dyn_cast<TypedefDecl>(*Lookup.first)) { + if (Importer.IsStructurallyEquivalent(D->getUnderlyingType(), + FoundTypedef->getUnderlyingType())) + return Importer.Imported(D, FoundTypedef); + } + + ConflictingDecls.push_back(*Lookup.first); + } + + if (!ConflictingDecls.empty()) { + Name = Importer.HandleNameConflict(Name, DC, IDNS, + ConflictingDecls.data(), + ConflictingDecls.size()); + if (!Name) + return 0; + } + } + + // Import the underlying type of this typedef; + QualType T = Importer.Import(D->getUnderlyingType()); + if (T.isNull()) + return 0; + + // Create the new typedef node. + TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo()); + TypedefDecl *ToTypedef = TypedefDecl::Create(Importer.getToContext(), DC, + Loc, Name.getAsIdentifierInfo(), + TInfo); + ToTypedef->setLexicalDeclContext(LexicalDC); + Importer.Imported(D, ToTypedef); + LexicalDC->addDecl(ToTypedef); + + return ToTypedef; +} + +Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) { + // Import the major distinguishing characteristics of this enum. + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + return 0; + + // Figure out what enum name we're looking for. + unsigned IDNS = Decl::IDNS_Tag; + DeclarationName SearchName = Name; + if (!SearchName && D->getTypedefForAnonDecl()) { + SearchName = Importer.Import(D->getTypedefForAnonDecl()->getDeclName()); + IDNS = Decl::IDNS_Ordinary; + } else if (Importer.getToContext().getLangOptions().CPlusPlus) + IDNS |= Decl::IDNS_Ordinary; + + // We may already have an enum of the same name; try to find and match it. + if (!DC->isFunctionOrMethod() && SearchName) { + llvm::SmallVector<NamedDecl *, 4> ConflictingDecls; + for (DeclContext::lookup_result Lookup = DC->lookup(Name); + Lookup.first != Lookup.second; + ++Lookup.first) { + if (!(*Lookup.first)->isInIdentifierNamespace(IDNS)) + continue; + + Decl *Found = *Lookup.first; + if (TypedefDecl *Typedef = dyn_cast<TypedefDecl>(Found)) { + if (const TagType *Tag = Typedef->getUnderlyingType()->getAs<TagType>()) + Found = Tag->getDecl(); + } + + if (EnumDecl *FoundEnum = dyn_cast<EnumDecl>(Found)) { + if (IsStructuralMatch(D, FoundEnum)) + return Importer.Imported(D, FoundEnum); + } + + ConflictingDecls.push_back(*Lookup.first); + } + + if (!ConflictingDecls.empty()) { + Name = Importer.HandleNameConflict(Name, DC, IDNS, + ConflictingDecls.data(), + ConflictingDecls.size()); + } + } + + // Create the enum declaration. + EnumDecl *D2 = EnumDecl::Create(Importer.getToContext(), DC, Loc, + Name.getAsIdentifierInfo(), + Importer.Import(D->getTagKeywordLoc()), + 0); + D2->setLexicalDeclContext(LexicalDC); + Importer.Imported(D, D2); + LexicalDC->addDecl(D2); + + // Import the integer type. + QualType ToIntegerType = Importer.Import(D->getIntegerType()); + if (ToIntegerType.isNull()) + return 0; + D2->setIntegerType(ToIntegerType); + + // Import the definition + if (D->isDefinition()) { + QualType T = Importer.Import(Importer.getFromContext().getTypeDeclType(D)); + if (T.isNull()) + return 0; + + QualType ToPromotionType = Importer.Import(D->getPromotionType()); + if (ToPromotionType.isNull()) + return 0; + + D2->startDefinition(); + for (DeclContext::decl_iterator FromMem = D->decls_begin(), + FromMemEnd = D->decls_end(); + FromMem != FromMemEnd; + ++FromMem) + Importer.Import(*FromMem); + + D2->completeDefinition(T, ToPromotionType); + } + + return D2; +} + +Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { + // If this record has a definition in the translation unit we're coming from, + // but this particular declaration is not that definition, import the + // definition and map to that. + TagDecl *Definition = D->getDefinition(); + if (Definition && Definition != D) { + Decl *ImportedDef = Importer.Import(Definition); + if (!ImportedDef) + return 0; + + return Importer.Imported(D, ImportedDef); + } + + // Import the major distinguishing characteristics of this record. + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + return 0; + + // Figure out what structure name we're looking for. + unsigned IDNS = Decl::IDNS_Tag; + DeclarationName SearchName = Name; + if (!SearchName && D->getTypedefForAnonDecl()) { + SearchName = Importer.Import(D->getTypedefForAnonDecl()->getDeclName()); + IDNS = Decl::IDNS_Ordinary; + } else if (Importer.getToContext().getLangOptions().CPlusPlus) + IDNS |= Decl::IDNS_Ordinary; + + // We may already have a record of the same name; try to find and match it. + RecordDecl *AdoptDecl = 0; + if (!DC->isFunctionOrMethod() && SearchName) { + llvm::SmallVector<NamedDecl *, 4> ConflictingDecls; + for (DeclContext::lookup_result Lookup = DC->lookup(Name); + Lookup.first != Lookup.second; + ++Lookup.first) { + if (!(*Lookup.first)->isInIdentifierNamespace(IDNS)) + continue; + + Decl *Found = *Lookup.first; + if (TypedefDecl *Typedef = dyn_cast<TypedefDecl>(Found)) { + if (const TagType *Tag = Typedef->getUnderlyingType()->getAs<TagType>()) + Found = Tag->getDecl(); + } + + if (RecordDecl *FoundRecord = dyn_cast<RecordDecl>(Found)) { + if (RecordDecl *FoundDef = FoundRecord->getDefinition()) { + if (!D->isDefinition() || IsStructuralMatch(D, FoundDef)) { + // The record types structurally match, or the "from" translation + // unit only had a forward declaration anyway; call it the same + // function. + // FIXME: For C++, we should also merge methods here. + return Importer.Imported(D, FoundDef); + } + } else { + // We have a forward declaration of this type, so adopt that forward + // declaration rather than building a new one. + AdoptDecl = FoundRecord; + continue; + } + } + + ConflictingDecls.push_back(*Lookup.first); + } + + if (!ConflictingDecls.empty()) { + Name = Importer.HandleNameConflict(Name, DC, IDNS, + ConflictingDecls.data(), + ConflictingDecls.size()); + } + } + + // Create the record declaration. + RecordDecl *D2 = AdoptDecl; + if (!D2) { + if (CXXRecordDecl *D1CXX = dyn_cast<CXXRecordDecl>(D)) { + CXXRecordDecl *D2CXX = CXXRecordDecl::Create(Importer.getToContext(), + D->getTagKind(), + DC, Loc, + Name.getAsIdentifierInfo(), + Importer.Import(D->getTagKeywordLoc())); + D2 = D2CXX; + + if (D->isDefinition()) { + // Add base classes. + llvm::SmallVector<CXXBaseSpecifier *, 4> Bases; + for (CXXRecordDecl::base_class_iterator + Base1 = D1CXX->bases_begin(), + FromBaseEnd = D1CXX->bases_end(); + Base1 != FromBaseEnd; + ++Base1) { + QualType T = Importer.Import(Base1->getType()); + if (T.isNull()) + return 0; + + Bases.push_back( + new (Importer.getToContext()) + CXXBaseSpecifier(Importer.Import(Base1->getSourceRange()), + Base1->isVirtual(), + Base1->isBaseOfClass(), + Base1->getAccessSpecifierAsWritten(), + T)); + } + if (!Bases.empty()) + D2CXX->setBases(Bases.data(), Bases.size()); + } + } else { + D2 = RecordDecl::Create(Importer.getToContext(), D->getTagKind(), + DC, Loc, + Name.getAsIdentifierInfo(), + Importer.Import(D->getTagKeywordLoc())); + } + D2->setLexicalDeclContext(LexicalDC); + LexicalDC->addDecl(D2); + } + + Importer.Imported(D, D2); + + if (D->isDefinition()) { + D2->startDefinition(); + for (DeclContext::decl_iterator FromMem = D->decls_begin(), + FromMemEnd = D->decls_end(); + FromMem != FromMemEnd; + ++FromMem) + Importer.Import(*FromMem); + + D2->completeDefinition(); + } + + return D2; +} + +Decl *ASTNodeImporter::VisitEnumConstantDecl(EnumConstantDecl *D) { + // Import the major distinguishing characteristics of this enumerator. + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + return 0; + + QualType T = Importer.Import(D->getType()); + if (T.isNull()) + return 0; + + // Determine whether there are any other declarations with the same name and + // in the same context. + if (!LexicalDC->isFunctionOrMethod()) { + llvm::SmallVector<NamedDecl *, 4> ConflictingDecls; + unsigned IDNS = Decl::IDNS_Ordinary; + for (DeclContext::lookup_result Lookup = DC->lookup(Name); + Lookup.first != Lookup.second; + ++Lookup.first) { + if (!(*Lookup.first)->isInIdentifierNamespace(IDNS)) + continue; + + ConflictingDecls.push_back(*Lookup.first); + } + + if (!ConflictingDecls.empty()) { + Name = Importer.HandleNameConflict(Name, DC, IDNS, + ConflictingDecls.data(), + ConflictingDecls.size()); + if (!Name) + return 0; + } + } + + Expr *Init = Importer.Import(D->getInitExpr()); + if (D->getInitExpr() && !Init) + return 0; + + EnumConstantDecl *ToEnumerator + = EnumConstantDecl::Create(Importer.getToContext(), cast<EnumDecl>(DC), Loc, + Name.getAsIdentifierInfo(), T, + Init, D->getInitVal()); + ToEnumerator->setLexicalDeclContext(LexicalDC); + Importer.Imported(D, ToEnumerator); + LexicalDC->addDecl(ToEnumerator); + return ToEnumerator; +} + +Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { + // Import the major distinguishing characteristics of this function. + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + return 0; + + // Try to find a function in our own ("to") context with the same name, same + // type, and in the same context as the function we're importing. + if (!LexicalDC->isFunctionOrMethod()) { + llvm::SmallVector<NamedDecl *, 4> ConflictingDecls; + unsigned IDNS = Decl::IDNS_Ordinary; + for (DeclContext::lookup_result Lookup = DC->lookup(Name); + Lookup.first != Lookup.second; + ++Lookup.first) { + if (!(*Lookup.first)->isInIdentifierNamespace(IDNS)) + continue; + + if (FunctionDecl *FoundFunction = dyn_cast<FunctionDecl>(*Lookup.first)) { + if (isExternalLinkage(FoundFunction->getLinkage()) && + isExternalLinkage(D->getLinkage())) { + if (Importer.IsStructurallyEquivalent(D->getType(), + FoundFunction->getType())) { + // FIXME: Actually try to merge the body and other attributes. + return Importer.Imported(D, FoundFunction); + } + + // FIXME: Check for overloading more carefully, e.g., by boosting + // Sema::IsOverload out to the AST library. + + // Function overloading is okay in C++. + if (Importer.getToContext().getLangOptions().CPlusPlus) + continue; + + // Complain about inconsistent function types. + Importer.ToDiag(Loc, diag::err_odr_function_type_inconsistent) + << Name << D->getType() << FoundFunction->getType(); + Importer.ToDiag(FoundFunction->getLocation(), + diag::note_odr_value_here) + << FoundFunction->getType(); + } + } + + ConflictingDecls.push_back(*Lookup.first); + } + + if (!ConflictingDecls.empty()) { + Name = Importer.HandleNameConflict(Name, DC, IDNS, + ConflictingDecls.data(), + ConflictingDecls.size()); + if (!Name) + return 0; + } + } + + // Import the type. + QualType T = Importer.Import(D->getType()); + if (T.isNull()) + return 0; + + // Import the function parameters. + llvm::SmallVector<ParmVarDecl *, 8> Parameters; + for (FunctionDecl::param_iterator P = D->param_begin(), PEnd = D->param_end(); + P != PEnd; ++P) { + ParmVarDecl *ToP = cast_or_null<ParmVarDecl>(Importer.Import(*P)); + if (!ToP) + return 0; + + Parameters.push_back(ToP); + } + + // Create the imported function. + TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo()); + FunctionDecl *ToEnumerator + = FunctionDecl::Create(Importer.getToContext(), DC, Loc, + Name, T, TInfo, D->getStorageClass(), + D->isInlineSpecified(), + D->hasWrittenPrototype()); + ToEnumerator->setLexicalDeclContext(LexicalDC); + Importer.Imported(D, ToEnumerator); + LexicalDC->addDecl(ToEnumerator); + + // Set the parameters. + for (unsigned I = 0, N = Parameters.size(); I != N; ++I) { + Parameters[I]->setOwningFunction(ToEnumerator); + ToEnumerator->addDecl(Parameters[I]); + } + ToEnumerator->setParams(Parameters.data(), Parameters.size()); + + // FIXME: Other bits to merge? + + return ToEnumerator; +} + +Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) { + // Import the major distinguishing characteristics of a variable. + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + return 0; + + // Import the type. + QualType T = Importer.Import(D->getType()); + if (T.isNull()) + return 0; + + TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo()); + Expr *BitWidth = Importer.Import(D->getBitWidth()); + if (!BitWidth && D->getBitWidth()) + return 0; + + FieldDecl *ToField = FieldDecl::Create(Importer.getToContext(), DC, + Loc, Name.getAsIdentifierInfo(), + T, TInfo, BitWidth, D->isMutable()); + ToField->setLexicalDeclContext(LexicalDC); + Importer.Imported(D, ToField); + LexicalDC->addDecl(ToField); + return ToField; +} + +Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) { + // Import the major distinguishing characteristics of a variable. + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + return 0; + + // Try to find a variable in our own ("to") context with the same name and + // in the same context as the variable we're importing. + if (D->isFileVarDecl()) { + VarDecl *MergeWithVar = 0; + llvm::SmallVector<NamedDecl *, 4> ConflictingDecls; + unsigned IDNS = Decl::IDNS_Ordinary; + for (DeclContext::lookup_result Lookup = DC->lookup(Name); + Lookup.first != Lookup.second; + ++Lookup.first) { + if (!(*Lookup.first)->isInIdentifierNamespace(IDNS)) + continue; + + if (VarDecl *FoundVar = dyn_cast<VarDecl>(*Lookup.first)) { + // We have found a variable that we may need to merge with. Check it. + if (isExternalLinkage(FoundVar->getLinkage()) && + isExternalLinkage(D->getLinkage())) { + if (Importer.IsStructurallyEquivalent(D->getType(), + FoundVar->getType())) { + MergeWithVar = FoundVar; + break; + } + + const ArrayType *FoundArray + = Importer.getToContext().getAsArrayType(FoundVar->getType()); + const ArrayType *TArray + = Importer.getToContext().getAsArrayType(D->getType()); + if (FoundArray && TArray) { + if (isa<IncompleteArrayType>(FoundArray) && + isa<ConstantArrayType>(TArray)) { + // Import the type. + QualType T = Importer.Import(D->getType()); + if (T.isNull()) + return 0; + + FoundVar->setType(T); + MergeWithVar = FoundVar; + break; + } else if (isa<IncompleteArrayType>(TArray) && + isa<ConstantArrayType>(FoundArray)) { + MergeWithVar = FoundVar; + break; + } + } + + Importer.ToDiag(Loc, diag::err_odr_variable_type_inconsistent) + << Name << D->getType() << FoundVar->getType(); + Importer.ToDiag(FoundVar->getLocation(), diag::note_odr_value_here) + << FoundVar->getType(); + } + } + + ConflictingDecls.push_back(*Lookup.first); + } + + if (MergeWithVar) { + // An equivalent variable with external linkage has been found. Link + // the two declarations, then merge them. + Importer.Imported(D, MergeWithVar); + + if (VarDecl *DDef = D->getDefinition()) { + if (VarDecl *ExistingDef = MergeWithVar->getDefinition()) { + Importer.ToDiag(ExistingDef->getLocation(), + diag::err_odr_variable_multiple_def) + << Name; + Importer.FromDiag(DDef->getLocation(), diag::note_odr_defined_here); + } else { + Expr *Init = Importer.Import(DDef->getInit()); + MergeWithVar->setInit(Init); + } + } + + return MergeWithVar; + } + + if (!ConflictingDecls.empty()) { + Name = Importer.HandleNameConflict(Name, DC, IDNS, + ConflictingDecls.data(), + ConflictingDecls.size()); + if (!Name) + return 0; + } + } + + // Import the type. + QualType T = Importer.Import(D->getType()); + if (T.isNull()) + return 0; + + // Create the imported variable. + TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo()); + VarDecl *ToVar = VarDecl::Create(Importer.getToContext(), DC, Loc, + Name.getAsIdentifierInfo(), T, TInfo, + D->getStorageClass()); + ToVar->setLexicalDeclContext(LexicalDC); + Importer.Imported(D, ToVar); + LexicalDC->addDecl(ToVar); + + // Merge the initializer. + // FIXME: Can we really import any initializer? Alternatively, we could force + // ourselves to import every declaration of a variable and then only use + // getInit() here. + ToVar->setInit(Importer.Import(const_cast<Expr *>(D->getAnyInitializer()))); + + // FIXME: Other bits to merge? + + return ToVar; +} + +Decl *ASTNodeImporter::VisitParmVarDecl(ParmVarDecl *D) { + // Parameters are created in the translation unit's context, then moved + // into the function declaration's context afterward. + DeclContext *DC = Importer.getToContext().getTranslationUnitDecl(); + + // Import the name of this declaration. + DeclarationName Name = Importer.Import(D->getDeclName()); + if (D->getDeclName() && !Name) + return 0; + + // Import the location of this declaration. + SourceLocation Loc = Importer.Import(D->getLocation()); + + // Import the parameter's type. + QualType T = Importer.Import(D->getType()); + if (T.isNull()) + return 0; + + // Create the imported parameter. + TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo()); + ParmVarDecl *ToParm = ParmVarDecl::Create(Importer.getToContext(), DC, + Loc, Name.getAsIdentifierInfo(), + T, TInfo, D->getStorageClass(), + /*FIXME: Default argument*/ 0); + return Importer.Imported(D, ToParm); +} + +Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { + // Import the major distinguishing characteristics of an @interface. + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + return 0; + + ObjCInterfaceDecl *MergeWithIface = 0; + for (DeclContext::lookup_result Lookup = DC->lookup(Name); + Lookup.first != Lookup.second; + ++Lookup.first) { + if (!(*Lookup.first)->isInIdentifierNamespace(Decl::IDNS_Ordinary)) + continue; + + if ((MergeWithIface = dyn_cast<ObjCInterfaceDecl>(*Lookup.first))) + break; + } + + ObjCInterfaceDecl *ToIface = MergeWithIface; + if (!ToIface || ToIface->isForwardDecl()) { + if (!ToIface) { + ToIface = ObjCInterfaceDecl::Create(Importer.getToContext(), + DC, Loc, + Name.getAsIdentifierInfo(), + Importer.Import(D->getClassLoc()), + D->isForwardDecl(), + D->isImplicitInterfaceDecl()); + ToIface->setLexicalDeclContext(LexicalDC); + LexicalDC->addDecl(ToIface); + } + Importer.Imported(D, ToIface); + + // Import superclass + // FIXME: If we're merging, make sure that both decls have the same + // superclass. + if (D->getSuperClass()) { + ObjCInterfaceDecl *Super + = cast_or_null<ObjCInterfaceDecl>(Importer.Import(D->getSuperClass())); + if (!Super) + return 0; + + ToIface->setSuperClass(Super); + ToIface->setSuperClassLoc(Importer.Import(D->getSuperClassLoc())); + } + + // Import protocols + llvm::SmallVector<ObjCProtocolDecl *, 4> Protocols; + llvm::SmallVector<SourceLocation, 4> ProtocolLocs; + ObjCInterfaceDecl::protocol_loc_iterator + FromProtoLoc = D->protocol_loc_begin(); + for (ObjCInterfaceDecl::protocol_iterator FromProto = D->protocol_begin(), + FromProtoEnd = D->protocol_end(); + FromProto != FromProtoEnd; + ++FromProto, ++FromProtoLoc) { + ObjCProtocolDecl *ToProto + = cast_or_null<ObjCProtocolDecl>(Importer.Import(*FromProto)); + if (!ToProto) + return 0; + Protocols.push_back(ToProto); + ProtocolLocs.push_back(Importer.Import(*FromProtoLoc)); + } + + // FIXME: If we're merging, make sure that the protocol list is the same. + ToIface->setProtocolList(Protocols.data(), Protocols.size(), + ProtocolLocs.data(), Importer.getToContext()); + + // FIXME: Import categories + + // Import @end range + ToIface->setAtEndRange(Importer.Import(D->getAtEndRange())); + } else { + Importer.Imported(D, ToIface); + } + + // Import all of the members of this class. + for (DeclContext::decl_iterator FromMem = D->decls_begin(), + FromMemEnd = D->decls_end(); + FromMem != FromMemEnd; + ++FromMem) + Importer.Import(*FromMem); + + // If we have an @implementation, import it as well. + if (D->getImplementation()) { + ObjCImplementationDecl *Impl + = cast<ObjCImplementationDecl>(Importer.Import(D->getImplementation())); + if (!Impl) + return 0; + + ToIface->setImplementation(Impl); + } + + return 0; +} + +//---------------------------------------------------------------------------- +// Import Statements +//---------------------------------------------------------------------------- + +Stmt *ASTNodeImporter::VisitStmt(Stmt *S) { + Importer.FromDiag(S->getLocStart(), diag::err_unsupported_ast_node) + << S->getStmtClassName(); + return 0; +} + +//---------------------------------------------------------------------------- +// Import Expressions +//---------------------------------------------------------------------------- +Expr *ASTNodeImporter::VisitExpr(Expr *E) { + Importer.FromDiag(E->getLocStart(), diag::err_unsupported_ast_node) + << E->getStmtClassName(); + return 0; +} + +Expr *ASTNodeImporter::VisitIntegerLiteral(IntegerLiteral *E) { + QualType T = Importer.Import(E->getType()); + if (T.isNull()) + return 0; + + return new (Importer.getToContext()) + IntegerLiteral(E->getValue(), T, Importer.Import(E->getLocation())); +} + +Expr *ASTNodeImporter::VisitImplicitCastExpr(ImplicitCastExpr *E) { + QualType T = Importer.Import(E->getType()); + if (T.isNull()) + return 0; + + Expr *SubExpr = Importer.Import(E->getSubExpr()); + if (!SubExpr) + return 0; + + return new (Importer.getToContext()) ImplicitCastExpr(T, E->getCastKind(), + SubExpr, + E->isLvalueCast()); +} + +ASTImporter::ASTImporter(Diagnostic &Diags, + ASTContext &ToContext, FileManager &ToFileManager, + ASTContext &FromContext, FileManager &FromFileManager) + : ToContext(ToContext), FromContext(FromContext), + ToFileManager(ToFileManager), FromFileManager(FromFileManager), + Diags(Diags) { + ImportedDecls[FromContext.getTranslationUnitDecl()] + = ToContext.getTranslationUnitDecl(); +} + +ASTImporter::~ASTImporter() { } + +QualType ASTImporter::Import(QualType FromT) { + if (FromT.isNull()) + return QualType(); + + // Check whether we've already imported this type. + llvm::DenseMap<Type *, Type *>::iterator Pos + = ImportedTypes.find(FromT.getTypePtr()); + if (Pos != ImportedTypes.end()) + return ToContext.getQualifiedType(Pos->second, FromT.getQualifiers()); + + // Import the type + ASTNodeImporter Importer(*this); + QualType ToT = Importer.Visit(FromT.getTypePtr()); + if (ToT.isNull()) + return ToT; + + // Record the imported type. + ImportedTypes[FromT.getTypePtr()] = ToT.getTypePtr(); + + return ToContext.getQualifiedType(ToT, FromT.getQualifiers()); +} + +TypeSourceInfo *ASTImporter::Import(TypeSourceInfo *FromTSI) { + if (!FromTSI) + return FromTSI; + + // FIXME: For now we just create a "trivial" type source info based + // on the type and a seingle location. Implement a real version of + // this. + QualType T = Import(FromTSI->getType()); + if (T.isNull()) + return 0; + + return ToContext.getTrivialTypeSourceInfo(T, + FromTSI->getTypeLoc().getFullSourceRange().getBegin()); +} + +Decl *ASTImporter::Import(Decl *FromD) { + if (!FromD) + return 0; + + // Check whether we've already imported this declaration. + llvm::DenseMap<Decl *, Decl *>::iterator Pos = ImportedDecls.find(FromD); + if (Pos != ImportedDecls.end()) + return Pos->second; + + // Import the type + ASTNodeImporter Importer(*this); + Decl *ToD = Importer.Visit(FromD); + if (!ToD) + return 0; + + // Record the imported declaration. + ImportedDecls[FromD] = ToD; + + if (TagDecl *FromTag = dyn_cast<TagDecl>(FromD)) { + // Keep track of anonymous tags that have an associated typedef. + if (FromTag->getTypedefForAnonDecl()) + AnonTagsWithPendingTypedefs.push_back(FromTag); + } else if (TypedefDecl *FromTypedef = dyn_cast<TypedefDecl>(FromD)) { + // When we've finished transforming a typedef, see whether it was the + // typedef for an anonymous tag. + for (llvm::SmallVector<TagDecl *, 4>::iterator + FromTag = AnonTagsWithPendingTypedefs.begin(), + FromTagEnd = AnonTagsWithPendingTypedefs.end(); + FromTag != FromTagEnd; ++FromTag) { + if ((*FromTag)->getTypedefForAnonDecl() == FromTypedef) { + if (TagDecl *ToTag = cast_or_null<TagDecl>(Import(*FromTag))) { + // We found the typedef for an anonymous tag; link them. + ToTag->setTypedefForAnonDecl(cast<TypedefDecl>(ToD)); + AnonTagsWithPendingTypedefs.erase(FromTag); + break; + } + } + } + } + + return ToD; +} + +DeclContext *ASTImporter::ImportContext(DeclContext *FromDC) { + if (!FromDC) + return FromDC; + + return cast_or_null<DeclContext>(Import(cast<Decl>(FromDC))); +} + +Expr *ASTImporter::Import(Expr *FromE) { + if (!FromE) + return 0; + + return cast_or_null<Expr>(Import(cast<Stmt>(FromE))); +} + +Stmt *ASTImporter::Import(Stmt *FromS) { + if (!FromS) + return 0; + + // Check whether we've already imported this declaration. + llvm::DenseMap<Stmt *, Stmt *>::iterator Pos = ImportedStmts.find(FromS); + if (Pos != ImportedStmts.end()) + return Pos->second; + + // Import the type + ASTNodeImporter Importer(*this); + Stmt *ToS = Importer.Visit(FromS); + if (!ToS) + return 0; + + // Record the imported declaration. + ImportedStmts[FromS] = ToS; + return ToS; +} + +NestedNameSpecifier *ASTImporter::Import(NestedNameSpecifier *FromNNS) { + if (!FromNNS) + return 0; + + // FIXME: Implement! + return 0; +} + +SourceLocation ASTImporter::Import(SourceLocation FromLoc) { + if (FromLoc.isInvalid()) + return SourceLocation(); + + SourceManager &FromSM = FromContext.getSourceManager(); + + // For now, map everything down to its spelling location, so that we + // don't have to import macro instantiations. + // FIXME: Import macro instantiations! + FromLoc = FromSM.getSpellingLoc(FromLoc); + std::pair<FileID, unsigned> Decomposed = FromSM.getDecomposedLoc(FromLoc); + SourceManager &ToSM = ToContext.getSourceManager(); + return ToSM.getLocForStartOfFile(Import(Decomposed.first)) + .getFileLocWithOffset(Decomposed.second); +} + +SourceRange ASTImporter::Import(SourceRange FromRange) { + return SourceRange(Import(FromRange.getBegin()), Import(FromRange.getEnd())); +} + +FileID ASTImporter::Import(FileID FromID) { + llvm::DenseMap<unsigned, FileID>::iterator Pos + = ImportedFileIDs.find(FromID.getHashValue()); + if (Pos != ImportedFileIDs.end()) + return Pos->second; + + SourceManager &FromSM = FromContext.getSourceManager(); + SourceManager &ToSM = ToContext.getSourceManager(); + const SrcMgr::SLocEntry &FromSLoc = FromSM.getSLocEntry(FromID); + assert(FromSLoc.isFile() && "Cannot handle macro instantiations yet"); + + // Include location of this file. + SourceLocation ToIncludeLoc = Import(FromSLoc.getFile().getIncludeLoc()); + + // Map the FileID for to the "to" source manager. + FileID ToID; + const SrcMgr::ContentCache *Cache = FromSLoc.getFile().getContentCache(); + if (Cache->Entry) { + // FIXME: We probably want to use getVirtualFile(), so we don't hit the + // disk again + // FIXME: We definitely want to re-use the existing MemoryBuffer, rather + // than mmap the files several times. + const FileEntry *Entry = ToFileManager.getFile(Cache->Entry->getName()); + ToID = ToSM.createFileID(Entry, ToIncludeLoc, + FromSLoc.getFile().getFileCharacteristic()); + } else { + // FIXME: We want to re-use the existing MemoryBuffer! + const llvm::MemoryBuffer *FromBuf = Cache->getBuffer(); + llvm::MemoryBuffer *ToBuf + = llvm::MemoryBuffer::getMemBufferCopy(FromBuf->getBufferStart(), + FromBuf->getBufferEnd(), + FromBuf->getBufferIdentifier()); + ToID = ToSM.createFileIDForMemBuffer(ToBuf); + } + + + ImportedFileIDs[FromID.getHashValue()] = ToID; + return ToID; +} + +DeclarationName ASTImporter::Import(DeclarationName FromName) { + if (!FromName) + return DeclarationName(); + + switch (FromName.getNameKind()) { + case DeclarationName::Identifier: + return Import(FromName.getAsIdentifierInfo()); + + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + return Import(FromName.getObjCSelector()); + + case DeclarationName::CXXConstructorName: { + QualType T = Import(FromName.getCXXNameType()); + if (T.isNull()) + return DeclarationName(); + + return ToContext.DeclarationNames.getCXXConstructorName( + ToContext.getCanonicalType(T)); + } + + case DeclarationName::CXXDestructorName: { + QualType T = Import(FromName.getCXXNameType()); + if (T.isNull()) + return DeclarationName(); + + return ToContext.DeclarationNames.getCXXDestructorName( + ToContext.getCanonicalType(T)); + } + + case DeclarationName::CXXConversionFunctionName: { + QualType T = Import(FromName.getCXXNameType()); + if (T.isNull()) + return DeclarationName(); + + return ToContext.DeclarationNames.getCXXConversionFunctionName( + ToContext.getCanonicalType(T)); + } + + case DeclarationName::CXXOperatorName: + return ToContext.DeclarationNames.getCXXOperatorName( + FromName.getCXXOverloadedOperator()); + + case DeclarationName::CXXLiteralOperatorName: + return ToContext.DeclarationNames.getCXXLiteralOperatorName( + Import(FromName.getCXXLiteralIdentifier())); + + case DeclarationName::CXXUsingDirective: + // FIXME: STATICS! + return DeclarationName::getUsingDirectiveName(); + } + + // Silence bogus GCC warning + return DeclarationName(); +} + +IdentifierInfo *ASTImporter::Import(IdentifierInfo *FromId) { + if (!FromId) + return 0; + + return &ToContext.Idents.get(FromId->getName()); +} + +DeclarationName ASTImporter::HandleNameConflict(DeclarationName Name, + DeclContext *DC, + unsigned IDNS, + NamedDecl **Decls, + unsigned NumDecls) { + return Name; +} + +DiagnosticBuilder ASTImporter::ToDiag(SourceLocation Loc, unsigned DiagID) { + return Diags.Report(FullSourceLoc(Loc, ToContext.getSourceManager()), + DiagID); +} + +DiagnosticBuilder ASTImporter::FromDiag(SourceLocation Loc, unsigned DiagID) { + return Diags.Report(FullSourceLoc(Loc, FromContext.getSourceManager()), + DiagID); +} + +Decl *ASTImporter::Imported(Decl *From, Decl *To) { + ImportedDecls[From] = To; + return To; +} + +bool ASTImporter::IsStructurallyEquivalent(QualType From, QualType To) { + llvm::DenseMap<Type *, Type *>::iterator Pos + = ImportedTypes.find(From.getTypePtr()); + if (Pos != ImportedTypes.end() && ToContext.hasSameType(Import(From), To)) + return true; + + StructuralEquivalenceContext SEC(FromContext, ToContext, Diags, + NonEquivalentDecls); + return SEC.IsStructurallyEquivalent(From, To); +} diff --git a/lib/AST/AttrImpl.cpp b/lib/AST/AttrImpl.cpp index 02c70b6..d819797 100644 --- a/lib/AST/AttrImpl.cpp +++ b/lib/AST/AttrImpl.cpp @@ -11,11 +11,61 @@ // //===----------------------------------------------------------------------===// - #include "clang/AST/Attr.h" #include "clang/AST/ASTContext.h" using namespace clang; +void Attr::Destroy(ASTContext &C) { + if (Next) { + Next->Destroy(C); + Next = 0; + } + this->~Attr(); + C.Deallocate((void*)this); +} + +AttrWithString::AttrWithString(Attr::Kind AK, ASTContext &C, llvm::StringRef s) + : Attr(AK) { + assert(!s.empty()); + StrLen = s.size(); + Str = new (C) char[StrLen]; + memcpy(const_cast<char*>(Str), s.data(), StrLen); +} + +void AttrWithString::Destroy(ASTContext &C) { + C.Deallocate(const_cast<char*>(Str)); + Attr::Destroy(C); +} + +void AttrWithString::ReplaceString(ASTContext &C, llvm::StringRef newS) { + if (newS.size() > StrLen) { + C.Deallocate(const_cast<char*>(Str)); + Str = new (C) char[newS.size()]; + } + StrLen = newS.size(); + memcpy(const_cast<char*>(Str), newS.data(), StrLen); +} + +void FormatAttr::setType(ASTContext &C, llvm::StringRef type) { + ReplaceString(C, type); +} + +NonNullAttr::NonNullAttr(ASTContext &C, unsigned* arg_nums, unsigned size) + : Attr(NonNull), ArgNums(0), Size(0) { + if (size == 0) + return; + assert(arg_nums); + ArgNums = new (C) unsigned[size]; + Size = size; + memcpy(ArgNums, arg_nums, sizeof(*ArgNums)*size); +} + +void NonNullAttr::Destroy(ASTContext &C) { + if (ArgNums) + C.Deallocate(ArgNums); + Attr::Destroy(C); +} + #define DEF_SIMPLE_ATTR_CLONE(ATTR) \ Attr *ATTR##Attr::clone(ASTContext &C) const { \ return ::new (C) ATTR##Attr; \ @@ -55,6 +105,7 @@ DEF_SIMPLE_ATTR_CLONE(Hiding) DEF_SIMPLE_ATTR_CLONE(Override) DEF_SIMPLE_ATTR_CLONE(DLLImport) DEF_SIMPLE_ATTR_CLONE(DLLExport) +DEF_SIMPLE_ATTR_CLONE(X86ForceAlignArgPointer) Attr* PragmaPackAttr::clone(ASTContext &C) const { return ::new (C) PragmaPackAttr(Alignment); @@ -65,15 +116,15 @@ Attr* AlignedAttr::clone(ASTContext &C) const { } Attr* AnnotateAttr::clone(ASTContext &C) const { - return ::new (C) AnnotateAttr(Annotation); + return ::new (C) AnnotateAttr(C, getAnnotation()); } Attr *AsmLabelAttr::clone(ASTContext &C) const { - return ::new (C) AsmLabelAttr(Label); + return ::new (C) AsmLabelAttr(C, getLabel()); } Attr *AliasAttr::clone(ASTContext &C) const { - return ::new (C) AliasAttr(Aliasee); + return ::new (C) AliasAttr(C, getAliasee()); } Attr *ConstructorAttr::clone(ASTContext &C) const { @@ -93,15 +144,15 @@ Attr *GNUInlineAttr::clone(ASTContext &C) const { } Attr *SectionAttr::clone(ASTContext &C) const { - return ::new (C) SectionAttr(Name); + return ::new (C) SectionAttr(C, getName()); } Attr *NonNullAttr::clone(ASTContext &C) const { - return ::new (C) NonNullAttr(ArgNums, Size); + return ::new (C) NonNullAttr(C, ArgNums, Size); } Attr *FormatAttr::clone(ASTContext &C) const { - return ::new (C) FormatAttr(Type, formatIdx, firstArg); + return ::new (C) FormatAttr(C, getType(), formatIdx, firstArg); } Attr *FormatArgAttr::clone(ASTContext &C) const { diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt index dea96e7..e5bd9b7 100644 --- a/lib/AST/CMakeLists.txt +++ b/lib/AST/CMakeLists.txt @@ -4,6 +4,8 @@ add_clang_library(clangAST APValue.cpp ASTConsumer.cpp ASTContext.cpp + ASTImporter.cpp + ASTDiagnostic.cpp AttrImpl.cpp CXXInheritance.cpp Decl.cpp diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp index 7208328..99f908c 100644 --- a/lib/AST/CXXInheritance.cpp +++ b/lib/AST/CXXInheritance.cpp @@ -102,7 +102,6 @@ bool CXXRecordDecl::isProvablyNotDerivedFrom(const CXXRecordDecl *Base) const { bool CXXRecordDecl::forallBases(ForallBasesCallback *BaseMatches, void *OpaqueData, bool AllowShortCircuit) const { - ASTContext &Context = getASTContext(); llvm::SmallVector<const CXXRecordDecl*, 8> Queue; const CXXRecordDecl *Record = this; @@ -118,7 +117,7 @@ bool CXXRecordDecl::forallBases(ForallBasesCallback *BaseMatches, } CXXRecordDecl *Base = - cast_or_null<CXXRecordDecl>(Ty->getDecl()->getDefinition(Context)); + cast_or_null<CXXRecordDecl>(Ty->getDecl()->getDefinition()); if (!Base) { if (AllowShortCircuit) return false; AllMatches = false; @@ -215,10 +214,13 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches, Paths.ScratchPath.Access = MergeAccess(AccessToHere, BaseSpec->getAccessSpecifier()); } - + + // Track whether there's a path involving this specific base. + bool FoundPathThroughBase = false; + if (BaseMatches(BaseSpec, Paths.ScratchPath, UserData)) { // We've found a path that terminates at this base. - FoundPath = true; + FoundPath = FoundPathThroughBase = true; if (Paths.isRecordingPaths()) { // We have a path. Make a copy of it before moving on. Paths.Paths.push_back(Paths.ScratchPath); @@ -240,7 +242,7 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches, // There is a path to a base class that meets the criteria. If we're // not collecting paths or finding ambiguities, we're done. - FoundPath = true; + FoundPath = FoundPathThroughBase = true; if (!Paths.isFindingAmbiguities()) return FoundPath; } @@ -253,7 +255,7 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches, } // If we set a virtual earlier, and this isn't a path, forget it again. - if (SetVirtual && !FoundPath) { + if (SetVirtual && !FoundPathThroughBase) { Paths.DetectedVirtual = 0; } } diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 794b14a..5acb82f 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -29,224 +29,81 @@ using namespace clang; -void Attr::Destroy(ASTContext &C) { - if (Next) { - Next->Destroy(C); - Next = 0; - } - this->~Attr(); - C.Deallocate((void*)this); -} - /// \brief Return the TypeLoc wrapper for the type source info. TypeLoc TypeSourceInfo::getTypeLoc() const { return TypeLoc(Ty, (void*)(this + 1)); } //===----------------------------------------------------------------------===// -// Decl Allocation/Deallocation Method Implementations +// NamedDecl Implementation //===----------------------------------------------------------------------===// +/// \brief Get the most restrictive linkage for the types in the given +/// template parameter list. +static Linkage +getLinkageForTemplateParameterList(const TemplateParameterList *Params) { + Linkage L = ExternalLinkage; + for (TemplateParameterList::const_iterator P = Params->begin(), + PEnd = Params->end(); + P != PEnd; ++P) { + if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) + if (!NTTP->getType()->isDependentType()) { + L = minLinkage(L, NTTP->getType()->getLinkage()); + continue; + } -TranslationUnitDecl *TranslationUnitDecl::Create(ASTContext &C) { - return new (C) TranslationUnitDecl(C); -} - -NamespaceDecl *NamespaceDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation L, IdentifierInfo *Id) { - return new (C) NamespaceDecl(DC, L, Id); -} - -void NamespaceDecl::Destroy(ASTContext& C) { - // NamespaceDecl uses "NextDeclarator" to chain namespace declarations - // together. They are all top-level Decls. - - this->~NamespaceDecl(); - C.Deallocate((void *)this); -} - - -ImplicitParamDecl *ImplicitParamDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation L, IdentifierInfo *Id, QualType T) { - return new (C) ImplicitParamDecl(ImplicitParam, DC, L, Id, T); -} - -const char *VarDecl::getStorageClassSpecifierString(StorageClass SC) { - switch (SC) { - case VarDecl::None: break; - case VarDecl::Auto: return "auto"; break; - case VarDecl::Extern: return "extern"; break; - case VarDecl::PrivateExtern: return "__private_extern__"; break; - case VarDecl::Register: return "register"; break; - case VarDecl::Static: return "static"; break; + if (TemplateTemplateParmDecl *TTP + = dyn_cast<TemplateTemplateParmDecl>(*P)) { + L = minLinkage(L, + getLinkageForTemplateParameterList(TTP->getTemplateParameters())); + } } - assert(0 && "Invalid storage class"); - return 0; -} - -ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation L, IdentifierInfo *Id, - QualType T, TypeSourceInfo *TInfo, - StorageClass S, Expr *DefArg) { - return new (C) ParmVarDecl(ParmVar, DC, L, Id, T, TInfo, S, DefArg); -} - -Expr *ParmVarDecl::getDefaultArg() { - assert(!hasUnparsedDefaultArg() && "Default argument is not yet parsed!"); - assert(!hasUninstantiatedDefaultArg() && - "Default argument is not yet instantiated!"); - - Expr *Arg = getInit(); - if (CXXExprWithTemporaries *E = dyn_cast_or_null<CXXExprWithTemporaries>(Arg)) - return E->getSubExpr(); - - return Arg; -} - -unsigned ParmVarDecl::getNumDefaultArgTemporaries() const { - if (const CXXExprWithTemporaries *E = - dyn_cast<CXXExprWithTemporaries>(getInit())) - return E->getNumTemporaries(); - - return 0; + return L; } -CXXTemporary *ParmVarDecl::getDefaultArgTemporary(unsigned i) { - assert(getNumDefaultArgTemporaries() && - "Default arguments does not have any temporaries!"); - - CXXExprWithTemporaries *E = cast<CXXExprWithTemporaries>(getInit()); - return E->getTemporary(i); -} +/// \brief Get the most restrictive linkage for the types and +/// declarations in the given template argument list. +static Linkage getLinkageForTemplateArgumentList(const TemplateArgument *Args, + unsigned NumArgs) { + Linkage L = ExternalLinkage; -SourceRange ParmVarDecl::getDefaultArgRange() const { - if (const Expr *E = getInit()) - return E->getSourceRange(); - - if (hasUninstantiatedDefaultArg()) - return getUninstantiatedDefaultArg()->getSourceRange(); - - return SourceRange(); -} - -void VarDecl::setInit(ASTContext &C, Expr *I) { - if (EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>()) { - Eval->~EvaluatedStmt(); - C.Deallocate(Eval); - } - - Init = I; -} + for (unsigned I = 0; I != NumArgs; ++I) { + switch (Args[I].getKind()) { + case TemplateArgument::Null: + case TemplateArgument::Integral: + case TemplateArgument::Expression: + break; + + case TemplateArgument::Type: + L = minLinkage(L, Args[I].getAsType()->getLinkage()); + break; -bool VarDecl::isExternC() const { - ASTContext &Context = getASTContext(); - if (!Context.getLangOptions().CPlusPlus) - return (getDeclContext()->isTranslationUnit() && - getStorageClass() != Static) || - (getDeclContext()->isFunctionOrMethod() && hasExternalStorage()); + case TemplateArgument::Declaration: + if (NamedDecl *ND = dyn_cast<NamedDecl>(Args[I].getAsDecl())) + L = minLinkage(L, ND->getLinkage()); + if (ValueDecl *VD = dyn_cast<ValueDecl>(Args[I].getAsDecl())) + L = minLinkage(L, VD->getType()->getLinkage()); + break; - for (const DeclContext *DC = getDeclContext(); !DC->isTranslationUnit(); - DC = DC->getParent()) { - if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC)) { - if (Linkage->getLanguage() == LinkageSpecDecl::lang_c) - return getStorageClass() != Static; + case TemplateArgument::Template: + if (TemplateDecl *Template + = Args[I].getAsTemplate().getAsTemplateDecl()) + L = minLinkage(L, Template->getLinkage()); + break; + case TemplateArgument::Pack: + L = minLinkage(L, + getLinkageForTemplateArgumentList(Args[I].pack_begin(), + Args[I].pack_size())); break; } - - if (DC->isFunctionOrMethod()) - return false; } - return false; + return L; } -FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation L, - DeclarationName N, QualType T, - TypeSourceInfo *TInfo, - StorageClass S, bool isInline, - bool hasWrittenPrototype) { - FunctionDecl *New - = new (C) FunctionDecl(Function, DC, L, N, T, TInfo, S, isInline); - New->HasWrittenPrototype = hasWrittenPrototype; - return New; -} - -BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) { - return new (C) BlockDecl(DC, L); -} - -FieldDecl *FieldDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, - IdentifierInfo *Id, QualType T, - TypeSourceInfo *TInfo, Expr *BW, bool Mutable) { - return new (C) FieldDecl(Decl::Field, DC, L, Id, T, TInfo, BW, Mutable); -} - -bool FieldDecl::isAnonymousStructOrUnion() const { - if (!isImplicit() || getDeclName()) - return false; - - if (const RecordType *Record = getType()->getAs<RecordType>()) - return Record->getDecl()->isAnonymousStructOrUnion(); - - return false; -} - -EnumConstantDecl *EnumConstantDecl::Create(ASTContext &C, EnumDecl *CD, - SourceLocation L, - IdentifierInfo *Id, QualType T, - Expr *E, const llvm::APSInt &V) { - return new (C) EnumConstantDecl(CD, L, Id, T, E, V); -} - -void EnumConstantDecl::Destroy(ASTContext& C) { - if (Init) Init->Destroy(C); - Decl::Destroy(C); -} - -TypedefDecl *TypedefDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation L, IdentifierInfo *Id, - TypeSourceInfo *TInfo) { - return new (C) TypedefDecl(DC, L, Id, TInfo); -} - -// Anchor TypedefDecl's vtable here. -TypedefDecl::~TypedefDecl() {} - -EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, - IdentifierInfo *Id, SourceLocation TKL, - EnumDecl *PrevDecl) { - EnumDecl *Enum = new (C) EnumDecl(DC, L, Id, PrevDecl, TKL); - C.getTypeDeclType(Enum, PrevDecl); - return Enum; -} - -void EnumDecl::Destroy(ASTContext& C) { - Decl::Destroy(C); -} - -void EnumDecl::completeDefinition(ASTContext &C, - QualType NewType, - QualType NewPromotionType) { - assert(!isDefinition() && "Cannot redefine enums!"); - IntegerType = NewType; - PromotionType = NewPromotionType; - TagDecl::completeDefinition(); -} - -FileScopeAsmDecl *FileScopeAsmDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation L, - StringLiteral *Str) { - return new (C) FileScopeAsmDecl(DC, L, Str); -} - -//===----------------------------------------------------------------------===// -// NamedDecl Implementation -//===----------------------------------------------------------------------===// - -static NamedDecl::Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) { +static Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) { assert(D->getDeclContext()->getLookupContext()->isFileContext() && "Not a name having namespace scope"); ASTContext &Context = D->getASTContext(); @@ -260,7 +117,7 @@ static NamedDecl::Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) { if (const VarDecl *Var = dyn_cast<VarDecl>(D)) { // Explicitly declared static. if (Var->getStorageClass() == VarDecl::Static) - return NamedDecl::InternalLinkage; + return InternalLinkage; // - an object or reference that is explicitly declared const // and neither explicitly declared extern nor previously @@ -274,13 +131,16 @@ static NamedDecl::Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) { for (const VarDecl *PrevVar = Var->getPreviousDeclaration(); PrevVar && !FoundExtern; PrevVar = PrevVar->getPreviousDeclaration()) - if (PrevVar->getLinkage() == NamedDecl::ExternalLinkage) + if (isExternalLinkage(PrevVar->getLinkage())) FoundExtern = true; if (!FoundExtern) - return NamedDecl::InternalLinkage; + return InternalLinkage; } } else if (isa<FunctionDecl>(D) || isa<FunctionTemplateDecl>(D)) { + // C++ [temp]p4: + // A non-member function template can have internal linkage; any + // other template name shall have external linkage. const FunctionDecl *Function = 0; if (const FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D)) @@ -290,11 +150,11 @@ static NamedDecl::Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) { // Explicitly declared static. if (Function->getStorageClass() == FunctionDecl::Static) - return NamedDecl::InternalLinkage; + return InternalLinkage; } else if (const FieldDecl *Field = dyn_cast<FieldDecl>(D)) { // - a data member of an anonymous union. if (cast<RecordDecl>(Field->getDeclContext())->isAnonymousStructOrUnion()) - return NamedDecl::InternalLinkage; + return InternalLinkage; } // C++ [basic.link]p4: @@ -317,7 +177,7 @@ static NamedDecl::Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) { // is visible, or if the prior declaration specifies no // linkage, then the identifier has external linkage. if (const VarDecl *PrevVar = Var->getPreviousDeclaration()) { - if (NamedDecl::Linkage L = PrevVar->getLinkage()) + if (Linkage L = PrevVar->getLinkage()) return L; } } @@ -326,7 +186,10 @@ static NamedDecl::Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) { // If the declaration of an identifier for an object has file // scope and no storage-class specifier, its linkage is // external. - return NamedDecl::ExternalLinkage; + if (Var->isInAnonymousNamespace()) + return UniqueExternalLinkage; + + return ExternalLinkage; } // - a function, unless it has internal linkage; or @@ -350,12 +213,26 @@ static NamedDecl::Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) { // is visible, or if the prior declaration specifies no // linkage, then the identifier has external linkage. if (const FunctionDecl *PrevFunc = Function->getPreviousDeclaration()) { - if (NamedDecl::Linkage L = PrevFunc->getLinkage()) + if (Linkage L = PrevFunc->getLinkage()) return L; } } - return NamedDecl::ExternalLinkage; + if (Function->isInAnonymousNamespace()) + return UniqueExternalLinkage; + + if (FunctionTemplateSpecializationInfo *SpecInfo + = Function->getTemplateSpecializationInfo()) { + Linkage L = SpecInfo->getTemplate()->getLinkage(); + const TemplateArgumentList &TemplateArgs = *SpecInfo->TemplateArguments; + L = minLinkage(L, + getLinkageForTemplateArgumentList( + TemplateArgs.getFlatArgumentList(), + TemplateArgs.flat_size())); + return L; + } + + return ExternalLinkage; } // - a named class (Clause 9), or an unnamed class defined in a @@ -365,29 +242,50 @@ static NamedDecl::Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) { // defined in a typedef declaration in which the enumeration // has the typedef name for linkage purposes (7.1.3); or if (const TagDecl *Tag = dyn_cast<TagDecl>(D)) - if (Tag->getDeclName() || Tag->getTypedefForAnonDecl()) - return NamedDecl::ExternalLinkage; + if (Tag->getDeclName() || Tag->getTypedefForAnonDecl()) { + if (Tag->isInAnonymousNamespace()) + return UniqueExternalLinkage; + + // If this is a class template specialization, consider the + // linkage of the template and template arguments. + if (const ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(Tag)) { + const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); + Linkage L = getLinkageForTemplateArgumentList( + TemplateArgs.getFlatArgumentList(), + TemplateArgs.flat_size()); + return minLinkage(L, Spec->getSpecializedTemplate()->getLinkage()); + } + + return ExternalLinkage; + } // - an enumerator belonging to an enumeration with external linkage; - if (isa<EnumConstantDecl>(D)) - if (cast<NamedDecl>(D->getDeclContext())->getLinkage() - == NamedDecl::ExternalLinkage) - return NamedDecl::ExternalLinkage; + if (isa<EnumConstantDecl>(D)) { + Linkage L = cast<NamedDecl>(D->getDeclContext())->getLinkage(); + if (isExternalLinkage(L)) + return L; + } // - a template, unless it is a function template that has // internal linkage (Clause 14); - if (isa<TemplateDecl>(D)) - return NamedDecl::ExternalLinkage; + if (const TemplateDecl *Template = dyn_cast<TemplateDecl>(D)) { + if (D->isInAnonymousNamespace()) + return UniqueExternalLinkage; + + return getLinkageForTemplateParameterList( + Template->getTemplateParameters()); + } // - a namespace (7.3), unless it is declared within an unnamed // namespace. if (isa<NamespaceDecl>(D) && !D->isInAnonymousNamespace()) - return NamedDecl::ExternalLinkage; + return ExternalLinkage; - return NamedDecl::NoLinkage; + return NoLinkage; } -NamedDecl::Linkage NamedDecl::getLinkage() const { +Linkage NamedDecl::getLinkage() const { // Handle linkage for namespace-scope names. if (getDeclContext()->getLookupContext()->isFileContext()) if (Linkage L = getLinkageForNamespaceScopeDecl(this)) @@ -403,9 +301,11 @@ NamedDecl::Linkage NamedDecl::getLinkage() const { if (getDeclContext()->isRecord() && (isa<CXXMethodDecl>(this) || isa<VarDecl>(this) || (isa<TagDecl>(this) && - (getDeclName() || cast<TagDecl>(this)->getTypedefForAnonDecl()))) && - cast<RecordDecl>(getDeclContext())->getLinkage() == ExternalLinkage) - return ExternalLinkage; + (getDeclName() || cast<TagDecl>(this)->getTypedefForAnonDecl())))) { + Linkage L = cast<RecordDecl>(getDeclContext())->getLinkage(); + if (isExternalLinkage(L)) + return L; + } // C++ [basic.link]p6: // The name of a function declared in block scope and the name of @@ -424,6 +324,9 @@ NamedDecl::Linkage NamedDecl::getLinkage() const { if (Linkage L = Function->getPreviousDeclaration()->getLinkage()) return L; + if (Function->isInAnonymousNamespace()) + return UniqueExternalLinkage; + return ExternalLinkage; } @@ -434,6 +337,9 @@ NamedDecl::Linkage NamedDecl::getLinkage() const { if (Linkage L = Var->getPreviousDeclaration()->getLinkage()) return L; + if (Var->isInAnonymousNamespace()) + return UniqueExternalLinkage; + return ExternalLinkage; } } @@ -441,7 +347,7 @@ NamedDecl::Linkage NamedDecl::getLinkage() const { // C++ [basic.link]p6: // Names not covered by these rules have no linkage. return NoLinkage; -} + } std::string NamedDecl::getQualifiedNameAsString() const { return getQualifiedNameAsString(getASTContext().getLangOptions()); @@ -606,6 +512,20 @@ SourceLocation DeclaratorDecl::getTypeSpecStartLoc() const { // VarDecl Implementation //===----------------------------------------------------------------------===// +const char *VarDecl::getStorageClassSpecifierString(StorageClass SC) { + switch (SC) { + case VarDecl::None: break; + case VarDecl::Auto: return "auto"; break; + case VarDecl::Extern: return "extern"; break; + case VarDecl::PrivateExtern: return "__private_extern__"; break; + case VarDecl::Register: return "register"; break; + case VarDecl::Static: return "static"; break; + } + + assert(0 && "Invalid storage class"); + return 0; +} + VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, StorageClass S) { @@ -638,6 +558,127 @@ SourceRange VarDecl::getSourceRange() const { return SourceRange(Start, getLocation()); } +bool VarDecl::isExternC() const { + ASTContext &Context = getASTContext(); + if (!Context.getLangOptions().CPlusPlus) + return (getDeclContext()->isTranslationUnit() && + getStorageClass() != Static) || + (getDeclContext()->isFunctionOrMethod() && hasExternalStorage()); + + for (const DeclContext *DC = getDeclContext(); !DC->isTranslationUnit(); + DC = DC->getParent()) { + if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC)) { + if (Linkage->getLanguage() == LinkageSpecDecl::lang_c) + return getStorageClass() != Static; + + break; + } + + if (DC->isFunctionOrMethod()) + return false; + } + + return false; +} + +VarDecl *VarDecl::getCanonicalDecl() { + return getFirstDeclaration(); +} + +VarDecl::DefinitionKind VarDecl::isThisDeclarationADefinition() const { + // C++ [basic.def]p2: + // A declaration is a definition unless [...] it contains the 'extern' + // specifier or a linkage-specification and neither an initializer [...], + // it declares a static data member in a class declaration [...]. + // C++ [temp.expl.spec]p15: + // An explicit specialization of a static data member of a template is a + // definition if the declaration includes an initializer; otherwise, it is + // a declaration. + if (isStaticDataMember()) { + if (isOutOfLine() && (hasInit() || + getTemplateSpecializationKind() != TSK_ExplicitSpecialization)) + return Definition; + else + return DeclarationOnly; + } + // C99 6.7p5: + // A definition of an identifier is a declaration for that identifier that + // [...] causes storage to be reserved for that object. + // Note: that applies for all non-file-scope objects. + // C99 6.9.2p1: + // If the declaration of an identifier for an object has file scope and an + // initializer, the declaration is an external definition for the identifier + if (hasInit()) + return Definition; + // AST for 'extern "C" int foo;' is annotated with 'extern'. + if (hasExternalStorage()) + return DeclarationOnly; + + // C99 6.9.2p2: + // A declaration of an object that has file scope without an initializer, + // and without a storage class specifier or the scs 'static', constitutes + // a tentative definition. + // No such thing in C++. + if (!getASTContext().getLangOptions().CPlusPlus && isFileVarDecl()) + return TentativeDefinition; + + // What's left is (in C, block-scope) declarations without initializers or + // external storage. These are definitions. + return Definition; +} + +VarDecl *VarDecl::getActingDefinition() { + DefinitionKind Kind = isThisDeclarationADefinition(); + if (Kind != TentativeDefinition) + return 0; + + VarDecl *LastTentative = false; + VarDecl *First = getFirstDeclaration(); + for (redecl_iterator I = First->redecls_begin(), E = First->redecls_end(); + I != E; ++I) { + Kind = (*I)->isThisDeclarationADefinition(); + if (Kind == Definition) + return 0; + else if (Kind == TentativeDefinition) + LastTentative = *I; + } + return LastTentative; +} + +bool VarDecl::isTentativeDefinitionNow() const { + DefinitionKind Kind = isThisDeclarationADefinition(); + if (Kind != TentativeDefinition) + return false; + + for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) { + if ((*I)->isThisDeclarationADefinition() == Definition) + return false; + } + return true; +} + +VarDecl *VarDecl::getDefinition() { + VarDecl *First = getFirstDeclaration(); + for (redecl_iterator I = First->redecls_begin(), E = First->redecls_end(); + I != E; ++I) { + if ((*I)->isThisDeclarationADefinition() == Definition) + return *I; + } + return 0; +} + +const Expr *VarDecl::getAnyInitializer(const VarDecl *&D) const { + redecl_iterator I = redecls_begin(), E = redecls_end(); + while (I != E && !I->getInit()) + ++I; + + if (I != E) { + D = *I; + return I->getInit(); + } + return 0; +} + bool VarDecl::isOutOfLine() const { if (!isStaticDataMember()) return false; @@ -667,6 +708,15 @@ VarDecl *VarDecl::getOutOfLineDefinition() { return 0; } +void VarDecl::setInit(Expr *I) { + if (EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>()) { + Eval->~EvaluatedStmt(); + getASTContext().Deallocate(Eval); + } + + Init = I; +} + VarDecl *VarDecl::getInstantiatedFromStaticDataMember() const { if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) return cast<VarDecl>(MSI->getInstantiatedFrom()); @@ -675,8 +725,7 @@ VarDecl *VarDecl::getInstantiatedFromStaticDataMember() const { } TemplateSpecializationKind VarDecl::getTemplateSpecializationKind() const { - if (MemberSpecializationInfo *MSI - = getASTContext().getInstantiatedFromStaticDataMember(this)) + if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) return MSI->getTemplateSpecializationKind(); return TSK_Undeclared; @@ -697,29 +746,53 @@ void VarDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK, MSI->setPointOfInstantiation(PointOfInstantiation); } -bool VarDecl::isTentativeDefinition(ASTContext &Context) const { - if (!isFileVarDecl() || Context.getLangOptions().CPlusPlus) - return false; +//===----------------------------------------------------------------------===// +// ParmVarDecl Implementation +//===----------------------------------------------------------------------===// - const VarDecl *Def = 0; - return (!getDefinition(Def) && - (getStorageClass() == None || getStorageClass() == Static)); +ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id, + QualType T, TypeSourceInfo *TInfo, + StorageClass S, Expr *DefArg) { + return new (C) ParmVarDecl(ParmVar, DC, L, Id, T, TInfo, S, DefArg); } -const Expr *VarDecl::getDefinition(const VarDecl *&Def) const { - redecl_iterator I = redecls_begin(), E = redecls_end(); - while (I != E && !I->getInit()) - ++I; +Expr *ParmVarDecl::getDefaultArg() { + assert(!hasUnparsedDefaultArg() && "Default argument is not yet parsed!"); + assert(!hasUninstantiatedDefaultArg() && + "Default argument is not yet instantiated!"); + + Expr *Arg = getInit(); + if (CXXExprWithTemporaries *E = dyn_cast_or_null<CXXExprWithTemporaries>(Arg)) + return E->getSubExpr(); + + return Arg; +} + +unsigned ParmVarDecl::getNumDefaultArgTemporaries() const { + if (const CXXExprWithTemporaries *E = + dyn_cast<CXXExprWithTemporaries>(getInit())) + return E->getNumTemporaries(); - if (I != E) { - Def = *I; - return I->getInit(); - } return 0; } -VarDecl *VarDecl::getCanonicalDecl() { - return getFirstDeclaration(); +CXXTemporary *ParmVarDecl::getDefaultArgTemporary(unsigned i) { + assert(getNumDefaultArgTemporaries() && + "Default arguments does not have any temporaries!"); + + CXXExprWithTemporaries *E = cast<CXXExprWithTemporaries>(getInit()); + return E->getTemporary(i); +} + +SourceRange ParmVarDecl::getDefaultArgRange() const { + if (const Expr *E = getInit()) + return E->getSourceRange(); + + if (hasUninstantiatedDefaultArg()) + return getUninstantiatedDefaultArg()->getSourceRange(); + + return SourceRange(); } //===----------------------------------------------------------------------===// @@ -826,6 +899,26 @@ bool FunctionDecl::isGlobal() const { return true; } +void +FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) { + redeclarable_base::setPreviousDeclaration(PrevDecl); + + if (FunctionTemplateDecl *FunTmpl = getDescribedFunctionTemplate()) { + FunctionTemplateDecl *PrevFunTmpl + = PrevDecl? PrevDecl->getDescribedFunctionTemplate() : 0; + assert((!PrevDecl || PrevFunTmpl) && "Function/function template mismatch"); + FunTmpl->setPreviousDeclaration(PrevFunTmpl); + } +} + +const FunctionDecl *FunctionDecl::getCanonicalDecl() const { + return getFirstDeclaration(); +} + +FunctionDecl *FunctionDecl::getCanonicalDecl() { + return getFirstDeclaration(); +} + /// \brief Returns a value indicating whether this function /// corresponds to a builtin function. /// @@ -882,14 +975,13 @@ unsigned FunctionDecl::getNumParams() const { } -void FunctionDecl::setParams(ASTContext& C, ParmVarDecl **NewParamInfo, - unsigned NumParams) { +void FunctionDecl::setParams(ParmVarDecl **NewParamInfo, unsigned NumParams) { assert(ParamInfo == 0 && "Already has param info!"); assert(NumParams == getNumParams() && "Parameter count mismatch!"); // Zero params -> null pointer. if (NumParams) { - void *Mem = C.Allocate(sizeof(ParmVarDecl*)*NumParams); + void *Mem = getASTContext().Allocate(sizeof(ParmVarDecl*)*NumParams); ParamInfo = new (Mem) ParmVarDecl*[NumParams]; memcpy(ParamInfo, NewParamInfo, sizeof(ParmVarDecl*)*NumParams); @@ -1014,26 +1106,6 @@ bool FunctionDecl::isInlineDefinitionExternallyVisible() const { return false; } -void -FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) { - redeclarable_base::setPreviousDeclaration(PrevDecl); - - if (FunctionTemplateDecl *FunTmpl = getDescribedFunctionTemplate()) { - FunctionTemplateDecl *PrevFunTmpl - = PrevDecl? PrevDecl->getDescribedFunctionTemplate() : 0; - assert((!PrevDecl || PrevFunTmpl) && "Function/function template mismatch"); - FunTmpl->setPreviousDeclaration(PrevFunTmpl); - } -} - -const FunctionDecl *FunctionDecl::getCanonicalDecl() const { - return getFirstDeclaration(); -} - -FunctionDecl *FunctionDecl::getCanonicalDecl() { - return getFirstDeclaration(); -} - /// getOverloadedOperator - Which C++ overloaded operator this /// function represents, if any. OverloadedOperatorKind FunctionDecl::getOverloadedOperator() const { @@ -1146,8 +1218,7 @@ FunctionDecl::getTemplateSpecializationArgs() const { } void -FunctionDecl::setFunctionTemplateSpecialization(ASTContext &Context, - FunctionTemplateDecl *Template, +FunctionDecl::setFunctionTemplateSpecialization(FunctionTemplateDecl *Template, const TemplateArgumentList *TemplateArgs, void *InsertPos, TemplateSpecializationKind TSK) { @@ -1156,7 +1227,7 @@ FunctionDecl::setFunctionTemplateSpecialization(ASTContext &Context, FunctionTemplateSpecializationInfo *Info = TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>(); if (!Info) - Info = new (Context) FunctionTemplateSpecializationInfo; + Info = new (getASTContext()) FunctionTemplateSpecializationInfo; Info->Function = this; Info->Template.setPointer(Template); @@ -1254,6 +1325,26 @@ bool FunctionDecl::isOutOfLine() const { } //===----------------------------------------------------------------------===// +// FieldDecl Implementation +//===----------------------------------------------------------------------===// + +FieldDecl *FieldDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, + IdentifierInfo *Id, QualType T, + TypeSourceInfo *TInfo, Expr *BW, bool Mutable) { + return new (C) FieldDecl(Decl::Field, DC, L, Id, T, TInfo, BW, Mutable); +} + +bool FieldDecl::isAnonymousStructOrUnion() const { + if (!isImplicit() || getDeclName()) + return false; + + if (const RecordType *Record = getType()->getAs<RecordType>()) + return Record->getDecl()->isAnonymousStructOrUnion(); + + return false; +} + +//===----------------------------------------------------------------------===// // TagDecl Implementation //===----------------------------------------------------------------------===// @@ -1271,9 +1362,23 @@ void TagDecl::startDefinition() { TagT->decl.setPointer(this); TagT->decl.setInt(1); } + + if (isa<CXXRecordDecl>(this)) { + CXXRecordDecl *D = cast<CXXRecordDecl>(this); + struct CXXRecordDecl::DefinitionData *Data = + new (getASTContext()) struct CXXRecordDecl::DefinitionData(D); + do { + D->DefinitionData = Data; + D = cast_or_null<CXXRecordDecl>(D->getPreviousDeclaration()); + } while (D); + } } void TagDecl::completeDefinition() { + assert((!isa<CXXRecordDecl>(this) || + cast<CXXRecordDecl>(this)->hasDefinition()) && + "definition completed but not started"); + IsDefinition = true; if (TagType *TagT = const_cast<TagType *>(TypeForDecl->getAs<TagType>())) { assert(TagT->decl.getPointer() == this && @@ -1282,7 +1387,7 @@ void TagDecl::completeDefinition() { } } -TagDecl* TagDecl::getDefinition(ASTContext& C) const { +TagDecl* TagDecl::getDefinition() const { if (isDefinition()) return const_cast<TagDecl *>(this); @@ -1305,6 +1410,30 @@ TagDecl::TagKind TagDecl::getTagKindForTypeSpec(unsigned TypeSpec) { } //===----------------------------------------------------------------------===// +// EnumDecl Implementation +//===----------------------------------------------------------------------===// + +EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, + IdentifierInfo *Id, SourceLocation TKL, + EnumDecl *PrevDecl) { + EnumDecl *Enum = new (C) EnumDecl(DC, L, Id, PrevDecl, TKL); + C.getTypeDeclType(Enum, PrevDecl); + return Enum; +} + +void EnumDecl::Destroy(ASTContext& C) { + Decl::Destroy(C); +} + +void EnumDecl::completeDefinition(QualType NewType, + QualType NewPromotionType) { + assert(!isDefinition() && "Cannot redefine enums!"); + IntegerType = NewType; + PromotionType = NewPromotionType; + TagDecl::completeDefinition(); +} + +//===----------------------------------------------------------------------===// // RecordDecl Implementation //===----------------------------------------------------------------------===// @@ -1341,7 +1470,7 @@ bool RecordDecl::isInjectedClassName() const { /// completeDefinition - Notes that the definition of this type is now /// complete. -void RecordDecl::completeDefinition(ASTContext& C) { +void RecordDecl::completeDefinition() { assert(!isDefinition() && "Cannot redefine record!"); TagDecl::completeDefinition(); } @@ -1364,14 +1493,14 @@ void BlockDecl::Destroy(ASTContext& C) { Decl::Destroy(C); } -void BlockDecl::setParams(ASTContext& C, ParmVarDecl **NewParamInfo, +void BlockDecl::setParams(ParmVarDecl **NewParamInfo, unsigned NParms) { assert(ParamInfo == 0 && "Already has param info!"); // Zero params -> null pointer. if (NParms) { NumParams = NParms; - void *Mem = C.Allocate(sizeof(ParmVarDecl*)*NumParams); + void *Mem = getASTContext().Allocate(sizeof(ParmVarDecl*)*NumParams); ParamInfo = new (Mem) ParmVarDecl*[NumParams]; memcpy(ParamInfo, NewParamInfo, sizeof(ParmVarDecl*)*NumParams); } @@ -1380,3 +1509,74 @@ void BlockDecl::setParams(ASTContext& C, ParmVarDecl **NewParamInfo, unsigned BlockDecl::getNumParams() const { return NumParams; } + + +//===----------------------------------------------------------------------===// +// Other Decl Allocation/Deallocation Method Implementations +//===----------------------------------------------------------------------===// + +TranslationUnitDecl *TranslationUnitDecl::Create(ASTContext &C) { + return new (C) TranslationUnitDecl(C); +} + +NamespaceDecl *NamespaceDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id) { + return new (C) NamespaceDecl(DC, L, Id); +} + +void NamespaceDecl::Destroy(ASTContext& C) { + // NamespaceDecl uses "NextDeclarator" to chain namespace declarations + // together. They are all top-level Decls. + + this->~NamespaceDecl(); + C.Deallocate((void *)this); +} + + +ImplicitParamDecl *ImplicitParamDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id, QualType T) { + return new (C) ImplicitParamDecl(ImplicitParam, DC, L, Id, T); +} + +FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + DeclarationName N, QualType T, + TypeSourceInfo *TInfo, + StorageClass S, bool isInline, + bool hasWrittenPrototype) { + FunctionDecl *New + = new (C) FunctionDecl(Function, DC, L, N, T, TInfo, S, isInline); + New->HasWrittenPrototype = hasWrittenPrototype; + return New; +} + +BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) { + return new (C) BlockDecl(DC, L); +} + +EnumConstantDecl *EnumConstantDecl::Create(ASTContext &C, EnumDecl *CD, + SourceLocation L, + IdentifierInfo *Id, QualType T, + Expr *E, const llvm::APSInt &V) { + return new (C) EnumConstantDecl(CD, L, Id, T, E, V); +} + +void EnumConstantDecl::Destroy(ASTContext& C) { + if (Init) Init->Destroy(C); + Decl::Destroy(C); +} + +TypedefDecl *TypedefDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id, + TypeSourceInfo *TInfo) { + return new (C) TypedefDecl(DC, L, Id, TInfo); +} + +// Anchor TypedefDecl's vtable here. +TypedefDecl::~TypedefDecl() {} + +FileScopeAsmDecl *FileScopeAsmDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + StringLiteral *Str) { + return new (C) FileScopeAsmDecl(DC, L, Str); +} diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index 84aa81c..863a1cb 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -448,7 +448,10 @@ bool DeclContext::classof(const Decl *D) { } DeclContext::~DeclContext() { - delete static_cast<StoredDeclsMap*>(LookupPtr); + // FIXME: Currently ~ASTContext will delete the StoredDeclsMaps because + // ~DeclContext() is not guaranteed to be called when ASTContext uses + // a BumpPtrAllocator. + // delete static_cast<StoredDeclsMap*>(LookupPtr); } void DeclContext::DestroyDecls(ASTContext &C) { @@ -622,7 +625,8 @@ DeclContext::LoadVisibleDeclsFromExternalStorage() const { // Load the declaration IDs for all of the names visible in this // context. assert(!LookupPtr && "Have a lookup map before de-serialization?"); - StoredDeclsMap *Map = new StoredDeclsMap; + StoredDeclsMap *Map = + (StoredDeclsMap*) getParentASTContext().CreateStoredDeclsMap(); LookupPtr = Map; for (unsigned I = 0, N = Decls.size(); I != N; ++I) { (*Map)[Decls[I].Name].setFromDeclIDs(Decls[I].Declarations); @@ -830,8 +834,11 @@ void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D) { if (isa<ClassTemplateSpecializationDecl>(D)) return; - if (!LookupPtr) - LookupPtr = new StoredDeclsMap; + ASTContext *C = 0; + if (!LookupPtr) { + C = &getParentASTContext(); + LookupPtr = (StoredDeclsMap*) C->CreateStoredDeclsMap(); + } // Insert this declaration into the map. StoredDeclsMap &Map = *static_cast<StoredDeclsMap*>(LookupPtr); @@ -844,7 +851,10 @@ void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D) { // If it is possible that this is a redeclaration, check to see if there is // already a decl for which declarationReplaces returns true. If there is // one, just replace it and return. - if (DeclNameEntries.HandleRedeclaration(getParentASTContext(), D)) + if (!C) + C = &getParentASTContext(); + + if (DeclNameEntries.HandleRedeclaration(*C, D)) return; // Put this declaration into the appropriate slot. @@ -896,3 +906,18 @@ void StoredDeclsList::materializeDecls(ASTContext &Context) { } } } + +//===----------------------------------------------------------------------===// +// Creation and Destruction of StoredDeclsMaps. // +//===----------------------------------------------------------------------===// + +void *ASTContext::CreateStoredDeclsMap() { + StoredDeclsMap *M = new StoredDeclsMap(); + SDMs.push_back(M); + return M; +} + +void ASTContext::ReleaseDeclContextMaps() { + for (std::vector<void*>::iterator I = SDMs.begin(), E = SDMs.end(); I!=E; ++I) + delete (StoredDeclsMap*) *I; +} diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index fe6064d..b0569d6 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -25,18 +25,23 @@ using namespace clang; // Decl Allocation/Deallocation Method Implementations //===----------------------------------------------------------------------===// -CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC, - SourceLocation L, IdentifierInfo *Id, - CXXRecordDecl *PrevDecl, - SourceLocation TKL) - : RecordDecl(K, TK, DC, L, Id, PrevDecl, TKL), - UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false), +CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D) + : UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false), UserDeclaredCopyAssignment(false), UserDeclaredDestructor(false), Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false), Abstract(false), HasTrivialConstructor(true), HasTrivialCopyConstructor(true), HasTrivialCopyAssignment(true), HasTrivialDestructor(true), ComputedVisibleConversions(false), Bases(0), NumBases(0), VBases(0), NumVBases(0), + Definition(D) { +} + +CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id, + CXXRecordDecl *PrevDecl, + SourceLocation TKL) + : RecordDecl(K, TK, DC, L, Id, PrevDecl, TKL), + DefinitionData(PrevDecl ? PrevDecl->DefinitionData : 0), TemplateOrInstantiation() { } CXXRecordDecl *CXXRecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC, @@ -57,31 +62,35 @@ CXXRecordDecl::~CXXRecordDecl() { } void CXXRecordDecl::Destroy(ASTContext &C) { - C.Deallocate(Bases); - C.Deallocate(VBases); + if (data().Definition == this) { + C.Deallocate(data().Bases); + C.Deallocate(data().VBases); + C.Deallocate(&data()); + } this->RecordDecl::Destroy(C); } void -CXXRecordDecl::setBases(ASTContext &C, - CXXBaseSpecifier const * const *Bases, +CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, unsigned NumBases) { + ASTContext &C = getASTContext(); + // C++ [dcl.init.aggr]p1: // An aggregate is an array or a class (clause 9) with [...] // no base classes [...]. - Aggregate = false; + data().Aggregate = false; - if (this->Bases) - C.Deallocate(this->Bases); + if (data().Bases) + C.Deallocate(data().Bases); int vbaseCount = 0; llvm::SmallVector<const CXXBaseSpecifier*, 8> UniqueVbases; bool hasDirectVirtualBase = false; - this->Bases = new(C) CXXBaseSpecifier [NumBases]; - this->NumBases = NumBases; + data().Bases = new(C) CXXBaseSpecifier [NumBases]; + data().NumBases = NumBases; for (unsigned i = 0; i < NumBases; ++i) { - this->Bases[i] = *Bases[i]; + data().Bases[i] = *Bases[i]; // Keep track of inherited vbases for this base class. const CXXBaseSpecifier *Base = Bases[i]; QualType BaseType = Base->getType(); @@ -130,13 +139,13 @@ CXXRecordDecl::setBases(ASTContext &C, } if (vbaseCount > 0) { // build AST for inhireted, direct or indirect, virtual bases. - this->VBases = new (C) CXXBaseSpecifier [vbaseCount]; - this->NumVBases = vbaseCount; + data().VBases = new (C) CXXBaseSpecifier [vbaseCount]; + data().NumVBases = vbaseCount; for (int i = 0; i < vbaseCount; i++) { QualType QT = UniqueVbases[i]->getType(); CXXRecordDecl *VBaseClassDecl = cast<CXXRecordDecl>(QT->getAs<RecordType>()->getDecl()); - this->VBases[i] = + data().VBases[i] = CXXBaseSpecifier(VBaseClassDecl->getSourceRange(), true, VBaseClassDecl->getTagKind() == RecordDecl::TK_class, UniqueVbases[i]->getAccessSpecifier(), QT); @@ -239,32 +248,32 @@ CXXRecordDecl::addedConstructor(ASTContext &Context, CXXConstructorDecl *ConDecl) { assert(!ConDecl->isImplicit() && "addedConstructor - not for implicit decl"); // Note that we have a user-declared constructor. - UserDeclaredConstructor = true; + data().UserDeclaredConstructor = true; // C++ [dcl.init.aggr]p1: // An aggregate is an array or a class (clause 9) with no // user-declared constructors (12.1) [...]. - Aggregate = false; + data().Aggregate = false; // C++ [class]p4: // A POD-struct is an aggregate class [...] - PlainOldData = false; + data().PlainOldData = false; // C++ [class.ctor]p5: // A constructor is trivial if it is an implicitly-declared default // constructor. // FIXME: C++0x: don't do this for "= default" default constructors. - HasTrivialConstructor = false; + data().HasTrivialConstructor = false; // Note when we have a user-declared copy constructor, which will // suppress the implicit declaration of a copy constructor. if (ConDecl->isCopyConstructor()) { - UserDeclaredCopyConstructor = true; + data().UserDeclaredCopyConstructor = true; // C++ [class.copy]p6: // A copy constructor is trivial if it is implicitly declared. // FIXME: C++0x: don't do this for "= default" copy constructors. - HasTrivialCopyConstructor = false; + data().HasTrivialCopyConstructor = false; } } @@ -295,17 +304,17 @@ void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context, OpDecl->setCopyAssignment(true); // Suppress the implicit declaration of a copy constructor. - UserDeclaredCopyAssignment = true; + data().UserDeclaredCopyAssignment = true; // C++ [class.copy]p11: // A copy assignment operator is trivial if it is implicitly declared. // FIXME: C++0x: don't do this for "= default" copy operators. - HasTrivialCopyAssignment = false; + data().HasTrivialCopyAssignment = false; // C++ [class]p4: // A POD-struct is an aggregate class that [...] has no user-defined copy // assignment operator [...]. - PlainOldData = false; + data().PlainOldData = false; } void @@ -415,42 +424,42 @@ CXXRecordDecl::getNestedVisibleConversionFunctions(CXXRecordDecl *RD, const UnresolvedSetImpl *CXXRecordDecl::getVisibleConversionFunctions() { // If root class, all conversions are visible. if (bases_begin() == bases_end()) - return &Conversions; + return &data().Conversions; // If visible conversion list is already evaluated, return it. - if (ComputedVisibleConversions) - return &VisibleConversions; + if (data().ComputedVisibleConversions) + return &data().VisibleConversions; llvm::SmallPtrSet<CanQualType, 8> TopConversionsTypeSet; collectConversionFunctions(TopConversionsTypeSet); getNestedVisibleConversionFunctions(this, TopConversionsTypeSet, TopConversionsTypeSet); - ComputedVisibleConversions = true; - return &VisibleConversions; + data().ComputedVisibleConversions = true; + return &data().VisibleConversions; } void CXXRecordDecl::addVisibleConversionFunction( CXXConversionDecl *ConvDecl) { assert(!ConvDecl->getDescribedFunctionTemplate() && "Conversion function templates should cast to FunctionTemplateDecl."); - VisibleConversions.addDecl(ConvDecl); + data().VisibleConversions.addDecl(ConvDecl); } void CXXRecordDecl::addVisibleConversionFunction( FunctionTemplateDecl *ConvDecl) { assert(isa<CXXConversionDecl>(ConvDecl->getTemplatedDecl()) && "Function template is not a conversion function template"); - VisibleConversions.addDecl(ConvDecl); + data().VisibleConversions.addDecl(ConvDecl); } void CXXRecordDecl::addConversionFunction(CXXConversionDecl *ConvDecl) { assert(!ConvDecl->getDescribedFunctionTemplate() && "Conversion function templates should cast to FunctionTemplateDecl."); - Conversions.addDecl(ConvDecl); + data().Conversions.addDecl(ConvDecl); } void CXXRecordDecl::addConversionFunction(FunctionTemplateDecl *ConvDecl) { assert(isa<CXXConversionDecl>(ConvDecl->getTemplatedDecl()) && "Function template is not a conversion function template"); - Conversions.addDecl(ConvDecl); + data().Conversions.addDecl(ConvDecl); } @@ -579,7 +588,8 @@ bool CXXMethodDecl::isUsualDeallocationFunction() const { // then this function is a usual deallocation function. ASTContext &Context = getASTContext(); if (getNumParams() != 2 || - !Context.hasSameType(getParamDecl(1)->getType(), Context.getSizeType())) + !Context.hasSameUnqualifiedType(getParamDecl(1)->getType(), + Context.getSizeType())) return false; // This function is a usual deallocation function if there are no @@ -604,7 +614,9 @@ static OverriddenMethodsMapTy *OverriddenMethods = 0; void CXXMethodDecl::addOverriddenMethod(const CXXMethodDecl *MD) { assert(MD->isCanonicalDecl() && "Method is not canonical!"); - + assert(!MD->getParent()->isDependentContext() && + "Can't add an overridden method to a class template!"); + // FIXME: The CXXMethodDecl dtor needs to remove and free the entry. if (!OverriddenMethods) @@ -671,42 +683,25 @@ bool CXXMethodDecl::hasInlineBody() const { CXXBaseOrMemberInitializer:: CXXBaseOrMemberInitializer(ASTContext &Context, - TypeSourceInfo *TInfo, CXXConstructorDecl *C, - SourceLocation L, - Expr **Args, unsigned NumArgs, - SourceLocation R) - : BaseOrMember(TInfo), Args(0), NumArgs(0), CtorOrAnonUnion(C), + TypeSourceInfo *TInfo, + SourceLocation L, Expr *Init, SourceLocation R) + : BaseOrMember(TInfo), Init(Init), AnonUnionMember(0), LParenLoc(L), RParenLoc(R) { - if (NumArgs > 0) { - this->NumArgs = NumArgs; - this->Args = new (Context) Stmt*[NumArgs]; - for (unsigned Idx = 0; Idx < NumArgs; ++Idx) - this->Args[Idx] = Args[Idx]; - } } CXXBaseOrMemberInitializer:: CXXBaseOrMemberInitializer(ASTContext &Context, FieldDecl *Member, SourceLocation MemberLoc, - CXXConstructorDecl *C, SourceLocation L, - Expr **Args, unsigned NumArgs, - SourceLocation R) - : BaseOrMember(Member), MemberLocation(MemberLoc), Args(0), NumArgs(0), - CtorOrAnonUnion(C), LParenLoc(L), RParenLoc(R) + SourceLocation L, Expr *Init, SourceLocation R) + : BaseOrMember(Member), MemberLocation(MemberLoc), Init(Init), + AnonUnionMember(0), LParenLoc(L), RParenLoc(R) { - if (NumArgs > 0) { - this->NumArgs = NumArgs; - this->Args = new (Context) Stmt*[NumArgs]; - for (unsigned Idx = 0; Idx < NumArgs; ++Idx) - this->Args[Idx] = Args[Idx]; - } } void CXXBaseOrMemberInitializer::Destroy(ASTContext &Context) { - for (unsigned I = 0; I != NumArgs; ++I) - Args[I]->Destroy(Context); - Context.Deallocate(Args); + if (Init) + Init->Destroy(Context); this->~CXXBaseOrMemberInitializer(); } diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index ffda505..131e098 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -111,8 +111,9 @@ ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const { // Look through categories. for (ObjCCategoryDecl *Category = OID->getCategoryList(); Category; Category = Category->getNextClassCategory()) { - if (ObjCPropertyDecl *P = Category->FindPropertyDeclaration(PropertyId)) - return P; + if (!Category->IsClassExtension()) + if (ObjCPropertyDecl *P = Category->FindPropertyDeclaration(PropertyId)) + return P; } // Look through protocols. for (ObjCInterfaceDecl::protocol_iterator I = OID->protocol_begin(), @@ -124,10 +125,11 @@ ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const { return OID->getSuperClass()->FindPropertyDeclaration(PropertyId); } else if (const ObjCCategoryDecl *OCD = dyn_cast<ObjCCategoryDecl>(this)) { // Look through protocols. - for (ObjCInterfaceDecl::protocol_iterator I = OCD->protocol_begin(), - E = OCD->protocol_end(); I != E; ++I) { - if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId)) - return P; + if (!OCD->IsClassExtension()) + for (ObjCInterfaceDecl::protocol_iterator I = OCD->protocol_begin(), + E = OCD->protocol_end(); I != E; ++I) { + if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId)) + return P; } } return 0; diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index 32ac53d..a625865 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -17,6 +17,7 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/PrettyPrinter.h" #include "llvm/Support/raw_ostream.h" using namespace clang; @@ -403,32 +404,51 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { CXXBaseOrMemberInitializer * BMInitializer = (*B); if (B != CDecl->init_begin()) Out << ", "; - bool hasArguments = (BMInitializer->arg_begin() != - BMInitializer->arg_end()); if (BMInitializer->isMemberInitializer()) { FieldDecl *FD = BMInitializer->getMember(); Out << FD->getNameAsString(); + } else { + Out << QualType(BMInitializer->getBaseClass(), 0).getAsString(); } - else // FIXME. skip dependent types for now. - if (const RecordType *RT = - BMInitializer->getBaseClass()->getAs<RecordType>()) { - const CXXRecordDecl *BaseDecl = - cast<CXXRecordDecl>(RT->getDecl()); - Out << BaseDecl->getNameAsString(); - } - if (hasArguments) { - Out << "("; - for (CXXBaseOrMemberInitializer::const_arg_iterator BE = - BMInitializer->const_arg_begin(), - EE = BMInitializer->const_arg_end(); BE != EE; ++BE) { - if (BE != BMInitializer->const_arg_begin()) - Out<< ", "; - const Expr *Exp = (*BE); - Exp->printPretty(Out, Context, 0, Policy, Indentation); + + Out << "("; + if (!BMInitializer->getInit()) { + // Nothing to print + } else { + Expr *Init = BMInitializer->getInit(); + if (CXXExprWithTemporaries *Tmp + = dyn_cast<CXXExprWithTemporaries>(Init)) + Init = Tmp->getSubExpr(); + + Init = Init->IgnoreParens(); + + Expr *SimpleInit = 0; + Expr **Args = 0; + unsigned NumArgs = 0; + if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(Init)) { + Args = ParenList->getExprs(); + NumArgs = ParenList->getNumExprs(); + } else if (CXXConstructExpr *Construct + = dyn_cast<CXXConstructExpr>(Init)) { + Args = Construct->getArgs(); + NumArgs = Construct->getNumArgs(); + } else + SimpleInit = Init; + + if (SimpleInit) + SimpleInit->printPretty(Out, Context, 0, Policy, Indentation); + else { + for (unsigned I = 0; I != NumArgs; ++I) { + if (isa<CXXDefaultArgExpr>(Args[I])) + break; + + if (I) + Out << ", "; + Args[I]->printPretty(Out, Context, 0, Policy, Indentation); + } } - Out << ")"; - } else - Out << "()"; + } + Out << ")"; } } } diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index 75b3975..d80db45 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -213,7 +213,8 @@ QualType ClassTemplateDecl::getInjectedClassNameType(ASTContext &Context) { TemplateArgs.push_back(TemplateArgument(ParamType)); } else if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*Param)) { - Expr *E = new (Context) DeclRefExpr(NTTP, NTTP->getType(), + Expr *E = new (Context) DeclRefExpr(NTTP, + NTTP->getType().getNonReferenceType(), NTTP->getLocation()); TemplateArgs.push_back(TemplateArgument(E)); } else { diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp index ff81073..19b58bc 100644 --- a/lib/AST/DeclarationName.cpp +++ b/lib/AST/DeclarationName.cpp @@ -66,27 +66,33 @@ public: } }; -bool operator<(DeclarationName LHS, DeclarationName RHS) { +static int compareInt(unsigned A, unsigned B) { + return (A < B ? -1 : (A > B ? 1 : 0)); +} + +int DeclarationName::compare(DeclarationName LHS, DeclarationName RHS) { if (LHS.getNameKind() != RHS.getNameKind()) - return LHS.getNameKind() < RHS.getNameKind(); + return (LHS.getNameKind() < RHS.getNameKind() ? -1 : 1); switch (LHS.getNameKind()) { - case DeclarationName::Identifier: - return LHS.getAsIdentifierInfo()->getName() < - RHS.getAsIdentifierInfo()->getName(); + case DeclarationName::Identifier: { + IdentifierInfo *LII = LHS.getAsIdentifierInfo(); + IdentifierInfo *RII = RHS.getAsIdentifierInfo(); + if (!LII) return RII ? -1 : 0; + if (!RII) return 1; + + return LII->getName().compare(RII->getName()); + } case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: { Selector LHSSelector = LHS.getObjCSelector(); Selector RHSSelector = RHS.getObjCSelector(); - for (unsigned I = 0, - N = std::min(LHSSelector.getNumArgs(), RHSSelector.getNumArgs()); - I != N; ++I) { + unsigned LN = LHSSelector.getNumArgs(), RN = RHSSelector.getNumArgs(); + for (unsigned I = 0, N = std::min(LN, RN); I != N; ++I) { IdentifierInfo *LHSId = LHSSelector.getIdentifierInfoForSlot(I); IdentifierInfo *RHSId = RHSSelector.getIdentifierInfoForSlot(I); - if (!LHSId || !RHSId) - return LHSId && !RHSId; switch (LHSId->getName().compare(RHSId->getName())) { case -1: return true; @@ -94,27 +100,32 @@ bool operator<(DeclarationName LHS, DeclarationName RHS) { default: break; } } - - return LHSSelector.getNumArgs() < RHSSelector.getNumArgs(); + + return compareInt(LN, RN); } case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: case DeclarationName::CXXConversionFunctionName: - return QualTypeOrdering()(LHS.getCXXNameType(), RHS.getCXXNameType()); + if (QualTypeOrdering()(LHS.getCXXNameType(), RHS.getCXXNameType())) + return -1; + if (QualTypeOrdering()(RHS.getCXXNameType(), LHS.getCXXNameType())) + return 1; + return 0; case DeclarationName::CXXOperatorName: - return LHS.getCXXOverloadedOperator() < RHS.getCXXOverloadedOperator(); + return compareInt(LHS.getCXXOverloadedOperator(), + RHS.getCXXOverloadedOperator()); case DeclarationName::CXXLiteralOperatorName: - return LHS.getCXXLiteralIdentifier()->getName() < - RHS.getCXXLiteralIdentifier()->getName(); + return LHS.getCXXLiteralIdentifier()->getName().compare( + RHS.getCXXLiteralIdentifier()->getName()); case DeclarationName::CXXUsingDirective: - return false; + return 0; } - return false; + return 0; } } // end namespace clang diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index fa44b51..4cb0aa4 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -99,8 +99,7 @@ void DeclRefExpr::computeDependence() { else if (VarDecl *Var = dyn_cast<VarDecl>(D)) { if (Var->getType()->isIntegralType() && Var->getType().getCVRQualifiers() == Qualifiers::Const) { - const VarDecl *Def = 0; - if (const Expr *Init = Var->getDefinition(Def)) + if (const Expr *Init = Var->getAnyInitializer()) if (Init->isValueDependent()) ValueDependent = true; } @@ -164,17 +163,18 @@ SourceRange DeclRefExpr::getSourceRange() const { // FIXME: Maybe this should use DeclPrinter with a special "print predefined // expr" policy instead. -std::string PredefinedExpr::ComputeName(ASTContext &Context, IdentType IT, - const Decl *CurrentDecl) { +std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) { + ASTContext &Context = CurrentDecl->getASTContext(); + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CurrentDecl)) { - if (IT != PrettyFunction) + if (IT != PrettyFunction && IT != PrettyFunctionNoVirtual) return FD->getNameAsString(); llvm::SmallString<256> Name; llvm::raw_svector_ostream Out(Name); if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) { - if (MD->isVirtual()) + if (MD->isVirtual() && IT != PrettyFunctionNoVirtual) Out << "virtual "; if (MD->isStatic()) Out << "static "; @@ -827,9 +827,17 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, case BinaryOperatorClass: { const BinaryOperator *BO = cast<BinaryOperator>(this); // Consider comma to have side effects if the LHS or RHS does. - if (BO->getOpcode() == BinaryOperator::Comma) + if (BO->getOpcode() == BinaryOperator::Comma) { + // ((foo = <blah>), 0) is an idiom for hiding the result (and + // lvalue-ness) of an assignment written in a macro. + if (IntegerLiteral *IE = + dyn_cast<IntegerLiteral>(BO->getRHS()->IgnoreParens())) + if (IE->getValue() == 0) + return false; + return (BO->getRHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx) || BO->getLHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx)); + } if (BO->isAssignmentOp()) return false; @@ -1068,9 +1076,7 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const { if (isa<FieldDecl>(Member)) { if (m->isArrow()) return LV_Valid; - Expr *BaseExp = m->getBase(); - return (BaseExp->getStmtClass() == ObjCPropertyRefExprClass) ? - LV_SubObjCPropertySetting : BaseExp->isLvalue(Ctx); + return m->getBase()->isLvalue(Ctx); } // -- If it refers to a static member function [...], then @@ -1093,8 +1099,11 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const { if (m->isArrow()) return LV_Valid; Expr *BaseExp = m->getBase(); - return (BaseExp->getStmtClass() == ObjCPropertyRefExprClass) ? - LV_SubObjCPropertySetting : BaseExp->isLvalue(Ctx); + if (BaseExp->getStmtClass() == ObjCPropertyRefExprClass) + return LV_SubObjCPropertySetting; + return + (BaseExp->getStmtClass() == ObjCImplicitSetterGetterRefExprClass) ? + LV_SubObjCPropertyGetterSetting : BaseExp->isLvalue(Ctx); } case UnaryOperatorClass: if (cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::Deref) @@ -1205,6 +1214,9 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const { case CXXBindTemporaryExprClass: return cast<CXXBindTemporaryExpr>(this)->getSubExpr()-> isLvalueInternal(Ctx); + case CXXBindReferenceExprClass: + // Something that's bound to a reference is always an lvalue. + return LV_Valid; case ConditionalOperatorClass: { // Complicated handling is only for C++. if (!Ctx.getLangOptions().CPlusPlus) @@ -1281,7 +1293,9 @@ Expr::isModifiableLvalue(ASTContext &Ctx, SourceLocation *Loc) const { } return MLV_InvalidExpression; case LV_MemberFunction: return MLV_MemberFunction; - case LV_SubObjCPropertySetting: return MLV_SubObjCPropertySetting; + case LV_SubObjCPropertySetting: return MLV_SubObjCPropertySetting; + case LV_SubObjCPropertyGetterSetting: + return MLV_SubObjCPropertyGetterSetting; } // The following is illegal: @@ -1594,6 +1608,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::DependentScopeDeclRefExprClass: case Expr::CXXConstructExprClass: case Expr::CXXBindTemporaryExprClass: + case Expr::CXXBindReferenceExprClass: case Expr::CXXExprWithTemporariesClass: case Expr::CXXTemporaryObjectExprClass: case Expr::CXXUnresolvedConstructExprClass: @@ -1613,7 +1628,6 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::BlockExprClass: case Expr::BlockDeclRefExprClass: case Expr::NoStmtClass: - case Expr::ExprClass: return ICEDiag(2, E->getLocStart()); case Expr::GNUNullExprClass: @@ -1650,30 +1664,22 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { if (Quals.hasVolatile() || !Quals.hasConst()) return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation()); - // Look for the definition of this variable, which will actually have - // an initializer. - const VarDecl *Def = 0; - const Expr *Init = Dcl->getDefinition(Def); + // Look for a declaration of this variable that has an initializer. + const VarDecl *ID = 0; + const Expr *Init = Dcl->getAnyInitializer(ID); if (Init) { - if (Def->isInitKnownICE()) { + if (ID->isInitKnownICE()) { // We have already checked whether this subexpression is an // integral constant expression. - if (Def->isInitICE()) + if (ID->isInitICE()) return NoDiag(); else return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation()); } - // C++ [class.static.data]p4: - // If a static data member is of const integral or const - // enumeration type, its declaration in the class definition can - // specify a constant-initializer which shall be an integral - // constant expression (5.19). In that case, the member can appear - // in integral constant expressions. - if (Def->isOutOfLine()) { - Dcl->setInitKnownICE(false); - return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation()); - } + // It's an ICE whether or not the definition we found is + // out-of-line. See DR 721 and the discussion in Clang PR + // 6206 for details. if (Dcl->isCheckingICE()) { return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation()); @@ -1810,9 +1816,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { } } } - case Expr::CastExprClass: case Expr::ImplicitCastExprClass: - case Expr::ExplicitCastExprClass: case Expr::CStyleCastExprClass: case Expr::CXXFunctionalCastExprClass: case Expr::CXXNamedCastExprClass: @@ -1954,6 +1958,13 @@ bool Expr::isNullPointerConstant(ASTContext &Ctx, FieldDecl *Expr::getBitField() { Expr *E = this->IgnoreParens(); + while (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) { + if (ICE->isLvalueCast() && ICE->getCastKind() == CastExpr::CK_NoOp) + E = ICE->getSubExpr()->IgnoreParens(); + else + break; + } + if (MemberExpr *MemRef = dyn_cast<MemberExpr>(E)) if (FieldDecl *Field = dyn_cast<FieldDecl>(MemRef->getMemberDecl())) if (Field->isBitField()) @@ -1966,6 +1977,25 @@ FieldDecl *Expr::getBitField() { return 0; } +bool Expr::refersToVectorElement() const { + const Expr *E = this->IgnoreParens(); + + while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) { + if (ICE->isLvalueCast() && ICE->getCastKind() == CastExpr::CK_NoOp) + E = ICE->getSubExpr()->IgnoreParens(); + else + break; + } + + if (const ArraySubscriptExpr *ASE = dyn_cast<ArraySubscriptExpr>(E)) + return ASE->getBase()->getType()->isVectorType(); + + if (isa<ExtVectorElementExpr>(E)) + return true; + + return false; +} + /// isArrow - Return true if the base expression is a pointer to vector, /// return false if the base expression is a vector. bool ExtVectorElementExpr::isArrow() const { @@ -2030,14 +2060,15 @@ void ExtVectorElementExpr::getEncodedElementAccess( } // constructor for instance messages. -ObjCMessageExpr::ObjCMessageExpr(Expr *receiver, Selector selInfo, - QualType retType, ObjCMethodDecl *mproto, - SourceLocation LBrac, SourceLocation RBrac, - Expr **ArgExprs, unsigned nargs) +ObjCMessageExpr::ObjCMessageExpr(ASTContext &C, Expr *receiver, + Selector selInfo, + QualType retType, ObjCMethodDecl *mproto, + SourceLocation LBrac, SourceLocation RBrac, + Expr **ArgExprs, unsigned nargs) : Expr(ObjCMessageExprClass, retType, false, false), SelName(selInfo), MethodProto(mproto) { NumArgs = nargs; - SubExprs = new Stmt*[NumArgs+1]; + SubExprs = new (C) Stmt*[NumArgs+1]; SubExprs[RECEIVER] = receiver; if (NumArgs) { for (unsigned i = 0; i != NumArgs; ++i) @@ -2049,14 +2080,15 @@ ObjCMessageExpr::ObjCMessageExpr(Expr *receiver, Selector selInfo, // constructor for class messages. // FIXME: clsName should be typed to ObjCInterfaceType -ObjCMessageExpr::ObjCMessageExpr(IdentifierInfo *clsName, Selector selInfo, - QualType retType, ObjCMethodDecl *mproto, - SourceLocation LBrac, SourceLocation RBrac, - Expr **ArgExprs, unsigned nargs) +ObjCMessageExpr::ObjCMessageExpr(ASTContext &C, IdentifierInfo *clsName, + Selector selInfo, QualType retType, + ObjCMethodDecl *mproto, + SourceLocation LBrac, SourceLocation RBrac, + Expr **ArgExprs, unsigned nargs) : Expr(ObjCMessageExprClass, retType, false, false), SelName(selInfo), MethodProto(mproto) { NumArgs = nargs; - SubExprs = new Stmt*[NumArgs+1]; + SubExprs = new (C) Stmt*[NumArgs+1]; SubExprs[RECEIVER] = (Expr*) ((uintptr_t) clsName | IsClsMethDeclUnknown); if (NumArgs) { for (unsigned i = 0; i != NumArgs; ++i) @@ -2067,14 +2099,15 @@ ObjCMessageExpr::ObjCMessageExpr(IdentifierInfo *clsName, Selector selInfo, } // constructor for class messages. -ObjCMessageExpr::ObjCMessageExpr(ObjCInterfaceDecl *cls, Selector selInfo, - QualType retType, ObjCMethodDecl *mproto, - SourceLocation LBrac, SourceLocation RBrac, - Expr **ArgExprs, unsigned nargs) +ObjCMessageExpr::ObjCMessageExpr(ASTContext &C, ObjCInterfaceDecl *cls, + Selector selInfo, QualType retType, + ObjCMethodDecl *mproto, SourceLocation LBrac, + SourceLocation RBrac, Expr **ArgExprs, + unsigned nargs) : Expr(ObjCMessageExprClass, retType, false, false), SelName(selInfo), MethodProto(mproto) { NumArgs = nargs; - SubExprs = new Stmt*[NumArgs+1]; + SubExprs = new (C) Stmt*[NumArgs+1]; SubExprs[RECEIVER] = (Expr*) ((uintptr_t) cls | IsClsMethDeclKnown); if (NumArgs) { for (unsigned i = 0; i != NumArgs; ++i) @@ -2109,6 +2142,13 @@ void ObjCMessageExpr::setClassInfo(const ObjCMessageExpr::ClassInfo &CI) { SubExprs[RECEIVER] = (Expr*)((uintptr_t)CI.first | IsClsMethDeclKnown); } +void ObjCMessageExpr::DoDestroy(ASTContext &C) { + DestroyChildren(C); + if (SubExprs) + C.Deallocate(SubExprs); + this->~ObjCMessageExpr(); + C.Deallocate((void*) this); +} bool ChooseExpr::isConditionTrue(ASTContext &C) const { return getCond()->EvaluateAsInt(C) != 0; diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index a6574ef..f4b8333 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -73,7 +73,7 @@ Stmt::child_iterator CXXZeroInitValueExpr::child_end() { } // CXXNewExpr -CXXNewExpr::CXXNewExpr(bool globalNew, FunctionDecl *operatorNew, +CXXNewExpr::CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew, Expr **placementArgs, unsigned numPlaceArgs, bool parenTypeId, Expr *arraySize, CXXConstructorDecl *constructor, bool initializer, @@ -87,7 +87,7 @@ CXXNewExpr::CXXNewExpr(bool globalNew, FunctionDecl *operatorNew, OperatorDelete(operatorDelete), Constructor(constructor), StartLoc(startLoc), EndLoc(endLoc) { unsigned TotalSize = Array + NumPlacementArgs + NumConstructorArgs; - SubExprs = new Stmt*[TotalSize]; + SubExprs = new (C) Stmt*[TotalSize]; unsigned i = 0; if (Array) SubExprs[i++] = arraySize; @@ -98,6 +98,14 @@ CXXNewExpr::CXXNewExpr(bool globalNew, FunctionDecl *operatorNew, assert(i == TotalSize); } +void CXXNewExpr::DoDestroy(ASTContext &C) { + DestroyChildren(C); + if (SubExprs) + C.Deallocate(SubExprs); + this->~CXXNewExpr(); + C.Deallocate((void*)this); +} + Stmt::child_iterator CXXNewExpr::child_begin() { return &SubExprs[0]; } Stmt::child_iterator CXXNewExpr::child_end() { return &SubExprs[0] + Array + getNumPlacementArgs() + getNumConstructorArgs(); @@ -116,6 +124,7 @@ Stmt::child_iterator CXXPseudoDestructorExpr::child_end() { // UnresolvedLookupExpr UnresolvedLookupExpr * UnresolvedLookupExpr::Create(ASTContext &C, bool Dependent, + CXXRecordDecl *NamingClass, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, DeclarationName Name, SourceLocation NameLoc, bool ADL, @@ -125,7 +134,8 @@ UnresolvedLookupExpr::Create(ASTContext &C, bool Dependent, ExplicitTemplateArgumentList::sizeFor(Args)); UnresolvedLookupExpr *ULE = new (Mem) UnresolvedLookupExpr(Dependent ? C.DependentTy : C.OverloadTy, - Dependent, Qualifier, QualifierRange, + Dependent, NamingClass, + Qualifier, QualifierRange, Name, NameLoc, ADL, /*Overload*/ true, /*ExplicitTemplateArgs*/ true); @@ -135,10 +145,9 @@ UnresolvedLookupExpr::Create(ASTContext &C, bool Dependent, return ULE; } -bool UnresolvedLookupExpr:: - ComputeDependence(UnresolvedSetImpl::const_iterator Begin, - UnresolvedSetImpl::const_iterator End, - const TemplateArgumentListInfo *Args) { +bool OverloadExpr::ComputeDependence(UnresolvedSetIterator Begin, + UnresolvedSetIterator End, + const TemplateArgumentListInfo *Args) { for (UnresolvedSetImpl::const_iterator I = Begin; I != End; ++I) if ((*I)->getDeclContext()->isDependentContext()) return true; @@ -393,6 +402,19 @@ void CXXBindTemporaryExpr::DoDestroy(ASTContext &C) { C.Deallocate(this); } +CXXBindReferenceExpr *CXXBindReferenceExpr::Create(ASTContext &C, Expr *SubExpr, + bool ExtendsLifetime, + bool RequiresTemporaryCopy) { + return new (C) CXXBindReferenceExpr(SubExpr, + ExtendsLifetime, + RequiresTemporaryCopy); +} + +void CXXBindReferenceExpr::DoDestroy(ASTContext &C) { + this->~CXXBindReferenceExpr(); + C.Deallocate(this); +} + CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(ASTContext &C, CXXConstructorDecl *Cons, QualType writtenTy, @@ -409,22 +431,26 @@ CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T, SourceLocation Loc, CXXConstructorDecl *D, bool Elidable, Expr **Args, unsigned NumArgs, - bool ZeroInitialization) { + bool ZeroInitialization, + bool BaseInitialization) { return new (C) CXXConstructExpr(C, CXXConstructExprClass, T, Loc, D, - Elidable, Args, NumArgs, ZeroInitialization); + Elidable, Args, NumArgs, ZeroInitialization, + BaseInitialization); } CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T, SourceLocation Loc, CXXConstructorDecl *D, bool elidable, Expr **args, unsigned numargs, - bool ZeroInitialization) + bool ZeroInitialization, + bool BaseInitialization) : Expr(SC, T, T->isDependentType(), (T->isDependentType() || CallExpr::hasAnyValueDependentArguments(args, numargs))), Constructor(D), Loc(Loc), Elidable(elidable), - ZeroInitialization(ZeroInitialization), Args(0), NumArgs(numargs) + ZeroInitialization(ZeroInitialization), + BaseInitialization(BaseInitialization), Args(0), NumArgs(numargs) { if (NumArgs) { Args = new (C) Stmt*[NumArgs]; @@ -491,6 +517,15 @@ Stmt::child_iterator CXXBindTemporaryExpr::child_end() { return &SubExpr + 1; } +// CXXBindReferenceExpr +Stmt::child_iterator CXXBindReferenceExpr::child_begin() { + return &SubExpr; +} + +Stmt::child_iterator CXXBindReferenceExpr::child_end() { + return &SubExpr + 1; +} + // CXXConstructExpr Stmt::child_iterator CXXConstructExpr::child_begin() { return &Args[0]; @@ -618,15 +653,13 @@ UnresolvedMemberExpr::UnresolvedMemberExpr(QualType T, bool Dependent, DeclarationName MemberName, SourceLocation MemberLoc, const TemplateArgumentListInfo *TemplateArgs) - : Expr(UnresolvedMemberExprClass, T, Dependent, Dependent), - Base(Base), BaseType(BaseType), IsArrow(IsArrow), - HasUnresolvedUsing(HasUnresolvedUsing), - HasExplicitTemplateArgs(TemplateArgs != 0), - OperatorLoc(OperatorLoc), - Qualifier(Qualifier), QualifierRange(QualifierRange), - MemberName(MemberName), MemberLoc(MemberLoc) { + : OverloadExpr(UnresolvedMemberExprClass, T, Dependent, + Qualifier, QualifierRange, MemberName, MemberLoc, + TemplateArgs != 0), + IsArrow(IsArrow), HasUnresolvedUsing(HasUnresolvedUsing), + Base(Base), BaseType(BaseType), OperatorLoc(OperatorLoc) { if (TemplateArgs) - getExplicitTemplateArgs()->initializeFrom(*TemplateArgs); + getExplicitTemplateArgs().initializeFrom(*TemplateArgs); } UnresolvedMemberExpr * @@ -651,6 +684,35 @@ UnresolvedMemberExpr::Create(ASTContext &C, bool Dependent, Member, MemberLoc, TemplateArgs); } +CXXRecordDecl *UnresolvedMemberExpr::getNamingClass() const { + // Unlike for UnresolvedLookupExpr, it is very easy to re-derive this. + + // If there was a nested name specifier, it names the naming class. + // It can't be dependent: after all, we were actually able to do the + // lookup. + const RecordType *RT; + if (getQualifier()) { + Type *T = getQualifier()->getAsType(); + assert(T && "qualifier in member expression does not name type"); + RT = T->getAs<RecordType>(); + assert(RT && "qualifier in member expression does not name record"); + + // Otherwise the naming class must have been the base class. + } else { + QualType BaseType = getBaseType().getNonReferenceType(); + if (isArrow()) { + const PointerType *PT = BaseType->getAs<PointerType>(); + assert(PT && "base of arrow member access is not pointer"); + BaseType = PT->getPointeeType(); + } + + RT = BaseType->getAs<RecordType>(); + assert(RT && "base of member expression does not name record"); + } + + return cast<CXXRecordDecl>(RT->getDecl()); +} + Stmt::child_iterator UnresolvedMemberExpr::child_begin() { return child_iterator(&Base); } diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 086249c..1a44cd0 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -263,8 +263,7 @@ APValue LValueExprEvaluator::VisitDeclRefExpr(DeclRefExpr *E) { if (!VD->getType()->isReferenceType()) return APValue(E); // FIXME: Check whether VD might be overridden! - const VarDecl *Def = 0; - if (const Expr *Init = VD->getDefinition(Def)) + if (const Expr *Init = VD->getAnyInitializer()) return Visit(const_cast<Expr *>(Init)); } @@ -813,7 +812,7 @@ public: return false; } - bool VisitCallExpr(const CallExpr *E); + bool VisitCallExpr(CallExpr *E); bool VisitBinaryOperator(const BinaryOperator *E); bool VisitUnaryOperator(const UnaryOperator *E); bool VisitConditionalOperator(const ConditionalOperator *E); @@ -849,8 +848,8 @@ public: bool VisitUnaryImag(const UnaryOperator *E); private: - unsigned GetAlignOfExpr(const Expr *E); - unsigned GetAlignOfType(QualType T); + CharUnits GetAlignOfExpr(const Expr *E); + CharUnits GetAlignOfType(QualType T); // FIXME: Missing: array subscript of vector, member of vector }; } // end anonymous namespace @@ -879,9 +878,12 @@ bool IntExprEvaluator::CheckReferencedDecl(const Expr* E, const Decl* D) { // In C, they can also be folded, although they are not ICEs. if (Info.Ctx.getCanonicalType(E->getType()).getCVRQualifiers() == Qualifiers::Const) { + + if (isa<ParmVarDecl>(D)) + return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E); + if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { - const VarDecl *Def = 0; - if (const Expr *Init = VD->getDefinition(Def)) { + if (const Expr *Init = VD->getAnyInitializer()) { if (APValue *V = VD->getEvaluatedValue()) { if (V->isInt()) return Success(V->getInt(), E); @@ -965,7 +967,7 @@ static int EvaluateBuiltinClassifyType(const CallExpr *E) { return -1; } -bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { +bool IntExprEvaluator::VisitCallExpr(CallExpr *E) { switch (E->isBuiltinCall(Info.Ctx)) { default: return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E); @@ -1020,6 +1022,9 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { Operand = Info.Ctx.Target.getEHDataRegisterNumber(Operand); return Success(Operand, E); } + + case Builtin::BI__builtin_expect: + return Visit(E->getArg(0)); } } @@ -1288,7 +1293,7 @@ bool IntExprEvaluator::VisitConditionalOperator(const ConditionalOperator *E) { return Visit(Cond ? E->getTrueExpr() : E->getFalseExpr()); } -unsigned IntExprEvaluator::GetAlignOfType(QualType T) { +CharUnits IntExprEvaluator::GetAlignOfType(QualType T) { // C++ [expr.sizeof]p2: "When applied to a reference or a reference type, // the result is the size of the referenced type." // C++ [expr.alignof]p3: "When alignof is applied to a reference type, the @@ -1300,20 +1305,22 @@ unsigned IntExprEvaluator::GetAlignOfType(QualType T) { unsigned CharSize = Info.Ctx.Target.getCharWidth(); // __alignof is defined to return the preferred alignment. - return Info.Ctx.getPreferredTypeAlign(T.getTypePtr()) / CharSize; + return CharUnits::fromQuantity( + Info.Ctx.getPreferredTypeAlign(T.getTypePtr()) / CharSize); } -unsigned IntExprEvaluator::GetAlignOfExpr(const Expr *E) { +CharUnits IntExprEvaluator::GetAlignOfExpr(const Expr *E) { E = E->IgnoreParens(); // alignof decl is always accepted, even if it doesn't make sense: we default // to 1 in those cases. if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) - return Info.Ctx.getDeclAlignInBytes(DRE->getDecl(), /*RefAsPointee*/true); + return Info.Ctx.getDeclAlign(DRE->getDecl(), + /*RefAsPointee*/true); if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) - return Info.Ctx.getDeclAlignInBytes(ME->getMemberDecl(), - /*RefAsPointee*/true); + return Info.Ctx.getDeclAlign(ME->getMemberDecl(), + /*RefAsPointee*/true); return GetAlignOfType(E->getType()); } @@ -1325,9 +1332,9 @@ bool IntExprEvaluator::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E) { // Handle alignof separately. if (!E->isSizeOf()) { if (E->isArgumentType()) - return Success(GetAlignOfType(E->getArgumentType()), E); + return Success(GetAlignOfType(E->getArgumentType()).getQuantity(), E); else - return Success(GetAlignOfExpr(E->getArgumentExpr()), E); + return Success(GetAlignOfExpr(E->getArgumentExpr()).getQuantity(), E); } QualType SrcTy = E->getTypeOfArgument(); diff --git a/lib/AST/Makefile b/lib/AST/Makefile index f7d4e9f..8afc629 100644 --- a/lib/AST/Makefile +++ b/lib/AST/Makefile @@ -14,7 +14,6 @@ LEVEL = ../../../.. LIBRARYNAME := clangAST BUILD_ARCHIVE = 1 -CXXFLAGS = -fno-rtti CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index 0aa0180..50acd15 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -119,11 +119,10 @@ ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD, return; } } - if (i->isVirtual()) { - SelectPrimaryVBase(Base, FirstPrimary); - if (PrimaryBase.getBase()) - return; - } + assert(i->isVirtual()); + SelectPrimaryVBase(Base, FirstPrimary); + if (PrimaryBase.getBase()) + return; } } diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index 104e336..8347249 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -35,6 +35,7 @@ static StmtClassNameTable &getStmtInfoTableEntry(Stmt::StmtClass E) { // Intialize the table on the first use. Initialized = true; +#define ABSTRACT_EXPR(CLASS, PARENT) #define STMT(CLASS, PARENT) \ StmtClassInfo[(unsigned)Stmt::CLASS##Class].Name = #CLASS; \ StmtClassInfo[(unsigned)Stmt::CLASS##Class].Size = sizeof(CLASS); @@ -132,9 +133,8 @@ Expr *AsmStmt::getOutputExpr(unsigned i) { /// getOutputConstraint - Return the constraint string for the specified /// output operand. All output constraints are known to be non-empty (either /// '=' or '+'). -std::string AsmStmt::getOutputConstraint(unsigned i) const { - return std::string(Constraints[i]->getStrData(), - Constraints[i]->getByteLength()); +llvm::StringRef AsmStmt::getOutputConstraint(unsigned i) const { + return getOutputConstraintLiteral(i)->getString(); } /// getNumPlusOperands - Return the number of output operands that have a "+" @@ -147,40 +147,52 @@ unsigned AsmStmt::getNumPlusOperands() const { return Res; } - - Expr *AsmStmt::getInputExpr(unsigned i) { return cast<Expr>(Exprs[i + NumOutputs]); } /// getInputConstraint - Return the specified input constraint. Unlike output /// constraints, these can be empty. -std::string AsmStmt::getInputConstraint(unsigned i) const { - return std::string(Constraints[i + NumOutputs]->getStrData(), - Constraints[i + NumOutputs]->getByteLength()); +llvm::StringRef AsmStmt::getInputConstraint(unsigned i) const { + return getInputConstraintLiteral(i)->getString(); } -void AsmStmt::setOutputsAndInputs(unsigned NumOutputs, - unsigned NumInputs, - const std::string *Names, - StringLiteral **Constraints, - Stmt **Exprs) { +void AsmStmt::setOutputsAndInputsAndClobbers(ASTContext &C, + IdentifierInfo **Names, + StringLiteral **Constraints, + Stmt **Exprs, + unsigned NumOutputs, + unsigned NumInputs, + StringLiteral **Clobbers, + unsigned NumClobbers) { this->NumOutputs = NumOutputs; this->NumInputs = NumInputs; - this->Names.clear(); - this->Names.insert(this->Names.end(), Names, Names + NumOutputs + NumInputs); - this->Constraints.clear(); - this->Constraints.insert(this->Constraints.end(), - Constraints, Constraints + NumOutputs + NumInputs); - this->Exprs.clear(); - this->Exprs.insert(this->Exprs.end(), Exprs, Exprs + NumOutputs + NumInputs); + this->NumClobbers = NumClobbers; + + unsigned NumExprs = NumOutputs + NumInputs; + + C.Deallocate(this->Names); + this->Names = new (C) IdentifierInfo*[NumExprs]; + std::copy(Names, Names + NumExprs, this->Names); + + C.Deallocate(this->Exprs); + this->Exprs = new (C) Stmt*[NumExprs]; + std::copy(Exprs, Exprs + NumExprs, this->Exprs); + + C.Deallocate(this->Constraints); + this->Constraints = new (C) StringLiteral*[NumExprs]; + std::copy(Constraints, Constraints + NumExprs, this->Constraints); + + C.Deallocate(this->Clobbers); + this->Clobbers = new (C) StringLiteral*[NumClobbers]; + std::copy(Clobbers, Clobbers + NumClobbers, this->Clobbers); } /// getNamedOperand - Given a symbolic operand reference like %[foo], /// translate this into a numeric value needed to reference the same operand. /// This returns -1 if the operand name is invalid. -int AsmStmt::getNamedOperand(const std::string &SymbolicName) const { +int AsmStmt::getNamedOperand(llvm::StringRef SymbolicName) const { unsigned NumPlusOperands = 0; // Check if this is an output operand. @@ -197,11 +209,6 @@ int AsmStmt::getNamedOperand(const std::string &SymbolicName) const { return -1; } -void AsmStmt::setClobbers(StringLiteral **Clobbers, unsigned NumClobbers) { - this->Clobbers.clear(); - this->Clobbers.insert(this->Clobbers.end(), Clobbers, Clobbers + NumClobbers); -} - /// AnalyzeAsmString - Analyze the asm string of the current asm, decomposing /// it into pieces. If the asm string is erroneous, emit errors and return /// true, otherwise return false. @@ -313,7 +320,7 @@ unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl<AsmStringPiece>&Pieces, if (NameEnd == CurPtr) return diag::err_asm_empty_symbolic_operand_name; - std::string SymbolicName(CurPtr, NameEnd); + llvm::StringRef SymbolicName(CurPtr, NameEnd - CurPtr); int N = getNamedOperand(SymbolicName); if (N == -1) { @@ -332,26 +339,39 @@ unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl<AsmStringPiece>&Pieces, } } +QualType CXXCatchStmt::getCaughtType() const { + if (ExceptionDecl) + return ExceptionDecl->getType(); + return QualType(); +} + //===----------------------------------------------------------------------===// // Constructors //===----------------------------------------------------------------------===// -AsmStmt::AsmStmt(SourceLocation asmloc, bool issimple, bool isvolatile, - bool msasm, unsigned numoutputs, unsigned numinputs, - std::string *names, StringLiteral **constraints, +AsmStmt::AsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple, + bool isvolatile, bool msasm, + unsigned numoutputs, unsigned numinputs, + IdentifierInfo **names, StringLiteral **constraints, Expr **exprs, StringLiteral *asmstr, unsigned numclobbers, StringLiteral **clobbers, SourceLocation rparenloc) : Stmt(AsmStmtClass), AsmLoc(asmloc), RParenLoc(rparenloc), AsmStr(asmstr) , IsSimple(issimple), IsVolatile(isvolatile), MSAsm(msasm) - , NumOutputs(numoutputs), NumInputs(numinputs) { - for (unsigned i = 0, e = numinputs + numoutputs; i != e; i++) { - Names.push_back(names[i]); - Exprs.push_back(exprs[i]); - Constraints.push_back(constraints[i]); - } + , NumOutputs(numoutputs), NumInputs(numinputs), NumClobbers(numclobbers) { - for (unsigned i = 0; i != numclobbers; i++) - Clobbers.push_back(clobbers[i]); + unsigned NumExprs = NumOutputs +NumInputs; + + Names = new (C) IdentifierInfo*[NumExprs]; + std::copy(names, names + NumExprs, Names); + + Exprs = new (C) Stmt*[NumExprs]; + std::copy(exprs, exprs + NumExprs, Exprs); + + Constraints = new (C) StringLiteral*[NumExprs]; + std::copy(constraints, constraints + NumExprs, Constraints); + + Clobbers = new (C) StringLiteral*[NumClobbers]; + std::copy(clobbers, clobbers + NumClobbers, Clobbers); } ObjCForCollectionStmt::ObjCForCollectionStmt(Stmt *Elem, Expr *Collect, @@ -387,6 +407,24 @@ ObjCAtCatchStmt::ObjCAtCatchStmt(SourceLocation atCatchLoc, RParenLoc = rparenloc; } +CXXTryStmt *CXXTryStmt::Create(ASTContext &C, SourceLocation tryLoc, + Stmt *tryBlock, Stmt **handlers, + unsigned numHandlers) { + std::size_t Size = sizeof(CXXTryStmt); + Size += ((numHandlers + 1) * sizeof(Stmt)); + + void *Mem = C.Allocate(Size, llvm::alignof<CXXTryStmt>()); + return new (Mem) CXXTryStmt(tryLoc, tryBlock, handlers, numHandlers); +} + +CXXTryStmt::CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock, + Stmt **handlers, unsigned numHandlers) + : Stmt(CXXTryStmtClass), TryLoc(tryLoc), NumHandlers(numHandlers) { + Stmt **Stmts = reinterpret_cast<Stmt **>(this + 1); + Stmts[0] = tryBlock; + std::copy(handlers, handlers + NumHandlers, Stmts + 1); +} + //===----------------------------------------------------------------------===// // AST Destruction. //===----------------------------------------------------------------------===// @@ -453,6 +491,18 @@ void WhileStmt::DoDestroy(ASTContext &C) { BranchDestroy(C, this, SubExprs, END_EXPR); } +void AsmStmt::DoDestroy(ASTContext &C) { + DestroyChildren(C); + + C.Deallocate(Names); + C.Deallocate(Constraints); + C.Deallocate(Exprs); + C.Deallocate(Clobbers); + + this->~AsmStmt(); + C.Deallocate((void *)this); +} + //===----------------------------------------------------------------------===// // Child Iterators for iterating over subexpressions/substatements //===----------------------------------------------------------------------===// @@ -566,10 +616,10 @@ Stmt::child_iterator ReturnStmt::child_end() { // AsmStmt Stmt::child_iterator AsmStmt::child_begin() { - return Exprs.empty() ? 0 : &Exprs[0]; + return NumOutputs + NumInputs == 0 ? 0 : &Exprs[0]; } Stmt::child_iterator AsmStmt::child_end() { - return Exprs.empty() ? 0 : &Exprs[0] + Exprs.size(); + return NumOutputs + NumInputs == 0 ? 0 : &Exprs[0] + NumOutputs + NumInputs; } // ObjCAtCatchStmt @@ -615,19 +665,11 @@ Stmt::child_iterator CXXCatchStmt::child_end() { return &HandlerBlock + 1; } -QualType CXXCatchStmt::getCaughtType() const { - if (ExceptionDecl) - return ExceptionDecl->getType(); - return QualType(); -} - // CXXTryStmt -Stmt::child_iterator CXXTryStmt::child_begin() { return &Stmts[0]; } -Stmt::child_iterator CXXTryStmt::child_end() { return &Stmts[0]+Stmts.size(); } +Stmt::child_iterator CXXTryStmt::child_begin() { + return reinterpret_cast<Stmt **>(this + 1); +} -CXXTryStmt::CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock, - Stmt **handlers, unsigned numHandlers) - : Stmt(CXXTryStmtClass), TryLoc(tryLoc) { - Stmts.push_back(tryBlock); - Stmts.insert(Stmts.end(), handlers, handlers + numHandlers); +Stmt::child_iterator CXXTryStmt::child_end() { + return reinterpret_cast<Stmt **>(this + 1) + NumHandlers + 1; } diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp index ae76526..ba6218b 100644 --- a/lib/AST/StmtDumper.cpp +++ b/lib/AST/StmtDumper.cpp @@ -472,6 +472,8 @@ void StmtDumper::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node) { void StmtDumper::VisitCXXConstructExpr(CXXConstructExpr *Node) { DumpExpr(Node); + CXXConstructorDecl *Ctor = Node->getConstructor(); + DumpType(Ctor->getType()); if (Node->isElidable()) OS << " elidable"; } diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index bbb904d..3ae306d 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -1038,6 +1038,10 @@ void StmtPrinter::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node) { PrintExpr(Node->getSubExpr()); } +void StmtPrinter::VisitCXXBindReferenceExpr(CXXBindReferenceExpr *Node) { + PrintExpr(Node->getSubExpr()); +} + void StmtPrinter::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *Node) { OS << Node->getType().getAsString(); OS << "("; diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index b74e1ef..3a19ec2 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -465,6 +465,10 @@ void StmtProfiler::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *S) { const_cast<CXXDestructorDecl *>(S->getTemporary()->getDestructor())); } +void StmtProfiler::VisitCXXBindReferenceExpr(CXXBindReferenceExpr *S) { + VisitExpr(S); +} + void StmtProfiler::VisitCXXConstructExpr(CXXConstructExpr *S) { VisitExpr(S); VisitDecl(S->getConstructor()); diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index edfb580..76cc382 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -339,21 +339,18 @@ const RecordType *Type::getAsUnionType() const { return 0; } -ObjCInterfaceType::ObjCInterfaceType(ASTContext &Ctx, QualType Canonical, +ObjCInterfaceType::ObjCInterfaceType(QualType Canonical, ObjCInterfaceDecl *D, ObjCProtocolDecl **Protos, unsigned NumP) : Type(ObjCInterface, Canonical, /*Dependent=*/false), - Decl(D), Protocols(0), NumProtocols(NumP) + Decl(D), NumProtocols(NumP) { - if (NumProtocols) { - Protocols = new (Ctx) ObjCProtocolDecl*[NumProtocols]; - memcpy(Protocols, Protos, NumProtocols * sizeof(*Protocols)); - } + if (NumProtocols) + memcpy(reinterpret_cast<ObjCProtocolDecl**>(this + 1), Protos, + NumProtocols * sizeof(*Protos)); } void ObjCInterfaceType::Destroy(ASTContext& C) { - if (Protocols) - C.Deallocate(Protocols); this->~ObjCInterfaceType(); C.Deallocate(this); } @@ -372,22 +369,18 @@ bool Type::isObjCQualifiedInterfaceType() const { return getAsObjCQualifiedInterfaceType() != 0; } -ObjCObjectPointerType::ObjCObjectPointerType(ASTContext &Ctx, - QualType Canonical, QualType T, +ObjCObjectPointerType::ObjCObjectPointerType(QualType Canonical, QualType T, ObjCProtocolDecl **Protos, unsigned NumP) : Type(ObjCObjectPointer, Canonical, /*Dependent=*/false), - PointeeType(T), Protocols(NULL), NumProtocols(NumP) + PointeeType(T), NumProtocols(NumP) { - if (NumProtocols) { - Protocols = new (Ctx) ObjCProtocolDecl*[NumProtocols]; - memcpy(Protocols, Protos, NumProtocols * sizeof(*Protocols)); - } + if (NumProtocols) + memcpy(reinterpret_cast<ObjCProtocolDecl **>(this + 1), Protos, + NumProtocols * sizeof(*Protos)); } void ObjCObjectPointerType::Destroy(ASTContext& C) { - if (Protocols) - C.Deallocate(Protocols); this->~ObjCObjectPointerType(); C.Deallocate(this); } @@ -720,6 +713,19 @@ bool Type::isPromotableIntegerType() const { default: return false; } + + // Enumerated types are promotable to their compatible integer types + // (C99 6.3.1.1) a.k.a. its underlying type (C++ [conv.prom]p2). + if (const EnumType *ET = getAs<EnumType>()){ + if (this->isDependentType() || ET->getDecl()->getPromotionType().isNull()) + return false; + + const BuiltinType *BT + = ET->getDecl()->getPromotionType()->getAs<BuiltinType>(); + return BT->getKind() == BuiltinType::Int + || BT->getKind() == BuiltinType::UInt; + } + return false; } @@ -797,12 +803,24 @@ const char *BuiltinType::getName(const LangOptions &LO) const { } } +llvm::StringRef FunctionType::getNameForCallConv(CallingConv CC) { + switch (CC) { + case CC_Default: llvm_unreachable("no name for default cc"); + default: return ""; + + case CC_C: return "cdecl"; + case CC_X86StdCall: return "stdcall"; + case CC_X86FastCall: return "fastcall"; + } +} + void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result, arg_type_iterator ArgTys, unsigned NumArgs, bool isVariadic, unsigned TypeQuals, bool hasExceptionSpec, bool anyExceptionSpec, unsigned NumExceptions, - exception_iterator Exs, bool NoReturn) { + exception_iterator Exs, bool NoReturn, + CallingConv CallConv) { ID.AddPointer(Result.getAsOpaquePtr()); for (unsigned i = 0; i != NumArgs; ++i) ID.AddPointer(ArgTys[i].getAsOpaquePtr()); @@ -815,16 +833,19 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result, ID.AddPointer(Exs[i].getAsOpaquePtr()); } ID.AddInteger(NoReturn); + ID.AddInteger(CallConv); } void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getResultType(), arg_type_begin(), NumArgs, isVariadic(), getTypeQuals(), hasExceptionSpec(), hasAnyExceptionSpec(), - getNumExceptions(), exception_begin(), getNoReturnAttr()); + getNumExceptions(), exception_begin(), getNoReturnAttr(), + getCallConv()); } void ObjCObjectPointerType::Profile(llvm::FoldingSetNodeID &ID, - QualType OIT, ObjCProtocolDecl **protocols, + QualType OIT, + ObjCProtocolDecl * const *protocols, unsigned NumProtocols) { ID.AddPointer(OIT.getAsOpaquePtr()); for (unsigned i = 0; i != NumProtocols; i++) @@ -832,10 +853,7 @@ void ObjCObjectPointerType::Profile(llvm::FoldingSetNodeID &ID, } void ObjCObjectPointerType::Profile(llvm::FoldingSetNodeID &ID) { - if (getNumProtocols()) - Profile(ID, getPointeeType(), &Protocols[0], getNumProtocols()); - else - Profile(ID, getPointeeType(), 0, 0); + Profile(ID, getPointeeType(), qual_begin(), getNumProtocols()); } /// LookThroughTypedefs - Return the ultimate type this typedef corresponds to @@ -894,8 +912,9 @@ void DependentDecltypeType::Profile(llvm::FoldingSetNodeID &ID, E->Profile(ID, Context, true); } -TagType::TagType(TypeClass TC, TagDecl *D, QualType can) - : Type(TC, can, D->isDependentType()), decl(D, 0) {} +TagType::TagType(TypeClass TC, const TagDecl *D, QualType can) + : Type(TC, can, D->isDependentType()), + decl(const_cast<TagDecl*>(D), 0) {} bool RecordType::classof(const TagType *TT) { return isa<RecordDecl>(TT->getDecl()); @@ -1023,7 +1042,7 @@ QualType QualifierCollector::apply(const Type *T) const { void ObjCInterfaceType::Profile(llvm::FoldingSetNodeID &ID, const ObjCInterfaceDecl *Decl, - ObjCProtocolDecl **protocols, + ObjCProtocolDecl * const *protocols, unsigned NumProtocols) { ID.AddPointer(Decl); for (unsigned i = 0; i != NumProtocols; i++) @@ -1031,8 +1050,81 @@ void ObjCInterfaceType::Profile(llvm::FoldingSetNodeID &ID, } void ObjCInterfaceType::Profile(llvm::FoldingSetNodeID &ID) { - if (getNumProtocols()) - Profile(ID, getDecl(), &Protocols[0], getNumProtocols()); - else - Profile(ID, getDecl(), 0, 0); + Profile(ID, getDecl(), qual_begin(), getNumProtocols()); +} + +Linkage Type::getLinkage() const { + // C++ [basic.link]p8: + // Names not covered by these rules have no linkage. + if (this != CanonicalType.getTypePtr()) + return CanonicalType->getLinkage(); + + return NoLinkage; +} + +Linkage BuiltinType::getLinkage() const { + // C++ [basic.link]p8: + // A type is said to have linkage if and only if: + // - it is a fundamental type (3.9.1); or + return ExternalLinkage; +} + +Linkage TagType::getLinkage() const { + // C++ [basic.link]p8: + // - it is a class or enumeration type that is named (or has a name for + // linkage purposes (7.1.3)) and the name has linkage; or + // - it is a specialization of a class template (14); or + return getDecl()->getLinkage(); +} + +// C++ [basic.link]p8: +// - it is a compound type (3.9.2) other than a class or enumeration, +// compounded exclusively from types that have linkage; or +Linkage ComplexType::getLinkage() const { + return ElementType->getLinkage(); +} + +Linkage PointerType::getLinkage() const { + return PointeeType->getLinkage(); +} + +Linkage BlockPointerType::getLinkage() const { + return PointeeType->getLinkage(); +} + +Linkage ReferenceType::getLinkage() const { + return PointeeType->getLinkage(); +} + +Linkage MemberPointerType::getLinkage() const { + return minLinkage(Class->getLinkage(), PointeeType->getLinkage()); +} + +Linkage ArrayType::getLinkage() const { + return ElementType->getLinkage(); +} + +Linkage VectorType::getLinkage() const { + return ElementType->getLinkage(); +} + +Linkage FunctionNoProtoType::getLinkage() const { + return getResultType()->getLinkage(); +} + +Linkage FunctionProtoType::getLinkage() const { + Linkage L = getResultType()->getLinkage(); + for (arg_type_iterator A = arg_type_begin(), AEnd = arg_type_end(); + A != AEnd; ++A) + L = minLinkage(L, (*A)->getLinkage()); + + return L; +} + +Linkage ObjCInterfaceType::getLinkage() const { + return ExternalLinkage; +} + +Linkage ObjCObjectPointerType::getLinkage() const { + return ExternalLinkage; } diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index 00b74bc..5b621cf 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -225,15 +225,24 @@ void TypePrinter::PrintDependentSizedExtVector( } void TypePrinter::PrintVector(const VectorType *T, std::string &S) { - // FIXME: We prefer to print the size directly here, but have no way - // to get the size of the type. - Print(T->getElementType(), S); - std::string V = "__attribute__((__vector_size__("; - V += llvm::utostr_32(T->getNumElements()); // convert back to bytes. - std::string ET; - Print(T->getElementType(), ET); - V += " * sizeof(" + ET + ")))) "; - S = V + S; + if (T->isAltiVec()) { + if (T->isPixel()) + S = "__vector __pixel " + S; + else { + Print(T->getElementType(), S); + S = "__vector " + S; + } + } else { + // FIXME: We prefer to print the size directly here, but have no way + // to get the size of the type. + Print(T->getElementType(), S); + std::string V = "__attribute__((__vector_size__("; + V += llvm::utostr_32(T->getNumElements()); // convert back to bytes. + std::string ET; + Print(T->getElementType(), ET); + V += " * sizeof(" + ET + ")))) "; + S = V + S; + } } void TypePrinter::PrintExtVector(const ExtVectorType *T, std::string &S) { @@ -271,6 +280,19 @@ void TypePrinter::PrintFunctionProto(const FunctionProtoType *T, S += ")"; + switch(T->getCallConv()) { + case CC_Default: + default: break; + case CC_C: + S += " __attribute__((cdecl))"; + break; + case CC_X86StdCall: + S += " __attribute__((stdcall))"; + break; + case CC_X86FastCall: + S += " __attribute__((fastcall))"; + break; + } if (T->getNoReturnAttr()) S += " __attribute__((noreturn))"; |