diff options
Diffstat (limited to 'lib/AST')
39 files changed, 13462 insertions, 3933 deletions
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 4591a0f..945dfb8 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -20,7 +20,9 @@ #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExternalASTSource.h" +#include "clang/AST/ASTMutationListener.h" #include "clang/AST/RecordLayout.h" +#include "clang/AST/Mangle.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" @@ -50,7 +52,7 @@ ASTContext::CanonicalTemplateTemplateParm::Profile(llvm::FoldingSetNodeID &ID, TemplateTemplateParmDecl *Parm) { ID.AddInteger(Parm->getDepth()); ID.AddInteger(Parm->getPosition()); - // FIXME: Parameter pack + ID.AddBoolean(Parm->isParameterPack()); TemplateParameterList *Params = Parm->getTemplateParameters(); ID.AddInteger(Params->size()); @@ -65,8 +67,15 @@ ASTContext::CanonicalTemplateTemplateParm::Profile(llvm::FoldingSetNodeID &ID, if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) { ID.AddInteger(1); - // FIXME: Parameter pack + ID.AddBoolean(NTTP->isParameterPack()); ID.AddPointer(NTTP->getType().getAsOpaquePtr()); + if (NTTP->isExpandedParameterPack()) { + ID.AddBoolean(true); + ID.AddInteger(NTTP->getNumExpansionTypes()); + for (unsigned I = 0, N = NTTP->getNumExpansionTypes(); I != N; ++I) + ID.AddPointer(NTTP->getExpansionType(I).getAsOpaquePtr()); + } else + ID.AddBoolean(false); continue; } @@ -78,7 +87,7 @@ ASTContext::CanonicalTemplateTemplateParm::Profile(llvm::FoldingSetNodeID &ID, TemplateTemplateParmDecl * ASTContext::getCanonicalTemplateTemplateParmDecl( - TemplateTemplateParmDecl *TTP) { + TemplateTemplateParmDecl *TTP) const { // Check if we already have a canonical template template parameter. llvm::FoldingSetNodeID ID; CanonicalTemplateTemplateParm::Profile(ID, TTP); @@ -102,14 +111,40 @@ ASTContext::getCanonicalTemplateTemplateParmDecl( TTP->getIndex(), 0, false, TTP->isParameterPack())); else if (NonTypeTemplateParmDecl *NTTP - = dyn_cast<NonTypeTemplateParmDecl>(*P)) - CanonParams.push_back( - NonTypeTemplateParmDecl::Create(*this, getTranslationUnitDecl(), - SourceLocation(), NTTP->getDepth(), - NTTP->getPosition(), 0, - getCanonicalType(NTTP->getType()), - 0)); - else + = dyn_cast<NonTypeTemplateParmDecl>(*P)) { + QualType T = getCanonicalType(NTTP->getType()); + TypeSourceInfo *TInfo = getTrivialTypeSourceInfo(T); + NonTypeTemplateParmDecl *Param; + if (NTTP->isExpandedParameterPack()) { + llvm::SmallVector<QualType, 2> ExpandedTypes; + llvm::SmallVector<TypeSourceInfo *, 2> ExpandedTInfos; + for (unsigned I = 0, N = NTTP->getNumExpansionTypes(); I != N; ++I) { + ExpandedTypes.push_back(getCanonicalType(NTTP->getExpansionType(I))); + ExpandedTInfos.push_back( + getTrivialTypeSourceInfo(ExpandedTypes.back())); + } + + Param = NonTypeTemplateParmDecl::Create(*this, getTranslationUnitDecl(), + SourceLocation(), + NTTP->getDepth(), + NTTP->getPosition(), 0, + T, + TInfo, + ExpandedTypes.data(), + ExpandedTypes.size(), + ExpandedTInfos.data()); + } else { + Param = NonTypeTemplateParmDecl::Create(*this, getTranslationUnitDecl(), + SourceLocation(), + NTTP->getDepth(), + NTTP->getPosition(), 0, + T, + NTTP->isParameterPack(), + TInfo); + } + CanonParams.push_back(Param); + + } else CanonParams.push_back(getCanonicalTemplateTemplateParmDecl( cast<TemplateTemplateParmDecl>(*P))); } @@ -117,7 +152,9 @@ ASTContext::getCanonicalTemplateTemplateParmDecl( TemplateTemplateParmDecl *CanonTTP = TemplateTemplateParmDecl::Create(*this, getTranslationUnitDecl(), SourceLocation(), TTP->getDepth(), - TTP->getPosition(), 0, + TTP->getPosition(), + TTP->isParameterPack(), + 0, TemplateParameterList::Create(*this, SourceLocation(), SourceLocation(), CanonParams.data(), @@ -160,12 +197,13 @@ ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM, CFConstantStringTypeDecl(0), NSConstantStringTypeDecl(0), ObjCFastEnumerationStateTypeDecl(0), FILEDecl(0), jmp_bufDecl(0), sigjmp_bufDecl(0), BlockDescriptorType(0), BlockDescriptorExtendedType(0), + cudaConfigureCallDecl(0), NullTypeSourceInfo(QualType()), SourceMgr(SM), LangOpts(LOpts), ABI(createCXXABI(t)), Target(t), Idents(idents), Selectors(sels), BuiltinInfo(builtins), DeclarationNames(*this), - ExternalSource(0), PrintingPolicy(LOpts), + ExternalSource(0), Listener(0), PrintingPolicy(LOpts), LastSDM(0, 0), UniqueBlockByRefTypeID(0), UniqueBlockParmTypeID(0) { ObjCIdRedefinitionType = QualType(); @@ -314,9 +352,12 @@ void ASTContext::InitBuiltinTypes() { InitBuiltinType(Int128Ty, BuiltinType::Int128); InitBuiltinType(UnsignedInt128Ty, BuiltinType::UInt128); - if (LangOpts.CPlusPlus) // C++ 3.9.1p5 - InitBuiltinType(WCharTy, BuiltinType::WChar); - else // C99 + if (LangOpts.CPlusPlus) { // C++ 3.9.1p5 + if (!LangOpts.ShortWChar) + InitBuiltinType(WCharTy, BuiltinType::WChar_S); + else // -fshort-wchar makes wchar_t be unsigned. + InitBuiltinType(WCharTy, BuiltinType::WChar_U); + } else // C99 WCharTy = getFromTargetType(Target.getWCharType()); if (LangOpts.CPlusPlus) // C++0x 3.9.1p5, extension for C++ @@ -329,9 +370,6 @@ void ASTContext::InitBuiltinTypes() { else // C99 Char32Ty = getFromTargetType(Target.getChar32Type()); - // Placeholder type for functions. - InitBuiltinType(OverloadTy, BuiltinType::Overload); - // Placeholder type for type-dependent expressions whose type is // completely unknown. No code should ever check a type against // DependentTy and users should never see it; however, it is here to @@ -339,9 +377,8 @@ void ASTContext::InitBuiltinTypes() { // expressions. InitBuiltinType(DependentTy, BuiltinType::Dependent); - // Placeholder type for C++0x auto declarations whose real type has - // not yet been deduced. - InitBuiltinType(UndeducedAutoTy, BuiltinType::UndeducedAuto); + // Placeholder type for functions. + InitBuiltinType(OverloadTy, BuiltinType::Overload); // C99 6.2.5p11. FloatComplexTy = getComplexType(FloatTy); @@ -369,6 +406,10 @@ void ASTContext::InitBuiltinTypes() { InitBuiltinType(NullPtrTy, BuiltinType::NullPtr); } +Diagnostic &ASTContext::getDiagnostics() const { + return SourceMgr.getDiagnostics(); +} + AttrVec& ASTContext::getDeclAttrs(const Decl *D) { AttrVec *&Result = DeclAttrs[D]; if (!Result) { @@ -525,12 +566,33 @@ const llvm::fltSemantics &ASTContext::getFloatTypeSemantics(QualType T) const { /// this method will assert on them. /// If @p RefAsPointee, references are treated like their underlying type /// (for alignof), else they're treated like pointers (for CodeGen). -CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) { +CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) const { unsigned Align = Target.getCharWidth(); - Align = std::max(Align, D->getMaxAlignment()); + bool UseAlignAttrOnly = false; + if (unsigned AlignFromAttr = D->getMaxAlignment()) { + Align = AlignFromAttr; + + // __attribute__((aligned)) can increase or decrease alignment + // *except* on a struct or struct member, where it only increases + // alignment unless 'packed' is also specified. + // + // It is an error for [[align]] to decrease alignment, so we can + // ignore that possibility; Sema should diagnose it. + if (isa<FieldDecl>(D)) { + UseAlignAttrOnly = D->hasAttr<PackedAttr>() || + cast<FieldDecl>(D)->getParent()->hasAttr<PackedAttr>(); + } else { + UseAlignAttrOnly = true; + } + } - if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) { + // If we're using the align attribute only, just ignore everything + // else about the declaration and its type. + if (UseAlignAttrOnly) { + // do nothing + + } else if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) { QualType T = VD->getType(); if (const ReferenceType* RT = T->getAs<ReferenceType>()) { if (RefAsPointee) @@ -539,41 +601,61 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) { T = getPointerType(RT->getPointeeType()); } if (!T->isIncompleteType() && !T->isFunctionType()) { + // Adjust alignments of declarations with array type by the + // large-array alignment on the target. unsigned MinWidth = Target.getLargeArrayMinWidth(); - unsigned ArrayAlign = Target.getLargeArrayAlign(); - if (isa<VariableArrayType>(T) && MinWidth != 0) - Align = std::max(Align, ArrayAlign); - if (ConstantArrayType *CT = dyn_cast<ConstantArrayType>(T)) { - unsigned Size = getTypeSize(CT); - if (MinWidth != 0 && MinWidth <= Size) - Align = std::max(Align, ArrayAlign); + const ArrayType *arrayType; + if (MinWidth && (arrayType = getAsArrayType(T))) { + if (isa<VariableArrayType>(arrayType)) + Align = std::max(Align, Target.getLargeArrayAlign()); + else if (isa<ConstantArrayType>(arrayType) && + MinWidth <= getTypeSize(cast<ConstantArrayType>(arrayType))) + Align = std::max(Align, Target.getLargeArrayAlign()); + + // Walk through any array types while we're at it. + T = getBaseElementType(arrayType); } - // Incomplete or function types default to 1. - while (isa<VariableArrayType>(T) || isa<IncompleteArrayType>(T)) - T = cast<ArrayType>(T)->getElementType(); - Align = std::max(Align, getPreferredTypeAlign(T.getTypePtr())); } - if (const FieldDecl *FD = dyn_cast<FieldDecl>(VD)) { - // In the case of a field in a packed struct, we want the minimum - // of the alignment of the field and the alignment of the struct. - Align = std::min(Align, - getPreferredTypeAlign(FD->getParent()->getTypeForDecl())); + + // Fields can be subject to extra alignment constraints, like if + // the field is packed, the struct is packed, or the struct has a + // a max-field-alignment constraint (#pragma pack). So calculate + // the actual alignment of the field within the struct, and then + // (as we're expected to) constrain that by the alignment of the type. + if (const FieldDecl *field = dyn_cast<FieldDecl>(VD)) { + // So calculate the alignment of the field. + const ASTRecordLayout &layout = getASTRecordLayout(field->getParent()); + + // Start with the record's overall alignment. + unsigned fieldAlign = toBits(layout.getAlignment()); + + // Use the GCD of that and the offset within the record. + uint64_t offset = layout.getFieldOffset(field->getFieldIndex()); + if (offset > 0) { + // Alignment is always a power of 2, so the GCD will be a power of 2, + // which means we get to do this crazy thing instead of Euclid's. + uint64_t lowBitOfOffset = offset & (~offset + 1); + if (lowBitOfOffset < fieldAlign) + fieldAlign = static_cast<unsigned>(lowBitOfOffset); + } + + Align = std::min(Align, fieldAlign); } } - return CharUnits::fromQuantity(Align / Target.getCharWidth()); + return toCharUnitsFromBits(Align); } std::pair<CharUnits, CharUnits> -ASTContext::getTypeInfoInChars(const Type *T) { +ASTContext::getTypeInfoInChars(const Type *T) const { std::pair<uint64_t, unsigned> Info = getTypeInfo(T); - return std::make_pair(CharUnits::fromQuantity(Info.first / getCharWidth()), - CharUnits::fromQuantity(Info.second / getCharWidth())); + return std::make_pair(toCharUnitsFromBits(Info.first), + toCharUnitsFromBits(Info.second)); } std::pair<CharUnits, CharUnits> -ASTContext::getTypeInfoInChars(QualType T) { +ASTContext::getTypeInfoInChars(QualType T) const { return getTypeInfoInChars(T.getTypePtr()); } @@ -584,7 +666,7 @@ ASTContext::getTypeInfoInChars(QualType T) { /// alignment requirements: getPointerInfo should take an AddrSpace, this /// should take a QualType, &c. std::pair<uint64_t, unsigned> -ASTContext::getTypeInfo(const Type *T) { +ASTContext::getTypeInfo(const Type *T) const { uint64_t Width=0; unsigned Align=8; switch (T->getTypeClass()) { @@ -652,7 +734,8 @@ ASTContext::getTypeInfo(const Type *T) { Width = Target.getCharWidth(); Align = Target.getCharAlign(); break; - case BuiltinType::WChar: + case BuiltinType::WChar_S: + case BuiltinType::WChar_U: Width = Target.getWCharWidth(); Align = Target.getWCharAlign(); break; @@ -760,8 +843,8 @@ ASTContext::getTypeInfo(const Type *T) { case Type::ObjCInterface: { const ObjCInterfaceType *ObjCI = cast<ObjCInterfaceType>(T); const ASTRecordLayout &Layout = getASTObjCInterfaceLayout(ObjCI->getDecl()); - Width = Layout.getSize(); - Align = Layout.getAlignment(); + Width = toBits(Layout.getSize()); + Align = toBits(Layout.getAlignment()); break; } case Type::Record: @@ -779,8 +862,8 @@ ASTContext::getTypeInfo(const Type *T) { const RecordType *RT = cast<RecordType>(TT); const ASTRecordLayout &Layout = getASTRecordLayout(RT->getDecl()); - Width = Layout.getSize(); - Align = Layout.getAlignment(); + Width = toBits(Layout.getSize()); + Align = toBits(Layout.getAlignment()); break; } @@ -788,11 +871,26 @@ ASTContext::getTypeInfo(const Type *T) { return getTypeInfo(cast<SubstTemplateTypeParmType>(T)-> getReplacementType().getTypePtr()); + case Type::Auto: { + const AutoType *A = cast<AutoType>(T); + assert(A->isDeduced() && "Cannot request the size of a dependent type"); + return getTypeInfo(cast<AutoType>(T)->getDeducedType().getTypePtr()); + } + + case Type::Paren: + return getTypeInfo(cast<ParenType>(T)->getInnerType().getTypePtr()); + case Type::Typedef: { const TypedefDecl *Typedef = cast<TypedefType>(T)->getDecl(); std::pair<uint64_t, unsigned> Info = getTypeInfo(Typedef->getUnderlyingType().getTypePtr()); - Align = std::max(Typedef->getMaxAlignment(), Info.second); + // If the typedef has an aligned attribute on it, it overrides any computed + // alignment we have. This violates the GCC documentation (which says that + // attribute(aligned) can only round up) but matches its implementation. + if (unsigned AttrAlign = Typedef->getMaxAlignment()) + Align = AttrAlign; + else + Align = Info.second; Width = Info.first; break; } @@ -811,6 +909,10 @@ ASTContext::getTypeInfo(const Type *T) { case Type::Elaborated: return getTypeInfo(cast<ElaboratedType>(T)->getNamedType().getTypePtr()); + case Type::Attributed: + return getTypeInfo( + cast<AttributedType>(T)->getEquivalentType().getTypePtr()); + case Type::TemplateSpecialization: assert(getCanonicalType(T) != T && "Cannot request the size of a dependent type"); @@ -824,29 +926,39 @@ ASTContext::getTypeInfo(const Type *T) { return std::make_pair(Width, Align); } +/// toCharUnitsFromBits - Convert a size in bits to a size in characters. +CharUnits ASTContext::toCharUnitsFromBits(int64_t BitSize) const { + return CharUnits::fromQuantity(BitSize / getCharWidth()); +} + +/// toBits - Convert a size in characters to a size in characters. +int64_t ASTContext::toBits(CharUnits CharSize) const { + return CharSize.getQuantity() * getCharWidth(); +} + /// getTypeSizeInChars - Return the size of the specified type, in characters. /// This method does not work on incomplete types. -CharUnits ASTContext::getTypeSizeInChars(QualType T) { - return CharUnits::fromQuantity(getTypeSize(T) / getCharWidth()); +CharUnits ASTContext::getTypeSizeInChars(QualType T) const { + return toCharUnitsFromBits(getTypeSize(T)); } -CharUnits ASTContext::getTypeSizeInChars(const Type *T) { - return CharUnits::fromQuantity(getTypeSize(T) / getCharWidth()); +CharUnits ASTContext::getTypeSizeInChars(const Type *T) const { + return toCharUnitsFromBits(getTypeSize(T)); } /// 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(QualType T) const { + return toCharUnitsFromBits(getTypeAlign(T)); } -CharUnits ASTContext::getTypeAlignInChars(const Type *T) { - return CharUnits::fromQuantity(getTypeAlign(T) / getCharWidth()); +CharUnits ASTContext::getTypeAlignInChars(const Type *T) const { + return toCharUnitsFromBits(getTypeAlign(T)); } /// getPreferredTypeAlign - Return the "preferred" alignment of the specified /// type for the current target in bits. This can be different than the ABI /// alignment in cases where it is beneficial for performance to overalign /// a data type. -unsigned ASTContext::getPreferredTypeAlign(const Type *T) { +unsigned ASTContext::getPreferredTypeAlign(const Type *T) const { unsigned ABIAlign = getTypeAlign(T); // Double and long long should be naturally aligned if possible. @@ -863,7 +975,7 @@ unsigned ASTContext::getPreferredTypeAlign(const Type *T) { /// Collect all ivars, including those synthesized, in the current class. /// void ASTContext::ShallowCollectObjCIvars(const ObjCInterfaceDecl *OI, - llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars) { + llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars) const { // FIXME. This need be removed but there are two many places which // assume const-ness of ObjCInterfaceDecl ObjCInterfaceDecl *IDecl = const_cast<ObjCInterfaceDecl *>(OI); @@ -880,7 +992,7 @@ void ASTContext::ShallowCollectObjCIvars(const ObjCInterfaceDecl *OI, /// void ASTContext::DeepCollectObjCIvars(const ObjCInterfaceDecl *OI, bool leafClass, - llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars) { + llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars) const { if (const ObjCInterfaceDecl *SuperClass = OI->getSuperClass()) DeepCollectObjCIvars(SuperClass, false, Ivars); if (!leafClass) { @@ -940,7 +1052,7 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl, } } -unsigned ASTContext::CountNonClassIvars(const ObjCInterfaceDecl *OI) { +unsigned ASTContext::CountNonClassIvars(const ObjCInterfaceDecl *OI) const { unsigned count = 0; // Count ivars declared in class extension. for (const ObjCCategoryDecl *CDecl = OI->getFirstClassExtension(); CDecl; @@ -985,6 +1097,25 @@ void ASTContext::setObjCImplementation(ObjCCategoryDecl *CatD, ObjCImpls[CatD] = ImplD; } +/// \brief Get the copy initialization expression of VarDecl,or NULL if +/// none exists. +Expr *ASTContext::getBlockVarCopyInits(const VarDecl*VD) { + assert(VD && "Passed null params"); + assert(VD->hasAttr<BlocksAttr>() && + "getBlockVarCopyInits - not __block var"); + llvm::DenseMap<const VarDecl*, Expr*>::iterator + I = BlockVarCopyInits.find(VD); + return (I != BlockVarCopyInits.end()) ? cast<Expr>(I->second) : 0; +} + +/// \brief Set the copy inialization expression of a block var decl. +void ASTContext::setBlockVarCopyInits(VarDecl*VD, Expr* Init) { + assert(VD && Init && "Passed null params"); + assert(VD->hasAttr<BlocksAttr>() && + "setBlockVarCopyInits - not __block var"); + BlockVarCopyInits[VD] = Init; +} + /// \brief Allocate an uninitialized TypeSourceInfo. /// /// The caller should initialize the memory held by TypeSourceInfo using @@ -994,7 +1125,7 @@ void ASTContext::setObjCImplementation(ObjCCategoryDecl *CatD, /// should refer to how the declarator was written in source code, not to /// what type semantic analysis resolved the declarator to. TypeSourceInfo *ASTContext::CreateTypeSourceInfo(QualType T, - unsigned DataSize) { + unsigned DataSize) const { if (!DataSize) DataSize = TypeLoc::getFullDataSizeForType(T); else @@ -1008,19 +1139,20 @@ TypeSourceInfo *ASTContext::CreateTypeSourceInfo(QualType T, } TypeSourceInfo *ASTContext::getTrivialTypeSourceInfo(QualType T, - SourceLocation L) { + SourceLocation L) const { TypeSourceInfo *DI = CreateTypeSourceInfo(T); - DI->getTypeLoc().initialize(L); + DI->getTypeLoc().initialize(const_cast<ASTContext &>(*this), L); return DI; } const ASTRecordLayout & -ASTContext::getASTObjCInterfaceLayout(const ObjCInterfaceDecl *D) { +ASTContext::getASTObjCInterfaceLayout(const ObjCInterfaceDecl *D) const { return getObjCLayout(D, 0); } const ASTRecordLayout & -ASTContext::getASTObjCImplementationLayout(const ObjCImplementationDecl *D) { +ASTContext::getASTObjCImplementationLayout( + const ObjCImplementationDecl *D) const { return getObjCLayout(D->getClassInterface(), D); } @@ -1028,38 +1160,38 @@ ASTContext::getASTObjCImplementationLayout(const ObjCImplementationDecl *D) { // Type creation/memoization methods //===----------------------------------------------------------------------===// -QualType ASTContext::getExtQualType(const Type *TypeNode, Qualifiers Quals) { - unsigned Fast = Quals.getFastQualifiers(); - Quals.removeFastQualifiers(); +QualType +ASTContext::getExtQualType(const Type *baseType, Qualifiers quals) const { + unsigned fastQuals = quals.getFastQualifiers(); + quals.removeFastQualifiers(); // Check if we've already instantiated this type. llvm::FoldingSetNodeID ID; - ExtQuals::Profile(ID, TypeNode, Quals); - void *InsertPos = 0; - if (ExtQuals *EQ = ExtQualNodes.FindNodeOrInsertPos(ID, InsertPos)) { - assert(EQ->getQualifiers() == Quals); - QualType T = QualType(EQ, Fast); - return T; + ExtQuals::Profile(ID, baseType, quals); + void *insertPos = 0; + if (ExtQuals *eq = ExtQualNodes.FindNodeOrInsertPos(ID, insertPos)) { + assert(eq->getQualifiers() == quals); + return QualType(eq, fastQuals); } - ExtQuals *New = new (*this, TypeAlignment) ExtQuals(*this, TypeNode, Quals); - ExtQualNodes.InsertNode(New, InsertPos); - QualType T = QualType(New, Fast); - return T; -} - -QualType ASTContext::getVolatileType(QualType T) { - QualType CanT = getCanonicalType(T); - if (CanT.isVolatileQualified()) return T; + // If the base type is not canonical, make the appropriate canonical type. + QualType canon; + if (!baseType->isCanonicalUnqualified()) { + SplitQualType canonSplit = baseType->getCanonicalTypeInternal().split(); + canonSplit.second.addConsistentQualifiers(quals); + canon = getExtQualType(canonSplit.first, canonSplit.second); - QualifierCollector Quals; - const Type *TypeNode = Quals.strip(T); - Quals.addVolatile(); + // Re-find the insert position. + (void) ExtQualNodes.FindNodeOrInsertPos(ID, insertPos); + } - return getExtQualType(TypeNode, Quals); + ExtQuals *eq = new (*this, TypeAlignment) ExtQuals(baseType, canon, quals); + ExtQualNodes.InsertNode(eq, insertPos); + return QualType(eq, fastQuals); } -QualType ASTContext::getAddrSpaceQualType(QualType T, unsigned AddressSpace) { +QualType +ASTContext::getAddrSpaceQualType(QualType T, unsigned AddressSpace) const { QualType CanT = getCanonicalType(T); if (CanT.getAddressSpace() == AddressSpace) return T; @@ -1079,13 +1211,13 @@ QualType ASTContext::getAddrSpaceQualType(QualType T, unsigned AddressSpace) { } QualType ASTContext::getObjCGCQualType(QualType T, - Qualifiers::GC GCAttr) { + Qualifiers::GC GCAttr) const { QualType CanT = getCanonicalType(T); if (CanT.getObjCGCAttr() == GCAttr) return T; - if (T->isPointerType()) { - QualType Pointee = T->getAs<PointerType>()->getPointeeType(); + if (const PointerType *ptr = T->getAs<PointerType>()) { + QualType Pointee = ptr->getPointeeType(); if (Pointee->isAnyPointerType()) { QualType ResultType = getObjCGCQualType(Pointee, GCAttr); return getPointerType(ResultType); @@ -1106,79 +1238,28 @@ QualType ASTContext::getObjCGCQualType(QualType T, return getExtQualType(TypeNode, Quals); } -static QualType getExtFunctionType(ASTContext& Context, QualType T, - const FunctionType::ExtInfo &Info) { - QualType ResultType; - if (const PointerType *Pointer = T->getAs<PointerType>()) { - QualType Pointee = Pointer->getPointeeType(); - ResultType = getExtFunctionType(Context, Pointee, Info); - if (ResultType == Pointee) - return T; - - ResultType = Context.getPointerType(ResultType); - } else if (const BlockPointerType *BlockPointer - = T->getAs<BlockPointerType>()) { - QualType Pointee = BlockPointer->getPointeeType(); - ResultType = getExtFunctionType(Context, Pointee, Info); - if (ResultType == Pointee) - return T; - - ResultType = Context.getBlockPointerType(ResultType); - } else if (const MemberPointerType *MemberPointer - = T->getAs<MemberPointerType>()) { - QualType Pointee = MemberPointer->getPointeeType(); - ResultType = getExtFunctionType(Context, Pointee, Info); - if (ResultType == Pointee) - return T; - - ResultType = Context.getMemberPointerType(ResultType, - MemberPointer->getClass()); - } else if (const FunctionType *F = T->getAs<FunctionType>()) { - if (F->getExtInfo() == Info) - return T; - - if (const FunctionNoProtoType *FNPT = dyn_cast<FunctionNoProtoType>(F)) { - ResultType = Context.getFunctionNoProtoType(FNPT->getResultType(), - Info); - } else { - const FunctionProtoType *FPT = cast<FunctionProtoType>(F); - ResultType - = Context.getFunctionType(FPT->getResultType(), FPT->arg_type_begin(), - FPT->getNumArgs(), FPT->isVariadic(), - FPT->getTypeQuals(), - FPT->hasExceptionSpec(), - FPT->hasAnyExceptionSpec(), - FPT->getNumExceptions(), - FPT->exception_begin(), - Info); - } - } else +const FunctionType *ASTContext::adjustFunctionType(const FunctionType *T, + FunctionType::ExtInfo Info) { + if (T->getExtInfo() == Info) return T; - return Context.getQualifiedType(ResultType, T.getLocalQualifiers()); -} - -QualType ASTContext::getNoReturnType(QualType T, bool AddNoReturn) { - FunctionType::ExtInfo Info = getFunctionExtInfo(T); - return getExtFunctionType(*this, T, - Info.withNoReturn(AddNoReturn)); -} - -QualType ASTContext::getCallConvType(QualType T, CallingConv CallConv) { - FunctionType::ExtInfo Info = getFunctionExtInfo(T); - return getExtFunctionType(*this, T, - Info.withCallingConv(CallConv)); -} + QualType Result; + if (const FunctionNoProtoType *FNPT = dyn_cast<FunctionNoProtoType>(T)) { + Result = getFunctionNoProtoType(FNPT->getResultType(), Info); + } else { + const FunctionProtoType *FPT = cast<FunctionProtoType>(T); + FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); + EPI.ExtInfo = Info; + Result = getFunctionType(FPT->getResultType(), FPT->arg_type_begin(), + FPT->getNumArgs(), EPI); + } -QualType ASTContext::getRegParmType(QualType T, unsigned RegParm) { - FunctionType::ExtInfo Info = getFunctionExtInfo(T); - return getExtFunctionType(*this, T, - Info.withRegParm(RegParm)); + return cast<FunctionType>(Result.getTypePtr()); } /// getComplexType - Return the uniqued reference to the type for a complex /// number with the specified element type. -QualType ASTContext::getComplexType(QualType T) { +QualType ASTContext::getComplexType(QualType T) const { // Unique pointers, to guarantee there is only one pointer of a particular // structure. llvm::FoldingSetNodeID ID; @@ -1196,7 +1277,7 @@ QualType ASTContext::getComplexType(QualType T) { // Get the new insert position for the node we care about. ComplexType *NewIP = ComplexTypes.FindNodeOrInsertPos(ID, InsertPos); - assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; + assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP; } ComplexType *New = new (*this, TypeAlignment) ComplexType(T, Canonical); Types.push_back(New); @@ -1206,7 +1287,7 @@ QualType ASTContext::getComplexType(QualType T) { /// getPointerType - Return the uniqued reference to the type for a pointer to /// the specified type. -QualType ASTContext::getPointerType(QualType T) { +QualType ASTContext::getPointerType(QualType T) const { // Unique pointers, to guarantee there is only one pointer of a particular // structure. llvm::FoldingSetNodeID ID; @@ -1224,7 +1305,7 @@ QualType ASTContext::getPointerType(QualType T) { // Get the new insert position for the node we care about. PointerType *NewIP = PointerTypes.FindNodeOrInsertPos(ID, InsertPos); - assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; + assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP; } PointerType *New = new (*this, TypeAlignment) PointerType(T, Canonical); Types.push_back(New); @@ -1234,7 +1315,7 @@ QualType ASTContext::getPointerType(QualType T) { /// getBlockPointerType - Return the uniqued reference to the type for /// a pointer to the specified block. -QualType ASTContext::getBlockPointerType(QualType T) { +QualType ASTContext::getBlockPointerType(QualType T) const { assert(T->isFunctionType() && "block of function types only"); // Unique pointers, to guarantee there is only one block of a particular // structure. @@ -1255,7 +1336,7 @@ QualType ASTContext::getBlockPointerType(QualType T) { // Get the new insert position for the node we care about. BlockPointerType *NewIP = BlockPointerTypes.FindNodeOrInsertPos(ID, InsertPos); - assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; + assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP; } BlockPointerType *New = new (*this, TypeAlignment) BlockPointerType(T, Canonical); @@ -1266,7 +1347,8 @@ QualType ASTContext::getBlockPointerType(QualType T) { /// getLValueReferenceType - Return the uniqued reference to the type for an /// lvalue reference to the specified type. -QualType ASTContext::getLValueReferenceType(QualType T, bool SpelledAsLValue) { +QualType +ASTContext::getLValueReferenceType(QualType T, bool SpelledAsLValue) const { // Unique pointers, to guarantee there is only one pointer of a particular // structure. llvm::FoldingSetNodeID ID; @@ -1289,7 +1371,7 @@ QualType ASTContext::getLValueReferenceType(QualType T, bool SpelledAsLValue) { // Get the new insert position for the node we care about. LValueReferenceType *NewIP = LValueReferenceTypes.FindNodeOrInsertPos(ID, InsertPos); - assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; + assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP; } LValueReferenceType *New @@ -1303,7 +1385,7 @@ QualType ASTContext::getLValueReferenceType(QualType T, bool SpelledAsLValue) { /// getRValueReferenceType - Return the uniqued reference to the type for an /// rvalue reference to the specified type. -QualType ASTContext::getRValueReferenceType(QualType T) { +QualType ASTContext::getRValueReferenceType(QualType T) const { // Unique pointers, to guarantee there is only one pointer of a particular // structure. llvm::FoldingSetNodeID ID; @@ -1326,7 +1408,7 @@ QualType ASTContext::getRValueReferenceType(QualType T) { // Get the new insert position for the node we care about. RValueReferenceType *NewIP = RValueReferenceTypes.FindNodeOrInsertPos(ID, InsertPos); - assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; + assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP; } RValueReferenceType *New @@ -1338,7 +1420,7 @@ QualType ASTContext::getRValueReferenceType(QualType T) { /// getMemberPointerType - Return the uniqued reference to the type for a /// member pointer to the specified type, in the specified class. -QualType ASTContext::getMemberPointerType(QualType T, const Type *Cls) { +QualType ASTContext::getMemberPointerType(QualType T, const Type *Cls) const { // Unique pointers, to guarantee there is only one pointer of a particular // structure. llvm::FoldingSetNodeID ID; @@ -1358,7 +1440,7 @@ QualType ASTContext::getMemberPointerType(QualType T, const Type *Cls) { // Get the new insert position for the node we care about. MemberPointerType *NewIP = MemberPointerTypes.FindNodeOrInsertPos(ID, InsertPos); - assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; + assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP; } MemberPointerType *New = new (*this, TypeAlignment) MemberPointerType(T, Cls, Canonical); @@ -1372,7 +1454,7 @@ QualType ASTContext::getMemberPointerType(QualType T, const Type *Cls) { QualType ASTContext::getConstantArrayType(QualType EltTy, const llvm::APInt &ArySizeIn, ArrayType::ArraySizeModifier ASM, - unsigned EltTypeQuals) { + unsigned IndexTypeQuals) const { assert((EltTy->isDependentType() || EltTy->isIncompleteType() || EltTy->isConstantSizeType()) && "Constant array of VLAs is illegal!"); @@ -1380,55 +1462,185 @@ QualType ASTContext::getConstantArrayType(QualType EltTy, // Convert the array size into a canonical width matching the pointer size for // the target. llvm::APInt ArySize(ArySizeIn); - ArySize.zextOrTrunc(Target.getPointerWidth(EltTy.getAddressSpace())); + ArySize = + ArySize.zextOrTrunc(Target.getPointerWidth(EltTy.getAddressSpace())); llvm::FoldingSetNodeID ID; - ConstantArrayType::Profile(ID, EltTy, ArySize, ASM, EltTypeQuals); + ConstantArrayType::Profile(ID, EltTy, ArySize, ASM, IndexTypeQuals); void *InsertPos = 0; if (ConstantArrayType *ATP = ConstantArrayTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(ATP, 0); - // If the element type isn't canonical, this won't be a canonical type either, - // so fill in the canonical type field. - QualType Canonical; - if (!EltTy.isCanonical()) { - Canonical = getConstantArrayType(getCanonicalType(EltTy), ArySize, - ASM, EltTypeQuals); + // If the element type isn't canonical or has qualifiers, this won't + // be a canonical type either, so fill in the canonical type field. + QualType Canon; + if (!EltTy.isCanonical() || EltTy.hasLocalQualifiers()) { + SplitQualType canonSplit = getCanonicalType(EltTy).split(); + Canon = getConstantArrayType(QualType(canonSplit.first, 0), ArySize, + ASM, IndexTypeQuals); + Canon = getQualifiedType(Canon, canonSplit.second); + // Get the new insert position for the node we care about. ConstantArrayType *NewIP = ConstantArrayTypes.FindNodeOrInsertPos(ID, InsertPos); - assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; + assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP; } ConstantArrayType *New = new(*this,TypeAlignment) - ConstantArrayType(EltTy, Canonical, ArySize, ASM, EltTypeQuals); + ConstantArrayType(EltTy, Canon, ArySize, ASM, IndexTypeQuals); ConstantArrayTypes.InsertNode(New, InsertPos); Types.push_back(New); return QualType(New, 0); } +/// getVariableArrayDecayedType - Turns the given type, which may be +/// variably-modified, into the corresponding type with all the known +/// sizes replaced with [*]. +QualType ASTContext::getVariableArrayDecayedType(QualType type) const { + // Vastly most common case. + if (!type->isVariablyModifiedType()) return type; + + QualType result; + + SplitQualType split = type.getSplitDesugaredType(); + const Type *ty = split.first; + switch (ty->getTypeClass()) { +#define TYPE(Class, Base) +#define ABSTRACT_TYPE(Class, Base) +#define NON_CANONICAL_TYPE(Class, Base) case Type::Class: +#include "clang/AST/TypeNodes.def" + llvm_unreachable("didn't desugar past all non-canonical types?"); + + // These types should never be variably-modified. + case Type::Builtin: + case Type::Complex: + case Type::Vector: + case Type::ExtVector: + case Type::DependentSizedExtVector: + case Type::ObjCObject: + case Type::ObjCInterface: + case Type::ObjCObjectPointer: + case Type::Record: + case Type::Enum: + case Type::UnresolvedUsing: + case Type::TypeOfExpr: + case Type::TypeOf: + case Type::Decltype: + case Type::DependentName: + case Type::InjectedClassName: + case Type::TemplateSpecialization: + case Type::DependentTemplateSpecialization: + case Type::TemplateTypeParm: + case Type::SubstTemplateTypeParmPack: + case Type::Auto: + case Type::PackExpansion: + llvm_unreachable("type should never be variably-modified"); + + // These types can be variably-modified but should never need to + // further decay. + case Type::FunctionNoProto: + case Type::FunctionProto: + case Type::BlockPointer: + case Type::MemberPointer: + return type; + + // These types can be variably-modified. All these modifications + // preserve structure except as noted by comments. + // TODO: if we ever care about optimizing VLAs, there are no-op + // optimizations available here. + case Type::Pointer: + result = getPointerType(getVariableArrayDecayedType( + cast<PointerType>(ty)->getPointeeType())); + break; + + case Type::LValueReference: { + const LValueReferenceType *lv = cast<LValueReferenceType>(ty); + result = getLValueReferenceType( + getVariableArrayDecayedType(lv->getPointeeType()), + lv->isSpelledAsLValue()); + break; + } + + case Type::RValueReference: { + const RValueReferenceType *lv = cast<RValueReferenceType>(ty); + result = getRValueReferenceType( + getVariableArrayDecayedType(lv->getPointeeType())); + break; + } + + case Type::ConstantArray: { + const ConstantArrayType *cat = cast<ConstantArrayType>(ty); + result = getConstantArrayType( + getVariableArrayDecayedType(cat->getElementType()), + cat->getSize(), + cat->getSizeModifier(), + cat->getIndexTypeCVRQualifiers()); + break; + } + + case Type::DependentSizedArray: { + const DependentSizedArrayType *dat = cast<DependentSizedArrayType>(ty); + result = getDependentSizedArrayType( + getVariableArrayDecayedType(dat->getElementType()), + dat->getSizeExpr(), + dat->getSizeModifier(), + dat->getIndexTypeCVRQualifiers(), + dat->getBracketsRange()); + break; + } + + // Turn incomplete types into [*] types. + case Type::IncompleteArray: { + const IncompleteArrayType *iat = cast<IncompleteArrayType>(ty); + result = getVariableArrayType( + getVariableArrayDecayedType(iat->getElementType()), + /*size*/ 0, + ArrayType::Normal, + iat->getIndexTypeCVRQualifiers(), + SourceRange()); + break; + } + + // Turn VLA types into [*] types. + case Type::VariableArray: { + const VariableArrayType *vat = cast<VariableArrayType>(ty); + result = getVariableArrayType( + getVariableArrayDecayedType(vat->getElementType()), + /*size*/ 0, + ArrayType::Star, + vat->getIndexTypeCVRQualifiers(), + vat->getBracketsRange()); + break; + } + } + + // Apply the top-level qualifiers from the original. + return getQualifiedType(result, split.second); +} + /// getVariableArrayType - Returns a non-unique reference to the type for a /// variable array of the specified element type. QualType ASTContext::getVariableArrayType(QualType EltTy, Expr *NumElts, ArrayType::ArraySizeModifier ASM, - unsigned EltTypeQuals, - SourceRange Brackets) { + unsigned IndexTypeQuals, + SourceRange Brackets) const { // Since we don't unique expressions, it isn't possible to unique VLA's // that have an expression provided for their size. - QualType CanonType; + QualType Canon; - if (!EltTy.isCanonical()) { - if (NumElts) - NumElts->Retain(); - CanonType = getVariableArrayType(getCanonicalType(EltTy), NumElts, ASM, - EltTypeQuals, Brackets); + // Be sure to pull qualifiers off the element type. + if (!EltTy.isCanonical() || EltTy.hasLocalQualifiers()) { + SplitQualType canonSplit = getCanonicalType(EltTy).split(); + Canon = getVariableArrayType(QualType(canonSplit.first, 0), NumElts, ASM, + IndexTypeQuals, Brackets); + Canon = getQualifiedType(Canon, canonSplit.second); } VariableArrayType *New = new(*this, TypeAlignment) - VariableArrayType(EltTy, CanonType, NumElts, ASM, EltTypeQuals, Brackets); + VariableArrayType(EltTy, Canon, NumElts, ASM, IndexTypeQuals, Brackets); VariableArrayTypes.push_back(New); Types.push_back(New); @@ -1438,109 +1650,118 @@ QualType ASTContext::getVariableArrayType(QualType EltTy, /// getDependentSizedArrayType - Returns a non-unique reference to /// the type for a dependently-sized array of the specified element /// type. -QualType ASTContext::getDependentSizedArrayType(QualType EltTy, - Expr *NumElts, +QualType ASTContext::getDependentSizedArrayType(QualType elementType, + Expr *numElements, ArrayType::ArraySizeModifier ASM, - unsigned EltTypeQuals, - SourceRange Brackets) { - assert((!NumElts || NumElts->isTypeDependent() || - NumElts->isValueDependent()) && + unsigned elementTypeQuals, + SourceRange brackets) const { + assert((!numElements || numElements->isTypeDependent() || + numElements->isValueDependent()) && "Size must be type- or value-dependent!"); - 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. - DependentSizedArrayType::Profile(ID, *this, getCanonicalType(EltTy), ASM, - EltTypeQuals, NumElts); - - Canon = DependentSizedArrayTypes.FindNodeOrInsertPos(ID, InsertPos); + // Dependently-sized array types that do not have a specified number + // of elements will have their sizes deduced from a dependent + // initializer. We do no canonicalization here at all, which is okay + // because they can't be used in most locations. + if (!numElements) { + DependentSizedArrayType *newType + = new (*this, TypeAlignment) + DependentSizedArrayType(*this, elementType, QualType(), + numElements, ASM, elementTypeQuals, + brackets); + Types.push_back(newType); + return QualType(newType, 0); } - DependentSizedArrayType *New; - if (Canon) { - // We already have a canonical version of this array type; use it as - // the canonical type for a newly-built type. - New = new (*this, TypeAlignment) - DependentSizedArrayType(*this, EltTy, QualType(Canon, 0), - NumElts, ASM, EltTypeQuals, Brackets); - } else { - QualType CanonEltTy = getCanonicalType(EltTy); - if (CanonEltTy == EltTy) { - New = new (*this, TypeAlignment) - DependentSizedArrayType(*this, EltTy, QualType(), - NumElts, ASM, EltTypeQuals, Brackets); - - 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, - SourceRange()); - New = new (*this, TypeAlignment) - DependentSizedArrayType(*this, EltTy, Canon, - NumElts, ASM, EltTypeQuals, Brackets); - } - } + // Otherwise, we actually build a new type every time, but we + // also build a canonical type. - Types.push_back(New); - return QualType(New, 0); -} + SplitQualType canonElementType = getCanonicalType(elementType).split(); -QualType ASTContext::getIncompleteArrayType(QualType EltTy, + void *insertPos = 0; + llvm::FoldingSetNodeID ID; + DependentSizedArrayType::Profile(ID, *this, + QualType(canonElementType.first, 0), + ASM, elementTypeQuals, numElements); + + // Look for an existing type with these properties. + DependentSizedArrayType *canonTy = + DependentSizedArrayTypes.FindNodeOrInsertPos(ID, insertPos); + + // If we don't have one, build one. + if (!canonTy) { + canonTy = new (*this, TypeAlignment) + DependentSizedArrayType(*this, QualType(canonElementType.first, 0), + QualType(), numElements, ASM, elementTypeQuals, + brackets); + DependentSizedArrayTypes.InsertNode(canonTy, insertPos); + Types.push_back(canonTy); + } + + // Apply qualifiers from the element type to the array. + QualType canon = getQualifiedType(QualType(canonTy,0), + canonElementType.second); + + // If we didn't need extra canonicalization for the element type, + // then just use that as our result. + if (QualType(canonElementType.first, 0) == elementType) + return canon; + + // Otherwise, we need to build a type which follows the spelling + // of the element type. + DependentSizedArrayType *sugaredType + = new (*this, TypeAlignment) + DependentSizedArrayType(*this, elementType, canon, numElements, + ASM, elementTypeQuals, brackets); + Types.push_back(sugaredType); + return QualType(sugaredType, 0); +} + +QualType ASTContext::getIncompleteArrayType(QualType elementType, ArrayType::ArraySizeModifier ASM, - unsigned EltTypeQuals) { + unsigned elementTypeQuals) const { llvm::FoldingSetNodeID ID; - IncompleteArrayType::Profile(ID, EltTy, ASM, EltTypeQuals); + IncompleteArrayType::Profile(ID, elementType, ASM, elementTypeQuals); - void *InsertPos = 0; - if (IncompleteArrayType *ATP = - IncompleteArrayTypes.FindNodeOrInsertPos(ID, InsertPos)) - return QualType(ATP, 0); + void *insertPos = 0; + if (IncompleteArrayType *iat = + IncompleteArrayTypes.FindNodeOrInsertPos(ID, insertPos)) + return QualType(iat, 0); // If the element type isn't canonical, this won't be a canonical type - // either, so fill in the canonical type field. - QualType Canonical; + // either, so fill in the canonical type field. We also have to pull + // qualifiers off the element type. + QualType canon; - if (!EltTy.isCanonical()) { - Canonical = getIncompleteArrayType(getCanonicalType(EltTy), - ASM, EltTypeQuals); + if (!elementType.isCanonical() || elementType.hasLocalQualifiers()) { + SplitQualType canonSplit = getCanonicalType(elementType).split(); + canon = getIncompleteArrayType(QualType(canonSplit.first, 0), + ASM, elementTypeQuals); + canon = getQualifiedType(canon, canonSplit.second); // Get the new insert position for the node we care about. - IncompleteArrayType *NewIP = - IncompleteArrayTypes.FindNodeOrInsertPos(ID, InsertPos); - assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; + IncompleteArrayType *existing = + IncompleteArrayTypes.FindNodeOrInsertPos(ID, insertPos); + assert(!existing && "Shouldn't be in the map!"); (void) existing; } - IncompleteArrayType *New = new (*this, TypeAlignment) - IncompleteArrayType(EltTy, Canonical, ASM, EltTypeQuals); + IncompleteArrayType *newType = new (*this, TypeAlignment) + IncompleteArrayType(elementType, canon, ASM, elementTypeQuals); - IncompleteArrayTypes.InsertNode(New, InsertPos); - Types.push_back(New); - return QualType(New, 0); + IncompleteArrayTypes.InsertNode(newType, insertPos); + Types.push_back(newType); + return QualType(newType, 0); } /// 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, - VectorType::AltiVecSpecific AltiVecSpec) { - BuiltinType *baseType; - - baseType = dyn_cast<BuiltinType>(getCanonicalType(vecType).getTypePtr()); - assert(baseType != 0 && "getVectorType(): Expecting a built-in type"); + VectorType::VectorKind VecKind) const { + assert(vecType->isBuiltinType()); // Check if we've already instantiated a vector of this type. llvm::FoldingSetNodeID ID; - VectorType::Profile(ID, vecType, NumElts, Type::Vector, AltiVecSpec); + VectorType::Profile(ID, vecType, NumElts, Type::Vector, VecKind); void *InsertPos = 0; if (VectorType *VTP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos)) @@ -1550,15 +1771,14 @@ QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts, // so fill in the canonical type field. QualType Canonical; if (!vecType.isCanonical()) { - Canonical = getVectorType(getCanonicalType(vecType), NumElts, - VectorType::NotAltiVec); + Canonical = getVectorType(getCanonicalType(vecType), NumElts, VecKind); // 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; + assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP; } VectorType *New = new (*this, TypeAlignment) - VectorType(vecType, NumElts, Canonical, AltiVecSpec); + VectorType(vecType, NumElts, Canonical, VecKind); VectorTypes.InsertNode(New, InsertPos); Types.push_back(New); return QualType(New, 0); @@ -1566,16 +1786,14 @@ QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts, /// getExtVectorType - Return the unique reference to an extended vector type of /// the specified element type and size. VectorType must be a built-in type. -QualType ASTContext::getExtVectorType(QualType vecType, unsigned NumElts) { - BuiltinType *baseType; - - baseType = dyn_cast<BuiltinType>(getCanonicalType(vecType).getTypePtr()); - assert(baseType != 0 && "getExtVectorType(): Expecting a built-in type"); +QualType +ASTContext::getExtVectorType(QualType vecType, unsigned NumElts) const { + assert(vecType->isBuiltinType()); // Check if we've already instantiated a vector of this type. llvm::FoldingSetNodeID ID; VectorType::Profile(ID, vecType, NumElts, Type::ExtVector, - VectorType::NotAltiVec); + VectorType::GenericVector); void *InsertPos = 0; if (VectorType *VTP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(VTP, 0); @@ -1588,7 +1806,7 @@ QualType ASTContext::getExtVectorType(QualType vecType, unsigned NumElts) { // 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; + assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP; } ExtVectorType *New = new (*this, TypeAlignment) ExtVectorType(vecType, NumElts, Canonical); @@ -1597,9 +1815,10 @@ QualType ASTContext::getExtVectorType(QualType vecType, unsigned NumElts) { return QualType(New, 0); } -QualType ASTContext::getDependentSizedExtVectorType(QualType vecType, - Expr *SizeExpr, - SourceLocation AttrLoc) { +QualType +ASTContext::getDependentSizedExtVectorType(QualType vecType, + Expr *SizeExpr, + SourceLocation AttrLoc) const { llvm::FoldingSetNodeID ID; DependentSizedExtVectorType::Profile(ID, *this, getCanonicalType(vecType), SizeExpr); @@ -1640,8 +1859,9 @@ QualType ASTContext::getDependentSizedExtVectorType(QualType vecType, /// getFunctionNoProtoType - Return a K&R style C function type like 'int()'. /// -QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, - const FunctionType::ExtInfo &Info) { +QualType +ASTContext::getFunctionNoProtoType(QualType ResultTy, + const FunctionType::ExtInfo &Info) const { const CallingConv CallConv = Info.getCC(); // Unique functions, to guarantee there is only one function of a particular // structure. @@ -1663,7 +1883,7 @@ QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, // Get the new insert position for the node we care about. FunctionNoProtoType *NewIP = FunctionNoProtoTypes.FindNodeOrInsertPos(ID, InsertPos); - assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; + assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP; } FunctionNoProtoType *New = new (*this, TypeAlignment) @@ -1675,19 +1895,14 @@ QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, /// getFunctionType - Return a normal function type with a typed argument /// list. isVariadic indicates whether the argument list includes '...'. -QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray, - unsigned NumArgs, bool isVariadic, - unsigned TypeQuals, bool hasExceptionSpec, - bool hasAnyExceptionSpec, unsigned NumExs, - const QualType *ExArray, - const FunctionType::ExtInfo &Info) { - const CallingConv CallConv= Info.getCC(); +QualType +ASTContext::getFunctionType(QualType ResultTy, + const QualType *ArgArray, unsigned NumArgs, + const FunctionProtoType::ExtProtoInfo &EPI) const { // Unique functions, to guarantee there is only one function of a particular // structure. llvm::FoldingSetNodeID ID; - FunctionProtoType::Profile(ID, ResultTy, ArgArray, NumArgs, isVariadic, - TypeQuals, hasExceptionSpec, hasAnyExceptionSpec, - NumExs, ExArray, Info); + FunctionProtoType::Profile(ID, ResultTy, ArgArray, NumArgs, EPI); void *InsertPos = 0; if (FunctionProtoType *FTP = @@ -1695,11 +1910,13 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray, return QualType(FTP, 0); // Determine whether the type being created is already canonical or not. - bool isCanonical = !hasExceptionSpec && ResultTy.isCanonical(); + bool isCanonical = !EPI.HasExceptionSpec && ResultTy.isCanonical(); for (unsigned i = 0; i != NumArgs && isCanonical; ++i) if (!ArgArray[i].isCanonicalAsParam()) isCanonical = false; + const CallingConv CallConv = EPI.ExtInfo.getCC(); + // If this type isn't canonical, get the canonical version of it. // The exception spec is not part of the canonical type. QualType Canonical; @@ -1709,28 +1926,33 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray, for (unsigned i = 0; i != NumArgs; ++i) CanonicalArgs.push_back(getCanonicalParamType(ArgArray[i])); + FunctionProtoType::ExtProtoInfo CanonicalEPI = EPI; + if (CanonicalEPI.HasExceptionSpec) { + CanonicalEPI.HasExceptionSpec = false; + CanonicalEPI.HasAnyExceptionSpec = false; + CanonicalEPI.NumExceptions = 0; + } + CanonicalEPI.ExtInfo + = CanonicalEPI.ExtInfo.withCallingConv(getCanonicalCallConv(CallConv)); + Canonical = getFunctionType(getCanonicalType(ResultTy), CanonicalArgs.data(), NumArgs, - isVariadic, TypeQuals, false, - false, 0, 0, - Info.withCallingConv(getCanonicalCallConv(CallConv))); + CanonicalEPI); // Get the new insert position for the node we care about. FunctionProtoType *NewIP = FunctionProtoTypes.FindNodeOrInsertPos(ID, InsertPos); - assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; + assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP; } // FunctionProtoType objects are allocated with extra bytes after them // for two variable size arrays (for parameter and exception types) at the // end of them. - FunctionProtoType *FTP = - (FunctionProtoType*)Allocate(sizeof(FunctionProtoType) + - NumArgs*sizeof(QualType) + - NumExs*sizeof(QualType), TypeAlignment); - new (FTP) FunctionProtoType(ResultTy, ArgArray, NumArgs, isVariadic, - TypeQuals, hasExceptionSpec, hasAnyExceptionSpec, - ExArray, NumExs, Canonical, Info); + size_t Size = sizeof(FunctionProtoType) + + NumArgs * sizeof(QualType) + + EPI.NumExceptions * sizeof(QualType); + FunctionProtoType *FTP = (FunctionProtoType*) Allocate(Size, TypeAlignment); + new (FTP) FunctionProtoType(ResultTy, ArgArray, NumArgs, Canonical, EPI); Types.push_back(FTP); FunctionProtoTypes.InsertNode(FTP, InsertPos); return QualType(FTP, 0); @@ -1752,7 +1974,7 @@ static bool NeedsInjectedClassNameType(const RecordDecl *D) { /// getInjectedClassNameType - Return the unique reference to the /// injected class name type for the specified templated declaration. QualType ASTContext::getInjectedClassNameType(CXXRecordDecl *Decl, - QualType TST) { + QualType TST) const { assert(NeedsInjectedClassNameType(Decl)); if (Decl->TypeForDecl) { assert(isa<InjectedClassNameType>(Decl->TypeForDecl)); @@ -1761,16 +1983,17 @@ QualType ASTContext::getInjectedClassNameType(CXXRecordDecl *Decl, Decl->TypeForDecl = PrevDecl->TypeForDecl; assert(isa<InjectedClassNameType>(Decl->TypeForDecl)); } else { - Decl->TypeForDecl = + Type *newType = new (*this, TypeAlignment) InjectedClassNameType(Decl, TST); - Types.push_back(Decl->TypeForDecl); + Decl->TypeForDecl = newType; + Types.push_back(newType); } return QualType(Decl->TypeForDecl, 0); } /// getTypeDeclType - Return the unique reference to the type for the /// specified type declaration. -QualType ASTContext::getTypeDeclTypeSlow(const TypeDecl *Decl) { +QualType ASTContext::getTypeDeclTypeSlow(const TypeDecl *Decl) const { assert(Decl && "Passed null for Decl param"); assert(!Decl->TypeForDecl && "TypeForDecl present in slow case"); @@ -1791,56 +2014,81 @@ QualType ASTContext::getTypeDeclTypeSlow(const TypeDecl *Decl) { return getEnumType(Enum); } else if (const UnresolvedUsingTypenameDecl *Using = dyn_cast<UnresolvedUsingTypenameDecl>(Decl)) { - Decl->TypeForDecl = new (*this, TypeAlignment) UnresolvedUsingType(Using); + Type *newType = new (*this, TypeAlignment) UnresolvedUsingType(Using); + Decl->TypeForDecl = newType; + Types.push_back(newType); } else llvm_unreachable("TypeDecl without a type?"); - Types.push_back(Decl->TypeForDecl); return QualType(Decl->TypeForDecl, 0); } /// getTypedefType - Return the unique reference to the type for the /// specified typename decl. QualType -ASTContext::getTypedefType(const TypedefDecl *Decl, QualType Canonical) { +ASTContext::getTypedefType(const TypedefDecl *Decl, QualType Canonical) const { if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0); if (Canonical.isNull()) Canonical = getCanonicalType(Decl->getUnderlyingType()); - Decl->TypeForDecl = new(*this, TypeAlignment) + TypedefType *newType = new(*this, TypeAlignment) TypedefType(Type::Typedef, Decl, Canonical); - Types.push_back(Decl->TypeForDecl); - return QualType(Decl->TypeForDecl, 0); + Decl->TypeForDecl = newType; + Types.push_back(newType); + return QualType(newType, 0); } -QualType ASTContext::getRecordType(const RecordDecl *Decl) { +QualType ASTContext::getRecordType(const RecordDecl *Decl) const { if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0); if (const RecordDecl *PrevDecl = Decl->getPreviousDeclaration()) if (PrevDecl->TypeForDecl) return QualType(Decl->TypeForDecl = PrevDecl->TypeForDecl, 0); - Decl->TypeForDecl = new (*this, TypeAlignment) RecordType(Decl); - Types.push_back(Decl->TypeForDecl); - return QualType(Decl->TypeForDecl, 0); + RecordType *newType = new (*this, TypeAlignment) RecordType(Decl); + Decl->TypeForDecl = newType; + Types.push_back(newType); + return QualType(newType, 0); } -QualType ASTContext::getEnumType(const EnumDecl *Decl) { +QualType ASTContext::getEnumType(const EnumDecl *Decl) const { if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0); if (const EnumDecl *PrevDecl = Decl->getPreviousDeclaration()) if (PrevDecl->TypeForDecl) return QualType(Decl->TypeForDecl = PrevDecl->TypeForDecl, 0); - Decl->TypeForDecl = new (*this, TypeAlignment) EnumType(Decl); - Types.push_back(Decl->TypeForDecl); - return QualType(Decl->TypeForDecl, 0); + EnumType *newType = new (*this, TypeAlignment) EnumType(Decl); + Decl->TypeForDecl = newType; + Types.push_back(newType); + return QualType(newType, 0); } +QualType ASTContext::getAttributedType(AttributedType::Kind attrKind, + QualType modifiedType, + QualType equivalentType) { + llvm::FoldingSetNodeID id; + AttributedType::Profile(id, attrKind, modifiedType, equivalentType); + + void *insertPos = 0; + AttributedType *type = AttributedTypes.FindNodeOrInsertPos(id, insertPos); + if (type) return QualType(type, 0); + + QualType canon = getCanonicalType(equivalentType); + type = new (*this, TypeAlignment) + AttributedType(canon, attrKind, modifiedType, equivalentType); + + Types.push_back(type); + AttributedTypes.InsertNode(type, insertPos); + + return QualType(type, 0); +} + + /// \brief Retrieve a substitution-result type. QualType ASTContext::getSubstTemplateTypeParmType(const TemplateTypeParmType *Parm, - QualType Replacement) { + QualType Replacement) const { assert(Replacement.isCanonical() && "replacement types must always be canonical"); @@ -1860,12 +2108,48 @@ ASTContext::getSubstTemplateTypeParmType(const TemplateTypeParmType *Parm, return QualType(SubstParm, 0); } +/// \brief Retrieve a +QualType ASTContext::getSubstTemplateTypeParmPackType( + const TemplateTypeParmType *Parm, + const TemplateArgument &ArgPack) { +#ifndef NDEBUG + for (TemplateArgument::pack_iterator P = ArgPack.pack_begin(), + PEnd = ArgPack.pack_end(); + P != PEnd; ++P) { + assert(P->getKind() == TemplateArgument::Type &&"Pack contains a non-type"); + assert(P->getAsType().isCanonical() && "Pack contains non-canonical type"); + } +#endif + + llvm::FoldingSetNodeID ID; + SubstTemplateTypeParmPackType::Profile(ID, Parm, ArgPack); + void *InsertPos = 0; + if (SubstTemplateTypeParmPackType *SubstParm + = SubstTemplateTypeParmPackTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(SubstParm, 0); + + QualType Canon; + if (!Parm->isCanonicalUnqualified()) { + Canon = getCanonicalType(QualType(Parm, 0)); + Canon = getSubstTemplateTypeParmPackType(cast<TemplateTypeParmType>(Canon), + ArgPack); + SubstTemplateTypeParmPackTypes.FindNodeOrInsertPos(ID, InsertPos); + } + + SubstTemplateTypeParmPackType *SubstParm + = new (*this, TypeAlignment) SubstTemplateTypeParmPackType(Parm, Canon, + ArgPack); + Types.push_back(SubstParm); + SubstTemplateTypeParmTypes.InsertNode(SubstParm, InsertPos); + return QualType(SubstParm, 0); +} + /// \brief Retrieve the template type parameter type for a template /// parameter or parameter pack with the given depth, index, and (optionally) /// name. QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index, bool ParameterPack, - IdentifierInfo *Name) { + IdentifierInfo *Name) const { llvm::FoldingSetNodeID ID; TemplateTypeParmType::Profile(ID, Depth, Index, ParameterPack, Name); void *InsertPos = 0; @@ -1898,7 +2182,7 @@ TypeSourceInfo * ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name, SourceLocation NameLoc, const TemplateArgumentListInfo &Args, - QualType CanonType) { + QualType CanonType) const { QualType TST = getTemplateSpecializationType(Name, Args, CanonType); TypeSourceInfo *DI = CreateTypeSourceInfo(TST); @@ -1915,7 +2199,7 @@ ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name, QualType ASTContext::getTemplateSpecializationType(TemplateName Template, const TemplateArgumentListInfo &Args, - QualType Canon) { + QualType Canon) const { unsigned NumArgs = Args.size(); llvm::SmallVector<TemplateArgument, 4> ArgVec; @@ -1931,7 +2215,7 @@ QualType ASTContext::getTemplateSpecializationType(TemplateName Template, const TemplateArgument *Args, unsigned NumArgs, - QualType Canon) { + QualType Canon) const { if (!Canon.isNull()) Canon = getCanonicalType(Canon); else @@ -1955,7 +2239,7 @@ ASTContext::getTemplateSpecializationType(TemplateName Template, QualType ASTContext::getCanonicalTemplateSpecializationType(TemplateName Template, const TemplateArgument *Args, - unsigned NumArgs) { + unsigned NumArgs) const { // Build the canonical template specialization type. TemplateName CanonTemplate = getCanonicalTemplateName(Template); llvm::SmallVector<TemplateArgument, 4> CanonArgs; @@ -1993,7 +2277,7 @@ ASTContext::getCanonicalTemplateSpecializationType(TemplateName Template, QualType ASTContext::getElaboratedType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, - QualType NamedType) { + QualType NamedType) const { llvm::FoldingSetNodeID ID; ElaboratedType::Profile(ID, Keyword, NNS, NamedType); @@ -2016,10 +2300,34 @@ ASTContext::getElaboratedType(ElaboratedTypeKeyword Keyword, return QualType(T, 0); } +QualType +ASTContext::getParenType(QualType InnerType) const { + llvm::FoldingSetNodeID ID; + ParenType::Profile(ID, InnerType); + + void *InsertPos = 0; + ParenType *T = ParenTypes.FindNodeOrInsertPos(ID, InsertPos); + if (T) + return QualType(T, 0); + + QualType Canon = InnerType; + if (!Canon.isCanonical()) { + Canon = getCanonicalType(InnerType); + ParenType *CheckT = ParenTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(!CheckT && "Paren canonical type broken"); + (void)CheckT; + } + + T = new (*this) ParenType(InnerType, Canon); + Types.push_back(T); + ParenTypes.InsertNode(T, InsertPos); + return QualType(T, 0); +} + QualType ASTContext::getDependentNameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, const IdentifierInfo *Name, - QualType Canon) { + QualType Canon) const { assert(NNS->isDependent() && "nested-name-specifier must be dependent"); if (Canon.isNull()) { @@ -2052,7 +2360,7 @@ ASTContext::getDependentTemplateSpecializationType( ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, const IdentifierInfo *Name, - const TemplateArgumentListInfo &Args) { + const TemplateArgumentListInfo &Args) const { // TODO: avoid this copy llvm::SmallVector<TemplateArgument, 16> ArgCopy; for (unsigned I = 0, E = Args.size(); I != E; ++I) @@ -2068,7 +2376,7 @@ ASTContext::getDependentTemplateSpecializationType( NestedNameSpecifier *NNS, const IdentifierInfo *Name, unsigned NumArgs, - const TemplateArgument *Args) { + const TemplateArgument *Args) const { assert(NNS->isDependent() && "nested-name-specifier must be dependent"); llvm::FoldingSetNodeID ID; @@ -2114,6 +2422,33 @@ ASTContext::getDependentTemplateSpecializationType( return QualType(T, 0); } +QualType ASTContext::getPackExpansionType(QualType Pattern, + llvm::Optional<unsigned> NumExpansions) { + llvm::FoldingSetNodeID ID; + PackExpansionType::Profile(ID, Pattern, NumExpansions); + + assert(Pattern->containsUnexpandedParameterPack() && + "Pack expansions must expand one or more parameter packs"); + void *InsertPos = 0; + PackExpansionType *T + = PackExpansionTypes.FindNodeOrInsertPos(ID, InsertPos); + if (T) + return QualType(T, 0); + + QualType Canon; + if (!Pattern.isCanonical()) { + Canon = getPackExpansionType(getCanonicalType(Pattern), NumExpansions); + + // Find the insert position again. + PackExpansionTypes.FindNodeOrInsertPos(ID, InsertPos); + } + + T = new (*this) PackExpansionType(Pattern, Canon, NumExpansions); + Types.push_back(T); + PackExpansionTypes.InsertNode(T, InsertPos); + return QualType(T, 0); +} + /// CmpProtocolNames - Comparison predicate for sorting protocols /// alphabetically. static bool CmpProtocolNames(const ObjCProtocolDecl *LHS, @@ -2145,7 +2480,7 @@ static void SortAndUniqueProtocols(ObjCProtocolDecl **Protocols, QualType ASTContext::getObjCObjectType(QualType BaseType, ObjCProtocolDecl * const *Protocols, - unsigned NumProtocols) { + unsigned NumProtocols) const { // If the base type is an interface and there aren't any protocols // to add, then the interface type will do just fine. if (!NumProtocols && isa<ObjCInterfaceType>(BaseType)) @@ -2193,7 +2528,7 @@ QualType ASTContext::getObjCObjectType(QualType BaseType, /// getObjCObjectPointerType - Return a ObjCObjectPointerType type for /// the given object type. -QualType ASTContext::getObjCObjectPointerType(QualType ObjectT) { +QualType ASTContext::getObjCObjectPointerType(QualType ObjectT) const { llvm::FoldingSetNodeID ID; ObjCObjectPointerType::Profile(ID, ObjectT); @@ -2223,7 +2558,7 @@ QualType ASTContext::getObjCObjectPointerType(QualType ObjectT) { /// getObjCInterfaceType - Return the unique reference to the type for the /// specified ObjC interface decl. The list of protocols is optional. -QualType ASTContext::getObjCInterfaceType(const ObjCInterfaceDecl *Decl) { +QualType ASTContext::getObjCInterfaceType(const ObjCInterfaceDecl *Decl) const { if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0); @@ -2240,7 +2575,7 @@ QualType ASTContext::getObjCInterfaceType(const ObjCInterfaceDecl *Decl) { /// multiple declarations that refer to "typeof(x)" all contain different /// DeclRefExpr's. This doesn't effect the type checker, since it operates /// on canonical type's (which are always unique). -QualType ASTContext::getTypeOfExprType(Expr *tofExpr) { +QualType ASTContext::getTypeOfExprType(Expr *tofExpr) const { TypeOfExprType *toe; if (tofExpr->isTypeDependent()) { llvm::FoldingSetNodeID ID; @@ -2275,7 +2610,7 @@ QualType ASTContext::getTypeOfExprType(Expr *tofExpr) { /// memory savings. Since typeof(t) is fairly uncommon, space shouldn't be /// an issue. This doesn't effect the type checker, since it operates /// on canonical type's (which are always unique). -QualType ASTContext::getTypeOfType(QualType tofType) { +QualType ASTContext::getTypeOfType(QualType tofType) const { QualType Canonical = getCanonicalType(tofType); TypeOfType *tot = new (*this, TypeAlignment) TypeOfType(tofType, Canonical); Types.push_back(tot); @@ -2284,7 +2619,7 @@ QualType ASTContext::getTypeOfType(QualType tofType) { /// getDecltypeForExpr - Given an expr, will return the decltype for that /// expression, according to the rules in C++0x [dcl.type.simple]p4 -static QualType getDecltypeForExpr(const Expr *e, ASTContext &Context) { +static QualType getDecltypeForExpr(const Expr *e, const ASTContext &Context) { if (e->isTypeDependent()) return Context.DependentTy; @@ -2308,7 +2643,7 @@ static QualType getDecltypeForExpr(const Expr *e, ASTContext &Context) { // Otherwise, where T is the type of e, if e is an lvalue, decltype(e) is // defined as T&, otherwise decltype(e) is defined as T. - if (e->isLvalue(Context) == Expr::LV_Valid) + if (e->isLValue()) T = Context.getLValueReferenceType(T); return T; @@ -2319,7 +2654,7 @@ static QualType getDecltypeForExpr(const Expr *e, ASTContext &Context) { /// memory savings. Since decltype(t) is fairly uncommon, space shouldn't be /// an issue. This doesn't effect the type checker, since it operates /// on canonical type's (which are always unique). -QualType ASTContext::getDecltypeType(Expr *e) { +QualType ASTContext::getDecltypeType(Expr *e) const { DecltypeType *dt; if (e->isTypeDependent()) { llvm::FoldingSetNodeID ID; @@ -2348,9 +2683,17 @@ QualType ASTContext::getDecltypeType(Expr *e) { return QualType(dt, 0); } +/// getAutoType - Unlike many "get<Type>" functions, we don't unique +/// AutoType AST's. +QualType ASTContext::getAutoType(QualType DeducedType) const { + AutoType *at = new (*this, TypeAlignment) AutoType(DeducedType); + Types.push_back(at); + return QualType(at, 0); +} + /// getTagDeclType - Return the unique reference to the type for the /// specified TagDecl (struct/union/class/enum) decl. -QualType ASTContext::getTagDeclType(const TagDecl *Decl) { +QualType ASTContext::getTagDeclType(const TagDecl *Decl) const { assert (Decl); // FIXME: What is the design on getTagDeclType when it requires casting // away const? mutable? @@ -2388,12 +2731,12 @@ QualType ASTContext::getPointerDiffType() const { // Type Operators //===----------------------------------------------------------------------===// -CanQualType ASTContext::getCanonicalParamType(QualType T) { +CanQualType ASTContext::getCanonicalParamType(QualType T) const { // Push qualifiers into arrays, and then discard any remaining // qualifiers. T = getCanonicalType(T); + T = getVariableArrayDecayedType(T); const Type *Ty = T.getTypePtr(); - QualType Result; if (isa<ArrayType>(Ty)) { Result = getArrayDecayedType(QualType(Ty,0)); @@ -2406,97 +2749,59 @@ CanQualType ASTContext::getCanonicalParamType(QualType T) { return CanQualType::CreateUnsafe(Result); } -/// getCanonicalType - Return the canonical (structural) type corresponding to -/// the specified potentially non-canonical type. The non-canonical version -/// of a type may have many "decorated" versions of types. Decorators can -/// include typedefs, 'typeof' operators, etc. The returned type is guaranteed -/// to be free of any of these, allowing two canonical types to be compared -/// for exact equality with a simple pointer comparison. -CanQualType ASTContext::getCanonicalType(QualType T) { - QualifierCollector Quals; - const Type *Ptr = Quals.strip(T); - QualType CanType = Ptr->getCanonicalTypeInternal(); - - // The canonical internal type will be the canonical type *except* - // that we push type qualifiers down through array types. - - // If there are no new qualifiers to push down, stop here. - if (!Quals.hasQualifiers()) - return CanQualType::CreateUnsafe(CanType); - - // If the type qualifiers are on an array type, get the canonical - // type of the array with the qualifiers applied to the element - // type. - ArrayType *AT = dyn_cast<ArrayType>(CanType); - if (!AT) - return CanQualType::CreateUnsafe(getQualifiedType(CanType, Quals)); - - // Get the canonical version of the element with the extra qualifiers on it. - // This can recursively sink qualifiers through multiple levels of arrays. - QualType NewEltTy = getQualifiedType(AT->getElementType(), Quals); - NewEltTy = getCanonicalType(NewEltTy); - - if (ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT)) - return CanQualType::CreateUnsafe( - getConstantArrayType(NewEltTy, CAT->getSize(), - CAT->getSizeModifier(), - CAT->getIndexTypeCVRQualifiers())); - if (IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(AT)) - return CanQualType::CreateUnsafe( - getIncompleteArrayType(NewEltTy, IAT->getSizeModifier(), - IAT->getIndexTypeCVRQualifiers())); - - if (DependentSizedArrayType *DSAT = dyn_cast<DependentSizedArrayType>(AT)) - return CanQualType::CreateUnsafe( - getDependentSizedArrayType(NewEltTy, - DSAT->getSizeExpr() ? - DSAT->getSizeExpr()->Retain() : 0, - DSAT->getSizeModifier(), - DSAT->getIndexTypeCVRQualifiers(), - DSAT->getBracketsRange())->getCanonicalTypeInternal()); - - VariableArrayType *VAT = cast<VariableArrayType>(AT); - return CanQualType::CreateUnsafe(getVariableArrayType(NewEltTy, - VAT->getSizeExpr() ? - VAT->getSizeExpr()->Retain() : 0, - VAT->getSizeModifier(), - VAT->getIndexTypeCVRQualifiers(), - VAT->getBracketsRange())); -} -QualType ASTContext::getUnqualifiedArrayType(QualType T, - Qualifiers &Quals) { - Quals = T.getQualifiers(); - const ArrayType *AT = getAsArrayType(T); +QualType ASTContext::getUnqualifiedArrayType(QualType type, + Qualifiers &quals) { + SplitQualType splitType = type.getSplitUnqualifiedType(); + + // FIXME: getSplitUnqualifiedType() actually walks all the way to + // the unqualified desugared type and then drops it on the floor. + // We then have to strip that sugar back off with + // getUnqualifiedDesugaredType(), which is silly. + const ArrayType *AT = + dyn_cast<ArrayType>(splitType.first->getUnqualifiedDesugaredType()); + + // If we don't have an array, just use the results in splitType. if (!AT) { - return T.getUnqualifiedType(); + quals = splitType.second; + return QualType(splitType.first, 0); } - QualType Elt = AT->getElementType(); - QualType UnqualElt = getUnqualifiedArrayType(Elt, Quals); - if (Elt == UnqualElt) - return T; + // Otherwise, recurse on the array's element type. + QualType elementType = AT->getElementType(); + QualType unqualElementType = getUnqualifiedArrayType(elementType, quals); + + // If that didn't change the element type, AT has no qualifiers, so we + // can just use the results in splitType. + if (elementType == unqualElementType) { + assert(quals.empty()); // from the recursive call + quals = splitType.second; + return QualType(splitType.first, 0); + } + + // Otherwise, add in the qualifiers from the outermost type, then + // build the type back up. + quals.addConsistentQualifiers(splitType.second); if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT)) { - return getConstantArrayType(UnqualElt, CAT->getSize(), + return getConstantArrayType(unqualElementType, CAT->getSize(), CAT->getSizeModifier(), 0); } if (const IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(AT)) { - return getIncompleteArrayType(UnqualElt, IAT->getSizeModifier(), 0); + return getIncompleteArrayType(unqualElementType, IAT->getSizeModifier(), 0); } if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(AT)) { - return getVariableArrayType(UnqualElt, - VAT->getSizeExpr() ? - VAT->getSizeExpr()->Retain() : 0, + return getVariableArrayType(unqualElementType, + VAT->getSizeExpr(), VAT->getSizeModifier(), VAT->getIndexTypeCVRQualifiers(), VAT->getBracketsRange()); } const DependentSizedArrayType *DSAT = cast<DependentSizedArrayType>(AT); - return getDependentSizedArrayType(UnqualElt, DSAT->getSizeExpr()->Retain(), + return getDependentSizedArrayType(unqualElementType, DSAT->getSizeExpr(), DSAT->getSizeModifier(), 0, SourceRange()); } @@ -2543,8 +2848,9 @@ bool ASTContext::UnwrapSimilarPointerTypes(QualType &T1, QualType &T2) { return false; } -DeclarationNameInfo ASTContext::getNameForTemplate(TemplateName Name, - SourceLocation NameLoc) { +DeclarationNameInfo +ASTContext::getNameForTemplate(TemplateName Name, + SourceLocation NameLoc) const { if (TemplateDecl *TD = Name.getAsTemplateDecl()) // DNInfo work in progress: CHECKME: what about DNLoc? return DeclarationNameInfo(TD->getDeclName(), NameLoc); @@ -2570,7 +2876,7 @@ DeclarationNameInfo ASTContext::getNameForTemplate(TemplateName Name, return DeclarationNameInfo((*Storage->begin())->getDeclName(), NameLoc); } -TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name) { +TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name) const { if (TemplateDecl *Template = Name.getAsTemplateDecl()) { if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(Template)) @@ -2580,6 +2886,15 @@ TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name) { return TemplateName(cast<TemplateDecl>(Template->getCanonicalDecl())); } + if (SubstTemplateTemplateParmPackStorage *SubstPack + = Name.getAsSubstTemplateTemplateParmPack()) { + TemplateTemplateParmDecl *CanonParam + = getCanonicalTemplateTemplateParmDecl(SubstPack->getParameterPack()); + TemplateArgument CanonArgPack + = getCanonicalTemplateArgument(SubstPack->getArgumentPack()); + return getSubstTemplateTemplateParmPack(CanonParam, CanonArgPack); + } + assert(!Name.getAsOverloadedTemplate()); DependentTemplateName *DTN = Name.getAsDependentTemplateName(); @@ -2594,7 +2909,7 @@ bool ASTContext::hasSameTemplateName(TemplateName X, TemplateName Y) { } TemplateArgument -ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) { +ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) const { switch (Arg.getKind()) { case TemplateArgument::Null: return Arg; @@ -2607,7 +2922,12 @@ ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) { case TemplateArgument::Template: return TemplateArgument(getCanonicalTemplateName(Arg.getAsTemplate())); - + + case TemplateArgument::TemplateExpansion: + return TemplateArgument(getCanonicalTemplateName( + Arg.getAsTemplateOrTemplatePattern()), + Arg.getNumTemplateExpansions()); + case TemplateArgument::Integral: return TemplateArgument(*Arg.getAsIntegral(), getCanonicalType(Arg.getIntegralType())); @@ -2616,17 +2936,18 @@ ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) { return TemplateArgument(getCanonicalType(Arg.getAsType())); case TemplateArgument::Pack: { - // FIXME: Allocate in ASTContext - TemplateArgument *CanonArgs = new TemplateArgument[Arg.pack_size()]; + if (Arg.pack_size() == 0) + return Arg; + + TemplateArgument *CanonArgs + = new (*this) TemplateArgument[Arg.pack_size()]; unsigned Idx = 0; for (TemplateArgument::pack_iterator A = Arg.pack_begin(), AEnd = Arg.pack_end(); A != AEnd; (void)++A, ++Idx) CanonArgs[Idx] = getCanonicalTemplateArgument(*A); - TemplateArgument Result; - Result.setArgumentPack(CanonArgs, Arg.pack_size(), false); - return Result; + return TemplateArgument(CanonArgs, Arg.pack_size()); } } @@ -2636,7 +2957,7 @@ ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) { } NestedNameSpecifier * -ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) { +ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const { if (!NNS) return 0; @@ -2655,9 +2976,35 @@ ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) { case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: { QualType T = getCanonicalType(QualType(NNS->getAsType(), 0)); - return NestedNameSpecifier::Create(*this, 0, - NNS->getKind() == NestedNameSpecifier::TypeSpecWithTemplate, - T.getTypePtr()); + + // If we have some kind of dependent-named type (e.g., "typename T::type"), + // break it apart into its prefix and identifier, then reconsititute those + // as the canonical nested-name-specifier. This is required to canonicalize + // a dependent nested-name-specifier involving typedefs of dependent-name + // types, e.g., + // typedef typename T::type T1; + // typedef typename T1::type T2; + if (const DependentNameType *DNT = T->getAs<DependentNameType>()) { + NestedNameSpecifier *Prefix + = getCanonicalNestedNameSpecifier(DNT->getQualifier()); + return NestedNameSpecifier::Create(*this, Prefix, + const_cast<IdentifierInfo *>(DNT->getIdentifier())); + } + + // Do the same thing as above, but with dependent-named specializations. + if (const DependentTemplateSpecializationType *DTST + = T->getAs<DependentTemplateSpecializationType>()) { + NestedNameSpecifier *Prefix + = getCanonicalNestedNameSpecifier(DTST->getQualifier()); + TemplateName Name + = getDependentTemplateName(Prefix, DTST->getIdentifier()); + T = getTemplateSpecializationType(Name, + DTST->getArgs(), DTST->getNumArgs()); + T = getCanonicalType(T); + } + + return NestedNameSpecifier::Create(*this, 0, false, + const_cast<Type*>(T.getTypePtr())); } case NestedNameSpecifier::Global: @@ -2670,7 +3017,7 @@ ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) { } -const ArrayType *ASTContext::getAsArrayType(QualType T) { +const ArrayType *ASTContext::getAsArrayType(QualType T) const { // Handle the non-qualified case efficiently. if (!T.hasLocalQualifiers()) { // Handle the common positive case fast. @@ -2679,8 +3026,7 @@ const ArrayType *ASTContext::getAsArrayType(QualType T) { } // Handle the common negative case fast. - QualType CType = T->getCanonicalTypeInternal(); - if (!isa<ArrayType>(CType)) + if (!isa<ArrayType>(T.getCanonicalType())) return 0; // Apply any qualifiers from the array type to the element type. This @@ -2691,19 +3037,17 @@ const ArrayType *ASTContext::getAsArrayType(QualType T) { // sugar such as a typedef in the way. If we have type qualifiers on the type // we must propagate them down into the element type. - QualifierCollector Qs; - const Type *Ty = Qs.strip(T.getDesugaredType()); + SplitQualType split = T.getSplitDesugaredType(); + Qualifiers qs = split.second; // If we have a simple case, just return now. - const ArrayType *ATy = dyn_cast<ArrayType>(Ty); - if (ATy == 0 || Qs.empty()) + const ArrayType *ATy = dyn_cast<ArrayType>(split.first); + if (ATy == 0 || qs.empty()) return ATy; // Otherwise, we have an array and we have qualifiers on it. Push the // qualifiers into the array element type and return a new array type. - // Get the canonical version of the element with the extra qualifiers on it. - // This can recursively sink qualifiers through multiple levels of arrays. - QualType NewEltTy = getQualifiedType(ATy->getElementType(), Qs); + QualType NewEltTy = getQualifiedType(ATy->getElementType(), qs); if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(ATy)) return cast<ArrayType>(getConstantArrayType(NewEltTy, CAT->getSize(), @@ -2718,29 +3062,26 @@ const ArrayType *ASTContext::getAsArrayType(QualType T) { = dyn_cast<DependentSizedArrayType>(ATy)) return cast<ArrayType>( getDependentSizedArrayType(NewEltTy, - DSAT->getSizeExpr() ? - DSAT->getSizeExpr()->Retain() : 0, + DSAT->getSizeExpr(), DSAT->getSizeModifier(), DSAT->getIndexTypeCVRQualifiers(), DSAT->getBracketsRange())); const VariableArrayType *VAT = cast<VariableArrayType>(ATy); return cast<ArrayType>(getVariableArrayType(NewEltTy, - VAT->getSizeExpr() ? - VAT->getSizeExpr()->Retain() : 0, + VAT->getSizeExpr(), VAT->getSizeModifier(), VAT->getIndexTypeCVRQualifiers(), VAT->getBracketsRange())); } - /// getArrayDecayedType - Return the properly qualified result of decaying the /// specified array type to a pointer. This operation is non-trivial when /// handling typedefs etc. The canonical type of "T" must be an array type, /// this returns a pointer to a properly qualified element of the array. /// /// See C99 6.7.5.3p7 and C99 6.3.2.1p3. -QualType ASTContext::getArrayDecayedType(QualType Ty) { +QualType ASTContext::getArrayDecayedType(QualType Ty) const { // Get the element type with 'getAsArrayType' so that we don't lose any // typedefs in the element type of the array. This also handles propagation // of type qualifiers from the array type into the element type if present @@ -2754,20 +3095,22 @@ QualType ASTContext::getArrayDecayedType(QualType Ty) { return getQualifiedType(PtrTy, PrettyArrayType->getIndexTypeQualifiers()); } -QualType ASTContext::getBaseElementType(QualType QT) { - QualifierCollector Qs; - while (const ArrayType *AT = getAsArrayType(QualType(Qs.strip(QT), 0))) - QT = AT->getElementType(); - return Qs.apply(QT); +QualType ASTContext::getBaseElementType(const ArrayType *array) const { + return getBaseElementType(array->getElementType()); } -QualType ASTContext::getBaseElementType(const ArrayType *AT) { - QualType ElemTy = AT->getElementType(); +QualType ASTContext::getBaseElementType(QualType type) const { + Qualifiers qs; + while (true) { + SplitQualType split = type.getSplitDesugaredType(); + const ArrayType *array = split.first->getAsArrayTypeUnsafe(); + if (!array) break; - if (const ArrayType *AT = getAsArrayType(ElemTy)) - return getBaseElementType(AT); + type = array->getElementType(); + qs.addConsistentQualifiers(split.second); + } - return ElemTy; + return getQualifiedType(type, qs); } /// getConstantArrayElementCount - Returns number of constant array elements. @@ -2825,7 +3168,7 @@ QualType ASTContext::getFloatingTypeOfSizeWithinDomain(QualType Size, /// point types, ignoring the domain of the type (i.e. 'double' == /// '_Complex double'). If LHS > RHS, return 1. If LHS == RHS, return 0. If /// LHS < RHS, return -1. -int ASTContext::getFloatingTypeOrder(QualType LHS, QualType RHS) { +int ASTContext::getFloatingTypeOrder(QualType LHS, QualType RHS) const { FloatingRank LHSR = getFloatingRank(LHS); FloatingRank RHSR = getFloatingRank(RHS); @@ -2839,12 +3182,13 @@ int ASTContext::getFloatingTypeOrder(QualType LHS, QualType RHS) { /// getIntegerRank - Return an integer conversion rank (C99 6.3.1.1p1). This /// routine will assert if passed a built-in type that isn't an integer or enum, /// or if it is not canonicalized. -unsigned ASTContext::getIntegerRank(Type *T) { +unsigned ASTContext::getIntegerRank(const Type *T) const { assert(T->isCanonicalUnqualified() && "T should be canonicalized"); - if (EnumType* ET = dyn_cast<EnumType>(T)) + if (const EnumType* ET = dyn_cast<EnumType>(T)) T = ET->getDecl()->getPromotionType().getTypePtr(); - if (T->isSpecificBuiltinType(BuiltinType::WChar)) + if (T->isSpecificBuiltinType(BuiltinType::WChar_S) || + T->isSpecificBuiltinType(BuiltinType::WChar_U)) T = getFromTargetType(Target.getWCharType()).getTypePtr(); if (T->isSpecificBuiltinType(BuiltinType::Char16)) @@ -2885,7 +3229,7 @@ unsigned ASTContext::getIntegerRank(Type *T) { /// /// \returns the type this bit-field will promote to, or NULL if no /// promotion occurs. -QualType ASTContext::isPromotableBitField(Expr *E) { +QualType ASTContext::isPromotableBitField(Expr *E) const { if (E->isTypeDependent() || E->isValueDependent()) return QualType(); @@ -2917,7 +3261,7 @@ QualType ASTContext::isPromotableBitField(Expr *E) { /// getPromotedIntegerType - Returns the type that Promotable will /// promote to: C99 6.3.1.1p2, assuming that Promotable is a promotable /// integer type. -QualType ASTContext::getPromotedIntegerType(QualType Promotable) { +QualType ASTContext::getPromotedIntegerType(QualType Promotable) const { assert(!Promotable.isNull()); assert(Promotable->isPromotableIntegerType()); if (const EnumType *ET = Promotable->getAs<EnumType>()) @@ -2933,9 +3277,9 @@ QualType ASTContext::getPromotedIntegerType(QualType Promotable) { /// getIntegerTypeOrder - Returns the highest ranked integer type: /// C99 6.3.1.8p1. If LHS > RHS, return 1. If LHS == RHS, return 0. If /// LHS < RHS, return -1. -int ASTContext::getIntegerTypeOrder(QualType LHS, QualType RHS) { - Type *LHSC = getCanonicalType(LHS).getTypePtr(); - Type *RHSC = getCanonicalType(RHS).getTypePtr(); +int ASTContext::getIntegerTypeOrder(QualType LHS, QualType RHS) const { + const Type *LHSC = getCanonicalType(LHS).getTypePtr(); + const Type *RHSC = getCanonicalType(RHS).getTypePtr(); if (LHSC == RHSC) return 0; bool LHSUnsigned = LHSC->isUnsignedIntegerType(); @@ -2972,7 +3316,7 @@ int ASTContext::getIntegerTypeOrder(QualType LHS, QualType RHS) { } static RecordDecl * -CreateRecordDecl(ASTContext &Ctx, RecordDecl::TagKind TK, DeclContext *DC, +CreateRecordDecl(const ASTContext &Ctx, RecordDecl::TagKind TK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id) { if (Ctx.getLangOptions().CPlusPlus) return CXXRecordDecl::Create(Ctx, TK, DC, L, Id); @@ -2981,7 +3325,7 @@ CreateRecordDecl(ASTContext &Ctx, RecordDecl::TagKind TK, DeclContext *DC, } // getCFConstantStringType - Return the type used for constant CFStrings. -QualType ASTContext::getCFConstantStringType() { +QualType ASTContext::getCFConstantStringType() const { if (!CFConstantStringTypeDecl) { CFConstantStringTypeDecl = CreateRecordDecl(*this, TTK_Struct, TUDecl, SourceLocation(), @@ -3023,7 +3367,7 @@ void ASTContext::setCFConstantStringType(QualType T) { } // getNSConstantStringType - Return the type used for constant NSStrings. -QualType ASTContext::getNSConstantStringType() { +QualType ASTContext::getNSConstantStringType() const { if (!NSConstantStringTypeDecl) { NSConstantStringTypeDecl = CreateRecordDecl(*this, TTK_Struct, TUDecl, SourceLocation(), @@ -3062,7 +3406,7 @@ void ASTContext::setNSConstantStringType(QualType T) { NSConstantStringTypeDecl = Rec->getDecl(); } -QualType ASTContext::getObjCFastEnumerationStateType() { +QualType ASTContext::getObjCFastEnumerationStateType() const { if (!ObjCFastEnumerationStateTypeDecl) { ObjCFastEnumerationStateTypeDecl = CreateRecordDecl(*this, TTK_Struct, TUDecl, SourceLocation(), @@ -3087,10 +3431,6 @@ QualType ASTContext::getObjCFastEnumerationStateType() { Field->setAccess(AS_public); ObjCFastEnumerationStateTypeDecl->addDecl(Field); } - if (getLangOptions().CPlusPlus) - if (CXXRecordDecl *CXXRD = - dyn_cast<CXXRecordDecl>(ObjCFastEnumerationStateTypeDecl)) - CXXRD->setEmpty(false); ObjCFastEnumerationStateTypeDecl->completeDefinition(); } @@ -3098,7 +3438,7 @@ QualType ASTContext::getObjCFastEnumerationStateType() { return getTagDeclType(ObjCFastEnumerationStateTypeDecl); } -QualType ASTContext::getBlockDescriptorType() { +QualType ASTContext::getBlockDescriptorType() const { if (BlockDescriptorType) return getTagDeclType(BlockDescriptorType); @@ -3143,7 +3483,7 @@ void ASTContext::setBlockDescriptorType(QualType T) { BlockDescriptorType = Rec->getDecl(); } -QualType ASTContext::getBlockDescriptorExtendedType() { +QualType ASTContext::getBlockDescriptorExtendedType() const { if (BlockDescriptorExtendedType) return getTagDeclType(BlockDescriptorExtendedType); @@ -3192,17 +3532,25 @@ void ASTContext::setBlockDescriptorExtendedType(QualType T) { BlockDescriptorExtendedType = Rec->getDecl(); } -bool ASTContext::BlockRequiresCopying(QualType Ty) { +bool ASTContext::BlockRequiresCopying(QualType Ty) const { if (Ty->isBlockPointerType()) return true; if (isObjCNSObjectType(Ty)) return true; if (Ty->isObjCObjectPointerType()) return true; + if (getLangOptions().CPlusPlus) { + if (const RecordType *RT = Ty->getAs<RecordType>()) { + CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); + return RD->hasConstCopyConstructor(*this); + + } + } return false; } -QualType ASTContext::BuildByRefType(llvm::StringRef DeclName, QualType Ty) { +QualType +ASTContext::BuildByRefType(llvm::StringRef DeclName, QualType Ty) const { // type = struct __Block_byref_1_X { // void *__isa; // struct __Block_byref_1_X *__forwarding; @@ -3264,7 +3612,7 @@ QualType ASTContext::BuildByRefType(llvm::StringRef DeclName, QualType Ty) { QualType ASTContext::getBlockParmType( bool BlockHasCopyDispose, - llvm::SmallVectorImpl<const Expr *> &Layout) { + llvm::SmallVectorImpl<const Expr *> &Layout) const { // FIXME: Move up llvm::SmallString<36> Name; @@ -3351,7 +3699,7 @@ static bool isTypeTypedefedAsBOOL(QualType T) { /// getObjCEncodingTypeSize returns size of type for objective-c encoding /// purpose. -CharUnits ASTContext::getObjCEncodingTypeSize(QualType type) { +CharUnits ASTContext::getObjCEncodingTypeSize(QualType type) const { CharUnits sz = getTypeSizeInChars(type); // Make all integer and enum types at least as large as an int @@ -3368,10 +3716,11 @@ std::string charUnitsToString(const CharUnits &CU) { return llvm::itostr(CU.getQuantity()); } -/// getObjCEncodingForBlockDecl - Return the encoded type for this block +/// getObjCEncodingForBlock - Return the encoded type for this block /// declaration. -void ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr, - std::string& S) { +std::string ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr) const { + std::string S; + const BlockDecl *Decl = Expr->getBlockDecl(); QualType BlockTy = Expr->getType()->getAs<BlockPointerType>()->getPointeeType(); @@ -3414,12 +3763,50 @@ void ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr, S += charUnitsToString(ParmOffset); ParmOffset += getObjCEncodingTypeSize(PType); } + + return S; +} + +void ASTContext::getObjCEncodingForFunctionDecl(const FunctionDecl *Decl, + std::string& S) { + // Encode result type. + getObjCEncodingForType(Decl->getResultType(), S); + CharUnits ParmOffset; + // Compute size of all parameters. + for (FunctionDecl::param_const_iterator PI = Decl->param_begin(), + E = Decl->param_end(); PI != E; ++PI) { + QualType PType = (*PI)->getType(); + CharUnits sz = getObjCEncodingTypeSize(PType); + assert (sz.isPositive() && + "getObjCEncodingForMethodDecl - Incomplete param type"); + ParmOffset += sz; + } + S += charUnitsToString(ParmOffset); + ParmOffset = CharUnits::Zero(); + + // Argument types. + for (FunctionDecl::param_const_iterator PI = Decl->param_begin(), + E = Decl->param_end(); PI != E; ++PI) { + ParmVarDecl *PVDecl = *PI; + QualType PType = PVDecl->getOriginalType(); + if (const ArrayType *AT = + dyn_cast<ArrayType>(PType->getCanonicalTypeInternal())) { + // Use array's original type only if it has known number of + // elements. + if (!isa<ConstantArrayType>(AT)) + PType = PVDecl->getType(); + } else if (PType->isFunctionType()) + PType = PVDecl->getType(); + getObjCEncodingForType(PType, S); + S += charUnitsToString(ParmOffset); + ParmOffset += getObjCEncodingTypeSize(PType); + } } /// getObjCEncodingForMethodDecl - Return the encoded type for this method /// declaration. void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, - std::string& S) { + std::string& S) const { // FIXME: This is not very efficient. // Encode type qualifer, 'in', 'inout', etc. for the return type. getObjCEncodingForTypeQualifier(Decl->getObjCDeclQualifier(), S); @@ -3495,7 +3882,7 @@ void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, /// @endcode void ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD, const Decl *Container, - std::string& S) { + std::string& S) const { // Collect information from the property implementation decl(s). bool Dynamic = false; ObjCPropertyImplDecl *SynthesizePID = 0; @@ -3588,19 +3975,17 @@ void ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD, void ASTContext::getLegacyIntegralTypeEncoding (QualType &PointeeTy) const { if (isa<TypedefType>(PointeeTy.getTypePtr())) { if (const BuiltinType *BT = PointeeTy->getAs<BuiltinType>()) { - if (BT->getKind() == BuiltinType::ULong && - ((const_cast<ASTContext *>(this))->getIntWidth(PointeeTy) == 32)) + if (BT->getKind() == BuiltinType::ULong && getIntWidth(PointeeTy) == 32) PointeeTy = UnsignedIntTy; else - if (BT->getKind() == BuiltinType::Long && - ((const_cast<ASTContext *>(this))->getIntWidth(PointeeTy) == 32)) + if (BT->getKind() == BuiltinType::Long && getIntWidth(PointeeTy) == 32) PointeeTy = IntTy; } } } void ASTContext::getObjCEncodingForType(QualType T, std::string& S, - const FieldDecl *Field) { + const FieldDecl *Field) const { // We follow the behavior of gcc, expanding structures which are // directly pointed to, and expanding embedded structures. Note that // these rules are sufficient to prevent recursive encoding of the @@ -3619,31 +4004,29 @@ static char ObjCEncodingForPrimitiveKind(const ASTContext *C, QualType T) { case BuiltinType::UShort: return 'S'; case BuiltinType::UInt: return 'I'; case BuiltinType::ULong: - return - (const_cast<ASTContext *>(C))->getIntWidth(T) == 32 ? 'L' : 'Q'; + return C->getIntWidth(T) == 32 ? 'L' : 'Q'; case BuiltinType::UInt128: return 'T'; case BuiltinType::ULongLong: return 'Q'; case BuiltinType::Char_S: case BuiltinType::SChar: return 'c'; case BuiltinType::Short: return 's'; - case BuiltinType::WChar: + case BuiltinType::WChar_S: + case BuiltinType::WChar_U: case BuiltinType::Int: return 'i'; case BuiltinType::Long: - return - (const_cast<ASTContext *>(C))->getIntWidth(T) == 32 ? 'l' : 'q'; + return C->getIntWidth(T) == 32 ? 'l' : 'q'; case BuiltinType::LongLong: return 'q'; case BuiltinType::Int128: return 't'; case BuiltinType::Float: return 'f'; case BuiltinType::Double: return 'd'; - case BuiltinType::LongDouble: return 'd'; + case BuiltinType::LongDouble: return 'D'; } } -static void EncodeBitField(const ASTContext *Context, std::string& S, +static void EncodeBitField(const ASTContext *Ctx, std::string& S, QualType T, const FieldDecl *FD) { const Expr *E = FD->getBitWidth(); assert(E && "bitfield width not there - getObjCEncodingForTypeImpl"); - ASTContext *Ctx = const_cast<ASTContext*>(Context); S += 'b'; // The NeXT runtime encodes bit fields as b followed by the number of bits. // The GNU runtime requires more information; bitfields are encoded as b, @@ -3674,7 +4057,10 @@ static void EncodeBitField(const ASTContext *Context, std::string& S, break; } S += llvm::utostr(RL.getFieldOffset(i)); - S += ObjCEncodingForPrimitiveKind(Context, T); + if (T->isEnumeralType()) + S += 'i'; + else + S += ObjCEncodingForPrimitiveKind(Ctx, T); } unsigned N = E->EvaluateAsInt(*Ctx).getZExtValue(); S += llvm::utostr(N); @@ -3686,7 +4072,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, bool ExpandStructures, const FieldDecl *FD, bool OutermostType, - bool EncodingProperty) { + bool EncodingProperty) const { if (T->getAs<BuiltinType>()) { if (FD && FD->isBitField()) return EncodeBitField(this, S, T, FD); @@ -3811,8 +4197,8 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); std::string TemplateArgsStr = TemplateSpecializationType::PrintTemplateArgumentList( - TemplateArgs.getFlatArgumentList(), - TemplateArgs.flat_size(), + TemplateArgs.data(), + TemplateArgs.size(), (*this).PrintingPolicy); S += TemplateArgsStr; @@ -3846,7 +4232,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, S += RDecl->isUnion() ? ')' : '}'; return; } - + if (T->isEnumeralType()) { if (FD && FD->isBitField()) EncodeBitField(this, S, T, FD); @@ -3949,7 +4335,14 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, // TODO: maybe there should be a mangling for these if (T->getAs<MemberPointerType>()) return; - + + if (T->isVectorType()) { + // This matches gcc's encoding, even though technically it is + // insufficient. + // FIXME. We should do a better job than gcc. + return; + } + assert(0 && "@encode for type not implemented!"); } @@ -4000,8 +4393,9 @@ void ASTContext::setObjCConstantStringInterface(ObjCInterfaceDecl *Decl) { /// \brief Retrieve the template name that corresponds to a non-empty /// lookup. -TemplateName ASTContext::getOverloadedTemplateName(UnresolvedSetIterator Begin, - UnresolvedSetIterator End) { +TemplateName +ASTContext::getOverloadedTemplateName(UnresolvedSetIterator Begin, + UnresolvedSetIterator End) const { unsigned size = End - Begin; assert(size > 1 && "set is not overloaded!"); @@ -4023,9 +4417,10 @@ TemplateName ASTContext::getOverloadedTemplateName(UnresolvedSetIterator Begin, /// \brief Retrieve the template name that represents a qualified /// template name such as \c std::vector. -TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS, - bool TemplateKeyword, - TemplateDecl *Template) { +TemplateName +ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS, + bool TemplateKeyword, + TemplateDecl *Template) const { // FIXME: Canonicalization? llvm::FoldingSetNodeID ID; QualifiedTemplateName::Profile(ID, NNS, TemplateKeyword, Template); @@ -4043,8 +4438,9 @@ TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS, /// \brief Retrieve the template name that represents a dependent /// template name such as \c MetaFun::template apply. -TemplateName ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS, - const IdentifierInfo *Name) { +TemplateName +ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS, + const IdentifierInfo *Name) const { assert((!NNS || NNS->isDependent()) && "Nested name specifier must be dependent"); @@ -4078,7 +4474,7 @@ TemplateName ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS, /// template name such as \c MetaFun::template operator+. TemplateName ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS, - OverloadedOperatorKind Operator) { + OverloadedOperatorKind Operator) const { assert((!NNS || NNS->isDependent()) && "Nested name specifier must be dependent"); @@ -4109,6 +4505,27 @@ ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS, return TemplateName(QTN); } +TemplateName +ASTContext::getSubstTemplateTemplateParmPack(TemplateTemplateParmDecl *Param, + const TemplateArgument &ArgPack) const { + ASTContext &Self = const_cast<ASTContext &>(*this); + llvm::FoldingSetNodeID ID; + SubstTemplateTemplateParmPackStorage::Profile(ID, Self, Param, ArgPack); + + void *InsertPos = 0; + SubstTemplateTemplateParmPackStorage *Subst + = SubstTemplateTemplateParmPacks.FindNodeOrInsertPos(ID, InsertPos); + + if (!Subst) { + Subst = new (*this) SubstTemplateTemplateParmPackStorage(Self, Param, + ArgPack.pack_size(), + ArgPack.pack_begin()); + SubstTemplateTemplateParmPacks.InsertNode(Subst, InsertPos); + } + + return TemplateName(Subst); +} + /// getFromTargetType - Given one of the integer types provided by /// TargetInfo, produce the corresponding type. The unsigned @p Type /// is actually a value of type @c TargetInfo::IntType. @@ -4139,7 +4556,7 @@ CanQualType ASTContext::getFromTargetType(unsigned Type) const { /// FIXME: Move to Type. /// bool ASTContext::isObjCNSObjectType(QualType Ty) const { - if (TypedefType *TDT = dyn_cast<TypedefType>(Ty)) { + if (const TypedefType *TDT = dyn_cast<TypedefType>(Ty)) { if (TypedefDecl *TD = TDT->getDecl()) if (TD->getAttr<ObjCNSObjectAttr>()) return true; @@ -4150,24 +4567,30 @@ bool ASTContext::isObjCNSObjectType(QualType Ty) const { /// getObjCGCAttr - Returns one of GCNone, Weak or Strong objc's /// garbage collection attribute. /// -Qualifiers::GC ASTContext::getObjCGCAttrKind(const QualType &Ty) const { - Qualifiers::GC GCAttrs = Qualifiers::GCNone; - if (getLangOptions().ObjC1 && - getLangOptions().getGCMode() != LangOptions::NonGC) { - GCAttrs = Ty.getObjCGCAttr(); - // Default behavious under objective-c's gc is for objective-c pointers - // (or pointers to them) be treated as though they were declared - // as __strong. - if (GCAttrs == Qualifiers::GCNone) { - if (Ty->isObjCObjectPointerType() || Ty->isBlockPointerType()) - GCAttrs = Qualifiers::Strong; - else if (Ty->isPointerType()) - return getObjCGCAttrKind(Ty->getAs<PointerType>()->getPointeeType()); - } - // Non-pointers have none gc'able attribute regardless of the attribute - // set on them. - else if (!Ty->isAnyPointerType() && !Ty->isBlockPointerType()) - return Qualifiers::GCNone; +Qualifiers::GC ASTContext::getObjCGCAttrKind(QualType Ty) const { + if (getLangOptions().getGCMode() == LangOptions::NonGC) + return Qualifiers::GCNone; + + assert(getLangOptions().ObjC1); + Qualifiers::GC GCAttrs = Ty.getObjCGCAttr(); + + // Default behaviour under objective-C's gc is for ObjC pointers + // (or pointers to them) be treated as though they were declared + // as __strong. + if (GCAttrs == Qualifiers::GCNone) { + if (Ty->isObjCObjectPointerType() || Ty->isBlockPointerType()) + return Qualifiers::Strong; + else if (Ty->isPointerType()) + return getObjCGCAttrKind(Ty->getAs<PointerType>()->getPointeeType()); + } else { + // It's not valid to set GC attributes on anything that isn't a + // pointer. +#ifndef NDEBUG + QualType CT = Ty->getCanonicalTypeInternal(); + while (const ArrayType *AT = dyn_cast<ArrayType>(CT)) + CT = AT->getElementType(); + assert(CT->isAnyPointerType() || CT->isBlockPointerType()); +#endif } return GCAttrs; } @@ -4193,15 +4616,16 @@ bool ASTContext::areCompatibleVectorTypes(QualType FirstVec, if (hasSameUnqualifiedType(FirstVec, SecondVec)) return true; - // AltiVec vectors types are identical to equivalent GCC vector types + // Treat Neon vector types and most AltiVec vector types as if they are the + // equivalent GCC vector types. const VectorType *First = FirstVec->getAs<VectorType>(); const VectorType *Second = SecondVec->getAs<VectorType>(); - if ((((First->getAltiVecSpecific() == VectorType::AltiVec) && - (Second->getAltiVecSpecific() == VectorType::NotAltiVec)) || - ((First->getAltiVecSpecific() == VectorType::NotAltiVec) && - (Second->getAltiVecSpecific() == VectorType::AltiVec))) && + if (First->getNumElements() == Second->getNumElements() && hasSameType(First->getElementType(), Second->getElementType()) && - (First->getNumElements() == Second->getNumElements())) + First->getVectorKind() != VectorType::AltiVecPixel && + First->getVectorKind() != VectorType::AltiVecBool && + Second->getVectorKind() != VectorType::AltiVecPixel && + Second->getVectorKind() != VectorType::AltiVecBool) return true; return false; @@ -4213,8 +4637,9 @@ bool ASTContext::areCompatibleVectorTypes(QualType FirstVec, /// ProtocolCompatibleWithProtocol - return 'true' if 'lProto' is in the /// inheritance hierarchy of 'rProto'. -bool ASTContext::ProtocolCompatibleWithProtocol(ObjCProtocolDecl *lProto, - ObjCProtocolDecl *rProto) { +bool +ASTContext::ProtocolCompatibleWithProtocol(ObjCProtocolDecl *lProto, + ObjCProtocolDecl *rProto) const { if (lProto == rProto) return true; for (ObjCProtocolDecl::protocol_iterator PI = rProto->protocol_begin(), @@ -4336,33 +4761,17 @@ bool ASTContext::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs, if (const ObjCObjectPointerType *lhsOPT = lhs->getAsObjCInterfacePointerType()) { - if (lhsOPT->qual_empty()) { - bool match = false; - if (ObjCInterfaceDecl *lhsID = lhsOPT->getInterfaceDecl()) { - for (ObjCObjectPointerType::qual_iterator I = rhsQID->qual_begin(), - E = rhsQID->qual_end(); I != E; ++I) { - // when comparing an id<P> on rhs with a static type on lhs, - // static class must implement all of id's protocols directly or - // indirectly through its super class. - if (lhsID->ClassImplementsProtocol(*I, true)) { - match = true; - break; - } - } - if (!match) - return false; - } - return true; - } - // Both the right and left sides have qualifiers. + // If both the right and left sides have qualifiers. for (ObjCObjectPointerType::qual_iterator I = lhsOPT->qual_begin(), E = lhsOPT->qual_end(); I != E; ++I) { ObjCProtocolDecl *lhsProto = *I; bool match = false; - // when comparing an id<P> on lhs with a static type on rhs, + // when comparing an id<P> on rhs with a static type on lhs, // see if static class implements all of id's protocols, directly or // through its super class and categories. + // First, lhs protocols in the qualifier list must be found, direct + // or indirect in rhs's qualifier list or it is a mismatch. for (ObjCObjectPointerType::qual_iterator J = rhsQID->qual_begin(), E = rhsQID->qual_end(); J != E; ++J) { ObjCProtocolDecl *rhsProto = *J; @@ -4375,6 +4784,35 @@ bool ASTContext::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs, if (!match) return false; } + + // Static class's protocols, or its super class or category protocols + // must be found, direct or indirect in rhs's qualifier list or it is a mismatch. + if (ObjCInterfaceDecl *lhsID = lhsOPT->getInterfaceDecl()) { + llvm::SmallPtrSet<ObjCProtocolDecl *, 8> LHSInheritedProtocols; + CollectInheritedProtocols(lhsID, LHSInheritedProtocols); + // This is rather dubious but matches gcc's behavior. If lhs has + // no type qualifier and its class has no static protocol(s) + // assume that it is mismatch. + if (LHSInheritedProtocols.empty() && lhsOPT->qual_empty()) + return false; + for (llvm::SmallPtrSet<ObjCProtocolDecl*,8>::iterator I = + LHSInheritedProtocols.begin(), + E = LHSInheritedProtocols.end(); I != E; ++I) { + bool match = false; + ObjCProtocolDecl *lhsProto = (*I); + for (ObjCObjectPointerType::qual_iterator J = rhsQID->qual_begin(), + E = rhsQID->qual_end(); J != E; ++J) { + ObjCProtocolDecl *rhsProto = *J; + if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) || + (compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto))) { + match = true; + break; + } + } + if (!match) + return false; + } + } return true; } return false; @@ -4600,6 +5038,49 @@ bool ASTContext::typesAreBlockPointerCompatible(QualType LHS, QualType RHS) { return !mergeTypes(LHS, RHS, true).isNull(); } +/// mergeTransparentUnionType - if T is a transparent union type and a member +/// of T is compatible with SubType, return the merged type, else return +/// QualType() +QualType ASTContext::mergeTransparentUnionType(QualType T, QualType SubType, + bool OfBlockPointer, + bool Unqualified) { + if (const RecordType *UT = T->getAsUnionType()) { + RecordDecl *UD = UT->getDecl(); + if (UD->hasAttr<TransparentUnionAttr>()) { + for (RecordDecl::field_iterator it = UD->field_begin(), + itend = UD->field_end(); it != itend; ++it) { + QualType ET = it->getType().getUnqualifiedType(); + QualType MT = mergeTypes(ET, SubType, OfBlockPointer, Unqualified); + if (!MT.isNull()) + return MT; + } + } + } + + return QualType(); +} + +/// mergeFunctionArgumentTypes - merge two types which appear as function +/// argument types +QualType ASTContext::mergeFunctionArgumentTypes(QualType lhs, QualType rhs, + bool OfBlockPointer, + bool Unqualified) { + // GNU extension: two types are compatible if they appear as a function + // argument, one of the types is a transparent union type and the other + // type is compatible with a union member + QualType lmerge = mergeTransparentUnionType(lhs, rhs, OfBlockPointer, + Unqualified); + if (!lmerge.isNull()) + return lmerge; + + QualType rmerge = mergeTransparentUnionType(rhs, lhs, OfBlockPointer, + Unqualified); + if (!rmerge.isNull()) + return rmerge; + + return mergeTypes(lhs, rhs, OfBlockPointer, Unqualified); +} + QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, bool OfBlockPointer, bool Unqualified) { @@ -4612,12 +5093,17 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, // Check return type QualType retType; - if (OfBlockPointer) - retType = mergeTypes(rbase->getResultType(), lbase->getResultType(), true, - Unqualified); + if (OfBlockPointer) { + QualType RHS = rbase->getResultType(); + QualType LHS = lbase->getResultType(); + bool UnqualifiedResult = Unqualified; + if (!UnqualifiedResult) + UnqualifiedResult = (!RHS.hasQualifiers() && LHS.hasQualifiers()); + retType = mergeTypes(RHS, LHS, true, UnqualifiedResult); + } else - retType = mergeTypes(lbase->getResultType(), rbase->getResultType(), - false, Unqualified); + retType = mergeTypes(lbase->getResultType(), rbase->getResultType(), false, + Unqualified); if (retType.isNull()) return QualType(); if (Unqualified) @@ -4634,26 +5120,33 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, allLTypes = false; if (getCanonicalType(retType) != RRetType) allRTypes = false; + // FIXME: double check this // FIXME: should we error if lbase->getRegParmAttr() != 0 && // rbase->getRegParmAttr() != 0 && // lbase->getRegParmAttr() != rbase->getRegParmAttr()? FunctionType::ExtInfo lbaseInfo = lbase->getExtInfo(); FunctionType::ExtInfo rbaseInfo = rbase->getExtInfo(); - unsigned RegParm = lbaseInfo.getRegParm() == 0 ? rbaseInfo.getRegParm() : - lbaseInfo.getRegParm(); + + // Compatible functions must have compatible calling conventions + if (!isSameCallConv(lbaseInfo.getCC(), rbaseInfo.getCC())) + return QualType(); + + // Regparm is part of the calling convention. + if (lbaseInfo.getRegParm() != rbaseInfo.getRegParm()) + return QualType(); + + // It's noreturn if either type is. + // FIXME: some uses, e.g. conditional exprs, really want this to be 'both'. bool NoReturn = lbaseInfo.getNoReturn() || rbaseInfo.getNoReturn(); - if (NoReturn != lbaseInfo.getNoReturn() || - RegParm != lbaseInfo.getRegParm()) + if (NoReturn != lbaseInfo.getNoReturn()) allLTypes = false; - if (NoReturn != rbaseInfo.getNoReturn() || - RegParm != rbaseInfo.getRegParm()) + if (NoReturn != rbaseInfo.getNoReturn()) allRTypes = false; - CallingConv lcc = lbaseInfo.getCC(); - CallingConv rcc = rbaseInfo.getCC(); - // Compatible functions must have compatible calling conventions - if (!isSameCallConv(lcc, rcc)) - return QualType(); + + FunctionType::ExtInfo einfo(NoReturn, + lbaseInfo.getRegParm(), + lbaseInfo.getCC()); if (lproto && rproto) { // two C99 style function prototypes assert(!lproto->hasExceptionSpec() && !rproto->hasExceptionSpec() && @@ -4677,8 +5170,9 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, for (unsigned i = 0; i < lproto_nargs; i++) { QualType largtype = lproto->getArgType(i).getUnqualifiedType(); QualType rargtype = rproto->getArgType(i).getUnqualifiedType(); - QualType argtype = mergeTypes(largtype, rargtype, OfBlockPointer, - Unqualified); + QualType argtype = mergeFunctionArgumentTypes(largtype, rargtype, + OfBlockPointer, + Unqualified); if (argtype.isNull()) return QualType(); if (Unqualified) @@ -4697,10 +5191,10 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, } if (allLTypes) return lhs; if (allRTypes) return rhs; - return getFunctionType(retType, types.begin(), types.size(), - lproto->isVariadic(), lproto->getTypeQuals(), - false, false, 0, 0, - FunctionType::ExtInfo(NoReturn, RegParm, lcc)); + + FunctionProtoType::ExtProtoInfo EPI = lproto->getExtProtoInfo(); + EPI.ExtInfo = einfo; + return getFunctionType(retType, types.begin(), types.size(), EPI); } if (lproto) allRTypes = false; @@ -4731,17 +5225,16 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, if (allLTypes) return lhs; if (allRTypes) return rhs; + + FunctionProtoType::ExtProtoInfo EPI = proto->getExtProtoInfo(); + EPI.ExtInfo = einfo; return getFunctionType(retType, proto->arg_type_begin(), - proto->getNumArgs(), proto->isVariadic(), - proto->getTypeQuals(), - false, false, 0, 0, - FunctionType::ExtInfo(NoReturn, RegParm, lcc)); + proto->getNumArgs(), EPI); } if (allLTypes) return lhs; if (allRTypes) return rhs; - FunctionType::ExtInfo Info(NoReturn, RegParm, lcc); - return getFunctionNoProtoType(retType, Info); + return getFunctionNoProtoType(retType, einfo); } QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, @@ -5020,16 +5513,11 @@ QualType ASTContext::mergeObjCGCQualifiers(QualType LHS, QualType RHS) { // In either case, use OldReturnType to build the new function type. const FunctionType *F = LHS->getAs<FunctionType>(); if (const FunctionProtoType *FPT = cast<FunctionProtoType>(F)) { - FunctionType::ExtInfo Info = getFunctionExtInfo(LHS); + FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); + EPI.ExtInfo = getFunctionExtInfo(LHS); QualType ResultType = getFunctionType(OldReturnType, FPT->arg_type_begin(), - FPT->getNumArgs(), FPT->isVariadic(), - FPT->getTypeQuals(), - FPT->hasExceptionSpec(), - FPT->hasAnyExceptionSpec(), - FPT->getNumExceptions(), - FPT->exception_begin(), - Info); + FPT->getNumArgs(), EPI); return ResultType; } } @@ -5080,11 +5568,11 @@ QualType ASTContext::mergeObjCGCQualifiers(QualType LHS, QualType RHS) { // Integer Predicates //===----------------------------------------------------------------------===// -unsigned ASTContext::getIntWidth(QualType T) { +unsigned ASTContext::getIntWidth(QualType T) const { + if (const EnumType *ET = dyn_cast<EnumType>(T)) + T = ET->getDecl()->getIntegerType(); if (T->isBooleanType()) return 1; - if (EnumType *ET = dyn_cast<EnumType>(T)) - T = ET->getDecl()->getIntegerType(); // For builtin types, just use the standard type sizing method return (unsigned)getTypeSize(T); } @@ -5095,7 +5583,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->getAltiVecSpecific()); + VTy->getNumElements(), VTy->getVectorKind()); // For enums, we return the unsigned version of the base type. if (const EnumType *ETy = T->getAs<EnumType>()) @@ -5127,25 +5615,38 @@ ExternalASTSource::~ExternalASTSource() { } void ExternalASTSource::PrintStats() { } +ASTMutationListener::~ASTMutationListener() { } + //===----------------------------------------------------------------------===// // Builtin Type Computation //===----------------------------------------------------------------------===// /// DecodeTypeFromStr - This decodes one type descriptor from Str, advancing the -/// pointer over the consumed characters. This returns the resultant type. -static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context, +/// pointer over the consumed characters. This returns the resultant type. If +/// AllowTypeModifiers is false then modifier like * are not parsed, just basic +/// types. This allows "v2i*" to be parsed as a pointer to a v2i instead of +/// a vector of "i*". +/// +/// RequiresICE is filled in on return to indicate whether the value is required +/// to be an Integer Constant Expression. +static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context, ASTContext::GetBuiltinTypeError &Error, - bool AllowTypeModifiers = true) { + bool &RequiresICE, + bool AllowTypeModifiers) { // Modifiers. int HowLong = 0; bool Signed = false, Unsigned = false; - - // Read the modifiers first. + RequiresICE = false; + + // Read the prefixed modifiers first. bool Done = false; while (!Done) { switch (*Str++) { default: Done = true; --Str; break; + case 'I': + RequiresICE = true; + break; case 'S': assert(!Unsigned && "Can't use both 'S' and 'U' modifiers!"); assert(!Signed && "Can't use 'S' modifier multiple times!"); @@ -5223,6 +5724,12 @@ static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context, case 'F': Type = Context.getCFConstantStringType(); break; + case 'G': + Type = Context.getObjCIdType(); + break; + case 'H': + Type = Context.getObjCSelType(); + break; case 'a': Type = Context.getBuiltinVaListType(); assert(!Type.isNull() && "builtin va list type not initialized!"); @@ -5238,27 +5745,30 @@ static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context, // it to be a __va_list_tag*. Type = Context.getBuiltinVaListType(); assert(!Type.isNull() && "builtin va list type not initialized!"); - if (Type->isArrayType()) { + if (Type->isArrayType()) Type = Context.getArrayDecayedType(Type); - } else { + else Type = Context.getLValueReferenceType(Type); - } break; case 'V': { char *End; unsigned NumElements = strtoul(Str, &End, 10); assert(End != Str && "Missing vector size"); - Str = End; - QualType ElementType = DecodeTypeFromStr(Str, Context, Error, false); - // FIXME: Don't know what to do about AltiVec. + QualType ElementType = DecodeTypeFromStr(Str, Context, Error, + RequiresICE, false); + assert(!RequiresICE && "Can't require vector ICE"); + + // TODO: No way to make AltiVec vectors in builtins yet. Type = Context.getVectorType(ElementType, NumElements, - VectorType::NotAltiVec); + VectorType::GenericVector); break; } case 'X': { - QualType ElementType = DecodeTypeFromStr(Str, Context, Error, false); + QualType ElementType = DecodeTypeFromStr(Str, Context, Error, RequiresICE, + false); + assert(!RequiresICE && "Can't require complex ICE"); Type = Context.getComplexType(ElementType); break; } @@ -5282,59 +5792,70 @@ static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context, break; } - if (!AllowTypeModifiers) - return Type; - - Done = false; + // If there are modifiers and if we're allowed to parse them, go for it. + Done = !AllowTypeModifiers; while (!Done) { switch (char c = *Str++) { - default: Done = true; --Str; break; - case '*': - case '&': - { - // Both pointers and references can have their pointee types - // qualified with an address space. - char *End; - unsigned AddrSpace = strtoul(Str, &End, 10); - if (End != Str && AddrSpace != 0) { - Type = Context.getAddrSpaceQualType(Type, AddrSpace); - Str = End; - } - } - if (c == '*') - Type = Context.getPointerType(Type); - else - Type = Context.getLValueReferenceType(Type); - break; - // FIXME: There's no way to have a built-in with an rvalue ref arg. - case 'C': - Type = Type.withConst(); - break; - case 'D': - Type = Context.getVolatileType(Type); - break; + default: Done = true; --Str; break; + case '*': + case '&': { + // Both pointers and references can have their pointee types + // qualified with an address space. + char *End; + unsigned AddrSpace = strtoul(Str, &End, 10); + if (End != Str && AddrSpace != 0) { + Type = Context.getAddrSpaceQualType(Type, AddrSpace); + Str = End; + } + if (c == '*') + Type = Context.getPointerType(Type); + else + Type = Context.getLValueReferenceType(Type); + break; + } + // FIXME: There's no way to have a built-in with an rvalue ref arg. + case 'C': + Type = Type.withConst(); + break; + case 'D': + Type = Context.getVolatileType(Type); + break; } } + + assert((!RequiresICE || Type->isIntegralOrEnumerationType()) && + "Integer constant 'I' type must be an integer"); return Type; } /// GetBuiltinType - Return the type for the specified builtin. -QualType ASTContext::GetBuiltinType(unsigned id, - GetBuiltinTypeError &Error) { - const char *TypeStr = BuiltinInfo.GetTypeString(id); +QualType ASTContext::GetBuiltinType(unsigned Id, + GetBuiltinTypeError &Error, + unsigned *IntegerConstantArgs) const { + const char *TypeStr = BuiltinInfo.GetTypeString(Id); llvm::SmallVector<QualType, 8> ArgTypes; + bool RequiresICE = false; Error = GE_None; - QualType ResType = DecodeTypeFromStr(TypeStr, *this, Error); + QualType ResType = DecodeTypeFromStr(TypeStr, *this, Error, + RequiresICE, true); if (Error != GE_None) return QualType(); + + assert(!RequiresICE && "Result of intrinsic cannot be required to be an ICE"); + while (TypeStr[0] && TypeStr[0] != '.') { - QualType Ty = DecodeTypeFromStr(TypeStr, *this, Error); + QualType Ty = DecodeTypeFromStr(TypeStr, *this, Error, RequiresICE, true); if (Error != GE_None) return QualType(); + // If this argument is required to be an IntegerConstantExpression and the + // caller cares, fill in the bitmask we return. + if (RequiresICE && IntegerConstantArgs) + *IntegerConstantArgs |= 1 << ArgTypes.size(); + // Do array -> pointer decay. The builtin should use the decayed type. if (Ty->isArrayType()) Ty = getArrayDecayedType(Ty); @@ -5345,164 +5866,26 @@ QualType ASTContext::GetBuiltinType(unsigned id, assert((TypeStr[0] != '.' || TypeStr[1] == 0) && "'.' should only occur at end of builtin type list!"); - // handle untyped/variadic arguments "T c99Style();" or "T cppStyle(...);". - if (ArgTypes.size() == 0 && TypeStr[0] == '.') - return getFunctionNoProtoType(ResType); - - // FIXME: Should we create noreturn types? - return getFunctionType(ResType, ArgTypes.data(), ArgTypes.size(), - TypeStr[0] == '.', 0, false, false, 0, 0, - FunctionType::ExtInfo()); -} - -QualType -ASTContext::UsualArithmeticConversionsType(QualType lhs, QualType rhs) { - // Perform the usual unary conversions. We do this early so that - // integral promotions to "int" can allow us to exit early, in the - // lhs == rhs check. Also, for conversion purposes, we ignore any - // qualifiers. For example, "const float" and "float" are - // equivalent. - if (lhs->isPromotableIntegerType()) - lhs = getPromotedIntegerType(lhs); - else - lhs = lhs.getUnqualifiedType(); - if (rhs->isPromotableIntegerType()) - rhs = getPromotedIntegerType(rhs); - else - rhs = rhs.getUnqualifiedType(); + FunctionType::ExtInfo EI; + if (BuiltinInfo.isNoReturn(Id)) EI = EI.withNoReturn(true); - // If both types are identical, no conversion is needed. - if (lhs == rhs) - return lhs; + bool Variadic = (TypeStr[0] == '.'); - // If either side is a non-arithmetic type (e.g. a pointer), we are done. - // The caller can deal with this (e.g. pointer + int). - if (!lhs->isArithmeticType() || !rhs->isArithmeticType()) - return lhs; + // We really shouldn't be making a no-proto type here, especially in C++. + if (ArgTypes.empty() && Variadic) + return getFunctionNoProtoType(ResType, EI); - // At this point, we have two different arithmetic types. + FunctionProtoType::ExtProtoInfo EPI; + EPI.ExtInfo = EI; + EPI.Variadic = Variadic; - // Handle complex types first (C99 6.3.1.8p1). - if (lhs->isComplexType() || rhs->isComplexType()) { - // if we have an integer operand, the result is the complex type. - if (rhs->isIntegerType() || rhs->isComplexIntegerType()) { - // convert the rhs to the lhs complex type. - return lhs; - } - if (lhs->isIntegerType() || lhs->isComplexIntegerType()) { - // convert the lhs to the rhs complex type. - return rhs; - } - // This handles complex/complex, complex/float, or float/complex. - // When both operands are complex, the shorter operand is converted to the - // type of the longer, and that is the type of the result. This corresponds - // to what is done when combining two real floating-point operands. - // The fun begins when size promotion occur across type domains. - // From H&S 6.3.4: When one operand is complex and the other is a real - // floating-point type, the less precise type is converted, within it's - // real or complex domain, to the precision of the other type. For example, - // when combining a "long double" with a "double _Complex", the - // "double _Complex" is promoted to "long double _Complex". - int result = getFloatingTypeOrder(lhs, rhs); - - if (result > 0) { // The left side is bigger, convert rhs. - rhs = getFloatingTypeOfSizeWithinDomain(lhs, rhs); - } else if (result < 0) { // The right side is bigger, convert lhs. - lhs = getFloatingTypeOfSizeWithinDomain(rhs, lhs); - } - // At this point, lhs and rhs have the same rank/size. Now, make sure the - // domains match. This is a requirement for our implementation, C99 - // does not require this promotion. - if (lhs != rhs) { // Domains don't match, we have complex/float mix. - if (lhs->isRealFloatingType()) { // handle "double, _Complex double". - return rhs; - } else { // handle "_Complex double, double". - return lhs; - } - } - return lhs; // The domain/size match exactly. - } - // Now handle "real" floating types (i.e. float, double, long double). - if (lhs->isRealFloatingType() || rhs->isRealFloatingType()) { - // if we have an integer operand, the result is the real floating type. - if (rhs->isIntegerType()) { - // convert rhs to the lhs floating point type. - return lhs; - } - if (rhs->isComplexIntegerType()) { - // convert rhs to the complex floating point type. - return getComplexType(lhs); - } - if (lhs->isIntegerType()) { - // convert lhs to the rhs floating point type. - return rhs; - } - if (lhs->isComplexIntegerType()) { - // convert lhs to the complex floating point type. - return getComplexType(rhs); - } - // We have two real floating types, float/complex combos were handled above. - // Convert the smaller operand to the bigger result. - int result = getFloatingTypeOrder(lhs, rhs); - if (result > 0) // convert the rhs - return lhs; - assert(result < 0 && "illegal float comparison"); - return rhs; // convert the lhs - } - if (lhs->isComplexIntegerType() || rhs->isComplexIntegerType()) { - // Handle GCC complex int extension. - const ComplexType *lhsComplexInt = lhs->getAsComplexIntegerType(); - const ComplexType *rhsComplexInt = rhs->getAsComplexIntegerType(); - - if (lhsComplexInt && rhsComplexInt) { - if (getIntegerTypeOrder(lhsComplexInt->getElementType(), - rhsComplexInt->getElementType()) >= 0) - return lhs; // convert the rhs - return rhs; - } else if (lhsComplexInt && rhs->isIntegerType()) { - // convert the rhs to the lhs complex type. - return lhs; - } else if (rhsComplexInt && lhs->isIntegerType()) { - // convert the lhs to the rhs complex type. - return rhs; - } - } - // Finally, we have two differing integer types. - // The rules for this case are in C99 6.3.1.8 - int compare = getIntegerTypeOrder(lhs, rhs); - bool lhsSigned = lhs->hasSignedIntegerRepresentation(), - rhsSigned = rhs->hasSignedIntegerRepresentation(); - QualType destType; - if (lhsSigned == rhsSigned) { - // Same signedness; use the higher-ranked type - destType = compare >= 0 ? lhs : rhs; - } else if (compare != (lhsSigned ? 1 : -1)) { - // The unsigned type has greater than or equal rank to the - // signed type, so use the unsigned type - destType = lhsSigned ? rhs : lhs; - } else if (getIntWidth(lhs) != getIntWidth(rhs)) { - // The two types are different widths; if we are here, that - // means the signed type is larger than the unsigned type, so - // use the signed type. - destType = lhsSigned ? lhs : rhs; - } else { - // The signed type is higher-ranked than the unsigned type, - // but isn't actually any bigger (like unsigned int and long - // on most 32-bit systems). Use the unsigned type corresponding - // to the signed type. - destType = getCorrespondingUnsignedType(lhsSigned ? lhs : rhs); - } - return destType; + return getFunctionType(ResType, ArgTypes.data(), ArgTypes.size(), EPI); } GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) { GVALinkage External = GVA_StrongExternal; Linkage L = FD->getLinkage(); - if (L == ExternalLinkage && getLangOptions().CPlusPlus && - FD->getType()->getLinkage() == UniqueExternalLinkage) - L = UniqueExternalLinkage; - switch (L) { case NoLinkage: case InternalLinkage: @@ -5663,4 +6046,26 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) { return true; } +CallingConv ASTContext::getDefaultMethodCallConv() { + // Pass through to the C++ ABI object + return ABI->getDefaultMethodCallConv(); +} + +bool ASTContext::isNearlyEmpty(const CXXRecordDecl *RD) const { + // Pass through to the C++ ABI object + return ABI->isNearlyEmpty(RD); +} + +MangleContext *ASTContext::createMangleContext() { + switch (Target.getCXXABI()) { + case CXXABI_ARM: + case CXXABI_Itanium: + return createItaniumMangleContext(*this, getDiagnostics()); + case CXXABI_Microsoft: + return createMicrosoftMangleContext(*this, getDiagnostics()); + } + assert(0 && "Unsupported ABI"); + return 0; +} + CXXABI::~CXXABI() {} diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp index 23f323d..5bf8a38 100644 --- a/lib/AST/ASTDiagnostic.cpp +++ b/lib/AST/ASTDiagnostic.cpp @@ -28,14 +28,26 @@ static QualType Desugar(ASTContext &Context, QualType QT, bool &ShouldAKA) { 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(); + if (const ElaboratedType *ET = dyn_cast<ElaboratedType>(Ty)) { + QT = ET->desugar(); continue; } - - // ...or a substituted template type parameter. - if (isa<SubstTemplateTypeParmType>(Ty)) { - QT = cast<SubstTemplateTypeParmType>(Ty)->desugar(); + // ... or a paren type ... + if (const ParenType *PT = dyn_cast<ParenType>(Ty)) { + QT = PT->desugar(); + continue; + } + // ...or a substituted template type parameter ... + if (const SubstTemplateTypeParmType *ST = + dyn_cast<SubstTemplateTypeParmType>(Ty)) { + QT = ST->desugar(); + continue; + } + // ... or an auto type. + if (const AutoType *AT = dyn_cast<AutoType>(Ty)) { + if (!AT->isSugared()) + break; + QT = AT->desugar(); continue; } @@ -81,10 +93,10 @@ break; \ 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; + if (const TagType *UTT = Underlying->getAs<TagType>()) + if (const TypedefType *QTT = dyn_cast<TypedefType>(QT)) + if (UTT->getDecl()->getTypedefForAnonDecl() == QTT->getDecl()) + break; // Record that we actually looked through an opaque type here. ShouldAKA = true; @@ -94,14 +106,17 @@ break; \ // If we have a pointer-like type, desugar the pointee as well. // FIXME: Handle other pointer-like types. if (const PointerType *Ty = QT->getAs<PointerType>()) { - QT = Context.getPointerType(Desugar(Context, Ty->getPointeeType(), - ShouldAKA)); + QT = Context.getPointerType(Desugar(Context, Ty->getPointeeType(), + ShouldAKA)); } else if (const LValueReferenceType *Ty = QT->getAs<LValueReferenceType>()) { - QT = Context.getLValueReferenceType(Desugar(Context, Ty->getPointeeType(), - ShouldAKA)); + QT = Context.getLValueReferenceType(Desugar(Context, Ty->getPointeeType(), + ShouldAKA)); + } else if (const RValueReferenceType *Ty = QT->getAs<RValueReferenceType>()) { + QT = Context.getRValueReferenceType(Desugar(Context, Ty->getPointeeType(), + ShouldAKA)); } - return QC.apply(QT); + return QC.apply(Context, QT); } /// \brief Convert the given type to a string suitable for printing as part of @@ -151,13 +166,10 @@ ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty, bool ShouldAKA = false; QualType DesugaredTy = Desugar(Context, Ty, ShouldAKA); if (ShouldAKA) { - std::string D = DesugaredTy.getAsString(Context.PrintingPolicy); - if (D != S) { - S = "'" + S + "' (aka '"; - S += D; - S += "')"; - return S; - } + S = "'" + S + "' (aka '"; + S += DesugaredTy.getAsString(Context.PrintingPolicy); + S += "')"; + return S; } } diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index 2edd09c..65c0a3b 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -41,41 +41,42 @@ namespace { 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); + QualType VisitType(const Type *T); + QualType VisitBuiltinType(const BuiltinType *T); + QualType VisitComplexType(const ComplexType *T); + QualType VisitPointerType(const PointerType *T); + QualType VisitBlockPointerType(const BlockPointerType *T); + QualType VisitLValueReferenceType(const LValueReferenceType *T); + QualType VisitRValueReferenceType(const RValueReferenceType *T); + QualType VisitMemberPointerType(const MemberPointerType *T); + QualType VisitConstantArrayType(const ConstantArrayType *T); + QualType VisitIncompleteArrayType(const IncompleteArrayType *T); + QualType VisitVariableArrayType(const VariableArrayType *T); // FIXME: DependentSizedArrayType // FIXME: DependentSizedExtVectorType - QualType VisitVectorType(VectorType *T); - QualType VisitExtVectorType(ExtVectorType *T); - QualType VisitFunctionNoProtoType(FunctionNoProtoType *T); - QualType VisitFunctionProtoType(FunctionProtoType *T); + QualType VisitVectorType(const VectorType *T); + QualType VisitExtVectorType(const ExtVectorType *T); + QualType VisitFunctionNoProtoType(const FunctionNoProtoType *T); + QualType VisitFunctionProtoType(const FunctionProtoType *T); // FIXME: UnresolvedUsingType - QualType VisitTypedefType(TypedefType *T); - QualType VisitTypeOfExprType(TypeOfExprType *T); + QualType VisitTypedefType(const TypedefType *T); + QualType VisitTypeOfExprType(const TypeOfExprType *T); // FIXME: DependentTypeOfExprType - QualType VisitTypeOfType(TypeOfType *T); - QualType VisitDecltypeType(DecltypeType *T); + QualType VisitTypeOfType(const TypeOfType *T); + QualType VisitDecltypeType(const DecltypeType *T); + QualType VisitAutoType(const AutoType *T); // FIXME: DependentDecltypeType - QualType VisitRecordType(RecordType *T); - QualType VisitEnumType(EnumType *T); + QualType VisitRecordType(const RecordType *T); + QualType VisitEnumType(const EnumType *T); // FIXME: TemplateTypeParmType // FIXME: SubstTemplateTypeParmType - // FIXME: TemplateSpecializationType - QualType VisitElaboratedType(ElaboratedType *T); + QualType VisitTemplateSpecializationType(const TemplateSpecializationType *T); + QualType VisitElaboratedType(const ElaboratedType *T); // FIXME: DependentNameType // FIXME: DependentTemplateSpecializationType - QualType VisitObjCInterfaceType(ObjCInterfaceType *T); - QualType VisitObjCObjectType(ObjCObjectType *T); - QualType VisitObjCObjectPointerType(ObjCObjectPointerType *T); + QualType VisitObjCInterfaceType(const ObjCInterfaceType *T); + QualType VisitObjCObjectType(const ObjCObjectType *T); + QualType VisitObjCObjectPointerType(const ObjCObjectPointerType *T); // Importing declarations bool ImportDeclParts(NamedDecl *D, DeclContext *&DC, @@ -83,9 +84,17 @@ namespace { SourceLocation &Loc); void ImportDeclarationNameLoc(const DeclarationNameInfo &From, DeclarationNameInfo& To); - void ImportDeclContext(DeclContext *FromDC); + void ImportDeclContext(DeclContext *FromDC, bool ForceImport = false); + bool ImportDefinition(RecordDecl *From, RecordDecl *To); + TemplateParameterList *ImportTemplateParameterList( + TemplateParameterList *Params); + TemplateArgument ImportTemplateArgument(const TemplateArgument &From); + bool ImportTemplateArguments(const TemplateArgument *FromArgs, + unsigned NumFromArgs, + llvm::SmallVectorImpl<TemplateArgument> &ToArgs); bool IsStructuralMatch(RecordDecl *FromRecord, RecordDecl *ToRecord); bool IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToRecord); + bool IsStructuralMatch(ClassTemplateDecl *From, ClassTemplateDecl *To); Decl *VisitDecl(Decl *D); Decl *VisitNamespaceDecl(NamespaceDecl *D); Decl *VisitTypedefDecl(TypedefDecl *D); @@ -98,6 +107,7 @@ namespace { Decl *VisitCXXDestructorDecl(CXXDestructorDecl *D); Decl *VisitCXXConversionDecl(CXXConversionDecl *D); Decl *VisitFieldDecl(FieldDecl *D); + Decl *VisitIndirectFieldDecl(IndirectFieldDecl *D); Decl *VisitObjCIvarDecl(ObjCIvarDecl *D); Decl *VisitVarDecl(VarDecl *D); Decl *VisitImplicitParamDecl(ImplicitParamDecl *D); @@ -106,9 +116,18 @@ namespace { Decl *VisitObjCCategoryDecl(ObjCCategoryDecl *D); Decl *VisitObjCProtocolDecl(ObjCProtocolDecl *D); Decl *VisitObjCInterfaceDecl(ObjCInterfaceDecl *D); + Decl *VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D); + Decl *VisitObjCImplementationDecl(ObjCImplementationDecl *D); Decl *VisitObjCPropertyDecl(ObjCPropertyDecl *D); + Decl *VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D); Decl *VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D); Decl *VisitObjCClassDecl(ObjCClassDecl *D); + Decl *VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D); + Decl *VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D); + Decl *VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); + Decl *VisitClassTemplateDecl(ClassTemplateDecl *D); + Decl *VisitClassTemplateSpecializationDecl( + ClassTemplateSpecializationDecl *D); // Importing statements Stmt *VisitStmt(Stmt *S); @@ -137,9 +156,6 @@ namespace { /// \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. @@ -158,10 +174,9 @@ namespace { 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), + : C1(C1), C2(C2), NonEquivalentDecls(NonEquivalentDecls), StrictTypeSpelling(StrictTypeSpelling) { } /// \brief Determine whether the two declarations are structurally @@ -179,11 +194,11 @@ namespace { public: DiagnosticBuilder Diag1(SourceLocation Loc, unsigned DiagID) { - return Diags.Report(FullSourceLoc(Loc, C1.getSourceManager()), DiagID); + return C1.getDiagnostics().Report(Loc, DiagID); } DiagnosticBuilder Diag2(SourceLocation Loc, unsigned DiagID) { - return Diags.Report(FullSourceLoc(Loc, C2.getSourceManager()), DiagID); + return C2.getDiagnostics().Report(Loc, DiagID); } }; } @@ -200,9 +215,9 @@ static bool IsSameValue(const llvm::APInt &I1, const llvm::APInt &I2) { return I1 == I2; if (I1.getBitWidth() > I2.getBitWidth()) - return I1 == llvm::APInt(I2).zext(I1.getBitWidth()); + return I1 == I2.zext(I1.getBitWidth()); - return llvm::APInt(I1).zext(I2.getBitWidth()) == I2; + return I1.zext(I2.getBitWidth()) == I2; } /// \brief Determine if two APSInts have the same value, zero- or sign-extending @@ -213,9 +228,9 @@ static bool IsSameValue(const llvm::APSInt &I1, const llvm::APSInt &I2) { // Check for a bit-width mismatch. if (I1.getBitWidth() > I2.getBitWidth()) - return IsSameValue(I1, llvm::APSInt(I2).extend(I1.getBitWidth())); + return IsSameValue(I1, I2.extend(I1.getBitWidth())); else if (I2.getBitWidth() > I1.getBitWidth()) - return IsSameValue(llvm::APSInt(I1).extend(I2.getBitWidth()), I2); + return IsSameValue(I1.extend(I2.getBitWidth()), I2); // We have a signedness mismatch. Turn the signed value into an unsigned // value. @@ -263,7 +278,54 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, const TemplateArgument &Arg1, const TemplateArgument &Arg2) { - // FIXME: Implement! + if (Arg1.getKind() != Arg2.getKind()) + return false; + + switch (Arg1.getKind()) { + case TemplateArgument::Null: + return true; + + case TemplateArgument::Type: + return Context.IsStructurallyEquivalent(Arg1.getAsType(), Arg2.getAsType()); + + case TemplateArgument::Integral: + if (!Context.IsStructurallyEquivalent(Arg1.getIntegralType(), + Arg2.getIntegralType())) + return false; + + return IsSameValue(*Arg1.getAsIntegral(), *Arg2.getAsIntegral()); + + case TemplateArgument::Declaration: + return Context.IsStructurallyEquivalent(Arg1.getAsDecl(), Arg2.getAsDecl()); + + case TemplateArgument::Template: + return IsStructurallyEquivalent(Context, + Arg1.getAsTemplate(), + Arg2.getAsTemplate()); + + case TemplateArgument::TemplateExpansion: + return IsStructurallyEquivalent(Context, + Arg1.getAsTemplateOrTemplatePattern(), + Arg2.getAsTemplateOrTemplatePattern()); + + case TemplateArgument::Expression: + return IsStructurallyEquivalent(Context, + Arg1.getAsExpr(), Arg2.getAsExpr()); + + case TemplateArgument::Pack: + if (Arg1.pack_size() != Arg2.pack_size()) + return false; + + for (unsigned I = 0, N = Arg1.pack_size(); I != N; ++I) + if (!IsStructurallyEquivalent(Context, + Arg1.pack_begin()[I], + Arg2.pack_begin()[I])) + return false; + + return true; + } + + llvm_unreachable("Invalid template argument kind"); return true; } @@ -441,7 +503,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, return false; if (Vec1->getNumElements() != Vec2->getNumElements()) return false; - if (Vec1->getAltiVecSpecific() != Vec2->getAltiVecSpecific()) + if (Vec1->getVectorKind() != Vec2->getVectorKind()) return false; break; } @@ -496,7 +558,25 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, return false; break; + + case Type::Attributed: + if (!IsStructurallyEquivalent(Context, + cast<AttributedType>(T1)->getModifiedType(), + cast<AttributedType>(T2)->getModifiedType())) + return false; + if (!IsStructurallyEquivalent(Context, + cast<AttributedType>(T1)->getEquivalentType(), + cast<AttributedType>(T2)->getEquivalentType())) + return false; + break; + case Type::Paren: + if (!IsStructurallyEquivalent(Context, + cast<ParenType>(T1)->getInnerType(), + cast<ParenType>(T2)->getInnerType())) + return false; + break; + case Type::Typedef: if (!IsStructurallyEquivalent(Context, cast<TypedefType>(T1)->getDecl(), @@ -525,6 +605,13 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, return false; break; + case Type::Auto: + if (!IsStructurallyEquivalent(Context, + cast<AutoType>(T1)->getDeducedType(), + cast<AutoType>(T2)->getDeducedType())) + return false; + break; + case Type::Record: case Type::Enum: if (!IsStructurallyEquivalent(Context, @@ -563,6 +650,21 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, break; } + case Type::SubstTemplateTypeParmPack: { + const SubstTemplateTypeParmPackType *Subst1 + = cast<SubstTemplateTypeParmPackType>(T1); + const SubstTemplateTypeParmPackType *Subst2 + = cast<SubstTemplateTypeParmPackType>(T2); + if (!IsStructurallyEquivalent(Context, + QualType(Subst1->getReplacedParameter(), 0), + QualType(Subst2->getReplacedParameter(), 0))) + return false; + if (!IsStructurallyEquivalent(Context, + Subst1->getArgumentPack(), + Subst2->getArgumentPack())) + return false; + break; + } case Type::TemplateSpecialization: { const TemplateSpecializationType *Spec1 = cast<TemplateSpecializationType>(T1); @@ -644,7 +746,14 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, } break; } - + + case Type::PackExpansion: + if (!IsStructurallyEquivalent(Context, + cast<PackExpansionType>(T1)->getPattern(), + cast<PackExpansionType>(T2)->getPattern())) + return false; + break; + case Type::ObjCInterface: { const ObjCInterfaceType *Iface1 = cast<ObjCInterfaceType>(T1); const ObjCInterfaceType *Iface2 = cast<ObjCInterfaceType>(T2); @@ -698,6 +807,33 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, return false; } + // If both declarations are class template specializations, we know + // the ODR applies, so check the template and template arguments. + ClassTemplateSpecializationDecl *Spec1 + = dyn_cast<ClassTemplateSpecializationDecl>(D1); + ClassTemplateSpecializationDecl *Spec2 + = dyn_cast<ClassTemplateSpecializationDecl>(D2); + if (Spec1 && Spec2) { + // Check that the specialized templates are the same. + if (!IsStructurallyEquivalent(Context, Spec1->getSpecializedTemplate(), + Spec2->getSpecializedTemplate())) + return false; + + // Check that the template arguments are the same. + if (Spec1->getTemplateArgs().size() != Spec2->getTemplateArgs().size()) + return false; + + for (unsigned I = 0, N = Spec1->getTemplateArgs().size(); I != N; ++I) + if (!IsStructurallyEquivalent(Context, + Spec1->getTemplateArgs().get(I), + Spec2->getTemplateArgs().get(I))) + return false; + } + // If one is a class template specialization and the other is not, these + // structures are diferent. + else if (Spec1 || Spec2) + return false; + // Compare the definitions of these two records. If either or both are // incomplete, we assume that they are equivalent. D1 = D1->getDefinition(); @@ -709,11 +845,11 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, 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.C2.getTypeDeclType(D2); Context.Diag2(D2->getLocation(), diag::note_odr_number_of_bases) - << D2CXX->getNumBases(); + << D2CXX->getNumBases(); Context.Diag1(D1->getLocation(), diag::note_odr_number_of_bases) - << D1CXX->getNumBases(); + << D1CXX->getNumBases(); return false; } @@ -892,7 +1028,112 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, return true; } + +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + TemplateParameterList *Params1, + TemplateParameterList *Params2) { + if (Params1->size() != Params2->size()) { + Context.Diag2(Params2->getTemplateLoc(), + diag::err_odr_different_num_template_parameters) + << Params1->size() << Params2->size(); + Context.Diag1(Params1->getTemplateLoc(), + diag::note_odr_template_parameter_list); + return false; + } + for (unsigned I = 0, N = Params1->size(); I != N; ++I) { + if (Params1->getParam(I)->getKind() != Params2->getParam(I)->getKind()) { + Context.Diag2(Params2->getParam(I)->getLocation(), + diag::err_odr_different_template_parameter_kind); + Context.Diag1(Params1->getParam(I)->getLocation(), + diag::note_odr_template_parameter_here); + return false; + } + + if (!Context.IsStructurallyEquivalent(Params1->getParam(I), + Params2->getParam(I))) { + + return false; + } + } + + return true; +} + +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + TemplateTypeParmDecl *D1, + TemplateTypeParmDecl *D2) { + if (D1->isParameterPack() != D2->isParameterPack()) { + Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack) + << D2->isParameterPack(); + Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack) + << D1->isParameterPack(); + return false; + } + + return true; +} + +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + NonTypeTemplateParmDecl *D1, + NonTypeTemplateParmDecl *D2) { + // FIXME: Enable once we have variadic templates. +#if 0 + if (D1->isParameterPack() != D2->isParameterPack()) { + Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack) + << D2->isParameterPack(); + Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack) + << D1->isParameterPack(); + return false; + } +#endif + + // Check types. + if (!Context.IsStructurallyEquivalent(D1->getType(), D2->getType())) { + Context.Diag2(D2->getLocation(), + diag::err_odr_non_type_parameter_type_inconsistent) + << D2->getType() << D1->getType(); + Context.Diag1(D1->getLocation(), diag::note_odr_value_here) + << D1->getType(); + return false; + } + + return true; +} + +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + TemplateTemplateParmDecl *D1, + TemplateTemplateParmDecl *D2) { + // FIXME: Enable once we have variadic templates. +#if 0 + if (D1->isParameterPack() != D2->isParameterPack()) { + Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack) + << D2->isParameterPack(); + Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack) + << D1->isParameterPack(); + return false; + } +#endif + + // Check template parameter lists. + return IsStructurallyEquivalent(Context, D1->getTemplateParameters(), + D2->getTemplateParameters()); +} + +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + ClassTemplateDecl *D1, + ClassTemplateDecl *D2) { + // Check template parameters. + if (!IsStructurallyEquivalent(Context, + D1->getTemplateParameters(), + D2->getTemplateParameters())) + return false; + + // Check the templated declaration. + return Context.IsStructurallyEquivalent(D1->getTemplatedDecl(), + D2->getTemplatedDecl()); +} + /// \brief Determine structural equivalence of two declarations. static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, Decl *D1, Decl *D2) { @@ -988,8 +1229,47 @@ bool StructuralEquivalenceContext::Finish() { // Typedef/non-typedef mismatch. Equivalent = false; } - } - + } else if (ClassTemplateDecl *ClassTemplate1 + = dyn_cast<ClassTemplateDecl>(D1)) { + if (ClassTemplateDecl *ClassTemplate2 = dyn_cast<ClassTemplateDecl>(D2)) { + if (!::IsStructurallyEquivalent(ClassTemplate1->getIdentifier(), + ClassTemplate2->getIdentifier()) || + !::IsStructurallyEquivalent(*this, ClassTemplate1, ClassTemplate2)) + Equivalent = false; + } else { + // Class template/non-class-template mismatch. + Equivalent = false; + } + } else if (TemplateTypeParmDecl *TTP1= dyn_cast<TemplateTypeParmDecl>(D1)) { + if (TemplateTypeParmDecl *TTP2 = dyn_cast<TemplateTypeParmDecl>(D2)) { + if (!::IsStructurallyEquivalent(*this, TTP1, TTP2)) + Equivalent = false; + } else { + // Kind mismatch. + Equivalent = false; + } + } else if (NonTypeTemplateParmDecl *NTTP1 + = dyn_cast<NonTypeTemplateParmDecl>(D1)) { + if (NonTypeTemplateParmDecl *NTTP2 + = dyn_cast<NonTypeTemplateParmDecl>(D2)) { + if (!::IsStructurallyEquivalent(*this, NTTP1, NTTP2)) + Equivalent = false; + } else { + // Kind mismatch. + Equivalent = false; + } + } else if (TemplateTemplateParmDecl *TTP1 + = dyn_cast<TemplateTemplateParmDecl>(D1)) { + if (TemplateTemplateParmDecl *TTP2 + = dyn_cast<TemplateTemplateParmDecl>(D2)) { + if (!::IsStructurallyEquivalent(*this, TTP1, TTP2)) + Equivalent = false; + } else { + // Kind mismatch. + Equivalent = false; + } + } + if (!Equivalent) { // Note that these two declarations are not equivalent (and we already // know about it). @@ -1007,13 +1287,13 @@ bool StructuralEquivalenceContext::Finish() { // Import Types //---------------------------------------------------------------------------- -QualType ASTNodeImporter::VisitType(Type *T) { +QualType ASTNodeImporter::VisitType(const Type *T) { Importer.FromDiag(SourceLocation(), diag::err_unsupported_ast_node) << T->getTypeClassName(); return QualType(); } -QualType ASTNodeImporter::VisitBuiltinType(BuiltinType *T) { +QualType ASTNodeImporter::VisitBuiltinType(const BuiltinType *T) { switch (T->getKind()) { case BuiltinType::Void: return Importer.getToContext().VoidTy; case BuiltinType::Bool: return Importer.getToContext().BoolTy; @@ -1054,7 +1334,8 @@ QualType ASTNodeImporter::VisitBuiltinType(BuiltinType *T) { return Importer.getToContext().CharTy; case BuiltinType::SChar: return Importer.getToContext().SignedCharTy; - case BuiltinType::WChar: + case BuiltinType::WChar_S: + case BuiltinType::WChar_U: // FIXME: If not in C++, shall we translate to the C equivalent of // wchar_t? return Importer.getToContext().WCharTy; @@ -1074,9 +1355,6 @@ QualType ASTNodeImporter::VisitBuiltinType(BuiltinType *T) { 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! @@ -1092,7 +1370,7 @@ QualType ASTNodeImporter::VisitBuiltinType(BuiltinType *T) { return QualType(); } -QualType ASTNodeImporter::VisitComplexType(ComplexType *T) { +QualType ASTNodeImporter::VisitComplexType(const ComplexType *T) { QualType ToElementType = Importer.Import(T->getElementType()); if (ToElementType.isNull()) return QualType(); @@ -1100,7 +1378,7 @@ QualType ASTNodeImporter::VisitComplexType(ComplexType *T) { return Importer.getToContext().getComplexType(ToElementType); } -QualType ASTNodeImporter::VisitPointerType(PointerType *T) { +QualType ASTNodeImporter::VisitPointerType(const PointerType *T) { QualType ToPointeeType = Importer.Import(T->getPointeeType()); if (ToPointeeType.isNull()) return QualType(); @@ -1108,7 +1386,7 @@ QualType ASTNodeImporter::VisitPointerType(PointerType *T) { return Importer.getToContext().getPointerType(ToPointeeType); } -QualType ASTNodeImporter::VisitBlockPointerType(BlockPointerType *T) { +QualType ASTNodeImporter::VisitBlockPointerType(const BlockPointerType *T) { // FIXME: Check for blocks support in "to" context. QualType ToPointeeType = Importer.Import(T->getPointeeType()); if (ToPointeeType.isNull()) @@ -1117,7 +1395,8 @@ QualType ASTNodeImporter::VisitBlockPointerType(BlockPointerType *T) { return Importer.getToContext().getBlockPointerType(ToPointeeType); } -QualType ASTNodeImporter::VisitLValueReferenceType(LValueReferenceType *T) { +QualType +ASTNodeImporter::VisitLValueReferenceType(const LValueReferenceType *T) { // FIXME: Check for C++ support in "to" context. QualType ToPointeeType = Importer.Import(T->getPointeeTypeAsWritten()); if (ToPointeeType.isNull()) @@ -1126,7 +1405,8 @@ QualType ASTNodeImporter::VisitLValueReferenceType(LValueReferenceType *T) { return Importer.getToContext().getLValueReferenceType(ToPointeeType); } -QualType ASTNodeImporter::VisitRValueReferenceType(RValueReferenceType *T) { +QualType +ASTNodeImporter::VisitRValueReferenceType(const RValueReferenceType *T) { // FIXME: Check for C++0x support in "to" context. QualType ToPointeeType = Importer.Import(T->getPointeeTypeAsWritten()); if (ToPointeeType.isNull()) @@ -1135,7 +1415,7 @@ QualType ASTNodeImporter::VisitRValueReferenceType(RValueReferenceType *T) { return Importer.getToContext().getRValueReferenceType(ToPointeeType); } -QualType ASTNodeImporter::VisitMemberPointerType(MemberPointerType *T) { +QualType ASTNodeImporter::VisitMemberPointerType(const MemberPointerType *T) { // FIXME: Check for C++ support in "to" context. QualType ToPointeeType = Importer.Import(T->getPointeeType()); if (ToPointeeType.isNull()) @@ -1146,7 +1426,7 @@ QualType ASTNodeImporter::VisitMemberPointerType(MemberPointerType *T) { ClassType.getTypePtr()); } -QualType ASTNodeImporter::VisitConstantArrayType(ConstantArrayType *T) { +QualType ASTNodeImporter::VisitConstantArrayType(const ConstantArrayType *T) { QualType ToElementType = Importer.Import(T->getElementType()); if (ToElementType.isNull()) return QualType(); @@ -1157,7 +1437,8 @@ QualType ASTNodeImporter::VisitConstantArrayType(ConstantArrayType *T) { T->getIndexTypeCVRQualifiers()); } -QualType ASTNodeImporter::VisitIncompleteArrayType(IncompleteArrayType *T) { +QualType +ASTNodeImporter::VisitIncompleteArrayType(const IncompleteArrayType *T) { QualType ToElementType = Importer.Import(T->getElementType()); if (ToElementType.isNull()) return QualType(); @@ -1167,7 +1448,7 @@ QualType ASTNodeImporter::VisitIncompleteArrayType(IncompleteArrayType *T) { T->getIndexTypeCVRQualifiers()); } -QualType ASTNodeImporter::VisitVariableArrayType(VariableArrayType *T) { +QualType ASTNodeImporter::VisitVariableArrayType(const VariableArrayType *T) { QualType ToElementType = Importer.Import(T->getElementType()); if (ToElementType.isNull()) return QualType(); @@ -1183,17 +1464,17 @@ QualType ASTNodeImporter::VisitVariableArrayType(VariableArrayType *T) { Brackets); } -QualType ASTNodeImporter::VisitVectorType(VectorType *T) { +QualType ASTNodeImporter::VisitVectorType(const VectorType *T) { QualType ToElementType = Importer.Import(T->getElementType()); if (ToElementType.isNull()) return QualType(); return Importer.getToContext().getVectorType(ToElementType, T->getNumElements(), - T->getAltiVecSpecific()); + T->getVectorKind()); } -QualType ASTNodeImporter::VisitExtVectorType(ExtVectorType *T) { +QualType ASTNodeImporter::VisitExtVectorType(const ExtVectorType *T) { QualType ToElementType = Importer.Import(T->getElementType()); if (ToElementType.isNull()) return QualType(); @@ -1202,7 +1483,8 @@ QualType ASTNodeImporter::VisitExtVectorType(ExtVectorType *T) { T->getNumElements()); } -QualType ASTNodeImporter::VisitFunctionNoProtoType(FunctionNoProtoType *T) { +QualType +ASTNodeImporter::VisitFunctionNoProtoType(const 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()); @@ -1213,7 +1495,7 @@ QualType ASTNodeImporter::VisitFunctionNoProtoType(FunctionNoProtoType *T) { T->getExtInfo()); } -QualType ASTNodeImporter::VisitFunctionProtoType(FunctionProtoType *T) { +QualType ASTNodeImporter::VisitFunctionProtoType(const FunctionProtoType *T) { QualType ToResultType = Importer.Import(T->getResultType()); if (ToResultType.isNull()) return QualType(); @@ -1239,19 +1521,15 @@ QualType ASTNodeImporter::VisitFunctionProtoType(FunctionProtoType *T) { return QualType(); ExceptionTypes.push_back(ExceptionType); } + + FunctionProtoType::ExtProtoInfo EPI = T->getExtProtoInfo(); + EPI.Exceptions = ExceptionTypes.data(); return Importer.getToContext().getFunctionType(ToResultType, ArgTypes.data(), - ArgTypes.size(), - T->isVariadic(), - T->getTypeQuals(), - T->hasExceptionSpec(), - T->hasAnyExceptionSpec(), - ExceptionTypes.size(), - ExceptionTypes.data(), - T->getExtInfo()); + ArgTypes.size(), EPI); } -QualType ASTNodeImporter::VisitTypedefType(TypedefType *T) { +QualType ASTNodeImporter::VisitTypedefType(const TypedefType *T) { TypedefDecl *ToDecl = dyn_cast_or_null<TypedefDecl>(Importer.Import(T->getDecl())); if (!ToDecl) @@ -1260,7 +1538,7 @@ QualType ASTNodeImporter::VisitTypedefType(TypedefType *T) { return Importer.getToContext().getTypeDeclType(ToDecl); } -QualType ASTNodeImporter::VisitTypeOfExprType(TypeOfExprType *T) { +QualType ASTNodeImporter::VisitTypeOfExprType(const TypeOfExprType *T) { Expr *ToExpr = Importer.Import(T->getUnderlyingExpr()); if (!ToExpr) return QualType(); @@ -1268,7 +1546,7 @@ QualType ASTNodeImporter::VisitTypeOfExprType(TypeOfExprType *T) { return Importer.getToContext().getTypeOfExprType(ToExpr); } -QualType ASTNodeImporter::VisitTypeOfType(TypeOfType *T) { +QualType ASTNodeImporter::VisitTypeOfType(const TypeOfType *T) { QualType ToUnderlyingType = Importer.Import(T->getUnderlyingType()); if (ToUnderlyingType.isNull()) return QualType(); @@ -1276,7 +1554,8 @@ QualType ASTNodeImporter::VisitTypeOfType(TypeOfType *T) { return Importer.getToContext().getTypeOfType(ToUnderlyingType); } -QualType ASTNodeImporter::VisitDecltypeType(DecltypeType *T) { +QualType ASTNodeImporter::VisitDecltypeType(const DecltypeType *T) { + // FIXME: Make sure that the "to" context supports C++0x! Expr *ToExpr = Importer.Import(T->getUnderlyingExpr()); if (!ToExpr) return QualType(); @@ -1284,7 +1563,20 @@ QualType ASTNodeImporter::VisitDecltypeType(DecltypeType *T) { return Importer.getToContext().getDecltypeType(ToExpr); } -QualType ASTNodeImporter::VisitRecordType(RecordType *T) { +QualType ASTNodeImporter::VisitAutoType(const AutoType *T) { + // FIXME: Make sure that the "to" context supports C++0x! + QualType FromDeduced = T->getDeducedType(); + QualType ToDeduced; + if (!FromDeduced.isNull()) { + ToDeduced = Importer.Import(FromDeduced); + if (ToDeduced.isNull()) + return QualType(); + } + + return Importer.getToContext().getAutoType(ToDeduced); +} + +QualType ASTNodeImporter::VisitRecordType(const RecordType *T) { RecordDecl *ToDecl = dyn_cast_or_null<RecordDecl>(Importer.Import(T->getDecl())); if (!ToDecl) @@ -1293,7 +1585,7 @@ QualType ASTNodeImporter::VisitRecordType(RecordType *T) { return Importer.getToContext().getTagDeclType(ToDecl); } -QualType ASTNodeImporter::VisitEnumType(EnumType *T) { +QualType ASTNodeImporter::VisitEnumType(const EnumType *T) { EnumDecl *ToDecl = dyn_cast_or_null<EnumDecl>(Importer.Import(T->getDecl())); if (!ToDecl) @@ -1302,7 +1594,31 @@ QualType ASTNodeImporter::VisitEnumType(EnumType *T) { return Importer.getToContext().getTagDeclType(ToDecl); } -QualType ASTNodeImporter::VisitElaboratedType(ElaboratedType *T) { +QualType ASTNodeImporter::VisitTemplateSpecializationType( + const TemplateSpecializationType *T) { + TemplateName ToTemplate = Importer.Import(T->getTemplateName()); + if (ToTemplate.isNull()) + return QualType(); + + llvm::SmallVector<TemplateArgument, 2> ToTemplateArgs; + if (ImportTemplateArguments(T->getArgs(), T->getNumArgs(), ToTemplateArgs)) + return QualType(); + + QualType ToCanonType; + if (!QualType(T, 0).isCanonical()) { + QualType FromCanonType + = Importer.getFromContext().getCanonicalType(QualType(T, 0)); + ToCanonType =Importer.Import(FromCanonType); + if (ToCanonType.isNull()) + return QualType(); + } + return Importer.getToContext().getTemplateSpecializationType(ToTemplate, + ToTemplateArgs.data(), + ToTemplateArgs.size(), + ToCanonType); +} + +QualType ASTNodeImporter::VisitElaboratedType(const ElaboratedType *T) { NestedNameSpecifier *ToQualifier = 0; // Note: the qualifier in an ElaboratedType is optional. if (T->getQualifier()) { @@ -1319,7 +1635,7 @@ QualType ASTNodeImporter::VisitElaboratedType(ElaboratedType *T) { ToQualifier, ToNamedType); } -QualType ASTNodeImporter::VisitObjCInterfaceType(ObjCInterfaceType *T) { +QualType ASTNodeImporter::VisitObjCInterfaceType(const ObjCInterfaceType *T) { ObjCInterfaceDecl *Class = dyn_cast_or_null<ObjCInterfaceDecl>(Importer.Import(T->getDecl())); if (!Class) @@ -1328,7 +1644,7 @@ QualType ASTNodeImporter::VisitObjCInterfaceType(ObjCInterfaceType *T) { return Importer.getToContext().getObjCInterfaceType(Class); } -QualType ASTNodeImporter::VisitObjCObjectType(ObjCObjectType *T) { +QualType ASTNodeImporter::VisitObjCObjectType(const ObjCObjectType *T) { QualType ToBaseType = Importer.Import(T->getBaseType()); if (ToBaseType.isNull()) return QualType(); @@ -1349,7 +1665,8 @@ QualType ASTNodeImporter::VisitObjCObjectType(ObjCObjectType *T) { Protocols.size()); } -QualType ASTNodeImporter::VisitObjCObjectPointerType(ObjCObjectPointerType *T) { +QualType +ASTNodeImporter::VisitObjCObjectPointerType(const ObjCObjectPointerType *T) { QualType ToPointeeType = Importer.Import(T->getPointeeType()); if (ToPointeeType.isNull()) return QualType(); @@ -1420,7 +1737,15 @@ ASTNodeImporter::ImportDeclarationNameLoc(const DeclarationNameInfo &From, } } -void ASTNodeImporter::ImportDeclContext(DeclContext *FromDC) { +void ASTNodeImporter::ImportDeclContext(DeclContext *FromDC, bool ForceImport) { + if (Importer.isMinimalImport() && !ForceImport) { + if (DeclContext *ToDC = Importer.ImportContext(FromDC)) { + ToDC->setHasExternalLexicalStorage(); + ToDC->setHasExternalVisibleStorage(); + } + return; + } + for (DeclContext::decl_iterator From = FromDC->decls_begin(), FromEnd = FromDC->decls_end(); From != FromEnd; @@ -1428,11 +1753,151 @@ void ASTNodeImporter::ImportDeclContext(DeclContext *FromDC) { Importer.Import(*From); } +bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To) { + if (To->getDefinition()) + return false; + + To->startDefinition(); + + // Add base classes. + if (CXXRecordDecl *ToCXX = dyn_cast<CXXRecordDecl>(To)) { + CXXRecordDecl *FromCXX = cast<CXXRecordDecl>(From); + + llvm::SmallVector<CXXBaseSpecifier *, 4> Bases; + for (CXXRecordDecl::base_class_iterator + Base1 = FromCXX->bases_begin(), + FromBaseEnd = FromCXX->bases_end(); + Base1 != FromBaseEnd; + ++Base1) { + QualType T = Importer.Import(Base1->getType()); + if (T.isNull()) + return true; + + SourceLocation EllipsisLoc; + if (Base1->isPackExpansion()) + EllipsisLoc = Importer.Import(Base1->getEllipsisLoc()); + + Bases.push_back( + new (Importer.getToContext()) + CXXBaseSpecifier(Importer.Import(Base1->getSourceRange()), + Base1->isVirtual(), + Base1->isBaseOfClass(), + Base1->getAccessSpecifierAsWritten(), + Importer.Import(Base1->getTypeSourceInfo()), + EllipsisLoc)); + } + if (!Bases.empty()) + ToCXX->setBases(Bases.data(), Bases.size()); + } + + ImportDeclContext(From); + To->completeDefinition(); + return false; +} + +TemplateParameterList *ASTNodeImporter::ImportTemplateParameterList( + TemplateParameterList *Params) { + llvm::SmallVector<NamedDecl *, 4> ToParams; + ToParams.reserve(Params->size()); + for (TemplateParameterList::iterator P = Params->begin(), + PEnd = Params->end(); + P != PEnd; ++P) { + Decl *To = Importer.Import(*P); + if (!To) + return 0; + + ToParams.push_back(cast<NamedDecl>(To)); + } + + return TemplateParameterList::Create(Importer.getToContext(), + Importer.Import(Params->getTemplateLoc()), + Importer.Import(Params->getLAngleLoc()), + ToParams.data(), ToParams.size(), + Importer.Import(Params->getRAngleLoc())); +} + +TemplateArgument +ASTNodeImporter::ImportTemplateArgument(const TemplateArgument &From) { + switch (From.getKind()) { + case TemplateArgument::Null: + return TemplateArgument(); + + case TemplateArgument::Type: { + QualType ToType = Importer.Import(From.getAsType()); + if (ToType.isNull()) + return TemplateArgument(); + return TemplateArgument(ToType); + } + + case TemplateArgument::Integral: { + QualType ToType = Importer.Import(From.getIntegralType()); + if (ToType.isNull()) + return TemplateArgument(); + return TemplateArgument(*From.getAsIntegral(), ToType); + } + + case TemplateArgument::Declaration: + if (Decl *To = Importer.Import(From.getAsDecl())) + return TemplateArgument(To); + return TemplateArgument(); + + case TemplateArgument::Template: { + TemplateName ToTemplate = Importer.Import(From.getAsTemplate()); + if (ToTemplate.isNull()) + return TemplateArgument(); + + return TemplateArgument(ToTemplate); + } + + case TemplateArgument::TemplateExpansion: { + TemplateName ToTemplate + = Importer.Import(From.getAsTemplateOrTemplatePattern()); + if (ToTemplate.isNull()) + return TemplateArgument(); + + return TemplateArgument(ToTemplate, From.getNumTemplateExpansions()); + } + + case TemplateArgument::Expression: + if (Expr *ToExpr = Importer.Import(From.getAsExpr())) + return TemplateArgument(ToExpr); + return TemplateArgument(); + + case TemplateArgument::Pack: { + llvm::SmallVector<TemplateArgument, 2> ToPack; + ToPack.reserve(From.pack_size()); + if (ImportTemplateArguments(From.pack_begin(), From.pack_size(), ToPack)) + return TemplateArgument(); + + TemplateArgument *ToArgs + = new (Importer.getToContext()) TemplateArgument[ToPack.size()]; + std::copy(ToPack.begin(), ToPack.end(), ToArgs); + return TemplateArgument(ToArgs, ToPack.size()); + } + } + + llvm_unreachable("Invalid template argument kind"); + return TemplateArgument(); +} + +bool ASTNodeImporter::ImportTemplateArguments(const TemplateArgument *FromArgs, + unsigned NumFromArgs, + llvm::SmallVectorImpl<TemplateArgument> &ToArgs) { + for (unsigned I = 0; I != NumFromArgs; ++I) { + TemplateArgument To = ImportTemplateArgument(FromArgs[I]); + if (To.isNull() && !FromArgs[I].isNull()) + return true; + + ToArgs.push_back(To); + } + + return false; +} + bool ASTNodeImporter::IsStructuralMatch(RecordDecl *FromRecord, RecordDecl *ToRecord) { StructuralEquivalenceContext Ctx(Importer.getFromContext(), Importer.getToContext(), - Importer.getDiags(), Importer.getNonEquivalentDecls()); return Ctx.IsStructurallyEquivalent(FromRecord, ToRecord); } @@ -1440,11 +1905,18 @@ bool ASTNodeImporter::IsStructuralMatch(RecordDecl *FromRecord, bool ASTNodeImporter::IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToEnum) { StructuralEquivalenceContext Ctx(Importer.getFromContext(), Importer.getToContext(), - Importer.getDiags(), Importer.getNonEquivalentDecls()); return Ctx.IsStructurallyEquivalent(FromEnum, ToEnum); } +bool ASTNodeImporter::IsStructuralMatch(ClassTemplateDecl *From, + ClassTemplateDecl *To) { + StructuralEquivalenceContext Ctx(Importer.getFromContext(), + Importer.getToContext(), + Importer.getNonEquivalentDecls()); + return Ctx.IsStructurallyEquivalent(From, To); +} + Decl *ASTNodeImporter::VisitDecl(Decl *D) { Importer.FromDiag(D->getLocation(), diag::err_unsupported_ast_node) << D->getDeclKindName(); @@ -1620,9 +2092,10 @@ Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) { // Create the enum declaration. EnumDecl *D2 = EnumDecl::Create(Importer.getToContext(), DC, Loc, - Name.getAsIdentifierInfo(), - Importer.Import(D->getTagKeywordLoc()), - 0); + Name.getAsIdentifierInfo(), + Importer.Import(D->getTagKeywordLoc()), 0, + D->isScoped(), D->isScopedUsingClassTag(), + D->isFixed()); // Import the qualifier, if any. if (D->getQualifier()) { NestedNameSpecifier *NNS = Importer.Import(D->getQualifier()); @@ -1764,38 +2237,8 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { Importer.Imported(D, D2); - if (D->isDefinition()) { - D2->startDefinition(); - - // Add base classes. - if (CXXRecordDecl *D2CXX = dyn_cast<CXXRecordDecl>(D2)) { - CXXRecordDecl *D1CXX = cast<CXXRecordDecl>(D); - - 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(), - Importer.Import(Base1->getTypeSourceInfo()))); - } - if (!Bases.empty()) - D2CXX->setBases(Bases.data(), Bases.size()); - } - - ImportDeclContext(D); - D2->completeDefinition(); - } + if (D->isDefinition() && ImportDefinition(D, D2)) + return 0; return D2; } @@ -1939,7 +2382,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { } else if (isa<CXXDestructorDecl>(D)) { ToFunction = CXXDestructorDecl::Create(Importer.getToContext(), cast<CXXRecordDecl>(DC), - NameInfo, T, + NameInfo, T, TInfo, D->isInlineSpecified(), D->isImplicit()); } else if (CXXConversionDecl *FromConversion @@ -1949,6 +2392,13 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { NameInfo, T, TInfo, D->isInlineSpecified(), FromConversion->isExplicit()); + } else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) { + ToFunction = CXXMethodDecl::Create(Importer.getToContext(), + cast<CXXRecordDecl>(DC), + NameInfo, T, TInfo, + Method->isStatic(), + Method->getStorageClassAsWritten(), + Method->isInlineSpecified()); } else { ToFunction = FunctionDecl::Create(Importer.getToContext(), DC, NameInfo, T, TInfo, D->getStorageClass(), @@ -1965,8 +2415,10 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { } ToFunction->setAccess(D->getAccess()); ToFunction->setLexicalDeclContext(LexicalDC); + ToFunction->setVirtualAsWritten(D->isVirtualAsWritten()); + ToFunction->setTrivial(D->isTrivial()); + ToFunction->setPure(D->isPure()); Importer.Imported(D, ToFunction); - LexicalDC->addDecl(ToFunction); // Set the parameters. for (unsigned I = 0, N = Parameters.size(); I != N; ++I) { @@ -1976,7 +2428,10 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { ToFunction->setParams(Parameters.data(), Parameters.size()); // FIXME: Other bits to merge? - + + // Add this function to the lexical context. + LexicalDC->addDecl(ToFunction); + return ToFunction; } @@ -2024,6 +2479,42 @@ Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) { return ToField; } +Decl *ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *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; + + NamedDecl **NamedChain = + new (Importer.getToContext())NamedDecl*[D->getChainingSize()]; + + unsigned i = 0; + for (IndirectFieldDecl::chain_iterator PI = D->chain_begin(), + PE = D->chain_end(); PI != PE; ++PI) { + Decl* D = Importer.Import(*PI); + if (!D) + return 0; + NamedChain[i++] = cast<NamedDecl>(D); + } + + IndirectFieldDecl *ToIndirectField = IndirectFieldDecl::Create( + Importer.getToContext(), DC, + Loc, Name.getAsIdentifierInfo(), T, + NamedChain, D->getChainingSize()); + ToIndirectField->setAccess(D->getAccess()); + ToIndirectField->setLexicalDeclContext(LexicalDC); + Importer.Imported(D, ToIndirectField); + LexicalDC->addDecl(ToIndirectField); + return ToIndirectField; +} + Decl *ASTNodeImporter::VisitObjCIvarDecl(ObjCIvarDecl *D) { // Import the major distinguishing characteristics of an ivar. DeclContext *DC, *LexicalDC; @@ -2434,7 +2925,8 @@ Decl *ASTNodeImporter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) { // If we have an implementation, import it as well. if (D->getImplementation()) { ObjCCategoryImplDecl *Impl - = cast<ObjCCategoryImplDecl>(Importer.Import(D->getImplementation())); + = cast_or_null<ObjCCategoryImplDecl>( + Importer.Import(D->getImplementation())); if (!Impl) return 0; @@ -2615,8 +3107,8 @@ Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { // If we have an @implementation, import it as well. if (D->getImplementation()) { - ObjCImplementationDecl *Impl - = cast<ObjCImplementationDecl>(Importer.Import(D->getImplementation())); + ObjCImplementationDecl *Impl = cast_or_null<ObjCImplementationDecl>( + Importer.Import(D->getImplementation())); if (!Impl) return 0; @@ -2626,6 +3118,114 @@ Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { return ToIface; } +Decl *ASTNodeImporter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) { + ObjCCategoryDecl *Category = cast_or_null<ObjCCategoryDecl>( + Importer.Import(D->getCategoryDecl())); + if (!Category) + return 0; + + ObjCCategoryImplDecl *ToImpl = Category->getImplementation(); + if (!ToImpl) { + DeclContext *DC = Importer.ImportContext(D->getDeclContext()); + if (!DC) + return 0; + + ToImpl = ObjCCategoryImplDecl::Create(Importer.getToContext(), DC, + Importer.Import(D->getLocation()), + Importer.Import(D->getIdentifier()), + Category->getClassInterface()); + + DeclContext *LexicalDC = DC; + if (D->getDeclContext() != D->getLexicalDeclContext()) { + LexicalDC = Importer.ImportContext(D->getLexicalDeclContext()); + if (!LexicalDC) + return 0; + + ToImpl->setLexicalDeclContext(LexicalDC); + } + + LexicalDC->addDecl(ToImpl); + Category->setImplementation(ToImpl); + } + + Importer.Imported(D, ToImpl); + ImportDeclContext(D); + return ToImpl; +} + +Decl *ASTNodeImporter::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { + // Find the corresponding interface. + ObjCInterfaceDecl *Iface = cast_or_null<ObjCInterfaceDecl>( + Importer.Import(D->getClassInterface())); + if (!Iface) + return 0; + + // Import the superclass, if any. + ObjCInterfaceDecl *Super = 0; + if (D->getSuperClass()) { + Super = cast_or_null<ObjCInterfaceDecl>( + Importer.Import(D->getSuperClass())); + if (!Super) + return 0; + } + + ObjCImplementationDecl *Impl = Iface->getImplementation(); + if (!Impl) { + // We haven't imported an implementation yet. Create a new @implementation + // now. + Impl = ObjCImplementationDecl::Create(Importer.getToContext(), + Importer.ImportContext(D->getDeclContext()), + Importer.Import(D->getLocation()), + Iface, Super); + + if (D->getDeclContext() != D->getLexicalDeclContext()) { + DeclContext *LexicalDC + = Importer.ImportContext(D->getLexicalDeclContext()); + if (!LexicalDC) + return 0; + Impl->setLexicalDeclContext(LexicalDC); + } + + // Associate the implementation with the class it implements. + Iface->setImplementation(Impl); + Importer.Imported(D, Iface->getImplementation()); + } else { + Importer.Imported(D, Iface->getImplementation()); + + // Verify that the existing @implementation has the same superclass. + if ((Super && !Impl->getSuperClass()) || + (!Super && Impl->getSuperClass()) || + (Super && Impl->getSuperClass() && + Super->getCanonicalDecl() != Impl->getSuperClass())) { + Importer.ToDiag(Impl->getLocation(), + diag::err_odr_objc_superclass_inconsistent) + << Iface->getDeclName(); + // FIXME: It would be nice to have the location of the superclass + // below. + if (Impl->getSuperClass()) + Importer.ToDiag(Impl->getLocation(), + diag::note_odr_objc_superclass) + << Impl->getSuperClass()->getDeclName(); + else + Importer.ToDiag(Impl->getLocation(), + diag::note_odr_objc_missing_superclass); + if (D->getSuperClass()) + Importer.FromDiag(D->getLocation(), + diag::note_odr_objc_superclass) + << D->getSuperClass()->getDeclName(); + else + Importer.FromDiag(D->getLocation(), + diag::note_odr_objc_missing_superclass); + return 0; + } + } + + // Import all of the members of this @implementation. + ImportDeclContext(D); + + return Impl; +} + Decl *ASTNodeImporter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { // Import the major distinguishing characteristics of an @property. DeclContext *DC, *LexicalDC; @@ -2688,6 +3288,87 @@ Decl *ASTNodeImporter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { return ToProperty; } +Decl *ASTNodeImporter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { + ObjCPropertyDecl *Property = cast_or_null<ObjCPropertyDecl>( + Importer.Import(D->getPropertyDecl())); + if (!Property) + return 0; + + DeclContext *DC = Importer.ImportContext(D->getDeclContext()); + if (!DC) + return 0; + + // Import the lexical declaration context. + DeclContext *LexicalDC = DC; + if (D->getDeclContext() != D->getLexicalDeclContext()) { + LexicalDC = Importer.ImportContext(D->getLexicalDeclContext()); + if (!LexicalDC) + return 0; + } + + ObjCImplDecl *InImpl = dyn_cast<ObjCImplDecl>(LexicalDC); + if (!InImpl) + return 0; + + // Import the ivar (for an @synthesize). + ObjCIvarDecl *Ivar = 0; + if (D->getPropertyIvarDecl()) { + Ivar = cast_or_null<ObjCIvarDecl>( + Importer.Import(D->getPropertyIvarDecl())); + if (!Ivar) + return 0; + } + + ObjCPropertyImplDecl *ToImpl + = InImpl->FindPropertyImplDecl(Property->getIdentifier()); + if (!ToImpl) { + ToImpl = ObjCPropertyImplDecl::Create(Importer.getToContext(), DC, + Importer.Import(D->getLocStart()), + Importer.Import(D->getLocation()), + Property, + D->getPropertyImplementation(), + Ivar, + Importer.Import(D->getPropertyIvarDeclLoc())); + ToImpl->setLexicalDeclContext(LexicalDC); + Importer.Imported(D, ToImpl); + LexicalDC->addDecl(ToImpl); + } else { + // Check that we have the same kind of property implementation (@synthesize + // vs. @dynamic). + if (D->getPropertyImplementation() != ToImpl->getPropertyImplementation()) { + Importer.ToDiag(ToImpl->getLocation(), + diag::err_odr_objc_property_impl_kind_inconsistent) + << Property->getDeclName() + << (ToImpl->getPropertyImplementation() + == ObjCPropertyImplDecl::Dynamic); + Importer.FromDiag(D->getLocation(), + diag::note_odr_objc_property_impl_kind) + << D->getPropertyDecl()->getDeclName() + << (D->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic); + return 0; + } + + // For @synthesize, check that we have the same + if (D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize && + Ivar != ToImpl->getPropertyIvarDecl()) { + Importer.ToDiag(ToImpl->getPropertyIvarDeclLoc(), + diag::err_odr_objc_synthesize_ivar_inconsistent) + << Property->getDeclName() + << ToImpl->getPropertyIvarDecl()->getDeclName() + << Ivar->getDeclName(); + Importer.FromDiag(D->getPropertyIvarDeclLoc(), + diag::note_odr_objc_synthesize_ivar_here) + << D->getPropertyIvarDecl()->getDeclName(); + return 0; + } + + // Merge the existing implementation with the new implementation. + Importer.Imported(D, ToImpl); + } + + return ToImpl; +} + Decl * ASTNodeImporter::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) { // Import the context of this declaration. @@ -2772,6 +3453,275 @@ Decl *ASTNodeImporter::VisitObjCClassDecl(ObjCClassDecl *D) { return ToClass; } +Decl *ASTNodeImporter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { + // For template arguments, we adopt the translation unit as our declaration + // context. This context will be fixed when the actual template declaration + // is created. + + // FIXME: Import default argument. + return TemplateTypeParmDecl::Create(Importer.getToContext(), + Importer.getToContext().getTranslationUnitDecl(), + Importer.Import(D->getLocation()), + D->getDepth(), + D->getIndex(), + Importer.Import(D->getIdentifier()), + D->wasDeclaredWithTypename(), + D->isParameterPack()); +} + +Decl * +ASTNodeImporter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { + // 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 type of this declaration. + QualType T = Importer.Import(D->getType()); + if (T.isNull()) + return 0; + + // Import type-source information. + TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo()); + if (D->getTypeSourceInfo() && !TInfo) + return 0; + + // FIXME: Import default argument. + + return NonTypeTemplateParmDecl::Create(Importer.getToContext(), + Importer.getToContext().getTranslationUnitDecl(), + Loc, D->getDepth(), D->getPosition(), + Name.getAsIdentifierInfo(), + T, D->isParameterPack(), TInfo); +} + +Decl * +ASTNodeImporter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { + // 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 template parameters. + TemplateParameterList *TemplateParams + = ImportTemplateParameterList(D->getTemplateParameters()); + if (!TemplateParams) + return 0; + + // FIXME: Import default argument. + + return TemplateTemplateParmDecl::Create(Importer.getToContext(), + Importer.getToContext().getTranslationUnitDecl(), + Loc, D->getDepth(), D->getPosition(), + D->isParameterPack(), + Name.getAsIdentifierInfo(), + TemplateParams); +} + +Decl *ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *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. + CXXRecordDecl *Definition + = cast_or_null<CXXRecordDecl>(D->getTemplatedDecl()->getDefinition()); + if (Definition && Definition != D->getTemplatedDecl()) { + Decl *ImportedDef + = Importer.Import(Definition->getDescribedClassTemplate()); + if (!ImportedDef) + return 0; + + return Importer.Imported(D, ImportedDef); + } + + // Import the major distinguishing characteristics of this class template. + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + return 0; + + // We may already have a template of the same name; try to find and match it. + if (!DC->isFunctionOrMethod()) { + llvm::SmallVector<NamedDecl *, 4> ConflictingDecls; + for (DeclContext::lookup_result Lookup = DC->lookup(Name); + Lookup.first != Lookup.second; + ++Lookup.first) { + if (!(*Lookup.first)->isInIdentifierNamespace(Decl::IDNS_Ordinary)) + continue; + + Decl *Found = *Lookup.first; + if (ClassTemplateDecl *FoundTemplate + = dyn_cast<ClassTemplateDecl>(Found)) { + if (IsStructuralMatch(D, FoundTemplate)) { + // The class templates structurally match; call it the same template. + // FIXME: We may be filling in a forward declaration here. Handle + // this case! + Importer.Imported(D->getTemplatedDecl(), + FoundTemplate->getTemplatedDecl()); + return Importer.Imported(D, FoundTemplate); + } + } + + ConflictingDecls.push_back(*Lookup.first); + } + + if (!ConflictingDecls.empty()) { + Name = Importer.HandleNameConflict(Name, DC, Decl::IDNS_Ordinary, + ConflictingDecls.data(), + ConflictingDecls.size()); + } + + if (!Name) + return 0; + } + + CXXRecordDecl *DTemplated = D->getTemplatedDecl(); + + // Create the declaration that is being templated. + CXXRecordDecl *D2Templated = CXXRecordDecl::Create(Importer.getToContext(), + DTemplated->getTagKind(), + DC, + Importer.Import(DTemplated->getLocation()), + Name.getAsIdentifierInfo(), + Importer.Import(DTemplated->getTagKeywordLoc())); + D2Templated->setAccess(DTemplated->getAccess()); + + + // Import the qualifier, if any. + if (DTemplated->getQualifier()) { + NestedNameSpecifier *NNS = Importer.Import(DTemplated->getQualifier()); + SourceRange NNSRange = Importer.Import(DTemplated->getQualifierRange()); + D2Templated->setQualifierInfo(NNS, NNSRange); + } + D2Templated->setLexicalDeclContext(LexicalDC); + + // Create the class template declaration itself. + TemplateParameterList *TemplateParams + = ImportTemplateParameterList(D->getTemplateParameters()); + if (!TemplateParams) + return 0; + + ClassTemplateDecl *D2 = ClassTemplateDecl::Create(Importer.getToContext(), DC, + Loc, Name, TemplateParams, + D2Templated, + /*PrevDecl=*/0); + D2Templated->setDescribedClassTemplate(D2); + + D2->setAccess(D->getAccess()); + D2->setLexicalDeclContext(LexicalDC); + LexicalDC->addDecl(D2); + + // Note the relationship between the class templates. + Importer.Imported(D, D2); + Importer.Imported(DTemplated, D2Templated); + + if (DTemplated->isDefinition() && !D2Templated->isDefinition()) { + // FIXME: Import definition! + } + + return D2; +} + +Decl *ASTNodeImporter::VisitClassTemplateSpecializationDecl( + ClassTemplateSpecializationDecl *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); + } + + ClassTemplateDecl *ClassTemplate + = cast_or_null<ClassTemplateDecl>(Importer.Import( + D->getSpecializedTemplate())); + if (!ClassTemplate) + return 0; + + // Import the context of this declaration. + DeclContext *DC = ClassTemplate->getDeclContext(); + if (!DC) + return 0; + + DeclContext *LexicalDC = DC; + if (D->getDeclContext() != D->getLexicalDeclContext()) { + LexicalDC = Importer.ImportContext(D->getLexicalDeclContext()); + if (!LexicalDC) + return 0; + } + + // Import the location of this declaration. + SourceLocation Loc = Importer.Import(D->getLocation()); + + // Import template arguments. + llvm::SmallVector<TemplateArgument, 2> TemplateArgs; + if (ImportTemplateArguments(D->getTemplateArgs().data(), + D->getTemplateArgs().size(), + TemplateArgs)) + return 0; + + // Try to find an existing specialization with these template arguments. + void *InsertPos = 0; + ClassTemplateSpecializationDecl *D2 + = ClassTemplate->findSpecialization(TemplateArgs.data(), + TemplateArgs.size(), InsertPos); + if (D2) { + // We already have a class template specialization with these template + // arguments. + + // FIXME: Check for specialization vs. instantiation errors. + + if (RecordDecl *FoundDef = D2->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. + return Importer.Imported(D, FoundDef); + } + } + } else { + // Create a new specialization. + D2 = ClassTemplateSpecializationDecl::Create(Importer.getToContext(), + D->getTagKind(), DC, + Loc, ClassTemplate, + TemplateArgs.data(), + TemplateArgs.size(), + /*PrevDecl=*/0); + D2->setSpecializationKind(D->getSpecializationKind()); + + // Add this specialization to the class template. + ClassTemplate->AddSpecialization(D2, InsertPos); + + // Import the qualifier, if any. + if (D->getQualifier()) { + NestedNameSpecifier *NNS = Importer.Import(D->getQualifier()); + SourceRange NNSRange = Importer.Import(D->getQualifierRange()); + D2->setQualifierInfo(NNS, NNSRange); + } + + + // Add the specialization to this context. + D2->setLexicalDeclContext(LexicalDC); + LexicalDC->addDecl(D2); + } + Importer.Imported(D, D2); + + if (D->isDefinition() && ImportDefinition(D, D2)) + return 0; + + return D2; +} + //---------------------------------------------------------------------------- // Import Statements //---------------------------------------------------------------------------- @@ -2811,7 +3761,7 @@ Expr *ASTNodeImporter::VisitDeclRefExpr(DeclRefExpr *E) { Importer.Import(E->getQualifierRange()), ToD, Importer.Import(E->getLocation()), - T, + T, E->getValueKind(), /*FIXME:TemplateArgs=*/0); } @@ -2856,7 +3806,8 @@ Expr *ASTNodeImporter::VisitUnaryOperator(UnaryOperator *E) { return 0; return new (Importer.getToContext()) UnaryOperator(SubExpr, E->getOpcode(), - T, + T, E->getValueKind(), + E->getObjectKind(), Importer.Import(E->getOperatorLoc())); } @@ -2898,7 +3849,8 @@ Expr *ASTNodeImporter::VisitBinaryOperator(BinaryOperator *E) { return 0; return new (Importer.getToContext()) BinaryOperator(LHS, RHS, E->getOpcode(), - T, + T, E->getValueKind(), + E->getObjectKind(), Importer.Import(E->getOperatorLoc())); } @@ -2925,7 +3877,9 @@ Expr *ASTNodeImporter::VisitCompoundAssignOperator(CompoundAssignOperator *E) { return new (Importer.getToContext()) CompoundAssignOperator(LHS, RHS, E->getOpcode(), - T, CompLHSType, CompResultType, + T, E->getValueKind(), + E->getObjectKind(), + CompLHSType, CompResultType, Importer.Import(E->getOperatorLoc())); } @@ -2970,18 +3924,20 @@ Expr *ASTNodeImporter::VisitCStyleCastExpr(CStyleCastExpr *E) { if (ImportCastPath(E, BasePath)) return 0; - return CStyleCastExpr::Create(Importer.getToContext(), T, E->getCastKind(), + return CStyleCastExpr::Create(Importer.getToContext(), T, + E->getValueKind(), E->getCastKind(), SubExpr, &BasePath, TInfo, Importer.Import(E->getLParenLoc()), Importer.Import(E->getRParenLoc())); } -ASTImporter::ASTImporter(Diagnostic &Diags, - ASTContext &ToContext, FileManager &ToFileManager, - ASTContext &FromContext, FileManager &FromFileManager) +ASTImporter::ASTImporter(ASTContext &ToContext, FileManager &ToFileManager, + ASTContext &FromContext, FileManager &FromFileManager, + bool MinimalImport) : ToContext(ToContext), FromContext(FromContext), ToFileManager(ToFileManager), FromFileManager(FromFileManager), - Diags(Diags) { + Minimal(MinimalImport) +{ ImportedDecls[FromContext.getTranslationUnitDecl()] = ToContext.getTranslationUnitDecl(); } @@ -2991,23 +3947,25 @@ ASTImporter::~ASTImporter() { } QualType ASTImporter::Import(QualType FromT) { if (FromT.isNull()) return QualType(); + + const Type *fromTy = FromT.getTypePtr(); // Check whether we've already imported this type. - llvm::DenseMap<Type *, Type *>::iterator Pos - = ImportedTypes.find(FromT.getTypePtr()); + llvm::DenseMap<const Type *, const Type *>::iterator Pos + = ImportedTypes.find(fromTy); if (Pos != ImportedTypes.end()) - return ToContext.getQualifiedType(Pos->second, FromT.getQualifiers()); + return ToContext.getQualifiedType(Pos->second, FromT.getLocalQualifiers()); // Import the type ASTNodeImporter Importer(*this); - QualType ToT = Importer.Visit(FromT.getTypePtr()); + QualType ToT = Importer.Visit(fromTy); if (ToT.isNull()) return ToT; // Record the imported type. - ImportedTypes[FromT.getTypePtr()] = ToT.getTypePtr(); + ImportedTypes[fromTy] = ToT.getTypePtr(); - return ToContext.getQualifiedType(ToT, FromT.getQualifiers()); + return ToContext.getQualifiedType(ToT, FromT.getLocalQualifiers()); } TypeSourceInfo *ASTImporter::Import(TypeSourceInfo *FromTSI) { @@ -3109,6 +4067,82 @@ NestedNameSpecifier *ASTImporter::Import(NestedNameSpecifier *FromNNS) { return 0; } +TemplateName ASTImporter::Import(TemplateName From) { + switch (From.getKind()) { + case TemplateName::Template: + if (TemplateDecl *ToTemplate + = cast_or_null<TemplateDecl>(Import(From.getAsTemplateDecl()))) + return TemplateName(ToTemplate); + + return TemplateName(); + + case TemplateName::OverloadedTemplate: { + OverloadedTemplateStorage *FromStorage = From.getAsOverloadedTemplate(); + UnresolvedSet<2> ToTemplates; + for (OverloadedTemplateStorage::iterator I = FromStorage->begin(), + E = FromStorage->end(); + I != E; ++I) { + if (NamedDecl *To = cast_or_null<NamedDecl>(Import(*I))) + ToTemplates.addDecl(To); + else + return TemplateName(); + } + return ToContext.getOverloadedTemplateName(ToTemplates.begin(), + ToTemplates.end()); + } + + case TemplateName::QualifiedTemplate: { + QualifiedTemplateName *QTN = From.getAsQualifiedTemplateName(); + NestedNameSpecifier *Qualifier = Import(QTN->getQualifier()); + if (!Qualifier) + return TemplateName(); + + if (TemplateDecl *ToTemplate + = cast_or_null<TemplateDecl>(Import(From.getAsTemplateDecl()))) + return ToContext.getQualifiedTemplateName(Qualifier, + QTN->hasTemplateKeyword(), + ToTemplate); + + return TemplateName(); + } + + case TemplateName::DependentTemplate: { + DependentTemplateName *DTN = From.getAsDependentTemplateName(); + NestedNameSpecifier *Qualifier = Import(DTN->getQualifier()); + if (!Qualifier) + return TemplateName(); + + if (DTN->isIdentifier()) { + return ToContext.getDependentTemplateName(Qualifier, + Import(DTN->getIdentifier())); + } + + return ToContext.getDependentTemplateName(Qualifier, DTN->getOperator()); + } + + case TemplateName::SubstTemplateTemplateParmPack: { + SubstTemplateTemplateParmPackStorage *SubstPack + = From.getAsSubstTemplateTemplateParmPack(); + TemplateTemplateParmDecl *Param + = cast_or_null<TemplateTemplateParmDecl>( + Import(SubstPack->getParameterPack())); + if (!Param) + return TemplateName(); + + ASTNodeImporter Importer(*this); + TemplateArgument ArgPack + = Importer.ImportTemplateArgument(SubstPack->getArgumentPack()); + if (ArgPack.isNull()) + return TemplateName(); + + return ToContext.getSubstTemplateTemplateParmPack(Param, ArgPack); + } + } + + llvm_unreachable("Invalid template name kind"); + return TemplateName(); +} + SourceLocation ASTImporter::Import(SourceLocation FromLoc) { if (FromLoc.isInvalid()) return SourceLocation(); @@ -3130,8 +4164,8 @@ SourceRange ASTImporter::Import(SourceRange FromRange) { } FileID ASTImporter::Import(FileID FromID) { - llvm::DenseMap<unsigned, FileID>::iterator Pos - = ImportedFileIDs.find(FromID.getHashValue()); + llvm::DenseMap<FileID, FileID>::iterator Pos + = ImportedFileIDs.find(FromID); if (Pos != ImportedFileIDs.end()) return Pos->second; @@ -3156,7 +4190,8 @@ FileID ASTImporter::Import(FileID FromID) { FromSLoc.getFile().getFileCharacteristic()); } else { // FIXME: We want to re-use the existing MemoryBuffer! - const llvm::MemoryBuffer *FromBuf = Cache->getBuffer(getDiags(), FromSM); + const llvm::MemoryBuffer * + FromBuf = Cache->getBuffer(FromContext.getDiagnostics(), FromSM); llvm::MemoryBuffer *ToBuf = llvm::MemoryBuffer::getMemBufferCopy(FromBuf->getBuffer(), FromBuf->getBufferIdentifier()); @@ -3164,10 +4199,21 @@ FileID ASTImporter::Import(FileID FromID) { } - ImportedFileIDs[FromID.getHashValue()] = ToID; + ImportedFileIDs[FromID] = ToID; return ToID; } +void ASTImporter::ImportDefinition(Decl *From) { + Decl *To = Import(From); + if (!To) + return; + + if (DeclContext *FromDC = cast<DeclContext>(From)) { + ASTNodeImporter Importer(*this); + Importer.ImportDeclContext(FromDC, true); + } +} + DeclarationName ASTImporter::Import(DeclarationName FromName) { if (!FromName) return DeclarationName(); @@ -3225,7 +4271,7 @@ DeclarationName ASTImporter::Import(DeclarationName FromName) { return DeclarationName(); } -IdentifierInfo *ASTImporter::Import(IdentifierInfo *FromId) { +IdentifierInfo *ASTImporter::Import(const IdentifierInfo *FromId) { if (!FromId) return 0; @@ -3252,13 +4298,11 @@ DeclarationName ASTImporter::HandleNameConflict(DeclarationName Name, } DiagnosticBuilder ASTImporter::ToDiag(SourceLocation Loc, unsigned DiagID) { - return Diags.Report(FullSourceLoc(Loc, ToContext.getSourceManager()), - DiagID); + return ToContext.getDiagnostics().Report(Loc, DiagID); } DiagnosticBuilder ASTImporter::FromDiag(SourceLocation Loc, unsigned DiagID) { - return Diags.Report(FullSourceLoc(Loc, FromContext.getSourceManager()), - DiagID); + return FromContext.getDiagnostics().Report(Loc, DiagID); } Decl *ASTImporter::Imported(Decl *From, Decl *To) { @@ -3267,12 +4311,11 @@ Decl *ASTImporter::Imported(Decl *From, Decl *To) { } bool ASTImporter::IsStructurallyEquivalent(QualType From, QualType To) { - llvm::DenseMap<Type *, Type *>::iterator Pos + llvm::DenseMap<const Type *, const Type *>::iterator Pos = ImportedTypes.find(From.getTypePtr()); if (Pos != ImportedTypes.end() && ToContext.hasSameType(Import(From), To)) return true; - StructuralEquivalenceContext Ctx(FromContext, ToContext, Diags, - NonEquivalentDecls); + StructuralEquivalenceContext Ctx(FromContext, ToContext, NonEquivalentDecls); return Ctx.IsStructurallyEquivalent(From, To); } diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt index 82a81ec..9fe1840 100644 --- a/lib/AST/CMakeLists.txt +++ b/lib/AST/CMakeLists.txt @@ -1,4 +1,6 @@ -set(LLVM_NO_RTTI 1) +set(LLVM_LINK_COMPONENTS support) + +set(LLVM_USED_LIBS clangBasic) add_clang_library(clangAST APValue.cpp @@ -17,14 +19,17 @@ add_clang_library(clangAST DeclObjC.cpp DeclPrinter.cpp DeclTemplate.cpp + DumpXML.cpp Expr.cpp ExprClassification.cpp ExprConstant.cpp ExprCXX.cpp - FullExpr.cpp InheritViz.cpp ItaniumCXXABI.cpp + ItaniumMangle.cpp + Mangle.cpp MicrosoftCXXABI.cpp + MicrosoftMangle.cpp NestedNameSpecifier.cpp ParentMap.cpp RecordLayout.cpp diff --git a/lib/AST/CXXABI.h b/lib/AST/CXXABI.h index 4b38d7a..943c43e 100644 --- a/lib/AST/CXXABI.h +++ b/lib/AST/CXXABI.h @@ -15,6 +15,8 @@ #ifndef LLVM_CLANG_AST_CXXABI_H #define LLVM_CLANG_AST_CXXABI_H +#include "clang/AST/Type.h" + namespace clang { class ASTContext; @@ -28,6 +30,13 @@ public: /// Returns the size of a member pointer in multiples of the target /// pointer size. virtual unsigned getMemberPointerSize(const MemberPointerType *MPT) const = 0; + + /// Returns the default calling convention for C++ methods. + virtual CallingConv getDefaultMethodCallConv() const = 0; + + // Returns whether the given class is nearly empty, with just virtual pointers + // and no data except possibly virtual bases. + virtual bool isNearlyEmpty(const CXXRecordDecl *RD) const = 0; }; /// Creates an instance of a C++ ABI class. diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp index c563c37..ca9ec18 100644 --- a/lib/AST/CXXInheritance.cpp +++ b/lib/AST/CXXInheritance.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// #include "clang/AST/CXXInheritance.h" +#include "clang/AST/RecordLayout.h" #include "clang/AST/DeclCXX.h" #include <algorithm> #include <set> @@ -75,18 +76,21 @@ void CXXBasePaths::swap(CXXBasePaths &Other) { std::swap(DetectedVirtual, Other.DetectedVirtual); } -bool CXXRecordDecl::isDerivedFrom(CXXRecordDecl *Base) const { +bool CXXRecordDecl::isDerivedFrom(const CXXRecordDecl *Base) const { CXXBasePaths Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/false, /*DetectVirtual=*/false); return isDerivedFrom(Base, Paths); } -bool CXXRecordDecl::isDerivedFrom(CXXRecordDecl *Base, CXXBasePaths &Paths) const { +bool CXXRecordDecl::isDerivedFrom(const CXXRecordDecl *Base, + CXXBasePaths &Paths) const { if (getCanonicalDecl() == Base->getCanonicalDecl()) return false; Paths.setOrigin(const_cast<CXXRecordDecl*>(this)); - return lookupInBases(&FindBaseClass, Base->getCanonicalDecl(), Paths); + return lookupInBases(&FindBaseClass, + const_cast<CXXRecordDecl*>(Base->getCanonicalDecl()), + Paths); } bool CXXRecordDecl::isVirtuallyDerivedFrom(CXXRecordDecl *Base) const { @@ -662,3 +666,50 @@ CXXRecordDecl::getFinalOverriders(CXXFinalOverriderMap &FinalOverriders) const { } } } + +static void +AddIndirectPrimaryBases(const CXXRecordDecl *RD, ASTContext &Context, + CXXIndirectPrimaryBaseSet& Bases) { + // If the record has a virtual primary base class, add it to our set. + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + if (Layout.isPrimaryBaseVirtual()) + Bases.insert(Layout.getPrimaryBase()); + + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + assert(!I->getType()->isDependentType() && + "Cannot get indirect primary bases for class with dependent bases."); + + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + // Only bases with virtual bases participate in computing the + // indirect primary virtual base classes. + if (BaseDecl->getNumVBases()) + AddIndirectPrimaryBases(BaseDecl, Context, Bases); + } + +} + +void +CXXRecordDecl::getIndirectPrimaryBases(CXXIndirectPrimaryBaseSet& Bases) const { + ASTContext &Context = getASTContext(); + + if (!getNumVBases()) + return; + + for (CXXRecordDecl::base_class_const_iterator I = bases_begin(), + E = bases_end(); I != E; ++I) { + assert(!I->getType()->isDependentType() && + "Cannot get indirect primary bases for class with dependent bases."); + + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + // Only bases with virtual bases participate in computing the + // indirect primary virtual base classes. + if (BaseDecl->getNumVBases()) + AddIndirectPrimaryBases(BaseDecl, Context, Bases); + } +} + diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index b7be02d..56db8c7 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -21,6 +21,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/PrettyPrinter.h" +#include "clang/AST/ASTMutationListener.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/Specifiers.h" @@ -32,35 +33,140 @@ using namespace clang; // NamedDecl Implementation //===----------------------------------------------------------------------===// +static const VisibilityAttr *GetExplicitVisibility(const Decl *d) { + // Use the most recent declaration of a variable. + if (const VarDecl *var = dyn_cast<VarDecl>(d)) + return var->getMostRecentDeclaration()->getAttr<VisibilityAttr>(); + + // Use the most recent declaration of a function, and also handle + // function template specializations. + if (const FunctionDecl *fn = dyn_cast<FunctionDecl>(d)) { + if (const VisibilityAttr *attr + = fn->getMostRecentDeclaration()->getAttr<VisibilityAttr>()) + return attr; + + // If the function is a specialization of a template with an + // explicit visibility attribute, use that. + if (FunctionTemplateSpecializationInfo *templateInfo + = fn->getTemplateSpecializationInfo()) + return templateInfo->getTemplate()->getTemplatedDecl() + ->getAttr<VisibilityAttr>(); + + return 0; + } + + // Otherwise, just check the declaration itself first. + if (const VisibilityAttr *attr = d->getAttr<VisibilityAttr>()) + return attr; + + // If there wasn't explicit visibility there, and this is a + // specialization of a class template, check for visibility + // on the pattern. + if (const ClassTemplateSpecializationDecl *spec + = dyn_cast<ClassTemplateSpecializationDecl>(d)) + return spec->getSpecializedTemplate()->getTemplatedDecl() + ->getAttr<VisibilityAttr>(); + + return 0; +} + +static Visibility GetVisibilityFromAttr(const VisibilityAttr *A) { + switch (A->getVisibility()) { + case VisibilityAttr::Default: + return DefaultVisibility; + case VisibilityAttr::Hidden: + return HiddenVisibility; + case VisibilityAttr::Protected: + return ProtectedVisibility; + } + return DefaultVisibility; +} + +typedef NamedDecl::LinkageInfo LinkageInfo; +typedef std::pair<Linkage,Visibility> LVPair; + +static LVPair merge(LVPair L, LVPair R) { + return LVPair(minLinkage(L.first, R.first), + minVisibility(L.second, R.second)); +} + +static LVPair merge(LVPair L, LinkageInfo R) { + return LVPair(minLinkage(L.first, R.linkage()), + minVisibility(L.second, R.visibility())); +} + +namespace { +/// Flags controlling the computation of linkage and visibility. +struct LVFlags { + bool ConsiderGlobalVisibility; + bool ConsiderVisibilityAttributes; + + LVFlags() : ConsiderGlobalVisibility(true), + ConsiderVisibilityAttributes(true) { + } + + /// \brief Returns a set of flags that is only useful for computing the + /// linkage, not the visibility, of a declaration. + static LVFlags CreateOnlyDeclLinkage() { + LVFlags F; + F.ConsiderGlobalVisibility = false; + F.ConsiderVisibilityAttributes = false; + return F; + } + + /// Returns a set of flags, otherwise based on these, which ignores + /// off all sources of visibility except template arguments. + LVFlags onlyTemplateVisibility() const { + LVFlags F = *this; + F.ConsiderGlobalVisibility = false; + F.ConsiderVisibilityAttributes = false; + return F; + } +}; +} // end anonymous namespace + /// \brief Get the most restrictive linkage for the types in the given /// template parameter list. -static Linkage -getLinkageForTemplateParameterList(const TemplateParameterList *Params) { - Linkage L = ExternalLinkage; +static LVPair +getLVForTemplateParameterList(const TemplateParameterList *Params) { + LVPair LV(ExternalLinkage, DefaultVisibility); for (TemplateParameterList::const_iterator P = Params->begin(), PEnd = Params->end(); P != PEnd; ++P) { - if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) + if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) { + if (NTTP->isExpandedParameterPack()) { + for (unsigned I = 0, N = NTTP->getNumExpansionTypes(); I != N; ++I) { + QualType T = NTTP->getExpansionType(I); + if (!T->isDependentType()) + LV = merge(LV, T->getLinkageAndVisibility()); + } + continue; + } + if (!NTTP->getType()->isDependentType()) { - L = minLinkage(L, NTTP->getType()->getLinkage()); + LV = merge(LV, NTTP->getType()->getLinkageAndVisibility()); continue; } + } if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(*P)) { - L = minLinkage(L, - getLinkageForTemplateParameterList(TTP->getTemplateParameters())); + LV = merge(LV, getLVForTemplateParameterList(TTP->getTemplateParameters())); } } - return L; + return LV; } +/// getLVForDecl - Get the linkage and visibility for the given declaration. +static LinkageInfo getLVForDecl(const NamedDecl *D, LVFlags F); + /// \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; +static LVPair getLVForTemplateArgumentList(const TemplateArgument *Args, + unsigned NumArgs, + LVFlags &F) { + LVPair LV(ExternalLinkage, DefaultVisibility); for (unsigned I = 0; I != NumArgs; ++I) { switch (Args[I].getKind()) { @@ -70,40 +176,43 @@ static Linkage getLinkageForTemplateArgumentList(const TemplateArgument *Args, break; case TemplateArgument::Type: - L = minLinkage(L, Args[I].getAsType()->getLinkage()); + LV = merge(LV, Args[I].getAsType()->getLinkageAndVisibility()); break; 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()); + // The decl can validly be null as the representation of nullptr + // arguments, valid only in C++0x. + if (Decl *D = Args[I].getAsDecl()) { + if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) + LV = merge(LV, getLVForDecl(ND, F)); + } break; case TemplateArgument::Template: - if (TemplateDecl *Template - = Args[I].getAsTemplate().getAsTemplateDecl()) - L = minLinkage(L, Template->getLinkage()); + case TemplateArgument::TemplateExpansion: + if (TemplateDecl *Template + = Args[I].getAsTemplateOrTemplatePattern().getAsTemplateDecl()) + LV = merge(LV, getLVForDecl(Template, F)); break; case TemplateArgument::Pack: - L = minLinkage(L, - getLinkageForTemplateArgumentList(Args[I].pack_begin(), - Args[I].pack_size())); + LV = merge(LV, getLVForTemplateArgumentList(Args[I].pack_begin(), + Args[I].pack_size(), + F)); break; } } - return L; + return LV; } -static Linkage -getLinkageForTemplateArgumentList(const TemplateArgumentList &TArgs) { - return getLinkageForTemplateArgumentList(TArgs.getFlatArgumentList(), - TArgs.flat_size()); +static LVPair +getLVForTemplateArgumentList(const TemplateArgumentList &TArgs, + LVFlags &F) { + return getLVForTemplateArgumentList(TArgs.data(), TArgs.size(), F); } -static Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) { +static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) { assert(D->getDeclContext()->getRedeclContext()->isFileContext() && "Not a name having namespace scope"); ASTContext &Context = D->getASTContext(); @@ -117,7 +226,7 @@ static Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) { if (const VarDecl *Var = dyn_cast<VarDecl>(D)) { // Explicitly declared static. if (Var->getStorageClass() == SC_Static) - return InternalLinkage; + return LinkageInfo::internal(); // - an object or reference that is explicitly declared const // and neither explicitly declared extern nor previously @@ -135,7 +244,7 @@ static Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) { FoundExtern = true; if (!FoundExtern) - return InternalLinkage; + return LinkageInfo::internal(); } } else if (isa<FunctionDecl>(D) || isa<FunctionTemplateDecl>(D)) { // C++ [temp]p4: @@ -150,23 +259,88 @@ static Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) { // Explicitly declared static. if (Function->getStorageClass() == SC_Static) - return InternalLinkage; + return LinkageInfo(InternalLinkage, DefaultVisibility, false); } else if (const FieldDecl *Field = dyn_cast<FieldDecl>(D)) { // - a data member of an anonymous union. if (cast<RecordDecl>(Field->getDeclContext())->isAnonymousStructOrUnion()) - return InternalLinkage; + return LinkageInfo::internal(); + } + + if (D->isInAnonymousNamespace()) + return LinkageInfo::uniqueExternal(); + + // Set up the defaults. + + // C99 6.2.2p5: + // If the declaration of an identifier for an object has file + // scope and no storage-class specifier, its linkage is + // external. + LinkageInfo LV; + + if (F.ConsiderVisibilityAttributes) { + if (const VisibilityAttr *VA = GetExplicitVisibility(D)) { + LV.setVisibility(GetVisibilityFromAttr(VA), true); + F.ConsiderGlobalVisibility = false; + } else { + // If we're declared in a namespace with a visibility attribute, + // use that namespace's visibility, but don't call it explicit. + for (const DeclContext *DC = D->getDeclContext(); + !isa<TranslationUnitDecl>(DC); + DC = DC->getParent()) { + if (!isa<NamespaceDecl>(DC)) continue; + if (const VisibilityAttr *VA = + cast<NamespaceDecl>(DC)->getAttr<VisibilityAttr>()) { + LV.setVisibility(GetVisibilityFromAttr(VA), false); + F.ConsiderGlobalVisibility = false; + break; + } + } + } } // C++ [basic.link]p4: - + // A name having namespace scope has external linkage if it is the // name of // // - an object or reference, unless it has internal linkage; or if (const VarDecl *Var = dyn_cast<VarDecl>(D)) { + // GCC applies the following optimization to variables and static + // data members, but not to functions: + // + // Modify the variable's LV by the LV of its type unless this is + // C or extern "C". This follows from [basic.link]p9: + // A type without linkage shall not be used as the type of a + // variable or function with external linkage unless + // - the entity has C language linkage, or + // - the entity is declared within an unnamed namespace, or + // - the entity is not used or is defined in the same + // translation unit. + // and [basic.link]p10: + // ...the types specified by all declarations referring to a + // given variable or function shall be identical... + // C does not have an equivalent rule. + // + // Ignore this if we've got an explicit attribute; the user + // probably knows what they're doing. + // + // Note that we don't want to make the variable non-external + // because of this, but unique-external linkage suits us. + if (Context.getLangOptions().CPlusPlus && !Var->isExternC()) { + LVPair TypeLV = Var->getType()->getLinkageAndVisibility(); + if (TypeLV.first != ExternalLinkage) + return LinkageInfo::uniqueExternal(); + if (!LV.visibilityExplicit()) + LV.mergeVisibility(TypeLV.second); + } + + if (Var->getStorageClass() == SC_PrivateExtern) + LV.setVisibility(HiddenVisibility, true); + if (!Context.getLangOptions().CPlusPlus && (Var->getStorageClass() == SC_Extern || Var->getStorageClass() == SC_PrivateExtern)) { + // C99 6.2.2p4: // For an identifier declared with the storage-class specifier // extern in a scope in which a prior declaration of that @@ -177,23 +351,22 @@ static 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 (Linkage L = PrevVar->getLinkage()) - return L; + LinkageInfo PrevLV = getLVForDecl(PrevVar, F); + if (PrevLV.linkage()) LV.setLinkage(PrevLV.linkage()); + LV.mergeVisibility(PrevLV); } } - // C99 6.2.2p5: - // If the declaration of an identifier for an object has file - // scope and no storage-class specifier, its linkage is - // external. - if (Var->isInAnonymousNamespace()) - return UniqueExternalLinkage; + // - a function, unless it has internal linkage; or + } else if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) { + // In theory, we can modify the function's LV by the LV of its + // type unless it has C linkage (see comment above about variables + // for justification). In practice, GCC doesn't do this, so it's + // just too painful to make work. - return ExternalLinkage; - } + if (Function->getStorageClass() == SC_PrivateExtern) + LV.setVisibility(HiddenVisibility, true); - // - a function, unless it has internal linkage; or - if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) { // C99 6.2.2p5: // If the declaration of an identifier for a function has no // storage-class specifier, its linkage is determined exactly @@ -213,141 +386,300 @@ static 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 (Linkage L = PrevFunc->getLinkage()) - return L; + LinkageInfo PrevLV = getLVForDecl(PrevFunc, F); + if (PrevLV.linkage()) LV.setLinkage(PrevLV.linkage()); + LV.mergeVisibility(PrevLV); } } - if (Function->isInAnonymousNamespace()) - return UniqueExternalLinkage; + // In C++, then if the type of the function uses a type with + // unique-external linkage, it's not legally usable from outside + // this translation unit. However, we should use the C linkage + // rules instead for extern "C" declarations. + if (Context.getLangOptions().CPlusPlus && !Function->isExternC() && + Function->getType()->getLinkage() == UniqueExternalLinkage) + return LinkageInfo::uniqueExternal(); if (FunctionTemplateSpecializationInfo *SpecInfo = Function->getTemplateSpecializationInfo()) { - Linkage L = SpecInfo->getTemplate()->getLinkage(); + LV.merge(getLVForDecl(SpecInfo->getTemplate(), + F.onlyTemplateVisibility())); const TemplateArgumentList &TemplateArgs = *SpecInfo->TemplateArguments; - L = minLinkage(L, getLinkageForTemplateArgumentList(TemplateArgs)); - return L; + LV.merge(getLVForTemplateArgumentList(TemplateArgs, F)); } - return ExternalLinkage; - } - // - a named class (Clause 9), or an unnamed class defined in a // typedef declaration in which the class has the typedef name // for linkage purposes (7.1.3); or // - a named enumeration (7.2), or an unnamed enumeration // 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()) { - 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); - return minLinkage(L, Spec->getSpecializedTemplate()->getLinkage()); - } + } else if (const TagDecl *Tag = dyn_cast<TagDecl>(D)) { + // Unnamed tags have no linkage. + if (!Tag->getDeclName() && !Tag->getTypedefForAnonDecl()) + return LinkageInfo::none(); + + // If this is a class template specialization, consider the + // linkage of the template and template arguments. + if (const ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(Tag)) { + // From the template. + LV.merge(getLVForDecl(Spec->getSpecializedTemplate(), + F.onlyTemplateVisibility())); - return ExternalLinkage; + // The arguments at which the template was instantiated. + const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); + LV.merge(getLVForTemplateArgumentList(TemplateArgs, F)); } + // Consider -fvisibility unless the type has C linkage. + if (F.ConsiderGlobalVisibility) + F.ConsiderGlobalVisibility = + (Context.getLangOptions().CPlusPlus && + !Tag->getDeclContext()->isExternCContext()); + // - an enumerator belonging to an enumeration with external linkage; - if (isa<EnumConstantDecl>(D)) { - Linkage L = cast<NamedDecl>(D->getDeclContext())->getLinkage(); - if (isExternalLinkage(L)) - return L; - } + } else if (isa<EnumConstantDecl>(D)) { + LinkageInfo EnumLV = getLVForDecl(cast<NamedDecl>(D->getDeclContext()), F); + if (!isExternalLinkage(EnumLV.linkage())) + return LinkageInfo::none(); + LV.merge(EnumLV); // - a template, unless it is a function template that has // internal linkage (Clause 14); - if (const TemplateDecl *Template = dyn_cast<TemplateDecl>(D)) { - if (D->isInAnonymousNamespace()) - return UniqueExternalLinkage; - - return getLinkageForTemplateParameterList( - Template->getTemplateParameters()); - } + } else if (const TemplateDecl *Template = dyn_cast<TemplateDecl>(D)) { + LV.merge(getLVForTemplateParameterList(Template->getTemplateParameters())); // - a namespace (7.3), unless it is declared within an unnamed // namespace. - if (isa<NamespaceDecl>(D) && !D->isInAnonymousNamespace()) - return ExternalLinkage; + } else if (isa<NamespaceDecl>(D) && !D->isInAnonymousNamespace()) { + return LV; + + // By extension, we assign external linkage to Objective-C + // interfaces. + } else if (isa<ObjCInterfaceDecl>(D)) { + // fallout - return NoLinkage; + // Everything not covered here has no linkage. + } else { + return LinkageInfo::none(); + } + + // If we ended up with non-external linkage, visibility should + // always be default. + if (LV.linkage() != ExternalLinkage) + return LinkageInfo(LV.linkage(), DefaultVisibility, false); + + // If we didn't end up with hidden visibility, consider attributes + // and -fvisibility. + if (F.ConsiderGlobalVisibility) + LV.mergeVisibility(Context.getLangOptions().getVisibilityMode()); + + return LV; } -static Linkage getLinkageForClassMember(const NamedDecl *D) { +static LinkageInfo getLVForClassMember(const NamedDecl *D, LVFlags F) { + // Only certain class members have linkage. Note that fields don't + // really have linkage, but it's convenient to say they do for the + // purposes of calculating linkage of pointer-to-data-member + // template arguments. if (!(isa<CXXMethodDecl>(D) || isa<VarDecl>(D) || + isa<FieldDecl>(D) || (isa<TagDecl>(D) && (D->getDeclName() || cast<TagDecl>(D)->getTypedefForAnonDecl())))) - return NoLinkage; + return LinkageInfo::none(); + + LinkageInfo LV; - // Class members only have linkage if their class has external linkage. - Linkage L = cast<RecordDecl>(D->getDeclContext())->getLinkage(); - if (!isExternalLinkage(L)) return NoLinkage; + // The flags we're going to use to compute the class's visibility. + LVFlags ClassF = F; + + // If we have an explicit visibility attribute, merge that in. + if (F.ConsiderVisibilityAttributes) { + if (const VisibilityAttr *VA = GetExplicitVisibility(D)) { + LV.mergeVisibility(GetVisibilityFromAttr(VA), true); + + // Ignore global visibility later, but not this attribute. + F.ConsiderGlobalVisibility = false; + + // Ignore both global visibility and attributes when computing our + // parent's visibility. + ClassF = F.onlyTemplateVisibility(); + } + } + + // Class members only have linkage if their class has external + // linkage. + LV.merge(getLVForDecl(cast<RecordDecl>(D->getDeclContext()), ClassF)); + if (!isExternalLinkage(LV.linkage())) + return LinkageInfo::none(); // If the class already has unique-external linkage, we can't improve. - if (L == UniqueExternalLinkage) return UniqueExternalLinkage; + if (LV.linkage() == UniqueExternalLinkage) + return LinkageInfo::uniqueExternal(); - // If this is a method template specialization, use the linkage for - // the template parameters and arguments. if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) { - if (FunctionTemplateSpecializationInfo *SpecInfo + // If the type of the function uses a type with unique-external + // linkage, it's not legally usable from outside this translation unit. + if (MD->getType()->getLinkage() == UniqueExternalLinkage) + return LinkageInfo::uniqueExternal(); + + TemplateSpecializationKind TSK = TSK_Undeclared; + + // If this is a method template specialization, use the linkage for + // the template parameters and arguments. + if (FunctionTemplateSpecializationInfo *Spec = MD->getTemplateSpecializationInfo()) { - Linkage ArgLinkage = - getLinkageForTemplateArgumentList(*SpecInfo->TemplateArguments); - Linkage ParamLinkage = - getLinkageForTemplateParameterList( - SpecInfo->getTemplate()->getTemplateParameters()); - return minLinkage(ArgLinkage, ParamLinkage); + LV.merge(getLVForTemplateArgumentList(*Spec->TemplateArguments, F)); + LV.merge(getLVForTemplateParameterList( + Spec->getTemplate()->getTemplateParameters())); + + TSK = Spec->getTemplateSpecializationKind(); + } else if (MemberSpecializationInfo *MSI = + MD->getMemberSpecializationInfo()) { + TSK = MSI->getTemplateSpecializationKind(); + } + + // If we're paying attention to global visibility, apply + // -finline-visibility-hidden if this is an inline method. + // + // Note that ConsiderGlobalVisibility doesn't yet have information + // about whether containing classes have visibility attributes, + // and that's intentional. + if (TSK != TSK_ExplicitInstantiationDeclaration && + F.ConsiderGlobalVisibility && + MD->getASTContext().getLangOptions().InlineVisibilityHidden) { + // InlineVisibilityHidden only applies to definitions, and + // isInlined() only gives meaningful answers on definitions + // anyway. + const FunctionDecl *Def = 0; + if (MD->hasBody(Def) && Def->isInlined()) + LV.setVisibility(HiddenVisibility); + } + + // Note that in contrast to basically every other situation, we + // *do* apply -fvisibility to method declarations. + + } else if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) { + if (const ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(RD)) { + // Merge template argument/parameter information for member + // class template specializations. + LV.merge(getLVForTemplateArgumentList(Spec->getTemplateArgs(), F)); + LV.merge(getLVForTemplateParameterList( + Spec->getSpecializedTemplate()->getTemplateParameters())); } - // Similarly for member class template specializations. - } else if (const ClassTemplateSpecializationDecl *Spec - = dyn_cast<ClassTemplateSpecializationDecl>(D)) { - Linkage ArgLinkage = - getLinkageForTemplateArgumentList(Spec->getTemplateArgs()); - Linkage ParamLinkage = - getLinkageForTemplateParameterList( - Spec->getSpecializedTemplate()->getTemplateParameters()); - return minLinkage(ArgLinkage, ParamLinkage); + // Static data members. + } else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { + // Modify the variable's linkage by its type, but ignore the + // type's visibility unless it's a definition. + LVPair TypeLV = VD->getType()->getLinkageAndVisibility(); + if (TypeLV.first != ExternalLinkage) + LV.mergeLinkage(UniqueExternalLinkage); + if (!LV.visibilityExplicit()) + LV.mergeVisibility(TypeLV.second); } - return ExternalLinkage; + F.ConsiderGlobalVisibility &= !LV.visibilityExplicit(); + + // Apply -fvisibility if desired. + if (F.ConsiderGlobalVisibility && LV.visibility() != HiddenVisibility) { + LV.mergeVisibility(D->getASTContext().getLangOptions().getVisibilityMode()); + } + + return LV; +} + +static void clearLinkageForClass(const CXXRecordDecl *record) { + for (CXXRecordDecl::decl_iterator + i = record->decls_begin(), e = record->decls_end(); i != e; ++i) { + Decl *child = *i; + if (isa<NamedDecl>(child)) + cast<NamedDecl>(child)->ClearLinkageCache(); + } +} + +void NamedDecl::ClearLinkageCache() { + // Note that we can't skip clearing the linkage of children just + // because the parent doesn't have cached linkage: we don't cache + // when computing linkage for parent contexts. + + HasCachedLinkage = 0; + + // If we're changing the linkage of a class, we need to reset the + // linkage of child declarations, too. + if (const CXXRecordDecl *record = dyn_cast<CXXRecordDecl>(this)) + clearLinkageForClass(record); + + if (ClassTemplateDecl *temp = + dyn_cast<ClassTemplateDecl>(const_cast<NamedDecl*>(this))) { + // Clear linkage for the template pattern. + CXXRecordDecl *record = temp->getTemplatedDecl(); + record->HasCachedLinkage = 0; + clearLinkageForClass(record); + + // We need to clear linkage for specializations, too. + for (ClassTemplateDecl::spec_iterator + i = temp->spec_begin(), e = temp->spec_end(); i != e; ++i) + i->ClearLinkageCache(); + } + + // Clear cached linkage for function template decls, too. + if (FunctionTemplateDecl *temp = + dyn_cast<FunctionTemplateDecl>(const_cast<NamedDecl*>(this))) + for (FunctionTemplateDecl::spec_iterator + i = temp->spec_begin(), e = temp->spec_end(); i != e; ++i) + i->ClearLinkageCache(); + } Linkage NamedDecl::getLinkage() const { + if (HasCachedLinkage) { + assert(Linkage(CachedLinkage) == + getLVForDecl(this, LVFlags::CreateOnlyDeclLinkage()).linkage()); + return Linkage(CachedLinkage); + } + + CachedLinkage = getLVForDecl(this, + LVFlags::CreateOnlyDeclLinkage()).linkage(); + HasCachedLinkage = 1; + return Linkage(CachedLinkage); +} +LinkageInfo NamedDecl::getLinkageAndVisibility() const { + LinkageInfo LI = getLVForDecl(this, LVFlags()); + assert(!HasCachedLinkage || Linkage(CachedLinkage) == LI.linkage()); + HasCachedLinkage = 1; + CachedLinkage = LI.linkage(); + return LI; +} + +static LinkageInfo getLVForDecl(const NamedDecl *D, LVFlags Flags) { // Objective-C: treat all Objective-C declarations as having external // linkage. - switch (getKind()) { + switch (D->getKind()) { default: break; + case Decl::TemplateTemplateParm: // count these as external + case Decl::NonTypeTemplateParm: case Decl::ObjCAtDefsField: case Decl::ObjCCategory: case Decl::ObjCCategoryImpl: - case Decl::ObjCClass: case Decl::ObjCCompatibleAlias: case Decl::ObjCForwardProtocol: case Decl::ObjCImplementation: - case Decl::ObjCInterface: - case Decl::ObjCIvar: case Decl::ObjCMethod: case Decl::ObjCProperty: case Decl::ObjCPropertyImpl: case Decl::ObjCProtocol: - return ExternalLinkage; + return LinkageInfo::external(); } // Handle linkage for namespace-scope names. - if (getDeclContext()->getRedeclContext()->isFileContext()) - if (Linkage L = getLinkageForNamespaceScopeDecl(this)) - return L; + if (D->getDeclContext()->getRedeclContext()->isFileContext()) + return getLVForNamespaceScopeDecl(D, Flags); // C++ [basic.link]p5: // In addition, a member function, static data member, a named @@ -356,8 +688,8 @@ Linkage NamedDecl::getLinkage() const { // that the class or enumeration has the typedef name for linkage // purposes (7.1.3), has external linkage if the name of the class // has external linkage. - if (getDeclContext()->isRecord()) - return getLinkageForClassMember(this); + if (D->getDeclContext()->isRecord()) + return getLVForClassMember(D, Flags); // C++ [basic.link]p6: // The name of a function declared in block scope and the name of @@ -370,36 +702,54 @@ Linkage NamedDecl::getLinkage() const { // one such matching entity, the program is ill-formed. Otherwise, // if no matching entity is found, the block scope entity receives // external linkage. - if (getLexicalDeclContext()->isFunctionOrMethod()) { - if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(this)) { - if (Function->getPreviousDeclaration()) - if (Linkage L = Function->getPreviousDeclaration()->getLinkage()) - return L; - + if (D->getLexicalDeclContext()->isFunctionOrMethod()) { + if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) { if (Function->isInAnonymousNamespace()) - return UniqueExternalLinkage; + return LinkageInfo::uniqueExternal(); - return ExternalLinkage; + LinkageInfo LV; + if (Flags.ConsiderVisibilityAttributes) { + if (const VisibilityAttr *VA = GetExplicitVisibility(Function)) + LV.setVisibility(GetVisibilityFromAttr(VA)); + } + + if (const FunctionDecl *Prev = Function->getPreviousDeclaration()) { + LinkageInfo PrevLV = getLVForDecl(Prev, Flags); + if (PrevLV.linkage()) LV.setLinkage(PrevLV.linkage()); + LV.mergeVisibility(PrevLV); + } + + return LV; } - if (const VarDecl *Var = dyn_cast<VarDecl>(this)) + if (const VarDecl *Var = dyn_cast<VarDecl>(D)) if (Var->getStorageClass() == SC_Extern || Var->getStorageClass() == SC_PrivateExtern) { - if (Var->getPreviousDeclaration()) - if (Linkage L = Var->getPreviousDeclaration()->getLinkage()) - return L; - if (Var->isInAnonymousNamespace()) - return UniqueExternalLinkage; + return LinkageInfo::uniqueExternal(); + + LinkageInfo LV; + if (Var->getStorageClass() == SC_PrivateExtern) + LV.setVisibility(HiddenVisibility); + else if (Flags.ConsiderVisibilityAttributes) { + if (const VisibilityAttr *VA = GetExplicitVisibility(Var)) + LV.setVisibility(GetVisibilityFromAttr(VA)); + } + + if (const VarDecl *Prev = Var->getPreviousDeclaration()) { + LinkageInfo PrevLV = getLVForDecl(Prev, Flags); + if (PrevLV.linkage()) LV.setLinkage(PrevLV.linkage()); + LV.mergeVisibility(PrevLV); + } - return ExternalLinkage; + return LV; } } // C++ [basic.link]p6: // Names not covered by these rules have no linkage. - return NoLinkage; - } + return LinkageInfo::none(); +} std::string NamedDecl::getQualifiedNameAsString() const { return getQualifiedNameAsString(getASTContext().getLangOptions()); @@ -430,8 +780,8 @@ std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const { const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); std::string TemplateArgsStr = TemplateSpecializationType::PrintTemplateArgumentList( - TemplateArgs.getFlatArgumentList(), - TemplateArgs.flat_size(), + TemplateArgs.data(), + TemplateArgs.size(), P); OS << Spec->getName() << TemplateArgsStr; } else if (const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(*I)) { @@ -514,6 +864,10 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD) const { return cast<UsingShadowDecl>(this)->getTargetDecl() == cast<UsingShadowDecl>(OldD)->getTargetDecl(); + if (isa<UsingDecl>(this) && isa<UsingDecl>(OldD)) + return cast<UsingDecl>(this)->getTargetNestedNameDecl() == + cast<UsingDecl>(OldD)->getTargetNestedNameDecl(); + // For non-function declarations, if the declarations are of the // same kind then this must be a redeclaration, or semantic analysis // would not have given us the new declaration. @@ -545,7 +899,7 @@ bool NamedDecl::isCXXInstanceMember() const { if (isa<UsingShadowDecl>(D)) D = cast<UsingShadowDecl>(D)->getTargetDecl(); - if (isa<FieldDecl>(D)) + if (isa<FieldDecl>(D) || isa<IndirectFieldDecl>(D)) return true; if (isa<CXXMethodDecl>(D)) return cast<CXXMethodDecl>(D)->isInstance(); @@ -655,6 +1009,14 @@ VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, return new (C) VarDecl(Var, DC, L, Id, T, TInfo, S, SCAsWritten); } +void VarDecl::setStorageClass(StorageClass SC) { + assert(isLegalForVariable(SC)); + if (getStorageClass() != SC) + ClearLinkageCache(); + + SClass = SC; +} + SourceLocation VarDecl::getInnerLocStart() const { SourceLocation Start = getTypeSpecStartLoc(); if (Start.isInvalid()) @@ -785,6 +1147,17 @@ VarDecl *VarDecl::getDefinition() { return 0; } +VarDecl::DefinitionKind VarDecl::hasDefinition() const { + DefinitionKind Kind = DeclarationOnly; + + const VarDecl *First = getFirstDeclaration(); + for (redecl_iterator I = First->redecls_begin(), E = First->redecls_end(); + I != E; ++I) + Kind = std::max(Kind, (*I)->isThisDeclarationADefinition()); + + return Kind; +} + const Expr *VarDecl::getAnyInitializer(const VarDecl *&D) const { redecl_iterator I = redecls_begin(), E = redecls_end(); while (I != E && !I->getInit()) @@ -883,15 +1256,14 @@ Expr *ParmVarDecl::getDefaultArg() { "Default argument is not yet instantiated!"); Expr *Arg = getInit(); - if (CXXExprWithTemporaries *E = dyn_cast_or_null<CXXExprWithTemporaries>(Arg)) + if (ExprWithCleanups *E = dyn_cast_or_null<ExprWithCleanups>(Arg)) return E->getSubExpr(); return Arg; } unsigned ParmVarDecl::getNumDefaultArgTemporaries() const { - if (const CXXExprWithTemporaries *E = - dyn_cast<CXXExprWithTemporaries>(getInit())) + if (const ExprWithCleanups *E = dyn_cast<ExprWithCleanups>(getInit())) return E->getNumTemporaries(); return 0; @@ -901,7 +1273,7 @@ CXXTemporary *ParmVarDecl::getDefaultArgTemporary(unsigned i) { assert(getNumDefaultArgTemporaries() && "Default arguments does not have any temporaries!"); - CXXExprWithTemporaries *E = cast<CXXExprWithTemporaries>(getInit()); + ExprWithCleanups *E = cast<ExprWithCleanups>(getInit()); return E->getTemporary(i); } @@ -915,6 +1287,10 @@ SourceRange ParmVarDecl::getDefaultArgRange() const { return SourceRange(); } +bool ParmVarDecl::isParameterPack() const { + return isa<PackExpansionType>(getType()); +} + //===----------------------------------------------------------------------===// // FunctionDecl Implementation //===----------------------------------------------------------------------===// @@ -926,8 +1302,8 @@ void FunctionDecl::getNameForDiagnostic(std::string &S, const TemplateArgumentList *TemplateArgs = getTemplateSpecializationArgs(); if (TemplateArgs) S += TemplateSpecializationType::PrintTemplateArgumentList( - TemplateArgs->getFlatArgumentList(), - TemplateArgs->flat_size(), + TemplateArgs->data(), + TemplateArgs->size(), Policy); } @@ -966,6 +1342,13 @@ void FunctionDecl::setBody(Stmt *B) { EndRangeLoc = B->getLocEnd(); } +void FunctionDecl::setPure(bool P) { + IsPure = P; + if (P) + if (CXXRecordDecl *Parent = dyn_cast<CXXRecordDecl>(getDeclContext())) + Parent->markedVirtualFunctionPure(); +} + bool FunctionDecl::isMain() const { ASTContext &Context = getASTContext(); return !Context.getLangOptions().Freestanding && @@ -994,7 +1377,7 @@ bool FunctionDecl::isExternC() const { break; } - return false; + return isMain(); } bool FunctionDecl::isGlobal() const { @@ -1027,6 +1410,9 @@ FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) { assert((!PrevDecl || PrevFunTmpl) && "Function/function template mismatch"); FunTmpl->setPreviousDeclaration(PrevFunTmpl); } + + if (PrevDecl->IsInline) + IsInline = true; } const FunctionDecl *FunctionDecl::getCanonicalDecl() const { @@ -1037,6 +1423,14 @@ FunctionDecl *FunctionDecl::getCanonicalDecl() { return getFirstDeclaration(); } +void FunctionDecl::setStorageClass(StorageClass SC) { + assert(isLegalForFunction(SC)); + if (getStorageClass() != SC) + ClearLinkageCache(); + + SClass = SC; +} + /// \brief Returns a value indicating whether this function /// corresponds to a builtin function. /// @@ -1083,7 +1477,7 @@ unsigned FunctionDecl::getBuiltinID() const { /// getNumParams - Return the number of parameters this function must have -/// based on its FunctionType. This is the length of the PararmInfo array +/// based on its FunctionType. This is the length of the ParamInfo array /// after it has been created. unsigned FunctionDecl::getNumParams() const { const FunctionType *FT = getType()->getAs<FunctionType>(); @@ -1093,13 +1487,14 @@ unsigned FunctionDecl::getNumParams() const { } -void FunctionDecl::setParams(ParmVarDecl **NewParamInfo, unsigned NumParams) { +void FunctionDecl::setParams(ASTContext &C, + 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 = getASTContext().Allocate(sizeof(ParmVarDecl*)*NumParams); + void *Mem = C.Allocate(sizeof(ParmVarDecl*)*NumParams); ParamInfo = new (Mem) ParmVarDecl*[NumParams]; memcpy(ParamInfo, NewParamInfo, sizeof(ParmVarDecl*)*NumParams); @@ -1113,25 +1508,40 @@ void FunctionDecl::setParams(ParmVarDecl **NewParamInfo, unsigned NumParams) { /// getMinRequiredArguments - Returns the minimum number of arguments /// needed to call this function. This may be fewer than the number of /// function parameters, if some of the parameters have default -/// arguments (in C++). +/// arguments (in C++) or the last parameter is a parameter pack. unsigned FunctionDecl::getMinRequiredArguments() const { - unsigned NumRequiredArgs = getNumParams(); - while (NumRequiredArgs > 0 - && getParamDecl(NumRequiredArgs-1)->hasDefaultArg()) + if (!getASTContext().getLangOptions().CPlusPlus) + return getNumParams(); + + unsigned NumRequiredArgs = getNumParams(); + + // If the last parameter is a parameter pack, we don't need an argument for + // it. + if (NumRequiredArgs > 0 && + getParamDecl(NumRequiredArgs - 1)->isParameterPack()) + --NumRequiredArgs; + + // If this parameter has a default argument, we don't need an argument for + // it. + while (NumRequiredArgs > 0 && + getParamDecl(NumRequiredArgs-1)->hasDefaultArg()) --NumRequiredArgs; + // We might have parameter packs before the end. These can't be deduced, + // but they can still handle multiple arguments. + unsigned ArgIdx = NumRequiredArgs; + while (ArgIdx > 0) { + if (getParamDecl(ArgIdx - 1)->isParameterPack()) + NumRequiredArgs = ArgIdx; + + --ArgIdx; + } + return NumRequiredArgs; } bool FunctionDecl::isInlined() const { - // FIXME: This is not enough. Consider: - // - // inline void f(); - // void f() { } - // - // f is inlined, but does not have inline specified. - // To fix this we should add an 'inline' flag to FunctionDecl. - if (isInlineSpecified()) + if (IsInline) return true; if (isa<CXXMethodDecl>(this)) { @@ -1185,20 +1595,22 @@ bool FunctionDecl::isInlineDefinitionExternallyVisible() const { ASTContext &Context = getASTContext(); if (!Context.getLangOptions().C99 || hasAttr<GNUInlineAttr>()) { - // GNU inline semantics. Based on a number of examples, we came up with the - // following heuristic: if the "inline" keyword is present on a - // declaration of the function but "extern" is not present on that - // declaration, then the symbol is externally visible. Otherwise, the GNU - // "extern inline" semantics applies and the symbol is not externally - // visible. + // If it's not the case that both 'inline' and 'extern' are + // specified on the definition, then this inline definition is + // externally visible. + if (!(isInlineSpecified() && getStorageClassAsWritten() == SC_Extern)) + return true; + + // If any declaration is 'inline' but not 'extern', then this definition + // is externally visible. for (redecl_iterator Redecl = redecls_begin(), RedeclEnd = redecls_end(); Redecl != RedeclEnd; ++Redecl) { - if (Redecl->isInlineSpecified() && Redecl->getStorageClass() != SC_Extern) + if (Redecl->isInlineSpecified() && + Redecl->getStorageClassAsWritten() != SC_Extern) return true; - } + } - // GNU "extern inline" semantics; no externally visible symbol. return false; } @@ -1271,12 +1683,13 @@ MemberSpecializationInfo *FunctionDecl::getMemberSpecializationInfo() const { } void -FunctionDecl::setInstantiationOfMemberFunction(FunctionDecl *FD, +FunctionDecl::setInstantiationOfMemberFunction(ASTContext &C, + FunctionDecl *FD, TemplateSpecializationKind TSK) { assert(TemplateOrSpecialization.isNull() && "Member function is already a specialization"); MemberSpecializationInfo *Info - = new (getASTContext()) MemberSpecializationInfo(FD, TSK); + = new (C) MemberSpecializationInfo(FD, TSK); TemplateOrSpecialization = Info; } @@ -1362,7 +1775,8 @@ FunctionDecl::getTemplateSpecializationArgsAsWritten() const { } void -FunctionDecl::setFunctionTemplateSpecialization(FunctionTemplateDecl *Template, +FunctionDecl::setFunctionTemplateSpecialization(ASTContext &C, + FunctionTemplateDecl *Template, const TemplateArgumentList *TemplateArgs, void *InsertPos, TemplateSpecializationKind TSK, @@ -1373,14 +1787,10 @@ FunctionDecl::setFunctionTemplateSpecialization(FunctionTemplateDecl *Template, FunctionTemplateSpecializationInfo *Info = TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>(); if (!Info) - Info = new (getASTContext()) FunctionTemplateSpecializationInfo; - - Info->Function = this; - Info->Template.setPointer(Template); - Info->Template.setInt(TSK - 1); - Info->TemplateArguments = TemplateArgs; - Info->TemplateArgumentsAsWritten = TemplateArgsAsWritten; - Info->PointOfInstantiation = PointOfInstantiation; + Info = FunctionTemplateSpecializationInfo::Create(C, this, Template, TSK, + TemplateArgs, + TemplateArgsAsWritten, + PointOfInstantiation); TemplateOrSpecialization = Info; // Insert this function template specialization into the set of known @@ -1401,28 +1811,6 @@ FunctionDecl::setFunctionTemplateSpecialization(FunctionTemplateDecl *Template, } void -FunctionDecl::setFunctionTemplateSpecialization(FunctionTemplateDecl *Template, - unsigned NumTemplateArgs, - const TemplateArgument *TemplateArgs, - TemplateSpecializationKind TSK, - unsigned NumTemplateArgsAsWritten, - TemplateArgumentLoc *TemplateArgsAsWritten, - SourceLocation LAngleLoc, - SourceLocation RAngleLoc, - SourceLocation PointOfInstantiation) { - ASTContext &Ctx = getASTContext(); - TemplateArgumentList *TemplArgs - = new (Ctx) TemplateArgumentList(Ctx, TemplateArgs, NumTemplateArgs); - TemplateArgumentListInfo *TemplArgsInfo - = new (Ctx) TemplateArgumentListInfo(LAngleLoc, RAngleLoc); - for (unsigned i=0; i != NumTemplateArgsAsWritten; ++i) - TemplArgsInfo->addArgument(TemplateArgsAsWritten[i]); - - setFunctionTemplateSpecialization(Template, TemplArgs, /*InsertPos=*/0, TSK, - TemplArgsInfo, PointOfInstantiation); -} - -void FunctionDecl::setDependentTemplateSpecialization(ASTContext &Context, const UnresolvedSetImpl &Templates, const TemplateArgumentListInfo &TemplateArgs) { @@ -1533,8 +1921,8 @@ bool FunctionDecl::isOutOfLine() const { // FieldDecl Implementation //===----------------------------------------------------------------------===// -FieldDecl *FieldDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, - IdentifierInfo *Id, QualType T, +FieldDecl *FieldDecl::Create(const 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); } @@ -1549,6 +1937,25 @@ bool FieldDecl::isAnonymousStructOrUnion() const { return false; } +unsigned FieldDecl::getFieldIndex() const { + if (CachedFieldIndex) return CachedFieldIndex - 1; + + unsigned index = 0; + RecordDecl::field_iterator + i = getParent()->field_begin(), e = getParent()->field_end(); + while (true) { + assert(i != e && "failed to find field in parent!"); + if (*i == this) + break; + + ++i; + ++index; + } + + CachedFieldIndex = index + 1; + return index; +} + //===----------------------------------------------------------------------===// // TagDecl Implementation //===----------------------------------------------------------------------===// @@ -1569,7 +1976,8 @@ TagDecl* TagDecl::getCanonicalDecl() { void TagDecl::setTypedefForAnonDecl(TypedefDecl *TDD) { TypedefDeclOrQualifier = TDD; if (TypeForDecl) - TypeForDecl->ClearLinkageCache(); + const_cast<Type*>(TypeForDecl)->ClearLinkageCache(); + ClearLinkageCache(); } void TagDecl::startDefinition() { @@ -1591,11 +1999,16 @@ void TagDecl::completeDefinition() { IsDefinition = true; IsBeingDefined = false; + + if (ASTMutationListener *L = getASTMutationListener()) + L->CompletedTagDefinition(this); } TagDecl* TagDecl::getDefinition() const { if (isDefinition()) return const_cast<TagDecl *>(this); + if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(this)) + return CXXRD->getDefinition(); for (redecl_iterator R = redecls_begin(), REnd = redecls_end(); R != REnd; ++R) @@ -1631,14 +2044,17 @@ void TagDecl::setQualifierInfo(NestedNameSpecifier *Qualifier, 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); + EnumDecl *PrevDecl, bool IsScoped, + bool IsScopedUsingClassTag, bool IsFixed) { + EnumDecl *Enum = new (C) EnumDecl(DC, L, Id, PrevDecl, TKL, + IsScoped, IsScopedUsingClassTag, IsFixed); C.getTypeDeclType(Enum, PrevDecl); return Enum; } EnumDecl *EnumDecl::Create(ASTContext &C, EmptyShell Empty) { - return new (C) EnumDecl(0, SourceLocation(), 0, 0, SourceLocation()); + return new (C) EnumDecl(0, SourceLocation(), 0, 0, SourceLocation(), + false, false, false); } void EnumDecl::completeDefinition(QualType NewType, @@ -1646,7 +2062,8 @@ void EnumDecl::completeDefinition(QualType NewType, unsigned NumPositiveBits, unsigned NumNegativeBits) { assert(!isDefinition() && "Cannot redefine enums!"); - IntegerType = NewType; + if (!IntegerType) + IntegerType = NewType.getTypePtr(); PromotionType = NewPromotionType; setNumPositiveBits(NumPositiveBits); setNumNegativeBits(NumNegativeBits); @@ -1664,10 +2081,11 @@ RecordDecl::RecordDecl(Kind DK, TagKind TK, DeclContext *DC, SourceLocation L, HasFlexibleArrayMember = false; AnonymousStructOrUnion = false; HasObjectMember = false; + LoadedFieldsFromExternalStorage = false; assert(classof(static_cast<Decl*>(this)) && "Invalid Kind!"); } -RecordDecl *RecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC, +RecordDecl *RecordDecl::Create(const ASTContext &C, TagKind TK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, SourceLocation TKL, RecordDecl* PrevDecl) { @@ -1676,7 +2094,7 @@ RecordDecl *RecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC, return R; } -RecordDecl *RecordDecl::Create(ASTContext &C, EmptyShell Empty) { +RecordDecl *RecordDecl::Create(const ASTContext &C, EmptyShell Empty) { return new (C) RecordDecl(Record, TTK_Struct, 0, SourceLocation(), 0, 0, SourceLocation()); } @@ -1686,6 +2104,13 @@ bool RecordDecl::isInjectedClassName() const { cast<RecordDecl>(getDeclContext())->getDeclName() == getDeclName(); } +RecordDecl::field_iterator RecordDecl::field_begin() const { + if (hasExternalLexicalStorage() && !LoadedFieldsFromExternalStorage) + LoadFieldsFromExternalStorage(); + + return field_iterator(decl_iterator(FirstDecl)); +} + /// completeDefinition - Notes that the definition of this type is now /// complete. void RecordDecl::completeDefinition() { @@ -1693,15 +2118,29 @@ void RecordDecl::completeDefinition() { TagDecl::completeDefinition(); } -ValueDecl *RecordDecl::getAnonymousStructOrUnionObject() { - // Force the decl chain to come into existence properly. - if (!getNextDeclInContext()) getParent()->decls_begin(); +void RecordDecl::LoadFieldsFromExternalStorage() const { + ExternalASTSource *Source = getASTContext().getExternalSource(); + assert(hasExternalLexicalStorage() && Source && "No external storage?"); + + // Notify that we have a RecordDecl doing some initialization. + ExternalASTSource::Deserializing TheFields(Source); - assert(isAnonymousStructOrUnion()); - ValueDecl *D = cast<ValueDecl>(getNextDeclInContext()); - assert(D->getType()->isRecordType()); - assert(D->getType()->getAs<RecordType>()->getDecl() == this); - return D; + llvm::SmallVector<Decl*, 64> Decls; + if (Source->FindExternalLexicalDeclsBy<FieldDecl>(this, Decls)) + return; + +#ifndef NDEBUG + // Check that all decls we got were FieldDecls. + for (unsigned i=0, e=Decls.size(); i != e; ++i) + assert(isa<FieldDecl>(Decls[i])); +#endif + + LoadedFieldsFromExternalStorage = true; + + if (Decls.empty()) + return; + + llvm::tie(FirstDecl, LastDecl) = BuildDeclChain(Decls); } //===----------------------------------------------------------------------===// @@ -1721,10 +2160,31 @@ void BlockDecl::setParams(ParmVarDecl **NewParamInfo, } } -unsigned BlockDecl::getNumParams() const { - return NumParams; +void BlockDecl::setCaptures(ASTContext &Context, + const Capture *begin, + const Capture *end, + bool capturesCXXThis) { + CapturesCXXThis = capturesCXXThis; + + if (begin == end) { + NumCaptures = 0; + Captures = 0; + return; + } + + NumCaptures = end - begin; + + // Avoid new Capture[] because we don't want to provide a default + // constructor. + size_t allocationSize = NumCaptures * sizeof(Capture); + void *buffer = Context.Allocate(allocationSize, /*alignment*/sizeof(void*)); + memcpy(buffer, begin, allocationSize); + Captures = static_cast<Capture*>(buffer); } +SourceRange BlockDecl::getSourceRange() const { + return SourceRange(getLocation(), Body? Body->getLocEnd() : getLocation()); +} //===----------------------------------------------------------------------===// // Other Decl Allocation/Deallocation Method Implementations @@ -1734,11 +2194,22 @@ TranslationUnitDecl *TranslationUnitDecl::Create(ASTContext &C) { return new (C) TranslationUnitDecl(C); } +LabelDecl *LabelDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, IdentifierInfo *II) { + return new (C) LabelDecl(DC, L, II, 0); +} + + NamespaceDecl *NamespaceDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id) { return new (C) NamespaceDecl(DC, L, Id); } +NamespaceDecl *NamespaceDecl::getNextNamespace() { + return dyn_cast_or_null<NamespaceDecl>( + NextNamespace.get(getASTContext().getExternalSource())); +} + ImplicitParamDecl *ImplicitParamDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, QualType T) { return new (C) ImplicitParamDecl(ImplicitParam, DC, L, Id, T); @@ -1748,9 +2219,10 @@ FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, StorageClass S, StorageClass SCAsWritten, - bool isInline, bool hasWrittenPrototype) { + bool isInlineSpecified, + bool hasWrittenPrototype) { FunctionDecl *New = new (C) FunctionDecl(Function, DC, NameInfo, T, TInfo, - S, SCAsWritten, isInline); + S, SCAsWritten, isInlineSpecified); New->HasWrittenPrototype = hasWrittenPrototype; return New; } @@ -1766,6 +2238,13 @@ EnumConstantDecl *EnumConstantDecl::Create(ASTContext &C, EnumDecl *CD, return new (C) EnumConstantDecl(CD, L, Id, T, E, V); } +IndirectFieldDecl * +IndirectFieldDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, + IdentifierInfo *Id, QualType T, NamedDecl **CH, + unsigned CHS) { + return new (C) IndirectFieldDecl(DC, L, Id, T, CH, CHS); +} + SourceRange EnumConstantDecl::getSourceRange() const { SourceLocation End = getLocation(); if (Init) diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index 0b958fe..be379d5 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -24,6 +24,7 @@ #include "clang/AST/Type.h" #include "clang/AST/Stmt.h" #include "clang/AST/StmtCXX.h" +#include "clang/AST/ASTMutationListener.h" #include "llvm/ADT/DenseMap.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> @@ -109,10 +110,22 @@ void Decl::add(Kind k) { bool Decl::isTemplateParameterPack() const { if (const TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(this)) return TTP->isParameterPack(); - + if (const NonTypeTemplateParmDecl *NTTP + = dyn_cast<NonTypeTemplateParmDecl>(this)) + return NTTP->isParameterPack(); + if (const TemplateTemplateParmDecl *TTP + = dyn_cast<TemplateTemplateParmDecl>(this)) + return TTP->isParameterPack(); return false; } +bool Decl::isParameterPack() const { + if (const ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(this)) + return Parm->isParameterPack(); + + return isTemplateParameterPack(); +} + bool Decl::isFunctionOrFunctionTemplate() const { if (const UsingShadowDecl *UD = dyn_cast<UsingShadowDecl>(this)) return UD->getTargetDecl()->isFunctionOrFunctionTemplate(); @@ -210,6 +223,10 @@ ASTContext &Decl::getASTContext() const { return getTranslationUnitDecl()->getASTContext(); } +ASTMutationListener *Decl::getASTMutationListener() const { + return getASTContext().getASTMutationListener(); +} + bool Decl::isUsed(bool CheckUsedAttr) const { if (Used) return true; @@ -243,6 +260,10 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case ObjCMethod: case ObjCProperty: return IDNS_Ordinary; + case Label: + return IDNS_Label; + case IndirectField: + return IDNS_Ordinary | IDNS_Member; case ObjCCompatibleAlias: case ObjCInterface: @@ -416,27 +437,34 @@ SourceLocation Decl::getBodyRBrace() const { return SourceLocation(); } -#ifndef NDEBUG void Decl::CheckAccessDeclContext() const { - // FIXME: Disable this until rdar://8146294 "access specifier for inner class - // templates is not set or checked" is fixed. - return; +#ifndef NDEBUG // Suppress this check if any of the following hold: // 1. this is the translation unit (and thus has no parent) // 2. this is a template parameter (and thus doesn't belong to its context) - // 3. the context is not a record - // 4. it's invalid + // 3. this is a non-type template parameter + // 4. the context is not a record + // 5. it's invalid + // 6. it's a C++0x static_assert. if (isa<TranslationUnitDecl>(this) || isa<TemplateTypeParmDecl>(this) || + isa<NonTypeTemplateParmDecl>(this) || !isa<CXXRecordDecl>(getDeclContext()) || - isInvalidDecl()) + isInvalidDecl() || + isa<StaticAssertDecl>(this) || + // FIXME: a ParmVarDecl can have ClassTemplateSpecialization + // as DeclContext (?). + isa<ParmVarDecl>(this) || + // FIXME: a ClassTemplateSpecialization or CXXRecordDecl can have + // AS_none as access specifier. + isa<CXXRecordDecl>(this)) return; assert(Access != AS_none && "Access specifier is AS_none inside a record decl"); +#endif } -#endif //===----------------------------------------------------------------------===// // DeclContext Implementation @@ -509,15 +537,24 @@ bool DeclContext::isDependentContext() const { bool DeclContext::isTransparentContext() const { if (DeclKind == Decl::Enum) - return true; // FIXME: Check for C++0x scoped enums + return !cast<EnumDecl>(this)->isScoped(); else if (DeclKind == Decl::LinkageSpec) return true; - else if (DeclKind >= Decl::firstRecord && DeclKind <= Decl::lastRecord) - return cast<RecordDecl>(this)->isAnonymousStructOrUnion(); return false; } +bool DeclContext::isExternCContext() const { + const DeclContext *DC = this; + while (DC->DeclKind != Decl::TranslationUnit) { + if (DC->DeclKind == Decl::LinkageSpec) + return cast<LinkageSpecDecl>(DC)->getLanguage() + == LinkageSpecDecl::lang_c; + DC = DC->getParent(); + } + return false; +} + bool DeclContext::Encloses(const DeclContext *DC) const { if (getPrimaryContext() != this) return getPrimaryContext()->Encloses(DC); @@ -592,6 +629,24 @@ DeclContext *DeclContext::getNextContext() { } } +std::pair<Decl *, Decl *> +DeclContext::BuildDeclChain(const llvm::SmallVectorImpl<Decl*> &Decls) { + // Build up a chain of declarations via the Decl::NextDeclInContext field. + Decl *FirstNewDecl = 0; + Decl *PrevDecl = 0; + for (unsigned I = 0, N = Decls.size(); I != N; ++I) { + Decl *D = Decls[I]; + if (PrevDecl) + PrevDecl->NextDeclInContext = D; + else + FirstNewDecl = D; + + PrevDecl = D; + } + + return std::make_pair(FirstNewDecl, PrevDecl); +} + /// \brief Load the declarations within this lexical storage from an /// external source. void @@ -612,26 +667,22 @@ DeclContext::LoadLexicalDeclsFromExternalStorage() const { if (Decls.empty()) return; - // Resolve all of the declaration IDs into declarations, building up - // a chain of declarations via the Decl::NextDeclInContext field. - Decl *FirstNewDecl = 0; - Decl *PrevDecl = 0; - for (unsigned I = 0, N = Decls.size(); I != N; ++I) { - Decl *D = Decls[I]; - if (PrevDecl) - PrevDecl->NextDeclInContext = D; - else - FirstNewDecl = D; - - PrevDecl = D; - } + // We may have already loaded just the fields of this record, in which case + // don't add the decls, just replace the FirstDecl/LastDecl chain. + if (const RecordDecl *RD = dyn_cast<RecordDecl>(this)) + if (RD->LoadedFieldsFromExternalStorage) { + llvm::tie(FirstDecl, LastDecl) = BuildDeclChain(Decls); + return; + } // Splice the newly-read declarations into the beginning of the list // of declarations. - PrevDecl->NextDeclInContext = FirstDecl; - FirstDecl = FirstNewDecl; + Decl *ExternalFirst, *ExternalLast; + llvm::tie(ExternalFirst, ExternalLast) = BuildDeclChain(Decls); + ExternalLast->NextDeclInContext = FirstDecl; + FirstDecl = ExternalFirst; if (!LastDecl) - LastDecl = PrevDecl; + LastDecl = ExternalLast; } DeclContext::lookup_result @@ -771,6 +822,11 @@ void DeclContext::addHiddenDecl(Decl *D) { } else { FirstDecl = LastDecl = D; } + + // Notify a C++ record declaration that we've added a member, so it can + // update it's class-specific state. + if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(this)) + Record->addedMember(D); } void DeclContext::addDecl(Decl *D) { @@ -911,6 +967,12 @@ void DeclContext::makeDeclVisibleInContext(NamedDecl *D, bool Recoverable) { // parent context, too. This operation is recursive. if (isTransparentContext() || isInlineNamespace()) getParent()->makeDeclVisibleInContext(D, Recoverable); + + Decl *DCAsDecl = cast<Decl>(this); + // Notify that a decl was made visible unless it's a Tag being defined. + if (!(isa<TagDecl>(DCAsDecl) && cast<TagDecl>(DCAsDecl)->isBeingDefined())) + if (ASTMutationListener *L = DCAsDecl->getASTMutationListener()) + L->AddedVisibleDecl(this, D); } void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D) { diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index f2f0694..fba73f5 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -14,6 +14,8 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/ASTMutationListener.h" +#include "clang/AST/CXXInheritance.h" #include "clang/AST/Expr.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/IdentifierTable.h" @@ -34,8 +36,8 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D) HasTrivialDestructor(true), ComputedVisibleConversions(false), DeclaredDefaultConstructor(false), DeclaredCopyConstructor(false), DeclaredCopyAssignment(false), DeclaredDestructor(false), - Bases(0), NumBases(0), VBases(0), NumVBases(0), - Definition(D), FirstFriend(0) { + NumBases(0), NumVBases(0), Bases(), VBases(), + Definition(D), FirstFriend(0) { } CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC, @@ -46,9 +48,9 @@ CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC, DefinitionData(PrevDecl ? PrevDecl->DefinitionData : 0), TemplateOrInstantiation() { } -CXXRecordDecl *CXXRecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC, - SourceLocation L, IdentifierInfo *Id, - SourceLocation TKL, +CXXRecordDecl *CXXRecordDecl::Create(const ASTContext &C, TagKind TK, + DeclContext *DC, SourceLocation L, + IdentifierInfo *Id, SourceLocation TKL, CXXRecordDecl* PrevDecl, bool DelayTypeCreation) { CXXRecordDecl* R = new (C) CXXRecordDecl(CXXRecord, TK, DC, L, Id, @@ -60,7 +62,7 @@ CXXRecordDecl *CXXRecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC, return R; } -CXXRecordDecl *CXXRecordDecl::Create(ASTContext &C, EmptyShell Empty) { +CXXRecordDecl *CXXRecordDecl::Create(const ASTContext &C, EmptyShell Empty) { return new (C) CXXRecordDecl(CXXRecord, TTK_Struct, 0, SourceLocation(), 0, 0, SourceLocation()); } @@ -75,8 +77,8 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, // no base classes [...]. data().Aggregate = false; - if (data().Bases) - C.Deallocate(data().Bases); + if (!data().Bases.isOffset() && data().NumBases > 0) + C.Deallocate(data().getBases()); // The set of seen virtual base types. llvm::SmallPtrSet<CanQualType, 8> SeenVBaseTypes; @@ -87,7 +89,7 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, data().Bases = new(C) CXXBaseSpecifier [NumBases]; data().NumBases = NumBases; for (unsigned i = 0; i < NumBases; ++i) { - data().Bases[i] = *Bases[i]; + data().getBases()[i] = *Bases[i]; // Keep track of inherited vbases for this base class. const CXXBaseSpecifier *Base = Bases[i]; QualType BaseType = Base->getType(); @@ -97,6 +99,25 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl()); + // C++ [dcl.init.aggr]p1: + // An aggregate is [...] a class with [...] no base classes [...]. + data().Aggregate = false; + + // C++ [class]p4: + // A POD-struct is an aggregate class... + data().PlainOldData = false; + + // A class with a non-empty base class is not empty. + // FIXME: Standard ref? + if (!BaseClassDecl->isEmpty()) + data().Empty = false; + + // C++ [class.virtual]p1: + // A class that declares or inherits a virtual function is called a + // polymorphic class. + if (BaseClassDecl->isPolymorphic()) + data().Polymorphic = true; + // Now go through all virtual bases of this base and add them. for (CXXRecordDecl::base_class_iterator VBase = BaseClassDecl->vbases_begin(), @@ -110,8 +131,50 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, // Add this base if it's not already in the list. if (SeenVBaseTypes.insert(C.getCanonicalType(BaseType))) VBases.push_back(Base); + + // C++0x [meta.unary.prop] is_empty: + // T is a class type, but not a union type, with ... no virtual base + // classes + data().Empty = false; + + // C++ [class.ctor]p5: + // A constructor is trivial if its class has no virtual base classes. + data().HasTrivialConstructor = false; + + // C++ [class.copy]p6: + // A copy constructor is trivial if its class has no virtual base + // classes. + data().HasTrivialCopyConstructor = false; + + // C++ [class.copy]p11: + // A copy assignment operator is trivial if its class has no virtual + // base classes. + data().HasTrivialCopyAssignment = false; + } else { + // C++ [class.ctor]p5: + // A constructor is trivial if all the direct base classes of its + // class have trivial constructors. + if (!BaseClassDecl->hasTrivialConstructor()) + data().HasTrivialConstructor = false; + + // C++ [class.copy]p6: + // A copy constructor is trivial if all the direct base classes of its + // class have trivial copy constructors. + if (!BaseClassDecl->hasTrivialCopyConstructor()) + data().HasTrivialCopyConstructor = false; + + // C++ [class.copy]p11: + // A copy assignment operator is trivial if all the direct base classes + // of its class have trivial copy assignment operators. + if (!BaseClassDecl->hasTrivialCopyAssignment()) + data().HasTrivialCopyAssignment = false; } - + + // C++ [class.ctor]p3: + // A destructor is trivial if all the direct base classes of its class + // have trivial destructors. + if (!BaseClassDecl->hasTrivialDestructor()) + data().HasTrivialDestructor = false; } if (VBases.empty()) @@ -130,10 +193,11 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, CXXRecordDecl *VBaseClassDecl = cast<CXXRecordDecl>( VBaseTypeInfo->getType()->getAs<RecordType>()->getDecl()); - data().VBases[I] = + data().getVBases()[I] = CXXBaseSpecifier(VBaseClassDecl->getSourceRange(), true, VBaseClassDecl->getTagKind() == TTK_Class, - VBases[I]->getAccessSpecifier(), VBaseTypeInfo); + VBases[I]->getAccessSpecifier(), VBaseTypeInfo, + SourceLocation()); } } @@ -150,7 +214,7 @@ bool CXXRecordDecl::hasAnyDependentBases() const { return !forallBases(SawBase, 0); } -bool CXXRecordDecl::hasConstCopyConstructor(ASTContext &Context) const { +bool CXXRecordDecl::hasConstCopyConstructor(const ASTContext &Context) const { return getCopyConstructor(Context, Qualifiers::Const) != 0; } @@ -177,7 +241,7 @@ GetBestOverloadCandidateSimple( return Cands[Best].first; } -CXXConstructorDecl *CXXRecordDecl::getCopyConstructor(ASTContext &Context, +CXXConstructorDecl *CXXRecordDecl::getCopyConstructor(const ASTContext &Context, unsigned TypeQuals) const{ QualType ClassType = Context.getTypeDeclType(const_cast<CXXRecordDecl*>(this)); @@ -258,84 +322,268 @@ CXXMethodDecl *CXXRecordDecl::getCopyAssignmentOperator(bool ArgIsConst) const { return GetBestOverloadCandidateSimple(Found); } -void -CXXRecordDecl::addedConstructor(ASTContext &Context, - CXXConstructorDecl *ConDecl) { - assert(!ConDecl->isImplicit() && "addedConstructor - not for implicit decl"); - // Note that we have a user-declared constructor. - data().UserDeclaredConstructor = true; - - // Note that we have no need of an implicitly-declared default constructor. - data().DeclaredDefaultConstructor = true; +void CXXRecordDecl::markedVirtualFunctionPure() { + // C++ [class.abstract]p2: + // A class is abstract if it has at least one pure virtual function. + data().Abstract = true; +} + +void CXXRecordDecl::addedMember(Decl *D) { + // Ignore friends and invalid declarations. + if (D->getFriendObjectKind() || D->isInvalidDecl()) + return; - // C++ [dcl.init.aggr]p1: - // An aggregate is an array or a class (clause 9) with no - // user-declared constructors (12.1) [...]. - data().Aggregate = false; + FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D); + if (FunTmpl) + D = FunTmpl->getTemplatedDecl(); + + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) { + if (Method->isVirtual()) { + // C++ [dcl.init.aggr]p1: + // An aggregate is an array or a class with [...] no virtual functions. + data().Aggregate = false; + + // C++ [class]p4: + // A POD-struct is an aggregate class... + data().PlainOldData = false; + + // Virtual functions make the class non-empty. + // FIXME: Standard ref? + data().Empty = false; + + // C++ [class.virtual]p1: + // A class that declares or inherits a virtual function is called a + // polymorphic class. + data().Polymorphic = true; + + // None of the special member functions are trivial. + data().HasTrivialConstructor = false; + data().HasTrivialCopyConstructor = false; + data().HasTrivialCopyAssignment = false; + // FIXME: Destructor? + } + } + + if (D->isImplicit()) { + // Notify that an implicit member was added after the definition + // was completed. + if (!isBeingDefined()) + if (ASTMutationListener *L = getASTMutationListener()) + L->AddedCXXImplicitMember(data().Definition, D); + + if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) { + // If this is the implicit default constructor, note that we have now + // declared it. + if (Constructor->isDefaultConstructor()) + data().DeclaredDefaultConstructor = true; + // If this is the implicit copy constructor, note that we have now + // declared it. + else if (Constructor->isCopyConstructor()) + data().DeclaredCopyConstructor = true; + return; + } - // C++ [class]p4: - // A POD-struct is an aggregate class [...] - data().PlainOldData = false; + if (isa<CXXDestructorDecl>(D)) { + data().DeclaredDestructor = true; + return; + } + + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) { + // If this is the implicit copy constructor, note that we have now + // declared it. + // FIXME: Move constructors + if (Method->getOverloadedOperator() == OO_Equal) + data().DeclaredCopyAssignment = true; + return; + } - // 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. - 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()) { - data().UserDeclaredCopyConstructor = true; - data().DeclaredCopyConstructor = true; + // Any other implicit declarations are handled like normal declarations. + } + + // Handle (user-declared) constructors. + if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) { + // Note that we have a user-declared constructor. + data().UserDeclaredConstructor = true; + + // Note that we have no need of an implicitly-declared default constructor. + data().DeclaredDefaultConstructor = 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. - data().HasTrivialCopyConstructor = false; + // C++ [dcl.init.aggr]p1: + // An aggregate is an array or a class (clause 9) with no + // user-declared constructors (12.1) [...]. + data().Aggregate = false; + + // C++ [class]p4: + // A POD-struct is an aggregate class [...] + 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. + data().HasTrivialConstructor = false; + + // Note when we have a user-declared copy constructor, which will + // suppress the implicit declaration of a copy constructor. + if (!FunTmpl && Constructor->isCopyConstructor()) { + data().UserDeclaredCopyConstructor = true; + data().DeclaredCopyConstructor = 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. + data().HasTrivialCopyConstructor = false; + } + return; } -} -void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context, - CXXMethodDecl *OpDecl) { - // We're interested specifically in copy assignment operators. - const FunctionProtoType *FnType = OpDecl->getType()->getAs<FunctionProtoType>(); - assert(FnType && "Overloaded operator has no proto function type."); - assert(FnType->getNumArgs() == 1 && !FnType->isVariadic()); - - // Copy assignment operators must be non-templates. - if (OpDecl->getPrimaryTemplate() || OpDecl->getDescribedFunctionTemplate()) + // Handle (user-declared) destructors. + if (isa<CXXDestructorDecl>(D)) { + data().DeclaredDestructor = true; + data().UserDeclaredDestructor = true; + + // C++ [class]p4: + // A POD-struct is an aggregate class that has [...] no user-defined + // destructor. + data().PlainOldData = false; + + // C++ [class.dtor]p3: + // A destructor is trivial if it is an implicitly-declared destructor and + // [...]. + // + // FIXME: C++0x: don't do this for "= default" destructors + data().HasTrivialDestructor = false; + return; + } - QualType ArgType = FnType->getArgType(0); - if (const LValueReferenceType *Ref = ArgType->getAs<LValueReferenceType>()) - ArgType = Ref->getPointeeType(); - - ArgType = ArgType.getUnqualifiedType(); - QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType( - const_cast<CXXRecordDecl*>(this))); + // Handle (user-declared) member functions. + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) { + if (Method->getOverloadedOperator() == OO_Equal) { + // We're interested specifically in copy assignment operators. + const FunctionProtoType *FnType + = Method->getType()->getAs<FunctionProtoType>(); + assert(FnType && "Overloaded operator has no proto function type."); + assert(FnType->getNumArgs() == 1 && !FnType->isVariadic()); + + // Copy assignment operators must be non-templates. + if (Method->getPrimaryTemplate() || FunTmpl) + return; + + ASTContext &Context = getASTContext(); + QualType ArgType = FnType->getArgType(0); + if (const LValueReferenceType *Ref =ArgType->getAs<LValueReferenceType>()) + ArgType = Ref->getPointeeType(); + + ArgType = ArgType.getUnqualifiedType(); + QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType( + const_cast<CXXRecordDecl*>(this))); + + if (!Context.hasSameUnqualifiedType(ClassType, ArgType)) + return; + + // This is a copy assignment operator. + // FIXME: Move assignment operators. + + // Suppress the implicit declaration of a copy constructor. + data().UserDeclaredCopyAssignment = true; + data().DeclaredCopyAssignment = 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. + data().HasTrivialCopyAssignment = false; + + // C++ [class]p4: + // A POD-struct is an aggregate class that [...] has no user-defined copy + // assignment operator [...]. + data().PlainOldData = false; + } + + // Keep the list of conversion functions up-to-date. + if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) { + // We don't record specializations. + if (Conversion->getPrimaryTemplate()) + return; + + // FIXME: We intentionally don't use the decl's access here because it + // hasn't been set yet. That's really just a misdesign in Sema. - if (!Context.hasSameUnqualifiedType(ClassType, ArgType)) + if (FunTmpl) { + if (FunTmpl->getPreviousDeclaration()) + data().Conversions.replace(FunTmpl->getPreviousDeclaration(), + FunTmpl); + else + data().Conversions.addDecl(FunTmpl); + } else { + if (Conversion->getPreviousDeclaration()) + data().Conversions.replace(Conversion->getPreviousDeclaration(), + Conversion); + else + data().Conversions.addDecl(Conversion); + } + } + return; - - // This is a copy assignment operator. - // Note on the decl that it is a copy assignment operator. - OpDecl->setCopyAssignment(true); - - // Suppress the implicit declaration of a copy constructor. - data().UserDeclaredCopyAssignment = true; - data().DeclaredCopyAssignment = 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. - data().HasTrivialCopyAssignment = false; - - // C++ [class]p4: - // A POD-struct is an aggregate class that [...] has no user-defined copy - // assignment operator [...]. - data().PlainOldData = false; + // Handle non-static data members. + if (FieldDecl *Field = dyn_cast<FieldDecl>(D)) { + // C++ [dcl.init.aggr]p1: + // An aggregate is an array or a class (clause 9) with [...] no + // private or protected non-static data members (clause 11). + // + // A POD must be an aggregate. + if (D->getAccess() == AS_private || D->getAccess() == AS_protected) { + data().Aggregate = false; + data().PlainOldData = false; + } + + // C++ [class]p9: + // A POD struct is a class that is both a trivial class and a + // standard-layout class, and has no non-static data members of type + // non-POD struct, non-POD union (or array of such types). + ASTContext &Context = getASTContext(); + QualType T = Context.getBaseElementType(Field->getType()); + if (!T->isPODType()) + data().PlainOldData = false; + if (T->isReferenceType()) + data().HasTrivialConstructor = false; + + if (const RecordType *RecordTy = T->getAs<RecordType>()) { + CXXRecordDecl* FieldRec = cast<CXXRecordDecl>(RecordTy->getDecl()); + if (FieldRec->getDefinition()) { + if (!FieldRec->hasTrivialConstructor()) + data().HasTrivialConstructor = false; + if (!FieldRec->hasTrivialCopyConstructor()) + data().HasTrivialCopyConstructor = false; + if (!FieldRec->hasTrivialCopyAssignment()) + data().HasTrivialCopyAssignment = false; + if (!FieldRec->hasTrivialDestructor()) + data().HasTrivialDestructor = false; + } + } + + // If this is not a zero-length bit-field, then the class is not empty. + if (data().Empty) { + if (!Field->getBitWidth()) + data().Empty = false; + else if (!Field->getBitWidth()->isTypeDependent() && + !Field->getBitWidth()->isValueDependent()) { + llvm::APSInt Bits; + if (Field->getBitWidth()->isIntegerConstantExpr(Bits, Context)) + if (!!Bits) + data().Empty = false; + } + } + } + + // Handle using declarations of conversion functions. + if (UsingShadowDecl *Shadow = dyn_cast<UsingShadowDecl>(D)) + if (Shadow->getDeclName().getNameKind() + == DeclarationName::CXXConversionFunctionName) + data().Conversions.addDecl(Shadow, Shadow->getAccess()); } static CanQualType GetConversionType(ASTContext &Context, NamedDecl *Conv) { @@ -479,20 +727,6 @@ const UnresolvedSetImpl *CXXRecordDecl::getVisibleConversionFunctions() { return &data().VisibleConversions; } -#ifndef NDEBUG -void CXXRecordDecl::CheckConversionFunction(NamedDecl *ConvDecl) { - assert(ConvDecl->getDeclContext() == this && - "conversion function does not belong to this record"); - - ConvDecl = ConvDecl->getUnderlyingDecl(); - if (FunctionTemplateDecl *Temp = dyn_cast<FunctionTemplateDecl>(ConvDecl)) { - assert(isa<CXXConversionDecl>(Temp->getTemplatedDecl())); - } else { - assert(isa<CXXConversionDecl>(ConvDecl)); - } -} -#endif - void CXXRecordDecl::removeConversion(const NamedDecl *ConvDecl) { // This operation is O(N) but extremely rare. Sema only uses it to // remove UsingShadowDecls in a class that were followed by a direct @@ -518,17 +752,6 @@ void CXXRecordDecl::removeConversion(const NamedDecl *ConvDecl) { llvm_unreachable("conversion not found in set!"); } -void CXXRecordDecl::setMethodAsVirtual(FunctionDecl *Method) { - Method->setVirtualAsWritten(true); - setAggregate(false); - setPOD(false); - setEmpty(false); - setPolymorphic(true); - setHasTrivialConstructor(false); - setHasTrivialCopyConstructor(false); - setHasTrivialCopyAssignment(false); -} - CXXRecordDecl *CXXRecordDecl::getInstantiatedFromMemberClass() const { if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo()) return cast<CXXRecordDecl>(MSInfo->getInstantiatedFrom()); @@ -577,28 +800,6 @@ CXXRecordDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) { assert(false && "Not a class template or member class specialization"); } -CXXConstructorDecl * -CXXRecordDecl::getDefaultConstructor() { - ASTContext &Context = getASTContext(); - QualType ClassType = Context.getTypeDeclType(this); - DeclarationName ConstructorName - = Context.DeclarationNames.getCXXConstructorName( - Context.getCanonicalType(ClassType.getUnqualifiedType())); - - DeclContext::lookup_const_iterator Con, ConEnd; - for (llvm::tie(Con, ConEnd) = lookup(ConstructorName); - Con != ConEnd; ++Con) { - // FIXME: In C++0x, a constructor template can be a default constructor. - if (isa<FunctionTemplateDecl>(*Con)) - continue; - - CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con); - if (Constructor->isDefaultConstructor()) - return Constructor; - } - return 0; -} - CXXDestructorDecl *CXXRecordDecl::getDestructor() const { ASTContext &Context = getASTContext(); QualType ClassType = Context.getTypeDeclType(this); @@ -618,6 +819,69 @@ CXXDestructorDecl *CXXRecordDecl::getDestructor() const { return Dtor; } +void CXXRecordDecl::completeDefinition() { + completeDefinition(0); +} + +void CXXRecordDecl::completeDefinition(CXXFinalOverriderMap *FinalOverriders) { + RecordDecl::completeDefinition(); + + // If the class may be abstract (but hasn't been marked as such), check for + // any pure final overriders. + if (mayBeAbstract()) { + CXXFinalOverriderMap MyFinalOverriders; + if (!FinalOverriders) { + getFinalOverriders(MyFinalOverriders); + FinalOverriders = &MyFinalOverriders; + } + + bool Done = false; + for (CXXFinalOverriderMap::iterator M = FinalOverriders->begin(), + MEnd = FinalOverriders->end(); + M != MEnd && !Done; ++M) { + for (OverridingMethods::iterator SO = M->second.begin(), + SOEnd = M->second.end(); + SO != SOEnd && !Done; ++SO) { + assert(SO->second.size() > 0 && + "All virtual functions have overridding virtual functions"); + + // C++ [class.abstract]p4: + // A class is abstract if it contains or inherits at least one + // pure virtual function for which the final overrider is pure + // virtual. + if (SO->second.front().Method->isPure()) { + data().Abstract = true; + Done = true; + break; + } + } + } + } + + // Set access bits correctly on the directly-declared conversions. + for (UnresolvedSetIterator I = data().Conversions.begin(), + E = data().Conversions.end(); + I != E; ++I) + data().Conversions.setAccess(I, (*I)->getAccess()); +} + +bool CXXRecordDecl::mayBeAbstract() const { + if (data().Abstract || isInvalidDecl() || !data().Polymorphic || + isDependentContext()) + return false; + + for (CXXRecordDecl::base_class_const_iterator B = bases_begin(), + BEnd = bases_end(); + B != BEnd; ++B) { + CXXRecordDecl *BaseDecl + = cast<CXXRecordDecl>(B->getType()->getAs<RecordType>()->getDecl()); + if (BaseDecl->isAbstract()) + return true; + } + + return false; +} + CXXMethodDecl * CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD, const DeclarationNameInfo &NameInfo, @@ -735,85 +999,90 @@ bool CXXMethodDecl::hasInlineBody() const { return CheckFn->hasBody(fn) && !fn->isOutOfLine(); } -CXXBaseOrMemberInitializer:: -CXXBaseOrMemberInitializer(ASTContext &Context, - TypeSourceInfo *TInfo, bool IsVirtual, - SourceLocation L, Expr *Init, SourceLocation R) - : BaseOrMember(TInfo), Init(Init), AnonUnionMember(0), +CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context, + TypeSourceInfo *TInfo, bool IsVirtual, + SourceLocation L, Expr *Init, + SourceLocation R, + SourceLocation EllipsisLoc) + : Initializee(TInfo), MemberOrEllipsisLocation(EllipsisLoc), Init(Init), LParenLoc(L), RParenLoc(R), IsVirtual(IsVirtual), IsWritten(false), SourceOrderOrNumArrayIndices(0) { } -CXXBaseOrMemberInitializer:: -CXXBaseOrMemberInitializer(ASTContext &Context, - FieldDecl *Member, SourceLocation MemberLoc, - SourceLocation L, Expr *Init, SourceLocation R) - : BaseOrMember(Member), MemberLocation(MemberLoc), Init(Init), - AnonUnionMember(0), LParenLoc(L), RParenLoc(R), IsVirtual(false), +CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context, + FieldDecl *Member, + SourceLocation MemberLoc, + SourceLocation L, Expr *Init, + SourceLocation R) + : Initializee(Member), MemberOrEllipsisLocation(MemberLoc), Init(Init), + LParenLoc(L), RParenLoc(R), IsVirtual(false), + IsWritten(false), SourceOrderOrNumArrayIndices(0) +{ +} + +CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context, + IndirectFieldDecl *Member, + SourceLocation MemberLoc, + SourceLocation L, Expr *Init, + SourceLocation R) + : Initializee(Member), MemberOrEllipsisLocation(MemberLoc), Init(Init), + LParenLoc(L), RParenLoc(R), IsVirtual(false), IsWritten(false), SourceOrderOrNumArrayIndices(0) { } -CXXBaseOrMemberInitializer:: -CXXBaseOrMemberInitializer(ASTContext &Context, - FieldDecl *Member, SourceLocation MemberLoc, - SourceLocation L, Expr *Init, SourceLocation R, - VarDecl **Indices, - unsigned NumIndices) - : BaseOrMember(Member), MemberLocation(MemberLoc), Init(Init), - AnonUnionMember(0), LParenLoc(L), RParenLoc(R), IsVirtual(false), +CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context, + FieldDecl *Member, + SourceLocation MemberLoc, + SourceLocation L, Expr *Init, + SourceLocation R, + VarDecl **Indices, + unsigned NumIndices) + : Initializee(Member), MemberOrEllipsisLocation(MemberLoc), Init(Init), + LParenLoc(L), RParenLoc(R), IsVirtual(false), IsWritten(false), SourceOrderOrNumArrayIndices(NumIndices) { VarDecl **MyIndices = reinterpret_cast<VarDecl **> (this + 1); memcpy(MyIndices, Indices, NumIndices * sizeof(VarDecl *)); } -CXXBaseOrMemberInitializer * -CXXBaseOrMemberInitializer::Create(ASTContext &Context, - FieldDecl *Member, - SourceLocation MemberLoc, - SourceLocation L, - Expr *Init, - SourceLocation R, - VarDecl **Indices, - unsigned NumIndices) { - void *Mem = Context.Allocate(sizeof(CXXBaseOrMemberInitializer) + +CXXCtorInitializer *CXXCtorInitializer::Create(ASTContext &Context, + FieldDecl *Member, + SourceLocation MemberLoc, + SourceLocation L, Expr *Init, + SourceLocation R, + VarDecl **Indices, + unsigned NumIndices) { + void *Mem = Context.Allocate(sizeof(CXXCtorInitializer) + sizeof(VarDecl *) * NumIndices, - llvm::alignof<CXXBaseOrMemberInitializer>()); - return new (Mem) CXXBaseOrMemberInitializer(Context, Member, MemberLoc, - L, Init, R, Indices, NumIndices); + llvm::alignOf<CXXCtorInitializer>()); + return new (Mem) CXXCtorInitializer(Context, Member, MemberLoc, L, Init, R, + Indices, NumIndices); } -TypeLoc CXXBaseOrMemberInitializer::getBaseClassLoc() const { +TypeLoc CXXCtorInitializer::getBaseClassLoc() const { if (isBaseInitializer()) - return BaseOrMember.get<TypeSourceInfo*>()->getTypeLoc(); + return Initializee.get<TypeSourceInfo*>()->getTypeLoc(); else return TypeLoc(); } -Type *CXXBaseOrMemberInitializer::getBaseClass() { - if (isBaseInitializer()) - return BaseOrMember.get<TypeSourceInfo*>()->getType().getTypePtr(); - else - return 0; -} - -const Type *CXXBaseOrMemberInitializer::getBaseClass() const { +const Type *CXXCtorInitializer::getBaseClass() const { if (isBaseInitializer()) - return BaseOrMember.get<TypeSourceInfo*>()->getType().getTypePtr(); + return Initializee.get<TypeSourceInfo*>()->getType().getTypePtr(); else return 0; } -SourceLocation CXXBaseOrMemberInitializer::getSourceLocation() const { - if (isMemberInitializer()) +SourceLocation CXXCtorInitializer::getSourceLocation() const { + if (isAnyMemberInitializer()) return getMemberLocation(); return getBaseClassLoc().getLocalSourceRange().getBegin(); } -SourceRange CXXBaseOrMemberInitializer::getSourceRange() const { +SourceRange CXXCtorInitializer::getSourceRange() const { return SourceRange(getSourceLocation(), getRParenLoc()); } @@ -847,25 +1116,40 @@ bool CXXConstructorDecl::isDefaultConstructor() const { bool CXXConstructorDecl::isCopyConstructor(unsigned &TypeQuals) const { + return isCopyOrMoveConstructor(TypeQuals) && + getParamDecl(0)->getType()->isLValueReferenceType(); +} + +bool CXXConstructorDecl::isMoveConstructor(unsigned &TypeQuals) const { + return isCopyOrMoveConstructor(TypeQuals) && + getParamDecl(0)->getType()->isRValueReferenceType(); +} + +/// \brief Determine whether this is a copy or move constructor. +bool CXXConstructorDecl::isCopyOrMoveConstructor(unsigned &TypeQuals) const { // C++ [class.copy]p2: // A non-template constructor for class X is a copy constructor // if its first parameter is of type X&, const X&, volatile X& or // const volatile X&, and either there are no other parameters // or else all other parameters have default arguments (8.3.6). + // C++0x [class.copy]p3: + // A non-template constructor for class X is a move constructor if its + // first parameter is of type X&&, const X&&, volatile X&&, or + // const volatile X&&, and either there are no other parameters or else + // all other parameters have default arguments. if ((getNumParams() < 1) || (getNumParams() > 1 && !getParamDecl(1)->hasDefaultArg()) || (getPrimaryTemplate() != 0) || (getDescribedFunctionTemplate() != 0)) return false; - + const ParmVarDecl *Param = getParamDecl(0); - - // Do we have a reference type? Rvalue references don't count. - const LValueReferenceType *ParamRefType = - Param->getType()->getAs<LValueReferenceType>(); + + // Do we have a reference type? + const ReferenceType *ParamRefType = Param->getType()->getAs<ReferenceType>(); if (!ParamRefType) return false; - + // Is it a reference to our class type? ASTContext &Context = getASTContext(); @@ -875,12 +1159,12 @@ CXXConstructorDecl::isCopyConstructor(unsigned &TypeQuals) const { = Context.getCanonicalType(Context.getTagDeclType(getParent())); if (PointeeType.getUnqualifiedType() != ClassTy) return false; - + // FIXME: other qualifiers? - - // We have a copy constructor. + + // We have a copy or move constructor. TypeQuals = PointeeType.getCVRQualifiers(); - return true; + return true; } bool CXXConstructorDecl::isConvertingConstructor(bool AllowExplicit) const { @@ -899,7 +1183,7 @@ bool CXXConstructorDecl::isConvertingConstructor(bool AllowExplicit) const { (getNumParams() > 1 && getParamDecl(1)->hasDefaultArg()); } -bool CXXConstructorDecl::isCopyConstructorLikeSpecialization() const { +bool CXXConstructorDecl::isSpecializationCopyingObject() const { if ((getNumParams() < 1) || (getNumParams() > 1 && !getParamDecl(1)->hasDefaultArg()) || (getPrimaryTemplate() == 0) || @@ -911,12 +1195,6 @@ bool CXXConstructorDecl::isCopyConstructorLikeSpecialization() const { ASTContext &Context = getASTContext(); CanQualType ParamType = Context.getCanonicalType(Param->getType()); - // Strip off the lvalue reference, if any. - if (CanQual<LValueReferenceType> ParamRefType - = ParamType->getAs<LValueReferenceType>()) - ParamType = ParamRefType->getPointeeType(); - - // Is it the same as our our class type? CanQualType ClassTy = Context.getCanonicalType(Context.getTagDeclType(getParent())); @@ -926,21 +1204,38 @@ bool CXXConstructorDecl::isCopyConstructorLikeSpecialization() const { return true; } +const CXXConstructorDecl *CXXConstructorDecl::getInheritedConstructor() const { + // Hack: we store the inherited constructor in the overridden method table + method_iterator It = begin_overridden_methods(); + if (It == end_overridden_methods()) + return 0; + + return cast<CXXConstructorDecl>(*It); +} + +void +CXXConstructorDecl::setInheritedConstructor(const CXXConstructorDecl *BaseCtor){ + // Hack: we store the inherited constructor in the overridden method table + assert(size_overridden_methods() == 0 && "Base ctor already set."); + addOverriddenMethod(BaseCtor); +} + CXXDestructorDecl * CXXDestructorDecl::Create(ASTContext &C, EmptyShell Empty) { return new (C) CXXDestructorDecl(0, DeclarationNameInfo(), - QualType(), false, false); + QualType(), 0, false, false); } CXXDestructorDecl * CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, const DeclarationNameInfo &NameInfo, - QualType T, bool isInline, + QualType T, TypeSourceInfo *TInfo, + bool isInline, bool isImplicitlyDeclared) { assert(NameInfo.getName().getNameKind() == DeclarationName::CXXDestructorName && "Name must refer to a destructor"); - return new (C) CXXDestructorDecl(RD, NameInfo, T, isInline, + return new (C) CXXDestructorDecl(RD, NameInfo, T, TInfo, isInline, isImplicitlyDeclared); } @@ -1004,6 +1299,44 @@ NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC, Qualifier, IdentLoc, Namespace); } +UsingDecl *UsingShadowDecl::getUsingDecl() const { + const UsingShadowDecl *Shadow = this; + while (const UsingShadowDecl *NextShadow = + dyn_cast<UsingShadowDecl>(Shadow->UsingOrNextShadow)) + Shadow = NextShadow; + return cast<UsingDecl>(Shadow->UsingOrNextShadow); +} + +void UsingDecl::addShadowDecl(UsingShadowDecl *S) { + assert(std::find(shadow_begin(), shadow_end(), S) == shadow_end() && + "declaration already in set"); + assert(S->getUsingDecl() == this); + + if (FirstUsingShadow) + S->UsingOrNextShadow = FirstUsingShadow; + FirstUsingShadow = S; +} + +void UsingDecl::removeShadowDecl(UsingShadowDecl *S) { + assert(std::find(shadow_begin(), shadow_end(), S) != shadow_end() && + "declaration not in set"); + assert(S->getUsingDecl() == this); + + // Remove S from the shadow decl chain. This is O(n) but hopefully rare. + + if (FirstUsingShadow == S) { + FirstUsingShadow = dyn_cast<UsingShadowDecl>(S->UsingOrNextShadow); + S->UsingOrNextShadow = this; + return; + } + + UsingShadowDecl *Prev = FirstUsingShadow; + while (Prev->UsingOrNextShadow != S) + Prev = cast<UsingShadowDecl>(Prev->UsingOrNextShadow); + Prev->UsingOrNextShadow = S->UsingOrNextShadow; + S->UsingOrNextShadow = this; +} + UsingDecl *UsingDecl::Create(ASTContext &C, DeclContext *DC, SourceRange NNR, SourceLocation UL, NestedNameSpecifier* TargetNNS, diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index d952cc3..45f5188 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -153,6 +153,9 @@ ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const { ObjCPropertyDecl * ObjCInterfaceDecl::FindPropertyVisibleInPrimaryClass( IdentifierInfo *PropertyId) const { + if (ExternallyCompleted) + LoadExternalDefinition(); + if (ObjCPropertyDecl *PD = ObjCPropertyDecl::findPropertyDecl(cast<DeclContext>(this), PropertyId)) return PD; @@ -171,6 +174,9 @@ void ObjCInterfaceDecl::mergeClassExtensionProtocolList( ObjCProtocolDecl *const* ExtList, unsigned ExtNum, ASTContext &C) { + if (ExternallyCompleted) + LoadExternalDefinition(); + if (AllReferencedProtocols.empty() && ReferencedProtocols.empty()) { AllReferencedProtocols.set(ExtList, ExtNum, C); return; @@ -270,6 +276,9 @@ ObjCMethodDecl *ObjCInterfaceDecl::lookupMethod(Selector Sel, const ObjCInterfaceDecl* ClassDecl = this; ObjCMethodDecl *MethodDecl = 0; + if (ExternallyCompleted) + LoadExternalDefinition(); + while (ClassDecl != NULL) { if ((MethodDecl = ClassDecl->getMethod(Sel, isInstance))) return MethodDecl; @@ -302,14 +311,16 @@ ObjCMethodDecl *ObjCInterfaceDecl::lookupMethod(Selector Sel, return NULL; } -ObjCMethodDecl *ObjCInterfaceDecl::lookupPrivateInstanceMethod( - const Selector &Sel) { +ObjCMethodDecl *ObjCInterfaceDecl::lookupPrivateMethod( + const Selector &Sel, + bool Instance) { ObjCMethodDecl *Method = 0; if (ObjCImplementationDecl *ImpDecl = getImplementation()) - Method = ImpDecl->getInstanceMethod(Sel); + Method = Instance ? ImpDecl->getInstanceMethod(Sel) + : ImpDecl->getClassMethod(Sel); if (!Method && getSuperClass()) - return getSuperClass()->lookupPrivateInstanceMethod(Sel); + return getSuperClass()->lookupPrivateMethod(Sel, Instance); return Method; } @@ -443,11 +454,29 @@ ObjCInterfaceDecl(DeclContext *DC, SourceLocation atLoc, IdentifierInfo *Id, : ObjCContainerDecl(ObjCInterface, DC, atLoc, Id), TypeForDecl(0), SuperClass(0), CategoryList(0), IvarList(0), - ForwardDecl(FD), InternalInterface(isInternal), + ForwardDecl(FD), InternalInterface(isInternal), ExternallyCompleted(false), ClassLoc(CLoc) { } +void ObjCInterfaceDecl::LoadExternalDefinition() const { + assert(ExternallyCompleted && "Class is not externally completed"); + ExternallyCompleted = false; + getASTContext().getExternalSource()->CompleteType( + const_cast<ObjCInterfaceDecl *>(this)); +} + +void ObjCInterfaceDecl::setExternallyCompleted() { + assert(getASTContext().getExternalSource() && + "Class can't be externally completed without an external source"); + assert(!ForwardDecl && + "Forward declarations can't be externally completed"); + ExternallyCompleted = true; +} + ObjCImplementationDecl *ObjCInterfaceDecl::getImplementation() const { + if (ExternallyCompleted) + LoadExternalDefinition(); + return getASTContext().getObjCImplementation( const_cast<ObjCInterfaceDecl*>(this)); } @@ -506,6 +535,9 @@ ObjCIvarDecl *ObjCInterfaceDecl::all_declared_ivar_begin() { /// ObjCCategoryDecl * ObjCInterfaceDecl::FindCategoryDeclaration(IdentifierInfo *CategoryId) const { + if (ExternallyCompleted) + LoadExternalDefinition(); + for (ObjCCategoryDecl *Category = getCategoryList(); Category; Category = Category->getNextClassCategory()) if (Category->getIdentifier() == CategoryId) @@ -711,7 +743,7 @@ ObjCClassDecl::ObjCClassDecl(DeclContext *DC, SourceLocation L, void ObjCClassDecl::setClassList(ASTContext &C, ObjCInterfaceDecl*const*List, const SourceLocation *Locs, unsigned Num) { ForwardDecls = (ObjCClassRef*) C.Allocate(sizeof(ObjCClassRef)*Num, - llvm::alignof<ObjCClassRef>()); + llvm::alignOf<ObjCClassRef>()); for (unsigned i = 0; i < Num; ++i) new (&ForwardDecls[i]) ObjCClassRef(List[i], Locs[i]); @@ -896,7 +928,6 @@ ObjCPropertyDecl *ObjCPropertyDecl::Create(ASTContext &C, DeclContext *DC, return new (C) ObjCPropertyDecl(DC, L, Id, AtLoc, T); } - //===----------------------------------------------------------------------===// // ObjCPropertyImplDecl //===----------------------------------------------------------------------===// @@ -907,8 +938,16 @@ ObjCPropertyImplDecl *ObjCPropertyImplDecl::Create(ASTContext &C, SourceLocation L, ObjCPropertyDecl *property, Kind PK, - ObjCIvarDecl *ivar) { - return new (C) ObjCPropertyImplDecl(DC, atLoc, L, property, PK, ivar); + ObjCIvarDecl *ivar, + SourceLocation ivarLoc) { + return new (C) ObjCPropertyImplDecl(DC, atLoc, L, property, PK, ivar, + ivarLoc); } +SourceRange ObjCPropertyImplDecl::getSourceRange() const { + SourceLocation EndLoc = getLocation(); + if (IvarLoc.isValid()) + EndLoc = IvarLoc; + return SourceRange(AtLoc, EndLoc); +} diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index f18d2f0..77b4257 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -51,6 +51,7 @@ namespace { void VisitFunctionDecl(FunctionDecl *D); void VisitFieldDecl(FieldDecl *D); void VisitVarDecl(VarDecl *D); + void VisitLabelDecl(LabelDecl *D); void VisitParmVarDecl(ParmVarDecl *D); void VisitFileScopeAsmDecl(FileScopeAsmDecl *D); void VisitNamespaceDecl(NamespaceDecl *D); @@ -307,9 +308,26 @@ void DeclPrinter::VisitTypedefDecl(TypedefDecl *D) { } void DeclPrinter::VisitEnumDecl(EnumDecl *D) { - Out << "enum " << D << " {\n"; - VisitDeclContext(D); - Indent() << "}"; + Out << "enum "; + if (D->isScoped()) { + if (D->isScopedUsingClassTag()) + Out << "class "; + else + Out << "struct "; + } + Out << D; + + if (D->isFixed()) { + std::string Underlying; + D->getIntegerType().getAsStringInternal(Underlying, Policy); + Out << " : " << Underlying; + } + + if (D->isDefinition()) { + Out << " {\n"; + VisitDeclContext(D); + Indent() << "}"; + } } void DeclPrinter::VisitRecordDecl(RecordDecl *D) { @@ -349,9 +367,15 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { PrintingPolicy SubPolicy(Policy); SubPolicy.SuppressSpecifiers = false; std::string Proto = D->getNameInfo().getAsString(); - if (isa<FunctionType>(D->getType().getTypePtr())) { - const FunctionType *AFT = D->getType()->getAs<FunctionType>(); + QualType Ty = D->getType(); + while (const ParenType *PT = dyn_cast<ParenType>(Ty)) { + Proto = '(' + Proto + ')'; + Ty = PT->getInnerType(); + } + + if (isa<FunctionType>(Ty)) { + const FunctionType *AFT = Ty->getAs<FunctionType>(); const FunctionProtoType *FT = 0; if (D->hasWrittenPrototype()) FT = dyn_cast<FunctionProtoType>(AFT); @@ -379,6 +403,16 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { Proto += ")"; + if (FT && FT->getTypeQuals()) { + unsigned TypeQuals = FT->getTypeQuals(); + if (TypeQuals & Qualifiers::Const) + Proto += " const"; + if (TypeQuals & Qualifiers::Volatile) + Proto += " volatile"; + if (TypeQuals & Qualifiers::Restrict) + Proto += " restrict"; + } + if (FT && FT->hasExceptionSpec()) { Proto += " throw("; if (FT->hasAnyExceptionSpec()) @@ -399,18 +433,18 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { if (D->hasAttr<NoReturnAttr>()) Proto += " __attribute((noreturn))"; if (CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(D)) { - if (CDecl->getNumBaseOrMemberInitializers() > 0) { + if (CDecl->getNumCtorInitializers() > 0) { Proto += " : "; Out << Proto; Proto.clear(); for (CXXConstructorDecl::init_const_iterator B = CDecl->init_begin(), E = CDecl->init_end(); B != E; ++B) { - CXXBaseOrMemberInitializer * BMInitializer = (*B); + CXXCtorInitializer * BMInitializer = (*B); if (B != CDecl->init_begin()) Out << ", "; - if (BMInitializer->isMemberInitializer()) { - FieldDecl *FD = BMInitializer->getMember(); + if (BMInitializer->isAnyMemberInitializer()) { + FieldDecl *FD = BMInitializer->getAnyMember(); Out << FD; } else { Out << QualType(BMInitializer->getBaseClass(), @@ -422,8 +456,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { // Nothing to print } else { Expr *Init = BMInitializer->getInit(); - if (CXXExprWithTemporaries *Tmp - = dyn_cast<CXXExprWithTemporaries>(Init)) + if (ExprWithCleanups *Tmp = dyn_cast<ExprWithCleanups>(Init)) Init = Tmp->getSubExpr(); Init = Init->IgnoreParens(); @@ -461,7 +494,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { else AFT->getResultType().getAsStringInternal(Proto, Policy); } else { - D->getType().getAsStringInternal(Proto, Policy); + Ty.getAsStringInternal(Proto, Policy); } Out << Proto; @@ -505,6 +538,11 @@ void DeclPrinter::VisitFieldDecl(FieldDecl *D) { } } +void DeclPrinter::VisitLabelDecl(LabelDecl *D) { + Out << D->getNameAsString() << ":"; +} + + void DeclPrinter::VisitVarDecl(VarDecl *D) { if (!Policy.SuppressSpecifiers && D->getStorageClass() != SC_None) Out << VarDecl::getStorageClassSpecifierString(D->getStorageClass()) << " "; @@ -518,12 +556,15 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) { T = Parm->getOriginalType(); T.getAsStringInternal(Name, Policy); Out << Name; - if (D->getInit()) { + if (Expr *Init = D->getInit()) { if (D->hasCXXDirectInitializer()) Out << "("; - else - Out << " = "; - D->getInit()->printPretty(Out, Context, 0, Policy, Indentation); + else { + CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(Init); + if (!CCE || CCE->getConstructor()->isCopyConstructor()) + Out << " = "; + } + Init->printPretty(Out, Context, 0, Policy, Indentation); if (D->hasCXXDirectInitializer()) Out << ")"; } @@ -646,6 +687,9 @@ void DeclPrinter::VisitTemplateDecl(TemplateDecl *D) { dyn_cast<NonTypeTemplateParmDecl>(Param)) { Out << NTTP->getType().getAsString(Policy); + if (NTTP->isParameterPack() && !isa<PackExpansionType>(NTTP->getType())) + Out << "..."; + if (IdentifierInfo *Name = NTTP->getIdentifier()) { Out << ' '; Out << Name->getName(); @@ -661,8 +705,11 @@ void DeclPrinter::VisitTemplateDecl(TemplateDecl *D) { Out << "> "; - if (isa<TemplateTemplateParmDecl>(D)) { - Out << "class " << D->getName(); + if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(D)) { + Out << "class "; + if (TTP->isParameterPack()) + Out << "..."; + Out << D->getName(); } else { Visit(D->getTemplatedDecl()); } diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index e69338a..a73deea 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -14,10 +14,13 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/ASTContext.h" #include "clang/AST/TypeLoc.h" +#include "clang/AST/ASTMutationListener.h" #include "clang/Basic/IdentifierTable.h" #include "llvm/ADT/STLExtras.h" +#include <memory> using namespace clang; //===----------------------------------------------------------------------===// @@ -35,7 +38,7 @@ TemplateParameterList::TemplateParameterList(SourceLocation TemplateLoc, } TemplateParameterList * -TemplateParameterList::Create(ASTContext &C, SourceLocation TemplateLoc, +TemplateParameterList::Create(const ASTContext &C, SourceLocation TemplateLoc, SourceLocation LAngleLoc, NamedDecl **Params, unsigned NumParams, SourceLocation RAngleLoc) { unsigned Size = sizeof(TemplateParameterList) @@ -47,24 +50,33 @@ TemplateParameterList::Create(ASTContext &C, SourceLocation TemplateLoc, } unsigned TemplateParameterList::getMinRequiredArguments() const { - unsigned NumRequiredArgs = size(); - iterator Param = const_cast<TemplateParameterList *>(this)->end(), - ParamBegin = const_cast<TemplateParameterList *>(this)->begin(); - while (Param != ParamBegin) { - --Param; - - if (!(*Param)->isTemplateParameterPack() && - !(isa<TemplateTypeParmDecl>(*Param) && - cast<TemplateTypeParmDecl>(*Param)->hasDefaultArgument()) && - !(isa<NonTypeTemplateParmDecl>(*Param) && - cast<NonTypeTemplateParmDecl>(*Param)->hasDefaultArgument()) && - !(isa<TemplateTemplateParmDecl>(*Param) && - cast<TemplateTemplateParmDecl>(*Param)->hasDefaultArgument())) + unsigned NumRequiredArgs = 0; + for (iterator P = const_cast<TemplateParameterList *>(this)->begin(), + PEnd = const_cast<TemplateParameterList *>(this)->end(); + P != PEnd; ++P) { + if ((*P)->isTemplateParameterPack()) { + if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) + if (NTTP->isExpandedParameterPack()) { + NumRequiredArgs += NTTP->getNumExpansionTypes(); + continue; + } + break; - - --NumRequiredArgs; + } + + if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*P)) { + if (TTP->hasDefaultArgument()) + break; + } else if (NonTypeTemplateParmDecl *NTTP + = dyn_cast<NonTypeTemplateParmDecl>(*P)) { + if (NTTP->hasDefaultArgument()) + break; + } else if (cast<TemplateTemplateParmDecl>(*P)->hasDefaultArgument()) + break; + + ++NumRequiredArgs; } - + return NumRequiredArgs; } @@ -92,7 +104,7 @@ RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() { RedeclarableTemplateDecl *First = getCanonicalDecl(); if (First->CommonOrPrev.isNull()) { - CommonBase *CommonPtr = First->newCommon(); + CommonBase *CommonPtr = First->newCommon(getASTContext()); First->CommonOrPrev = CommonPtr; CommonPtr->Latest = First; } @@ -156,9 +168,10 @@ FunctionTemplateDecl *FunctionTemplateDecl::Create(ASTContext &C, return new (C) FunctionTemplateDecl(DC, L, Name, Params, Decl); } -RedeclarableTemplateDecl::CommonBase *FunctionTemplateDecl::newCommon() { - Common *CommonPtr = new (getASTContext()) Common; - getASTContext().AddDeallocation(DeallocateCommon, CommonPtr); +RedeclarableTemplateDecl::CommonBase * +FunctionTemplateDecl::newCommon(ASTContext &C) { + Common *CommonPtr = new (C) Common; + C.AddDeallocation(DeallocateCommon, CommonPtr); return CommonPtr; } @@ -188,9 +201,33 @@ ClassTemplateDecl *ClassTemplateDecl::Create(ASTContext &C, return New; } -RedeclarableTemplateDecl::CommonBase *ClassTemplateDecl::newCommon() { - Common *CommonPtr = new (getASTContext()) Common; - getASTContext().AddDeallocation(DeallocateCommon, CommonPtr); +void ClassTemplateDecl::LoadLazySpecializations() { + Common *CommonPtr = getCommonPtr(); + if (CommonPtr->LazySpecializations) { + ASTContext &Context = getASTContext(); + uint32_t *Specs = CommonPtr->LazySpecializations; + CommonPtr->LazySpecializations = 0; + for (uint32_t I = 0, N = *Specs++; I != N; ++I) + (void)Context.getExternalSource()->GetExternalDecl(Specs[I]); + } +} + +llvm::FoldingSet<ClassTemplateSpecializationDecl> & +ClassTemplateDecl::getSpecializations() { + LoadLazySpecializations(); + return getCommonPtr()->Specializations; +} + +llvm::FoldingSet<ClassTemplatePartialSpecializationDecl> & +ClassTemplateDecl::getPartialSpecializations() { + LoadLazySpecializations(); + return getCommonPtr()->PartialSpecializations; +} + +RedeclarableTemplateDecl::CommonBase * +ClassTemplateDecl::newCommon(ASTContext &C) { + Common *CommonPtr = new (C) Common; + C.AddDeallocation(DeallocateCommon, CommonPtr); return CommonPtr; } @@ -200,6 +237,13 @@ ClassTemplateDecl::findSpecialization(const TemplateArgument *Args, return findSpecializationImpl(getSpecializations(), Args, NumArgs, InsertPos); } +void ClassTemplateDecl::AddSpecialization(ClassTemplateSpecializationDecl *D, + void *InsertPos) { + getSpecializations().InsertNode(D, InsertPos); + if (ASTMutationListener *L = getASTMutationListener()) + L->AddedCXXTemplateSpecialization(this, D); +} + ClassTemplatePartialSpecializationDecl * ClassTemplateDecl::findPartialSpecialization(const TemplateArgument *Args, unsigned NumArgs, @@ -208,6 +252,14 @@ ClassTemplateDecl::findPartialSpecialization(const TemplateArgument *Args, InsertPos); } +void ClassTemplateDecl::AddPartialSpecialization( + ClassTemplatePartialSpecializationDecl *D, + void *InsertPos) { + getPartialSpecializations().InsertNode(D, InsertPos); + if (ASTMutationListener *L = getASTMutationListener()) + L->AddedCXXTemplateSpecialization(this, D); +} + void ClassTemplateDecl::getPartialSpecializations( llvm::SmallVectorImpl<ClassTemplatePartialSpecializationDecl *> &PS) { llvm::FoldingSet<ClassTemplatePartialSpecializationDecl> &PartialSpecs @@ -258,10 +310,13 @@ ClassTemplateDecl::getInjectedClassNameSpecialization() { if (!CommonPtr->InjectedClassNameType.isNull()) return CommonPtr->InjectedClassNameType; - // FIXME: n2800 14.6.1p1 should say how the template arguments - // corresponding to template parameter packs should be pack - // expansions. We already say that in 14.6.2.1p2, so it would be - // better to fix that redundancy. + // C++0x [temp.dep.type]p2: + // The template argument list of a primary template is a template argument + // list in which the nth template argument has the value of the nth template + // parameter of the class template. If the nth template parameter is a + // template parameter pack (14.5.3), the nth template argument is a pack + // expansion (14.5.3) whose pattern is the name of the template parameter + // pack. ASTContext &Context = getASTContext(); TemplateParameterList *Params = getTemplateParameters(); llvm::SmallVector<TemplateArgument, 16> TemplateArgs; @@ -269,19 +324,38 @@ ClassTemplateDecl::getInjectedClassNameSpecialization() { for (TemplateParameterList::iterator Param = Params->begin(), ParamEnd = Params->end(); Param != ParamEnd; ++Param) { - if (isa<TemplateTypeParmDecl>(*Param)) { - QualType ParamType = Context.getTypeDeclType(cast<TypeDecl>(*Param)); - TemplateArgs.push_back(TemplateArgument(ParamType)); + TemplateArgument Arg; + if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) { + QualType ArgType = Context.getTypeDeclType(TTP); + if (TTP->isParameterPack()) + ArgType = Context.getPackExpansionType(ArgType, + llvm::Optional<unsigned>()); + + Arg = TemplateArgument(ArgType); } else if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*Param)) { Expr *E = new (Context) DeclRefExpr(NTTP, NTTP->getType().getNonLValueExprType(Context), + Expr::getValueKindForType(NTTP->getType()), NTTP->getLocation()); - TemplateArgs.push_back(TemplateArgument(E)); + + if (NTTP->isParameterPack()) + E = new (Context) PackExpansionExpr(Context.DependentTy, E, + NTTP->getLocation(), + llvm::Optional<unsigned>()); + Arg = TemplateArgument(E); } else { TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*Param); - TemplateArgs.push_back(TemplateArgument(TemplateName(TTP))); + if (TTP->isParameterPack()) + Arg = TemplateArgument(TemplateName(TTP), llvm::Optional<unsigned>()); + else + Arg = TemplateArgument(TemplateName(TTP)); } + + if ((*Param)->isTemplateParameterPack()) + Arg = TemplateArgument::CreatePackCopy(Context, &Arg, 1); + + TemplateArgs.push_back(Arg); } CommonPtr->InjectedClassNameType @@ -296,7 +370,7 @@ ClassTemplateDecl::getInjectedClassNameSpecialization() { //===----------------------------------------------------------------------===// TemplateTypeParmDecl * -TemplateTypeParmDecl::Create(ASTContext &C, DeclContext *DC, +TemplateTypeParmDecl::Create(const ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D, unsigned P, IdentifierInfo *Id, bool Typename, bool ParameterPack) { @@ -305,7 +379,7 @@ TemplateTypeParmDecl::Create(ASTContext &C, DeclContext *DC, } TemplateTypeParmDecl * -TemplateTypeParmDecl::Create(ASTContext &C, EmptyShell Empty) { +TemplateTypeParmDecl::Create(const ASTContext &C, EmptyShell Empty) { return new (C) TemplateTypeParmDecl(0, SourceLocation(), 0, false, QualType(), false); } @@ -326,12 +400,62 @@ unsigned TemplateTypeParmDecl::getIndex() const { // NonTypeTemplateParmDecl Method Implementations //===----------------------------------------------------------------------===// +NonTypeTemplateParmDecl::NonTypeTemplateParmDecl(DeclContext *DC, + SourceLocation L, unsigned D, + unsigned P, IdentifierInfo *Id, + QualType T, + TypeSourceInfo *TInfo, + const QualType *ExpandedTypes, + unsigned NumExpandedTypes, + TypeSourceInfo **ExpandedTInfos) + : DeclaratorDecl(NonTypeTemplateParm, DC, L, Id, T, TInfo), + TemplateParmPosition(D, P), DefaultArgumentAndInherited(0, false), + ParameterPack(true), ExpandedParameterPack(true), + NumExpandedTypes(NumExpandedTypes) +{ + if (ExpandedTypes && ExpandedTInfos) { + void **TypesAndInfos = reinterpret_cast<void **>(this + 1); + for (unsigned I = 0; I != NumExpandedTypes; ++I) { + TypesAndInfos[2*I] = ExpandedTypes[I].getAsOpaquePtr(); + TypesAndInfos[2*I + 1] = ExpandedTInfos[I]; + } + } +} + NonTypeTemplateParmDecl * -NonTypeTemplateParmDecl::Create(ASTContext &C, DeclContext *DC, +NonTypeTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D, unsigned P, IdentifierInfo *Id, QualType T, - TypeSourceInfo *TInfo) { - return new (C) NonTypeTemplateParmDecl(DC, L, D, P, Id, T, TInfo); + bool ParameterPack, TypeSourceInfo *TInfo) { + return new (C) NonTypeTemplateParmDecl(DC, L, D, P, Id, T, ParameterPack, + TInfo); +} + +NonTypeTemplateParmDecl * +NonTypeTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC, + SourceLocation L, unsigned D, unsigned P, + IdentifierInfo *Id, QualType T, + TypeSourceInfo *TInfo, + const QualType *ExpandedTypes, + unsigned NumExpandedTypes, + TypeSourceInfo **ExpandedTInfos) { + unsigned Size = sizeof(NonTypeTemplateParmDecl) + + NumExpandedTypes * 2 * sizeof(void*); + void *Mem = C.Allocate(Size); + return new (Mem) NonTypeTemplateParmDecl(DC, L, D, P, Id, T, TInfo, + ExpandedTypes, NumExpandedTypes, + ExpandedTInfos); +} + +SourceLocation NonTypeTemplateParmDecl::getInnerLocStart() const { + SourceLocation Start = getTypeSpecStartLoc(); + if (Start.isInvalid()) + Start = getLocation(); + return Start; +} + +SourceRange NonTypeTemplateParmDecl::getSourceRange() const { + return SourceRange(getOuterLocStart(), getLocation()); } SourceLocation NonTypeTemplateParmDecl::getDefaultArgumentLoc() const { @@ -345,128 +469,29 @@ SourceLocation NonTypeTemplateParmDecl::getDefaultArgumentLoc() const { //===----------------------------------------------------------------------===// TemplateTemplateParmDecl * -TemplateTemplateParmDecl::Create(ASTContext &C, DeclContext *DC, +TemplateTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D, unsigned P, - IdentifierInfo *Id, + bool ParameterPack, IdentifierInfo *Id, TemplateParameterList *Params) { - return new (C) TemplateTemplateParmDecl(DC, L, D, P, Id, Params); -} - -//===----------------------------------------------------------------------===// -// TemplateArgumentListBuilder Implementation -//===----------------------------------------------------------------------===// - -void TemplateArgumentListBuilder::Append(const TemplateArgument &Arg) { - assert((Arg.getKind() != TemplateArgument::Type || - Arg.getAsType().isCanonical()) && "Type must be canonical!"); - assert(FlatArgs.size() < MaxFlatArgs && "Argument list builder is full!"); - assert(!StructuredArgs && - "Can't append arguments when an argument pack has been added!"); - - FlatArgs.push_back(Arg); -} - -void TemplateArgumentListBuilder::BeginPack() { - assert(!AddingToPack && "Already adding to pack!"); - assert(!StructuredArgs && "Argument list already contains a pack!"); - - AddingToPack = true; - PackBeginIndex = FlatArgs.size(); -} - -void TemplateArgumentListBuilder::EndPack() { - assert(AddingToPack && "Not adding to pack!"); - assert(!StructuredArgs && "Argument list already contains a pack!"); - - AddingToPack = false; - - // FIXME: This is a memory leak! - StructuredArgs = new TemplateArgument[MaxStructuredArgs]; - - // First copy the flat entries over to the list (if any) - for (unsigned I = 0; I != PackBeginIndex; ++I) { - NumStructuredArgs++; - StructuredArgs[I] = FlatArgs[I]; - } - - // Next, set the pack. - TemplateArgument *PackArgs = 0; - unsigned NumPackArgs = NumFlatArgs - PackBeginIndex; - // FIXME: NumPackArgs shouldn't be negative here??? - if (NumPackArgs) - PackArgs = FlatArgs.data()+PackBeginIndex; - - StructuredArgs[NumStructuredArgs++].setArgumentPack(PackArgs, NumPackArgs, - /*CopyArgs=*/false); + return new (C) TemplateTemplateParmDecl(DC, L, D, P, ParameterPack, Id, + Params); } //===----------------------------------------------------------------------===// // TemplateArgumentList Implementation //===----------------------------------------------------------------------===// -TemplateArgumentList::TemplateArgumentList(ASTContext &Context, - TemplateArgumentListBuilder &Builder, - bool TakeArgs) - : FlatArguments(Builder.getFlatArguments(), TakeArgs), - NumFlatArguments(Builder.flatSize()), - StructuredArguments(Builder.getStructuredArguments(), TakeArgs), - NumStructuredArguments(Builder.structuredSize()) { - - if (!TakeArgs) - return; - - // If this does take ownership of the arguments, then we have to new them - // and copy over. - TemplateArgument *NewArgs = - new (Context) TemplateArgument[Builder.flatSize()]; - std::copy(Builder.getFlatArguments(), - Builder.getFlatArguments()+Builder.flatSize(), NewArgs); - FlatArguments.setPointer(NewArgs); - - // Just reuse the structured and flat arguments array if possible. - if (Builder.getStructuredArguments() == Builder.getFlatArguments()) { - StructuredArguments.setPointer(NewArgs); - StructuredArguments.setInt(0); - } else { - TemplateArgument *NewSArgs = - new (Context) TemplateArgument[Builder.flatSize()]; - std::copy(Builder.getFlatArguments(), - Builder.getFlatArguments()+Builder.flatSize(), NewSArgs); - StructuredArguments.setPointer(NewSArgs); - } -} - -TemplateArgumentList::TemplateArgumentList(ASTContext &Context, - const TemplateArgument *Args, - unsigned NumArgs) - : NumFlatArguments(0), NumStructuredArguments(0) { - init(Context, Args, NumArgs); -} - -/// Produces a shallow copy of the given template argument list. This -/// assumes that the input argument list outlives it. This takes the list as -/// a pointer to avoid looking like a copy constructor, since this really -/// really isn't safe to use that way. -TemplateArgumentList::TemplateArgumentList(const TemplateArgumentList *Other) - : FlatArguments(Other->FlatArguments.getPointer(), false), - NumFlatArguments(Other->flat_size()), - StructuredArguments(Other->StructuredArguments.getPointer(), false), - NumStructuredArguments(Other->NumStructuredArguments) { } - -void TemplateArgumentList::init(ASTContext &Context, - const TemplateArgument *Args, - unsigned NumArgs) { -assert(NumFlatArguments == 0 && NumStructuredArguments == 0 && - "Already initialized!"); - -NumFlatArguments = NumStructuredArguments = NumArgs; -TemplateArgument *NewArgs = new (Context) TemplateArgument[NumArgs]; -std::copy(Args, Args+NumArgs, NewArgs); -FlatArguments.setPointer(NewArgs); -FlatArguments.setInt(1); // Owns the pointer. - -// Just reuse the flat arguments array. -StructuredArguments.setPointer(NewArgs); -StructuredArguments.setInt(0); // Doesn't own the pointer. +TemplateArgumentList * +TemplateArgumentList::CreateCopy(ASTContext &Context, + const TemplateArgument *Args, + unsigned NumArgs) { + std::size_t Size = sizeof(TemplateArgumentList) + + NumArgs * sizeof(TemplateArgument); + void *Mem = Context.Allocate(Size); + TemplateArgument *StoredArgs + = reinterpret_cast<TemplateArgument *>( + static_cast<TemplateArgumentList *>(Mem) + 1); + std::uninitialized_copy(Args, Args + NumArgs, StoredArgs); + return new (Mem) TemplateArgumentList(StoredArgs, NumArgs, true); } //===----------------------------------------------------------------------===// @@ -476,14 +501,15 @@ ClassTemplateSpecializationDecl:: ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK, TagKind TK, DeclContext *DC, SourceLocation L, ClassTemplateDecl *SpecializedTemplate, - TemplateArgumentListBuilder &Builder, + const TemplateArgument *Args, + unsigned NumArgs, ClassTemplateSpecializationDecl *PrevDecl) : CXXRecordDecl(DK, TK, DC, L, SpecializedTemplate->getIdentifier(), PrevDecl), SpecializedTemplate(SpecializedTemplate), ExplicitInfo(0), - TemplateArgs(Context, Builder, /*TakeArgs=*/true), + TemplateArgs(TemplateArgumentList::CreateCopy(Context, Args, NumArgs)), SpecializationKind(TSK_Undeclared) { } @@ -497,14 +523,15 @@ ClassTemplateSpecializationDecl * ClassTemplateSpecializationDecl::Create(ASTContext &Context, TagKind TK, DeclContext *DC, SourceLocation L, ClassTemplateDecl *SpecializedTemplate, - TemplateArgumentListBuilder &Builder, + const TemplateArgument *Args, + unsigned NumArgs, ClassTemplateSpecializationDecl *PrevDecl) { ClassTemplateSpecializationDecl *Result = new (Context)ClassTemplateSpecializationDecl(Context, ClassTemplateSpecialization, TK, DC, L, SpecializedTemplate, - Builder, + Args, NumArgs, PrevDecl); Context.getTypeDeclType(Result, PrevDecl); return Result; @@ -524,8 +551,8 @@ ClassTemplateSpecializationDecl::getNameForDiagnostic(std::string &S, const TemplateArgumentList &TemplateArgs = getTemplateArgs(); S += TemplateSpecializationType::PrintTemplateArgumentList( - TemplateArgs.getFlatArgumentList(), - TemplateArgs.flat_size(), + TemplateArgs.data(), + TemplateArgs.size(), Policy); } @@ -545,7 +572,8 @@ ClassTemplatePartialSpecializationDecl:: Create(ASTContext &Context, TagKind TK,DeclContext *DC, SourceLocation L, TemplateParameterList *Params, ClassTemplateDecl *SpecializedTemplate, - TemplateArgumentListBuilder &Builder, + const TemplateArgument *Args, + unsigned NumArgs, const TemplateArgumentListInfo &ArgInfos, QualType CanonInjectedType, ClassTemplatePartialSpecializationDecl *PrevDecl, @@ -559,7 +587,7 @@ Create(ASTContext &Context, TagKind TK,DeclContext *DC, SourceLocation L, = new (Context)ClassTemplatePartialSpecializationDecl(Context, TK, DC, L, Params, SpecializedTemplate, - Builder, + Args, NumArgs, ClonedArgs, N, PrevDecl, SequenceNumber); @@ -575,19 +603,6 @@ ClassTemplatePartialSpecializationDecl::Create(ASTContext &Context, return new (Context)ClassTemplatePartialSpecializationDecl(); } -void ClassTemplatePartialSpecializationDecl:: -initTemplateArgsAsWritten(const TemplateArgumentListInfo &ArgInfos) { - assert(ArgsAsWritten == 0 && "ArgsAsWritten already set"); - unsigned N = ArgInfos.size(); - TemplateArgumentLoc *ClonedArgs - = new (getASTContext()) TemplateArgumentLoc[N]; - for (unsigned I = 0; I != N; ++I) - ClonedArgs[I] = ArgInfos[I]; - - ArgsAsWritten = ClonedArgs; - NumArgsAsWritten = N; -} - //===----------------------------------------------------------------------===// // FriendTemplateDecl Implementation //===----------------------------------------------------------------------===// diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp index 860a0b2..cef54e9 100644 --- a/lib/AST/DeclarationName.cpp +++ b/lib/AST/DeclarationName.cpp @@ -20,6 +20,7 @@ #include "clang/Basic/IdentifierTable.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" using namespace clang; @@ -93,10 +94,8 @@ int DeclarationName::compare(DeclarationName LHS, DeclarationName RHS) { Selector RHSSelector = RHS.getObjCSelector(); 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); - - switch (LHSId->getName().compare(RHSId->getName())) { + switch (LHSSelector.getNameForSlot(I).compare( + RHSSelector.getNameForSlot(I))) { case -1: return true; case 1: return false; default: break; @@ -385,7 +384,7 @@ void DeclarationName::dump() const { llvm::errs() << '\n'; } -DeclarationNameTable::DeclarationNameTable(ASTContext &C) : Ctx(C) { +DeclarationNameTable::DeclarationNameTable(const ASTContext &C) : Ctx(C) { CXXSpecialNamesImpl = new llvm::FoldingSet<CXXSpecialName>; CXXLiteralOperatorNames = new llvm::FoldingSet<CXXLiteralOperatorIdName>; @@ -512,6 +511,28 @@ DeclarationNameLoc::DeclarationNameLoc(DeclarationName Name) { } } +bool DeclarationNameInfo::containsUnexpandedParameterPack() const { + switch (Name.getNameKind()) { + case DeclarationName::Identifier: + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + case DeclarationName::CXXOperatorName: + case DeclarationName::CXXLiteralOperatorName: + case DeclarationName::CXXUsingDirective: + return false; + + case DeclarationName::CXXConstructorName: + case DeclarationName::CXXDestructorName: + case DeclarationName::CXXConversionFunctionName: + if (TypeSourceInfo *TInfo = LocInfo.NamedType.TInfo) + return TInfo->getType()->containsUnexpandedParameterPack(); + + return Name.getCXXNameType()->containsUnexpandedParameterPack(); + } + llvm_unreachable("All name kinds handled."); +} + std::string DeclarationNameInfo::getAsString() const { std::string Result; llvm::raw_string_ostream OS(Result); diff --git a/lib/AST/DumpXML.cpp b/lib/AST/DumpXML.cpp new file mode 100644 index 0000000..9d828fc --- /dev/null +++ b/lib/AST/DumpXML.cpp @@ -0,0 +1,1028 @@ +//===--- DumpXML.cpp - Detailed XML dumping ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Decl::dumpXML() method, a debugging tool to +// print a detailed graph of an AST in an unspecified XML format. +// +// There is no guarantee of stability for this format. +// +//===----------------------------------------------------------------------===// + +// Only pay for this in code size in assertions-enabled builds. + +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclFriend.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/DeclVisitor.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" +#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/Stmt.h" +#include "clang/AST/StmtCXX.h" +#include "clang/AST/StmtObjC.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/AST/TemplateBase.h" +#include "clang/AST/TemplateName.h" +#include "clang/AST/Type.h" +#include "clang/AST/TypeLoc.h" +#include "clang/AST/TypeLocVisitor.h" +#include "clang/AST/TypeVisitor.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" + +using namespace clang; + +#ifndef NDEBUG + +namespace { + +enum NodeState { + NS_Attrs, NS_LazyChildren, NS_Children +}; + +struct Node { + llvm::StringRef Name; + NodeState State; + Node(llvm::StringRef name) : Name(name), State(NS_Attrs) {} + + bool isDoneWithAttrs() const { return State != NS_Attrs; } +}; + +template <class Impl> struct XMLDeclVisitor { +#define DISPATCH(NAME, CLASS) \ + static_cast<Impl*>(this)->NAME(static_cast<CLASS*>(D)) + + void dispatch(Decl *D) { + switch (D->getKind()) { + default: llvm_unreachable("Decl that isn't part of DeclNodes.inc!"); +#define DECL(DERIVED, BASE) \ + case Decl::DERIVED: \ + DISPATCH(dispatch##DERIVED##DeclAttrs, DERIVED##Decl); \ + static_cast<Impl*>(this)->completeAttrs(); \ + DISPATCH(dispatch##DERIVED##DeclChildren, DERIVED##Decl); \ + DISPATCH(dispatch##DERIVED##DeclAsContext, DERIVED##Decl); \ + break; +#define ABSTRACT_DECL(DECL) +#include "clang/AST/DeclNodes.inc" + } + } + +#define DECL(DERIVED, BASE) \ + void dispatch##DERIVED##DeclAttrs(DERIVED##Decl *D) { \ + DISPATCH(dispatch##BASE##Attrs, BASE); \ + DISPATCH(visit##DERIVED##DeclAttrs, DERIVED##Decl); \ + } \ + void visit##DERIVED##DeclAttrs(DERIVED##Decl *D) {} \ + void dispatch##DERIVED##DeclChildren(DERIVED##Decl *D) { \ + DISPATCH(dispatch##BASE##Children, BASE); \ + DISPATCH(visit##DERIVED##DeclChildren, DERIVED##Decl); \ + } \ + void visit##DERIVED##DeclChildren(DERIVED##Decl *D) {} \ + void dispatch##DERIVED##DeclAsContext(DERIVED##Decl *D) { \ + DISPATCH(dispatch##BASE##AsContext, BASE); \ + DISPATCH(visit##DERIVED##DeclAsContext, DERIVED##Decl); \ + } \ + void visit##DERIVED##DeclAsContext(DERIVED##Decl *D) {} +#include "clang/AST/DeclNodes.inc" + + void dispatchDeclAttrs(Decl *D) { + DISPATCH(visitDeclAttrs, Decl); + } + void visitDeclAttrs(Decl *D) {} + + void dispatchDeclChildren(Decl *D) { + DISPATCH(visitDeclChildren, Decl); + } + void visitDeclChildren(Decl *D) {} + + void dispatchDeclAsContext(Decl *D) { + DISPATCH(visitDeclAsContext, Decl); + } + void visitDeclAsContext(Decl *D) {} + +#undef DISPATCH +}; + +template <class Impl> struct XMLTypeVisitor { +#define DISPATCH(NAME, CLASS) \ + static_cast<Impl*>(this)->NAME(static_cast<CLASS*>(T)) + + void dispatch(Type *T) { + switch (T->getTypeClass()) { + default: llvm_unreachable("Type that isn't part of TypeNodes.inc!"); +#define TYPE(DERIVED, BASE) \ + case Type::DERIVED: \ + DISPATCH(dispatch##DERIVED##TypeAttrs, DERIVED##Type); \ + static_cast<Impl*>(this)->completeAttrs(); \ + DISPATCH(dispatch##DERIVED##TypeChildren, DERIVED##Type); \ + break; +#define ABSTRACT_TYPE(DERIVED, BASE) +#include "clang/AST/TypeNodes.def" + } + } + +#define TYPE(DERIVED, BASE) \ + void dispatch##DERIVED##TypeAttrs(DERIVED##Type *T) { \ + DISPATCH(dispatch##BASE##Attrs, BASE); \ + DISPATCH(visit##DERIVED##TypeAttrs, DERIVED##Type); \ + } \ + void visit##DERIVED##TypeAttrs(DERIVED##Type *T) {} \ + void dispatch##DERIVED##TypeChildren(DERIVED##Type *T) { \ + DISPATCH(dispatch##BASE##Children, BASE); \ + DISPATCH(visit##DERIVED##TypeChildren, DERIVED##Type); \ + } \ + void visit##DERIVED##TypeChildren(DERIVED##Type *T) {} +#include "clang/AST/TypeNodes.def" + + void dispatchTypeAttrs(Type *T) { + DISPATCH(visitTypeAttrs, Type); + } + void visitTypeAttrs(Type *T) {} + + void dispatchTypeChildren(Type *T) { + DISPATCH(visitTypeChildren, Type); + } + void visitTypeChildren(Type *T) {} + +#undef DISPATCH +}; + +static llvm::StringRef getTypeKindName(Type *T) { + switch (T->getTypeClass()) { +#define TYPE(DERIVED, BASE) case Type::DERIVED: return #DERIVED "Type"; +#define ABSTRACT_TYPE(DERIVED, BASE) +#include "clang/AST/TypeNodes.def" + } + + llvm_unreachable("unknown type kind!"); + return "unknown_type"; +} + +struct XMLDumper : public XMLDeclVisitor<XMLDumper>, + public XMLTypeVisitor<XMLDumper> { + llvm::raw_ostream &out; + ASTContext &Context; + llvm::SmallVector<Node, 16> Stack; + unsigned Indent; + explicit XMLDumper(llvm::raw_ostream &OS, ASTContext &context) + : out(OS), Context(context), Indent(0) {} + + void indent() { + for (unsigned I = Indent; I; --I) + out << ' '; + } + + /// Push a new node on the stack. + void push(llvm::StringRef name) { + if (!Stack.empty()) { + assert(Stack.back().isDoneWithAttrs()); + if (Stack.back().State == NS_LazyChildren) { + Stack.back().State = NS_Children; + out << ">\n"; + } + Indent++; + indent(); + } + Stack.push_back(Node(name)); + out << '<' << name; + } + + /// Set the given attribute to the given value. + void set(llvm::StringRef attr, llvm::StringRef value) { + assert(!Stack.empty() && !Stack.back().isDoneWithAttrs()); + out << ' ' << attr << '=' << '"' << value << '"'; // TODO: quotation + } + + /// Finish attributes. + void completeAttrs() { + assert(!Stack.empty() && !Stack.back().isDoneWithAttrs()); + Stack.back().State = NS_LazyChildren; + } + + /// Pop a node. + void pop() { + assert(!Stack.empty() && Stack.back().isDoneWithAttrs()); + if (Stack.back().State == NS_LazyChildren) { + out << "/>\n"; + } else { + indent(); + out << "</" << Stack.back().Name << ">\n"; + } + if (Stack.size() > 1) Indent--; + Stack.pop_back(); + } + + //---- General utilities -------------------------------------------// + + void setPointer(llvm::StringRef prop, const void *p) { + llvm::SmallString<10> buffer; + llvm::raw_svector_ostream os(buffer); + os << p; + os.flush(); + set(prop, buffer); + } + + void setPointer(void *p) { + setPointer("ptr", p); + } + + void setInteger(llvm::StringRef prop, const llvm::APSInt &v) { + set(prop, v.toString(10)); + } + + void setInteger(llvm::StringRef prop, unsigned n) { + llvm::SmallString<10> buffer; + llvm::raw_svector_ostream os(buffer); + os << n; + os.flush(); + set(prop, buffer); + } + + void setFlag(llvm::StringRef prop, bool flag) { + if (flag) set(prop, "true"); + } + + void setName(DeclarationName Name) { + if (!Name) + return set("name", ""); + + // Common case. + if (Name.isIdentifier()) + return set("name", Name.getAsIdentifierInfo()->getName()); + + set("name", Name.getAsString()); + } + + class TemporaryContainer { + XMLDumper &Dumper; + public: + TemporaryContainer(XMLDumper &dumper, llvm::StringRef name) + : Dumper(dumper) { + Dumper.push(name); + Dumper.completeAttrs(); + } + + ~TemporaryContainer() { + Dumper.pop(); + } + }; + + void visitTemplateParameters(TemplateParameterList *L) { + push("template_parameters"); + completeAttrs(); + for (TemplateParameterList::iterator + I = L->begin(), E = L->end(); I != E; ++I) + dispatch(*I); + pop(); + } + + void visitTemplateArguments(const TemplateArgumentList &L) { + push("template_arguments"); + completeAttrs(); + for (unsigned I = 0, E = L.size(); I != E; ++I) + dispatch(L[I]); + pop(); + } + + /// Visits a reference to the given declaration. + void visitDeclRef(Decl *D) { + push(D->getDeclKindName()); + setPointer("ref", D); + completeAttrs(); + pop(); + } + void visitDeclRef(llvm::StringRef Name, Decl *D) { + TemporaryContainer C(*this, Name); + if (D) visitDeclRef(D); + } + + void dispatch(const TemplateArgument &A) { + switch (A.getKind()) { + case TemplateArgument::Null: { + TemporaryContainer C(*this, "null"); + break; + } + case TemplateArgument::Type: { + dispatch(A.getAsType()); + break; + } + case TemplateArgument::Template: + case TemplateArgument::TemplateExpansion: + // FIXME: Implement! + break; + + case TemplateArgument::Declaration: { + visitDeclRef(A.getAsDecl()); + break; + } + case TemplateArgument::Integral: { + push("integer"); + setInteger("value", *A.getAsIntegral()); + completeAttrs(); + pop(); + break; + } + case TemplateArgument::Expression: { + dispatch(A.getAsExpr()); + break; + } + case TemplateArgument::Pack: { + for (TemplateArgument::pack_iterator P = A.pack_begin(), + PEnd = A.pack_end(); + P != PEnd; ++P) + dispatch(*P); + break; + } + } + } + + void dispatch(const TemplateArgumentLoc &A) { + dispatch(A.getArgument()); + } + + //---- Declarations ------------------------------------------------// + // Calls are made in this order: + // # Enter a new node. + // push("FieldDecl") + // + // # In this phase, attributes are set on the node. + // visitDeclAttrs(D) + // visitNamedDeclAttrs(D) + // ... + // visitFieldDeclAttrs(D) + // + // # No more attributes after this point. + // completeAttrs() + // + // # Create "header" child nodes, i.e. those which logically + // # belong to the declaration itself. + // visitDeclChildren(D) + // visitNamedDeclChildren(D) + // ... + // visitFieldDeclChildren(D) + // + // # Create nodes for the lexical children. + // visitDeclAsContext(D) + // visitNamedDeclAsContext(D) + // ... + // visitFieldDeclAsContext(D) + // + // # Finish the node. + // pop(); + void dispatch(Decl *D) { + push(D->getDeclKindName()); + XMLDeclVisitor<XMLDumper>::dispatch(D); + pop(); + } + void visitDeclAttrs(Decl *D) { + setPointer(D); + } + + /// Visit all the lexical decls in the given context. + void visitDeclContext(DeclContext *DC) { + for (DeclContext::decl_iterator + I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) + dispatch(*I); + + // FIXME: point out visible declarations not in lexical context? + } + + /// Set the "access" attribute on the current node according to the + /// given specifier. + void setAccess(AccessSpecifier AS) { + switch (AS) { + case AS_public: return set("access", "public"); + case AS_protected: return set("access", "protected"); + case AS_private: return set("access", "private"); + case AS_none: llvm_unreachable("explicit forbidden access"); + } + } + + template <class T> void visitRedeclarableAttrs(T *D) { + if (T *Prev = D->getPreviousDeclaration()) + setPointer("previous", Prev); + } + + + // TranslationUnitDecl + void visitTranslationUnitDeclAsContext(TranslationUnitDecl *D) { + visitDeclContext(D); + } + + // LinkageSpecDecl + void visitLinkageSpecDeclAttrs(LinkageSpecDecl *D) { + llvm::StringRef lang = ""; + switch (D->getLanguage()) { + case LinkageSpecDecl::lang_c: lang = "C"; break; + case LinkageSpecDecl::lang_cxx: lang = "C++"; break; + } + set("lang", lang); + } + void visitLinkageSpecDeclAsContext(LinkageSpecDecl *D) { + visitDeclContext(D); + } + + // NamespaceDecl + void visitNamespaceDeclAttrs(NamespaceDecl *D) { + setFlag("inline", D->isInline()); + if (!D->isOriginalNamespace()) + setPointer("original", D->getOriginalNamespace()); + } + void visitNamespaceDeclAsContext(NamespaceDecl *D) { + visitDeclContext(D); + } + + // NamedDecl + void visitNamedDeclAttrs(NamedDecl *D) { + setName(D->getDeclName()); + } + + // ValueDecl + void visitValueDeclChildren(ValueDecl *D) { + dispatch(D->getType()); + } + + // DeclaratorDecl + void visitDeclaratorDeclChildren(DeclaratorDecl *D) { + //dispatch(D->getTypeSourceInfo()->getTypeLoc()); + } + + // VarDecl + void visitVarDeclAttrs(VarDecl *D) { + visitRedeclarableAttrs(D); + if (D->getStorageClass() != SC_None) + set("storage", + VarDecl::getStorageClassSpecifierString(D->getStorageClass())); + setFlag("directinit", D->hasCXXDirectInitializer()); + setFlag("nrvo", D->isNRVOVariable()); + // TODO: instantiation, etc. + } + void visitVarDeclChildren(VarDecl *D) { + if (D->hasInit()) dispatch(D->getInit()); + } + + // ParmVarDecl? + + // FunctionDecl + void visitFunctionDeclAttrs(FunctionDecl *D) { + visitRedeclarableAttrs(D); + setFlag("pure", D->isPure()); + setFlag("trivial", D->isTrivial()); + setFlag("returnzero", D->hasImplicitReturnZero()); + setFlag("prototype", D->hasWrittenPrototype()); + setFlag("deleted", D->isDeleted()); + if (D->getStorageClass() != SC_None) + set("storage", + VarDecl::getStorageClassSpecifierString(D->getStorageClass())); + setFlag("inline", D->isInlineSpecified()); + // TODO: instantiation, etc. + } + void visitFunctionDeclChildren(FunctionDecl *D) { + for (FunctionDecl::param_iterator + I = D->param_begin(), E = D->param_end(); I != E; ++I) + dispatch(*I); + if (D->isThisDeclarationADefinition()) + dispatch(D->getBody()); + } + + // CXXMethodDecl ? + // CXXConstructorDecl ? + // CXXDestructorDecl ? + // CXXConversionDecl ? + + void dispatch(CXXCtorInitializer *Init) { + // TODO + } + + // FieldDecl + void visitFieldDeclAttrs(FieldDecl *D) { + setFlag("mutable", D->isMutable()); + } + void visitFieldDeclChildren(FieldDecl *D) { + if (D->isBitField()) { + TemporaryContainer C(*this, "bitwidth"); + dispatch(D->getBitWidth()); + } + // TODO: C++0x member initializer + } + + // EnumConstantDecl + void visitEnumConstantDeclChildren(EnumConstantDecl *D) { + // value in any case? + if (D->getInitExpr()) dispatch(D->getInitExpr()); + } + + // IndirectFieldDecl + void visitIndirectFieldDeclChildren(IndirectFieldDecl *D) { + for (IndirectFieldDecl::chain_iterator + I = D->chain_begin(), E = D->chain_end(); I != E; ++I) { + NamedDecl *VD = const_cast<NamedDecl*>(*I); + push(isa<VarDecl>(VD) ? "variable" : "field"); + setPointer("ptr", VD); + completeAttrs(); + pop(); + } + } + + // TypeDecl + void visitTypeDeclAttrs(TypeDecl *D) { + setPointer("typeptr", D->getTypeForDecl()); + } + + // TypedefDecl + void visitTypedefDeclAttrs(TypedefDecl *D) { + visitRedeclarableAttrs(D); + } + void visitTypedefDeclChildren(TypedefDecl *D) { + dispatch(D->getTypeSourceInfo()->getTypeLoc()); + } + + // TagDecl + void visitTagDeclAttrs(TagDecl *D) { + visitRedeclarableAttrs(D); + } + void visitTagDeclAsContext(TagDecl *D) { + visitDeclContext(D); + } + + // EnumDecl + void visitEnumDeclAttrs(EnumDecl *D) { + setFlag("scoped", D->isScoped()); + setFlag("fixed", D->isFixed()); + } + void visitEnumDeclChildren(EnumDecl *D) { + { + TemporaryContainer C(*this, "promotion_type"); + dispatch(D->getPromotionType()); + } + { + TemporaryContainer C(*this, "integer_type"); + dispatch(D->getIntegerType()); + } + } + + // RecordDecl ? + + void visitCXXRecordDeclChildren(CXXRecordDecl *D) { + if (!D->isThisDeclarationADefinition()) return; + + for (CXXRecordDecl::base_class_iterator + I = D->bases_begin(), E = D->bases_end(); I != E; ++I) { + push("base"); + setAccess(I->getAccessSpecifier()); + completeAttrs(); + dispatch(I->getTypeSourceInfo()->getTypeLoc()); + pop(); + } + } + + // ClassTemplateSpecializationDecl ? + + // FileScopeAsmDecl ? + + // BlockDecl + void visitBlockDeclAttrs(BlockDecl *D) { + setFlag("variadic", D->isVariadic()); + } + void visitBlockDeclChildren(BlockDecl *D) { + for (FunctionDecl::param_iterator + I = D->param_begin(), E = D->param_end(); I != E; ++I) + dispatch(*I); + dispatch(D->getBody()); + } + + // AccessSpecDecl + void visitAccessSpecDeclAttrs(AccessSpecDecl *D) { + setAccess(D->getAccess()); + } + + // TemplateDecl + void visitTemplateDeclChildren(TemplateDecl *D) { + visitTemplateParameters(D->getTemplateParameters()); + dispatch(D->getTemplatedDecl()); + } + + // FunctionTemplateDecl + void visitFunctionTemplateDeclAttrs(FunctionTemplateDecl *D) { + visitRedeclarableAttrs(D); + } + void visitFunctionTemplateDeclChildren(FunctionTemplateDecl *D) { + // Mention all the specializations which don't have explicit + // declarations elsewhere. + for (FunctionTemplateDecl::spec_iterator + I = D->spec_begin(), E = D->spec_end(); I != E; ++I) { + FunctionTemplateSpecializationInfo *Info + = I->getTemplateSpecializationInfo(); + + bool Unknown = false; + switch (Info->getTemplateSpecializationKind()) { + case TSK_ImplicitInstantiation: Unknown = false; break; + case TSK_Undeclared: Unknown = true; break; + + // These will be covered at their respective sites. + case TSK_ExplicitSpecialization: continue; + case TSK_ExplicitInstantiationDeclaration: continue; + case TSK_ExplicitInstantiationDefinition: continue; + } + + TemporaryContainer C(*this, + Unknown ? "uninstantiated" : "instantiation"); + visitTemplateArguments(*Info->TemplateArguments); + dispatch(Info->Function); + } + } + + // ClasTemplateDecl + void visitClassTemplateDeclAttrs(ClassTemplateDecl *D) { + visitRedeclarableAttrs(D); + } + void visitClassTemplateDeclChildren(ClassTemplateDecl *D) { + // Mention all the specializations which don't have explicit + // declarations elsewhere. + for (ClassTemplateDecl::spec_iterator + I = D->spec_begin(), E = D->spec_end(); I != E; ++I) { + + bool Unknown = false; + switch (I->getTemplateSpecializationKind()) { + case TSK_ImplicitInstantiation: Unknown = false; break; + case TSK_Undeclared: Unknown = true; break; + + // These will be covered at their respective sites. + case TSK_ExplicitSpecialization: continue; + case TSK_ExplicitInstantiationDeclaration: continue; + case TSK_ExplicitInstantiationDefinition: continue; + } + + TemporaryContainer C(*this, + Unknown ? "uninstantiated" : "instantiation"); + visitTemplateArguments(I->getTemplateArgs()); + dispatch(*I); + } + } + + // TemplateTypeParmDecl + void visitTemplateTypeParmDeclAttrs(TemplateTypeParmDecl *D) { + setInteger("depth", D->getDepth()); + setInteger("index", D->getIndex()); + } + void visitTemplateTypeParmDeclChildren(TemplateTypeParmDecl *D) { + if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) + dispatch(D->getDefaultArgumentInfo()->getTypeLoc()); + // parameter pack? + } + + // NonTypeTemplateParmDecl + void visitNonTypeTemplateParmDeclAttrs(NonTypeTemplateParmDecl *D) { + setInteger("depth", D->getDepth()); + setInteger("index", D->getIndex()); + } + void visitNonTypeTemplateParmDeclChildren(NonTypeTemplateParmDecl *D) { + if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) + dispatch(D->getDefaultArgument()); + // parameter pack? + } + + // TemplateTemplateParmDecl + void visitTemplateTemplateParmDeclAttrs(TemplateTemplateParmDecl *D) { + setInteger("depth", D->getDepth()); + setInteger("index", D->getIndex()); + } + void visitTemplateTemplateParmDeclChildren(TemplateTemplateParmDecl *D) { + if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) + dispatch(D->getDefaultArgument()); + // parameter pack? + } + + // FriendDecl + void visitFriendDeclChildren(FriendDecl *D) { + if (TypeSourceInfo *T = D->getFriendType()) + dispatch(T->getTypeLoc()); + else + dispatch(D->getFriendDecl()); + } + + // UsingDirectiveDecl ? + // UsingDecl ? + // UsingShadowDecl ? + // NamespaceAliasDecl ? + // UnresolvedUsingValueDecl ? + // UnresolvedUsingTypenameDecl ? + // StaticAssertDecl ? + + // ObjCImplDecl + void visitObjCImplDeclChildren(ObjCImplDecl *D) { + visitDeclRef(D->getClassInterface()); + } + void visitObjCImplDeclAsContext(ObjCImplDecl *D) { + visitDeclContext(D); + } + + // ObjCClassDecl + void visitObjCClassDeclChildren(ObjCClassDecl *D) { + for (ObjCClassDecl::iterator I = D->begin(), E = D->end(); I != E; ++I) + visitDeclRef(I->getInterface()); + } + + // ObjCInterfaceDecl + void visitCategoryList(ObjCCategoryDecl *D) { + if (!D) return; + + TemporaryContainer C(*this, "categories"); + for (; D; D = D->getNextClassCategory()) + visitDeclRef(D); + } + void visitObjCInterfaceDeclAttrs(ObjCInterfaceDecl *D) { + setPointer("typeptr", D->getTypeForDecl()); + setFlag("forward_decl", D->isForwardDecl()); + setFlag("implicit_interface", D->isImplicitInterfaceDecl()); + } + void visitObjCInterfaceDeclChildren(ObjCInterfaceDecl *D) { + visitDeclRef("super", D->getSuperClass()); + visitDeclRef("implementation", D->getImplementation()); + if (D->protocol_begin() != D->protocol_end()) { + TemporaryContainer C(*this, "protocols"); + for (ObjCInterfaceDecl::protocol_iterator + I = D->protocol_begin(), E = D->protocol_end(); I != E; ++I) + visitDeclRef(*I); + } + visitCategoryList(D->getCategoryList()); + } + void visitObjCInterfaceDeclAsContext(ObjCInterfaceDecl *D) { + visitDeclContext(D); + } + + // ObjCCategoryDecl + void visitObjCCategoryDeclAttrs(ObjCCategoryDecl *D) { + setFlag("extension", D->IsClassExtension()); + setFlag("synth_bitfield", D->hasSynthBitfield()); + } + void visitObjCCategoryDeclChildren(ObjCCategoryDecl *D) { + visitDeclRef("interface", D->getClassInterface()); + visitDeclRef("implementation", D->getImplementation()); + if (D->protocol_begin() != D->protocol_end()) { + TemporaryContainer C(*this, "protocols"); + for (ObjCCategoryDecl::protocol_iterator + I = D->protocol_begin(), E = D->protocol_end(); I != E; ++I) + visitDeclRef(*I); + } + } + void visitObjCCategoryDeclAsContext(ObjCCategoryDecl *D) { + visitDeclContext(D); + } + + // ObjCCategoryImplDecl + void visitObjCCategoryImplDeclAttrs(ObjCCategoryImplDecl *D) { + set("identifier", D->getName()); + } + void visitObjCCategoryImplDeclChildren(ObjCCategoryImplDecl *D) { + visitDeclRef(D->getCategoryDecl()); + } + + // ObjCImplementationDecl + void visitObjCImplementationDeclAttrs(ObjCImplementationDecl *D) { + setFlag("synth_bitfield", D->hasSynthBitfield()); + set("identifier", D->getName()); + } + void visitObjCImplementationDeclChildren(ObjCImplementationDecl *D) { + visitDeclRef("super", D->getSuperClass()); + if (D->init_begin() != D->init_end()) { + TemporaryContainer C(*this, "initializers"); + for (ObjCImplementationDecl::init_iterator + I = D->init_begin(), E = D->init_end(); I != E; ++I) + dispatch(*I); + } + } + + // ObjCForwardProtocolDecl + void visitObjCForwardProtocolDeclChildren(ObjCForwardProtocolDecl *D) { + for (ObjCForwardProtocolDecl::protocol_iterator + I = D->protocol_begin(), E = D->protocol_end(); I != E; ++I) + visitDeclRef(*I); + } + + // ObjCProtocolDecl + void visitObjCProtocolDeclAttrs(ObjCProtocolDecl *D) { + setFlag("forward_decl", D->isForwardDecl()); + } + void visitObjCProtocolDeclChildren(ObjCProtocolDecl *D) { + if (D->protocol_begin() != D->protocol_end()) { + TemporaryContainer C(*this, "protocols"); + for (ObjCInterfaceDecl::protocol_iterator + I = D->protocol_begin(), E = D->protocol_end(); I != E; ++I) + visitDeclRef(*I); + } + } + void visitObjCProtocolDeclAsContext(ObjCProtocolDecl *D) { + visitDeclContext(D); + } + + // ObjCMethodDecl + void visitObjCMethodDeclAttrs(ObjCMethodDecl *D) { + // decl qualifier? + // implementation control? + + setFlag("instance", D->isInstanceMethod()); + setFlag("variadic", D->isVariadic()); + setFlag("synthesized", D->isSynthesized()); + setFlag("defined", D->isDefined()); + } + void visitObjCMethodDeclChildren(ObjCMethodDecl *D) { + dispatch(D->getResultType()); + for (ObjCMethodDecl::param_iterator + I = D->param_begin(), E = D->param_end(); I != E; ++I) + dispatch(*I); + if (D->isThisDeclarationADefinition()) + dispatch(D->getBody()); + } + + // ObjCIvarDecl + void setAccessControl(llvm::StringRef prop, ObjCIvarDecl::AccessControl AC) { + switch (AC) { + case ObjCIvarDecl::None: return set(prop, "none"); + case ObjCIvarDecl::Private: return set(prop, "private"); + case ObjCIvarDecl::Protected: return set(prop, "protected"); + case ObjCIvarDecl::Public: return set(prop, "public"); + case ObjCIvarDecl::Package: return set(prop, "package"); + } + } + void visitObjCIvarDeclAttrs(ObjCIvarDecl *D) { + setFlag("synthesize", D->getSynthesize()); + setAccessControl("access", D->getAccessControl()); + } + + // ObjCCompatibleAliasDecl + void visitObjCCompatibleAliasDeclChildren(ObjCCompatibleAliasDecl *D) { + visitDeclRef(D->getClassInterface()); + } + + // FIXME: ObjCPropertyDecl + // FIXME: ObjCPropertyImplDecl + + //---- Types -----------------------------------------------------// + void dispatch(TypeLoc TL) { + dispatch(TL.getType()); // for now + } + + void dispatch(QualType T) { + if (T.hasLocalQualifiers()) { + push("QualType"); + Qualifiers Qs = T.getLocalQualifiers(); + setFlag("const", Qs.hasConst()); + setFlag("volatile", Qs.hasVolatile()); + setFlag("restrict", Qs.hasRestrict()); + if (Qs.hasAddressSpace()) setInteger("addrspace", Qs.getAddressSpace()); + if (Qs.hasObjCGCAttr()) { + switch (Qs.getObjCGCAttr()) { + case Qualifiers::Weak: set("gc", "weak"); break; + case Qualifiers::Strong: set("gc", "strong"); break; + case Qualifiers::GCNone: llvm_unreachable("explicit none"); + } + } + + completeAttrs(); + dispatch(QualType(T.getTypePtr(), 0)); + pop(); + return; + } + + Type *Ty = const_cast<Type*>(T.getTypePtr()); + push(getTypeKindName(Ty)); + XMLTypeVisitor<XMLDumper>::dispatch(const_cast<Type*>(T.getTypePtr())); + pop(); + } + + void setCallingConv(CallingConv CC) { + switch (CC) { + case CC_Default: return; + case CC_C: return set("cc", "cdecl"); + case CC_X86FastCall: return set("cc", "x86_fastcall"); + case CC_X86StdCall: return set("cc", "x86_stdcall"); + case CC_X86ThisCall: return set("cc", "x86_thiscall"); + case CC_X86Pascal: return set("cc", "x86_pascal"); + } + } + + void visitTypeAttrs(Type *D) { + setPointer(D); + setFlag("dependent", D->isDependentType()); + setFlag("variably_modified", D->isVariablyModifiedType()); + + setPointer("canonical", D->getCanonicalTypeInternal().getAsOpaquePtr()); + } + + void visitPointerTypeChildren(PointerType *T) { + dispatch(T->getPointeeType()); + } + void visitReferenceTypeChildren(ReferenceType *T) { + dispatch(T->getPointeeType()); + } + void visitObjCObjectPointerTypeChildren(ObjCObjectPointerType *T) { + dispatch(T->getPointeeType()); + } + void visitBlockPointerTypeChildren(BlockPointerType *T) { + dispatch(T->getPointeeType()); + } + + // Types that just wrap declarations. + void visitTagTypeChildren(TagType *T) { + visitDeclRef(T->getDecl()); + } + void visitTypedefTypeChildren(TypedefType *T) { + visitDeclRef(T->getDecl()); + } + void visitObjCInterfaceTypeChildren(ObjCInterfaceType *T) { + visitDeclRef(T->getDecl()); + } + void visitUnresolvedUsingTypeChildren(UnresolvedUsingType *T) { + visitDeclRef(T->getDecl()); + } + void visitInjectedClassNameTypeChildren(InjectedClassNameType *T) { + visitDeclRef(T->getDecl()); + } + + void visitFunctionTypeAttrs(FunctionType *T) { + setFlag("noreturn", T->getNoReturnAttr()); + setCallingConv(T->getCallConv()); + if (T->getRegParmType()) setInteger("regparm", T->getRegParmType()); + } + void visitFunctionTypeChildren(FunctionType *T) { + dispatch(T->getResultType()); + } + + void visitFunctionProtoTypeAttrs(FunctionProtoType *T) { + setFlag("const", T->getTypeQuals() & Qualifiers::Const); + setFlag("volatile", T->getTypeQuals() & Qualifiers::Volatile); + setFlag("restrict", T->getTypeQuals() & Qualifiers::Restrict); + } + void visitFunctionProtoTypeChildren(FunctionProtoType *T) { + push("parameters"); + setFlag("variadic", T->isVariadic()); + completeAttrs(); + for (FunctionProtoType::arg_type_iterator + I = T->arg_type_begin(), E = T->arg_type_end(); I != E; ++I) + dispatch(*I); + pop(); + + if (T->hasExceptionSpec()) { + push("exception_specifiers"); + setFlag("any", T->hasAnyExceptionSpec()); + completeAttrs(); + for (FunctionProtoType::exception_iterator + I = T->exception_begin(), E = T->exception_end(); I != E; ++I) + dispatch(*I); + pop(); + } + } + + void visitTemplateSpecializationTypeChildren(TemplateSpecializationType *T) { + if (const RecordType *RT = T->getAs<RecordType>()) + visitDeclRef(RT->getDecl()); + + // TODO: TemplateName + + push("template_arguments"); + completeAttrs(); + for (unsigned I = 0, E = T->getNumArgs(); I != E; ++I) + dispatch(T->getArg(I)); + pop(); + } + + //---- Statements ------------------------------------------------// + void dispatch(Stmt *S) { + // FIXME: this is not really XML at all + push("Stmt"); + out << ">\n"; + Stack.back().State = NS_Children; // explicitly become non-lazy + S->dump(out, Context.getSourceManager()); + out << '\n'; + pop(); + } +}; +} + +void Decl::dumpXML() const { + dumpXML(llvm::errs()); +} + +void Decl::dumpXML(llvm::raw_ostream &out) const { + XMLDumper(out, getASTContext()).dispatch(const_cast<Decl*>(this)); +} + +#else /* ifndef NDEBUG */ + +void Decl::dumpXML() const {} +void Decl::dumpXML(llvm::raw_ostream &out) const {} + +#endif diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 5feef1c..391b26a 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -20,15 +20,16 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/StmtVisitor.h" +#include "clang/Lex/LiteralSupport.h" +#include "clang/Lex/Lexer.h" #include "clang/Basic/Builtins.h" +#include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> using namespace clang; -void Expr::ANCHOR() {} // key function for Expr class. - /// isKnownToHaveBooleanValue - Return true if this is an integer expression /// that is known to return 0 or 1. This happens for _Bool/bool expressions /// but also int expressions which are produced by things like comparisons in @@ -90,6 +91,42 @@ bool Expr::isKnownToHaveBooleanValue() const { return false; } +// Amusing macro metaprogramming hack: check whether a class provides +// a more specific implementation of getExprLoc(). +namespace { + /// This implementation is used when a class provides a custom + /// implementation of getExprLoc. + template <class E, class T> + SourceLocation getExprLocImpl(const Expr *expr, + SourceLocation (T::*v)() const) { + return static_cast<const E*>(expr)->getExprLoc(); + } + + /// This implementation is used when a class doesn't provide + /// a custom implementation of getExprLoc. Overload resolution + /// should pick it over the implementation above because it's + /// more specialized according to function template partial ordering. + template <class E> + SourceLocation getExprLocImpl(const Expr *expr, + SourceLocation (Expr::*v)() const) { + return static_cast<const E*>(expr)->getSourceRange().getBegin(); + } +} + +SourceLocation Expr::getExprLoc() const { + switch (getStmtClass()) { + case Stmt::NoStmtClass: llvm_unreachable("statement without class"); +#define ABSTRACT_STMT(type) +#define STMT(type, base) \ + case Stmt::type##Class: llvm_unreachable(#type " is not an Expr"); break; +#define EXPR(type, base) \ + case Stmt::type##Class: return getExprLocImpl<type>(this, &type::getExprLoc); +#include "clang/AST/StmtNodes.inc" + } + llvm_unreachable("unknown statement kind"); + return SourceLocation(); +} + //===----------------------------------------------------------------------===// // Primary Expressions. //===----------------------------------------------------------------------===// @@ -105,6 +142,25 @@ void ExplicitTemplateArgumentList::initializeFrom( new (&ArgBuffer[i]) TemplateArgumentLoc(Info[i]); } +void ExplicitTemplateArgumentList::initializeFrom( + const TemplateArgumentListInfo &Info, + bool &Dependent, + bool &ContainsUnexpandedParameterPack) { + LAngleLoc = Info.getLAngleLoc(); + RAngleLoc = Info.getRAngleLoc(); + NumTemplateArgs = Info.size(); + + TemplateArgumentLoc *ArgBuffer = getTemplateArgs(); + for (unsigned i = 0; i != NumTemplateArgs; ++i) { + Dependent = Dependent || Info[i].getArgument().isDependent(); + ContainsUnexpandedParameterPack + = ContainsUnexpandedParameterPack || + Info[i].getArgument().containsUnexpandedParameterPack(); + + new (&ArgBuffer[i]) TemplateArgumentLoc(Info[i]); + } +} + void ExplicitTemplateArgumentList::copyInto( TemplateArgumentListInfo &Info) const { Info.setLAngleLoc(LAngleLoc); @@ -123,11 +179,14 @@ std::size_t ExplicitTemplateArgumentList::sizeFor( return sizeFor(Info.size()); } -void DeclRefExpr::computeDependence() { +/// \brief Compute the type- and value-dependence of a declaration reference +/// based on the declaration being referenced. +static void computeDeclRefDependence(NamedDecl *D, QualType T, + bool &TypeDependent, + bool &ValueDependent) { TypeDependent = false; ValueDependent = false; - NamedDecl *D = getDecl(); // (TD) C++ [temp.dep.expr]p3: // An id-expression is type-dependent if it contains: @@ -136,63 +195,93 @@ void DeclRefExpr::computeDependence() { // // (VD) C++ [temp.dep.constexpr]p2: // An identifier is value-dependent if it is: - + // (TD) - an identifier that was declared with dependent type // (VD) - a name declared with a dependent type, - if (getType()->isDependentType()) { + if (T->isDependentType()) { TypeDependent = true; ValueDependent = true; + return; } + // (TD) - a conversion-function-id that specifies a dependent type - else if (D->getDeclName().getNameKind() - == DeclarationName::CXXConversionFunctionName && + if (D->getDeclName().getNameKind() + == DeclarationName::CXXConversionFunctionName && D->getDeclName().getCXXNameType()->isDependentType()) { TypeDependent = true; ValueDependent = true; - } - // (TD) - a template-id that is dependent, - else if (hasExplicitTemplateArgs() && - TemplateSpecializationType::anyDependentTemplateArguments( - getTemplateArgs(), - getNumTemplateArgs())) { - TypeDependent = true; - ValueDependent = true; + return; } // (VD) - the name of a non-type template parameter, - else if (isa<NonTypeTemplateParmDecl>(D)) + if (isa<NonTypeTemplateParmDecl>(D)) { ValueDependent = true; + return; + } + // (VD) - a constant with integral or enumeration type and is // initialized with an expression that is value-dependent. - else if (VarDecl *Var = dyn_cast<VarDecl>(D)) { + if (VarDecl *Var = dyn_cast<VarDecl>(D)) { if (Var->getType()->isIntegralOrEnumerationType() && Var->getType().getCVRQualifiers() == Qualifiers::Const) { if (const Expr *Init = Var->getAnyInitializer()) if (Init->isValueDependent()) ValueDependent = true; } + // (VD) - FIXME: Missing from the standard: // - a member function or a static data member of the current // instantiation else if (Var->isStaticDataMember() && Var->getDeclContext()->isDependentContext()) ValueDependent = true; - } + + return; + } + // (VD) - FIXME: Missing from the standard: // - a member function or a static data member of the current // instantiation - else if (isa<CXXMethodDecl>(D) && D->getDeclContext()->isDependentContext()) + if (isa<CXXMethodDecl>(D) && D->getDeclContext()->isDependentContext()) { ValueDependent = true; - // (TD) - a nested-name-specifier or a qualified-id that names a - // member of an unknown specialization. - // (handled by DependentScopeDeclRefExpr) + return; + } +} + +void DeclRefExpr::computeDependence() { + bool TypeDependent = false; + bool ValueDependent = false; + computeDeclRefDependence(getDecl(), getType(), TypeDependent, ValueDependent); + + // (TD) C++ [temp.dep.expr]p3: + // An id-expression is type-dependent if it contains: + // + // and + // + // (VD) C++ [temp.dep.constexpr]p2: + // An identifier is value-dependent if it is: + if (!TypeDependent && !ValueDependent && + hasExplicitTemplateArgs() && + TemplateSpecializationType::anyDependentTemplateArguments( + getTemplateArgs(), + getNumTemplateArgs())) { + TypeDependent = true; + ValueDependent = true; + } + + ExprBits.TypeDependent = TypeDependent; + ExprBits.ValueDependent = ValueDependent; + + // Is the declaration a parameter pack? + if (getDecl()->isParameterPack()) + ExprBits.ContainsUnexpandedParameterPack = true; } DeclRefExpr::DeclRefExpr(NestedNameSpecifier *Qualifier, SourceRange QualifierRange, ValueDecl *D, SourceLocation NameLoc, const TemplateArgumentListInfo *TemplateArgs, - QualType T) - : Expr(DeclRefExprClass, T, false, false), + QualType T, ExprValueKind VK) + : Expr(DeclRefExprClass, T, VK, OK_Ordinary, false, false, false), DecoratedD(D, (Qualifier? HasQualifierFlag : 0) | (TemplateArgs ? HasExplicitTemplateArgumentListFlag : 0)), @@ -213,8 +302,8 @@ DeclRefExpr::DeclRefExpr(NestedNameSpecifier *Qualifier, SourceRange QualifierRange, ValueDecl *D, const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *TemplateArgs, - QualType T) - : Expr(DeclRefExprClass, T, false, false), + QualType T, ExprValueKind VK) + : Expr(DeclRefExprClass, T, VK, OK_Ordinary, false, false, false), DecoratedD(D, (Qualifier? HasQualifierFlag : 0) | (TemplateArgs ? HasExplicitTemplateArgumentListFlag : 0)), @@ -237,10 +326,11 @@ DeclRefExpr *DeclRefExpr::Create(ASTContext &Context, ValueDecl *D, SourceLocation NameLoc, QualType T, + ExprValueKind VK, const TemplateArgumentListInfo *TemplateArgs) { return Create(Context, Qualifier, QualifierRange, D, DeclarationNameInfo(D->getDeclName(), NameLoc), - T, TemplateArgs); + T, VK, TemplateArgs); } DeclRefExpr *DeclRefExpr::Create(ASTContext &Context, @@ -249,6 +339,7 @@ DeclRefExpr *DeclRefExpr::Create(ASTContext &Context, ValueDecl *D, const DeclarationNameInfo &NameInfo, QualType T, + ExprValueKind VK, const TemplateArgumentListInfo *TemplateArgs) { std::size_t Size = sizeof(DeclRefExpr); if (Qualifier != 0) @@ -257,21 +348,23 @@ DeclRefExpr *DeclRefExpr::Create(ASTContext &Context, if (TemplateArgs) Size += ExplicitTemplateArgumentList::sizeFor(*TemplateArgs); - void *Mem = Context.Allocate(Size, llvm::alignof<DeclRefExpr>()); + void *Mem = Context.Allocate(Size, llvm::alignOf<DeclRefExpr>()); return new (Mem) DeclRefExpr(Qualifier, QualifierRange, D, NameInfo, - TemplateArgs, T); + TemplateArgs, T, VK); } -DeclRefExpr *DeclRefExpr::CreateEmpty(ASTContext &Context, bool HasQualifier, +DeclRefExpr *DeclRefExpr::CreateEmpty(ASTContext &Context, + bool HasQualifier, + bool HasExplicitTemplateArgs, unsigned NumTemplateArgs) { std::size_t Size = sizeof(DeclRefExpr); if (HasQualifier) Size += sizeof(NameQualifier); - if (NumTemplateArgs) + if (HasExplicitTemplateArgs) Size += ExplicitTemplateArgumentList::sizeFor(NumTemplateArgs); - void *Mem = Context.Allocate(Size, llvm::alignof<DeclRefExpr>()); + void *Mem = Context.Allocate(Size, llvm::alignOf<DeclRefExpr>()); return new (Mem) DeclRefExpr(EmptyShell()); } @@ -432,7 +525,7 @@ StringLiteral *StringLiteral::Create(ASTContext &C, const char *StrData, // any concatenated string tokens. void *Mem = C.Allocate(sizeof(StringLiteral)+ sizeof(SourceLocation)*(NumStrs-1), - llvm::alignof<StringLiteral>()); + llvm::alignOf<StringLiteral>()); StringLiteral *SL = new (Mem) StringLiteral(Ty); // OPTIMIZE: could allocate this appended to the StringLiteral. @@ -452,7 +545,7 @@ StringLiteral *StringLiteral::Create(ASTContext &C, const char *StrData, StringLiteral *StringLiteral::CreateEmpty(ASTContext &C, unsigned NumStrs) { void *Mem = C.Allocate(sizeof(StringLiteral)+ sizeof(SourceLocation)*(NumStrs-1), - llvm::alignof<StringLiteral>()); + llvm::alignOf<StringLiteral>()); StringLiteral *SL = new (Mem) StringLiteral(QualType()); SL->StrData = 0; SL->ByteLength = 0; @@ -467,6 +560,72 @@ void StringLiteral::setString(ASTContext &C, llvm::StringRef Str) { ByteLength = Str.size(); } +/// getLocationOfByte - Return a source location that points to the specified +/// byte of this string literal. +/// +/// Strings are amazingly complex. They can be formed from multiple tokens and +/// can have escape sequences in them in addition to the usual trigraph and +/// escaped newline business. This routine handles this complexity. +/// +SourceLocation StringLiteral:: +getLocationOfByte(unsigned ByteNo, const SourceManager &SM, + const LangOptions &Features, const TargetInfo &Target) const { + assert(!isWide() && "This doesn't work for wide strings yet"); + + // Loop over all of the tokens in this string until we find the one that + // contains the byte we're looking for. + unsigned TokNo = 0; + while (1) { + assert(TokNo < getNumConcatenated() && "Invalid byte number!"); + SourceLocation StrTokLoc = getStrTokenLoc(TokNo); + + // Get the spelling of the string so that we can get the data that makes up + // the string literal, not the identifier for the macro it is potentially + // expanded through. + SourceLocation StrTokSpellingLoc = SM.getSpellingLoc(StrTokLoc); + + // Re-lex the token to get its length and original spelling. + std::pair<FileID, unsigned> LocInfo =SM.getDecomposedLoc(StrTokSpellingLoc); + bool Invalid = false; + llvm::StringRef Buffer = SM.getBufferData(LocInfo.first, &Invalid); + if (Invalid) + return StrTokSpellingLoc; + + const char *StrData = Buffer.data()+LocInfo.second; + + // Create a langops struct and enable trigraphs. This is sufficient for + // relexing tokens. + LangOptions LangOpts; + LangOpts.Trigraphs = true; + + // Create a lexer starting at the beginning of this token. + Lexer TheLexer(StrTokSpellingLoc, Features, Buffer.begin(), StrData, + Buffer.end()); + Token TheTok; + TheLexer.LexFromRawLexer(TheTok); + + // Use the StringLiteralParser to compute the length of the string in bytes. + StringLiteralParser SLP(&TheTok, 1, SM, Features, Target); + unsigned TokNumBytes = SLP.GetStringLength(); + + // If the byte is in this token, return the location of the byte. + if (ByteNo < TokNumBytes || + (ByteNo == TokNumBytes && TokNo == getNumConcatenated())) { + unsigned Offset = SLP.getOffsetOfStringByte(TheTok, ByteNo); + + // Now that we know the offset of the token in the spelling, use the + // preprocessor to get the offset in the original source. + return Lexer::AdvanceToTokenCharacter(StrTokLoc, Offset, SM, Features); + } + + // Move to the next string token. + ++TokNo; + ByteNo -= TokNumBytes; + } +} + + + /// getOpcodeStr - Turn an Opcode enum value into the punctuation char it /// corresponds to, e.g. "sizeof" or "[pre]++". const char *UnaryOperator::getOpcodeStr(Opcode Op) { @@ -522,43 +681,82 @@ OverloadedOperatorKind UnaryOperator::getOverloadedOperator(Opcode Opc) { // Postfix Operators. //===----------------------------------------------------------------------===// -CallExpr::CallExpr(ASTContext& C, StmtClass SC, Expr *fn, Expr **args, - unsigned numargs, QualType t, SourceLocation rparenloc) - : Expr(SC, t, - fn->isTypeDependent() || hasAnyTypeDependentArguments(args, numargs), - fn->isValueDependent() || hasAnyValueDependentArguments(args,numargs)), +CallExpr::CallExpr(ASTContext& C, StmtClass SC, Expr *fn, unsigned NumPreArgs, + Expr **args, unsigned numargs, QualType t, ExprValueKind VK, + SourceLocation rparenloc) + : Expr(SC, t, VK, OK_Ordinary, + fn->isTypeDependent(), + fn->isValueDependent(), + fn->containsUnexpandedParameterPack()), NumArgs(numargs) { - SubExprs = new (C) Stmt*[numargs+1]; + SubExprs = new (C) Stmt*[numargs+PREARGS_START+NumPreArgs]; SubExprs[FN] = fn; - for (unsigned i = 0; i != numargs; ++i) - SubExprs[i+ARGS_START] = args[i]; + for (unsigned i = 0; i != numargs; ++i) { + if (args[i]->isTypeDependent()) + ExprBits.TypeDependent = true; + if (args[i]->isValueDependent()) + ExprBits.ValueDependent = true; + if (args[i]->containsUnexpandedParameterPack()) + ExprBits.ContainsUnexpandedParameterPack = true; + + SubExprs[i+PREARGS_START+NumPreArgs] = args[i]; + } + CallExprBits.NumPreArgs = NumPreArgs; RParenLoc = rparenloc; } CallExpr::CallExpr(ASTContext& C, Expr *fn, Expr **args, unsigned numargs, - QualType t, SourceLocation rparenloc) - : Expr(CallExprClass, t, - fn->isTypeDependent() || hasAnyTypeDependentArguments(args, numargs), - fn->isValueDependent() || hasAnyValueDependentArguments(args,numargs)), + QualType t, ExprValueKind VK, SourceLocation rparenloc) + : Expr(CallExprClass, t, VK, OK_Ordinary, + fn->isTypeDependent(), + fn->isValueDependent(), + fn->containsUnexpandedParameterPack()), NumArgs(numargs) { - SubExprs = new (C) Stmt*[numargs+1]; + SubExprs = new (C) Stmt*[numargs+PREARGS_START]; SubExprs[FN] = fn; - for (unsigned i = 0; i != numargs; ++i) - SubExprs[i+ARGS_START] = args[i]; + for (unsigned i = 0; i != numargs; ++i) { + if (args[i]->isTypeDependent()) + ExprBits.TypeDependent = true; + if (args[i]->isValueDependent()) + ExprBits.ValueDependent = true; + if (args[i]->containsUnexpandedParameterPack()) + ExprBits.ContainsUnexpandedParameterPack = true; + + SubExprs[i+PREARGS_START] = args[i]; + } + CallExprBits.NumPreArgs = 0; RParenLoc = rparenloc; } CallExpr::CallExpr(ASTContext &C, StmtClass SC, EmptyShell Empty) : Expr(SC, Empty), SubExprs(0), NumArgs(0) { - SubExprs = new (C) Stmt*[1]; + // FIXME: Why do we allocate this? + SubExprs = new (C) Stmt*[PREARGS_START]; + CallExprBits.NumPreArgs = 0; +} + +CallExpr::CallExpr(ASTContext &C, StmtClass SC, unsigned NumPreArgs, + EmptyShell Empty) + : Expr(SC, Empty), SubExprs(0), NumArgs(0) { + // FIXME: Why do we allocate this? + SubExprs = new (C) Stmt*[PREARGS_START+NumPreArgs]; + CallExprBits.NumPreArgs = NumPreArgs; } Decl *CallExpr::getCalleeDecl() { Expr *CEE = getCallee()->IgnoreParenCasts(); + // If we're calling a dereference, look at the pointer instead. + if (BinaryOperator *BO = dyn_cast<BinaryOperator>(CEE)) { + if (BO->isPtrMemOp()) + CEE = BO->getRHS()->IgnoreParenCasts(); + } else if (UnaryOperator *UO = dyn_cast<UnaryOperator>(CEE)) { + if (UO->getOpcode() == UO_Deref) + CEE = UO->getSubExpr()->IgnoreParenCasts(); + } if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) return DRE->getDecl(); if (MemberExpr *ME = dyn_cast<MemberExpr>(CEE)) @@ -585,12 +783,14 @@ void CallExpr::setNumArgs(ASTContext& C, unsigned NumArgs) { } // Otherwise, we are growing the # arguments. New an bigger argument array. - Stmt **NewSubExprs = new (C) Stmt*[NumArgs+1]; + unsigned NumPreArgs = getNumPreArgs(); + Stmt **NewSubExprs = new (C) Stmt*[NumArgs+PREARGS_START+NumPreArgs]; // Copy over args. - for (unsigned i = 0; i != getNumArgs()+ARGS_START; ++i) + for (unsigned i = 0; i != getNumArgs()+PREARGS_START+NumPreArgs; ++i) NewSubExprs[i] = SubExprs[i]; // Null out new args. - for (unsigned i = getNumArgs()+ARGS_START; i != NumArgs+ARGS_START; ++i) + for (unsigned i = getNumArgs()+PREARGS_START+NumPreArgs; + i != NumArgs+PREARGS_START+NumPreArgs; ++i) NewSubExprs[i] = 0; if (SubExprs) C.Deallocate(SubExprs); @@ -600,7 +800,7 @@ void CallExpr::setNumArgs(ASTContext& C, unsigned NumArgs) { /// isBuiltinCall - If this is a call to a builtin, return the builtin ID. If /// not, return 0. -unsigned CallExpr::isBuiltinCall(ASTContext &Context) const { +unsigned CallExpr::isBuiltinCall(const ASTContext &Context) const { // All simple function calls (e.g. func()) are implicitly cast to pointer to // function. As a result, we try and obtain the DeclRefExpr from the // ImplicitCastExpr. @@ -663,10 +863,10 @@ OffsetOfExpr::OffsetOfExpr(ASTContext &C, QualType type, OffsetOfNode* compsPtr, unsigned numComps, Expr** exprsPtr, unsigned numExprs, SourceLocation RParenLoc) - : Expr(OffsetOfExprClass, type, /*TypeDependent=*/false, - /*ValueDependent=*/tsi->getType()->isDependentType() || - hasAnyTypeDependentArguments(exprsPtr, numExprs) || - hasAnyValueDependentArguments(exprsPtr, numExprs)), + : Expr(OffsetOfExprClass, type, VK_RValue, OK_Ordinary, + /*TypeDependent=*/false, + /*ValueDependent=*/tsi->getType()->isDependentType(), + tsi->getType()->containsUnexpandedParameterPack()), OperatorLoc(OperatorLoc), RParenLoc(RParenLoc), TSInfo(tsi), NumComps(numComps), NumExprs(numExprs) { @@ -675,6 +875,11 @@ OffsetOfExpr::OffsetOfExpr(ASTContext &C, QualType type, } for(unsigned i = 0; i < numExprs; ++i) { + if (exprsPtr[i]->isTypeDependent() || exprsPtr[i]->isValueDependent()) + ExprBits.ValueDependent = true; + if (exprsPtr[i]->containsUnexpandedParameterPack()) + ExprBits.ContainsUnexpandedParameterPack = true; + setIndexExpr(i, exprsPtr[i]); } } @@ -694,7 +899,9 @@ MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow, DeclAccessPair founddecl, DeclarationNameInfo nameinfo, const TemplateArgumentListInfo *targs, - QualType ty) { + QualType ty, + ExprValueKind vk, + ExprObjectKind ok) { std::size_t Size = sizeof(MemberExpr); bool hasQualOrFound = (qual != 0 || @@ -706,8 +913,9 @@ MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow, if (targs) Size += ExplicitTemplateArgumentList::sizeFor(*targs); - void *Mem = C.Allocate(Size, llvm::alignof<MemberExpr>()); - MemberExpr *E = new (Mem) MemberExpr(base, isarrow, memberdecl, nameinfo, ty); + void *Mem = C.Allocate(Size, llvm::alignOf<MemberExpr>()); + MemberExpr *E = new (Mem) MemberExpr(base, isarrow, memberdecl, nameinfo, + ty, vk, ok); if (hasQualOrFound) { if (qual && qual->isDependent()) { @@ -732,12 +940,16 @@ MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow, const char *CastExpr::getCastKindName() const { switch (getCastKind()) { - case CK_Unknown: - return "Unknown"; + case CK_Dependent: + return "Dependent"; case CK_BitCast: return "BitCast"; case CK_LValueBitCast: return "LValueBitCast"; + case CK_LValueToRValue: + return "LValueToRValue"; + case CK_GetObjCProperty: + return "GetObjCProperty"; case CK_NoOp: return "NoOp"; case CK_BaseToDerived: @@ -756,6 +968,8 @@ const char *CastExpr::getCastKindName() const { return "FunctionToPointerDecay"; case CK_NullToMemberPointer: return "NullToMemberPointer"; + case CK_NullToPointer: + return "NullToPointer"; case CK_BaseToDerivedMemberPointer: return "BaseToDerivedMemberPointer"; case CK_DerivedToBaseMemberPointer: @@ -768,18 +982,24 @@ const char *CastExpr::getCastKindName() const { return "IntegralToPointer"; case CK_PointerToIntegral: return "PointerToIntegral"; + case CK_PointerToBoolean: + return "PointerToBoolean"; case CK_ToVoid: return "ToVoid"; case CK_VectorSplat: return "VectorSplat"; case CK_IntegralCast: return "IntegralCast"; + case CK_IntegralToBoolean: + return "IntegralToBoolean"; case CK_IntegralToFloating: return "IntegralToFloating"; case CK_FloatingToIntegral: return "FloatingToIntegral"; case CK_FloatingCast: return "FloatingCast"; + case CK_FloatingToBoolean: + return "FloatingToBoolean"; case CK_MemberPointerToBoolean: return "MemberPointerToBoolean"; case CK_AnyPointerToObjCPointerCast: @@ -788,9 +1008,29 @@ const char *CastExpr::getCastKindName() const { return "AnyPointerToBlockPointerCast"; case CK_ObjCObjectLValueCast: return "ObjCObjectLValueCast"; + case CK_FloatingRealToComplex: + return "FloatingRealToComplex"; + case CK_FloatingComplexToReal: + return "FloatingComplexToReal"; + case CK_FloatingComplexToBoolean: + return "FloatingComplexToBoolean"; + case CK_FloatingComplexCast: + return "FloatingComplexCast"; + case CK_FloatingComplexToIntegralComplex: + return "FloatingComplexToIntegralComplex"; + case CK_IntegralRealToComplex: + return "IntegralRealToComplex"; + case CK_IntegralComplexToReal: + return "IntegralComplexToReal"; + case CK_IntegralComplexToBoolean: + return "IntegralComplexToBoolean"; + case CK_IntegralComplexCast: + return "IntegralComplexCast"; + case CK_IntegralComplexToFloatingComplex: + return "IntegralComplexToFloatingComplex"; } - assert(0 && "Unhandled cast kind!"); + llvm_unreachable("Unhandled cast kind!"); return 0; } @@ -859,7 +1099,7 @@ ImplicitCastExpr *ImplicitCastExpr::CreateEmpty(ASTContext &C, CStyleCastExpr *CStyleCastExpr::Create(ASTContext &C, QualType T, - CastKind K, Expr *Op, + ExprValueKind VK, CastKind K, Expr *Op, const CXXCastPath *BasePath, TypeSourceInfo *WrittenTy, SourceLocation L, SourceLocation R) { @@ -867,7 +1107,7 @@ CStyleCastExpr *CStyleCastExpr::Create(ASTContext &C, QualType T, void *Buffer = C.Allocate(sizeof(CStyleCastExpr) + PathSize * sizeof(CXXBaseSpecifier*)); CStyleCastExpr *E = - new (Buffer) CStyleCastExpr(T, K, Op, PathSize, WrittenTy, L, R); + new (Buffer) CStyleCastExpr(T, VK, K, Op, PathSize, WrittenTy, L, R); if (PathSize) E->setCastPath(*BasePath); return E; } @@ -984,16 +1224,19 @@ OverloadedOperatorKind BinaryOperator::getOverloadedOperator(Opcode Opc) { InitListExpr::InitListExpr(ASTContext &C, SourceLocation lbraceloc, Expr **initExprs, unsigned numInits, SourceLocation rbraceloc) - : Expr(InitListExprClass, QualType(), false, false), + : Expr(InitListExprClass, QualType(), VK_RValue, OK_Ordinary, false, false, + false), InitExprs(C, numInits), LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), SyntacticForm(0), UnionFieldInit(0), HadArrayRangeDesignator(false) { for (unsigned I = 0; I != numInits; ++I) { if (initExprs[I]->isTypeDependent()) - TypeDependent = true; + ExprBits.TypeDependent = true; if (initExprs[I]->isValueDependent()) - ValueDependent = true; + ExprBits.ValueDependent = true; + if (initExprs[I]->containsUnexpandedParameterPack()) + ExprBits.ContainsUnexpandedParameterPack = true; } InitExprs.insert(C, InitExprs.end(), initExprs, initExprs+numInits); @@ -1020,6 +1263,35 @@ Expr *InitListExpr::updateInit(ASTContext &C, unsigned Init, Expr *expr) { return Result; } +SourceRange InitListExpr::getSourceRange() const { + if (SyntacticForm) + return SyntacticForm->getSourceRange(); + SourceLocation Beg = LBraceLoc, End = RBraceLoc; + if (Beg.isInvalid()) { + // Find the first non-null initializer. + for (InitExprsTy::const_iterator I = InitExprs.begin(), + E = InitExprs.end(); + I != E; ++I) { + if (Stmt *S = *I) { + Beg = S->getLocStart(); + break; + } + } + } + if (End.isInvalid()) { + // Find the first non-null initializer from the end. + for (InitExprsTy::const_reverse_iterator I = InitExprs.rbegin(), + E = InitExprs.rend(); + I != E; ++I) { + if (Stmt *S = *I) { + End = S->getSourceRange().getEnd(); + break; + } + } + } + return SourceRange(Beg, End); +} + /// getFunctionType - Return the underlying function type for this block. /// const FunctionType *BlockExpr::getFunctionType() const { @@ -1195,21 +1467,11 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, return false; } - case ObjCImplicitSetterGetterRefExprClass: { // Dot syntax for message send. -#if 0 - const ObjCImplicitSetterGetterRefExpr *Ref = - cast<ObjCImplicitSetterGetterRefExpr>(this); - // FIXME: We really want the location of the '.' here. - Loc = Ref->getLocation(); - R1 = SourceRange(Ref->getLocation(), Ref->getLocation()); - if (Ref->getBase()) - R2 = Ref->getBase()->getSourceRange(); -#else + case ObjCPropertyRefExprClass: Loc = getExprLoc(); R1 = getSourceRange(); -#endif return true; - } + case StmtExprClass: { // Statement exprs don't logically have side effects themselves, but are // sometimes used in macros in ways that give them a type that is unused. @@ -1217,9 +1479,13 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, // however, if the result of the stmt expr is dead, we don't want to emit a // warning. const CompoundStmt *CS = cast<StmtExpr>(this)->getSubStmt(); - if (!CS->body_empty()) + if (!CS->body_empty()) { if (const Expr *E = dyn_cast<Expr>(CS->body_back())) return E->isUnusedResultAWarning(Loc, R1, R2, Ctx); + if (const LabelStmt *Label = dyn_cast<LabelStmt>(CS->body_back())) + if (const Expr *E = dyn_cast<Expr>(Label->getSubStmt())) + return E->isUnusedResultAWarning(Loc, R1, R2, Ctx); + } if (getType()->isVoidType()) return false; @@ -1268,8 +1534,8 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, case CXXBindTemporaryExprClass: return (cast<CXXBindTemporaryExpr>(this) ->getSubExpr()->isUnusedResultAWarning(Loc, R1, R2, Ctx)); - case CXXExprWithTemporariesClass: - return (cast<CXXExprWithTemporaries>(this) + case ExprWithCleanupsClass: + return (cast<ExprWithCleanups>(this) ->getSubExpr()->isUnusedResultAWarning(Loc, R1, R2, Ctx)); } } @@ -1311,12 +1577,254 @@ bool Expr::isOBJCGCCandidate(ASTContext &Ctx) const { return cast<ArraySubscriptExpr>(this)->getBase()->isOBJCGCCandidate(Ctx); } } + +bool Expr::isBoundMemberFunction(ASTContext &Ctx) const { + if (isTypeDependent()) + return false; + return ClassifyLValue(Ctx) == Expr::LV_MemberFunction; +} + +static Expr::CanThrowResult MergeCanThrow(Expr::CanThrowResult CT1, + Expr::CanThrowResult CT2) { + // CanThrowResult constants are ordered so that the maximum is the correct + // merge result. + return CT1 > CT2 ? CT1 : CT2; +} + +static Expr::CanThrowResult CanSubExprsThrow(ASTContext &C, const Expr *CE) { + Expr *E = const_cast<Expr*>(CE); + Expr::CanThrowResult R = Expr::CT_Cannot; + for (Expr::child_range I = E->children(); I && R != Expr::CT_Can; ++I) { + R = MergeCanThrow(R, cast<Expr>(*I)->CanThrow(C)); + } + return R; +} + +static Expr::CanThrowResult CanCalleeThrow(const Decl *D, + bool NullThrows = true) { + if (!D) + return NullThrows ? Expr::CT_Can : Expr::CT_Cannot; + + // See if we can get a function type from the decl somehow. + const ValueDecl *VD = dyn_cast<ValueDecl>(D); + if (!VD) // If we have no clue what we're calling, assume the worst. + return Expr::CT_Can; + + // As an extension, we assume that __attribute__((nothrow)) functions don't + // throw. + if (isa<FunctionDecl>(D) && D->hasAttr<NoThrowAttr>()) + return Expr::CT_Cannot; + + QualType T = VD->getType(); + const FunctionProtoType *FT; + if ((FT = T->getAs<FunctionProtoType>())) { + } else if (const PointerType *PT = T->getAs<PointerType>()) + FT = PT->getPointeeType()->getAs<FunctionProtoType>(); + else if (const ReferenceType *RT = T->getAs<ReferenceType>()) + FT = RT->getPointeeType()->getAs<FunctionProtoType>(); + else if (const MemberPointerType *MT = T->getAs<MemberPointerType>()) + FT = MT->getPointeeType()->getAs<FunctionProtoType>(); + else if (const BlockPointerType *BT = T->getAs<BlockPointerType>()) + FT = BT->getPointeeType()->getAs<FunctionProtoType>(); + + if (!FT) + return Expr::CT_Can; + + return FT->hasEmptyExceptionSpec() ? Expr::CT_Cannot : Expr::CT_Can; +} + +static Expr::CanThrowResult CanDynamicCastThrow(const CXXDynamicCastExpr *DC) { + if (DC->isTypeDependent()) + return Expr::CT_Dependent; + + if (!DC->getTypeAsWritten()->isReferenceType()) + return Expr::CT_Cannot; + + return DC->getCastKind() == clang::CK_Dynamic? Expr::CT_Can : Expr::CT_Cannot; +} + +static Expr::CanThrowResult CanTypeidThrow(ASTContext &C, + const CXXTypeidExpr *DC) { + if (DC->isTypeOperand()) + return Expr::CT_Cannot; + + Expr *Op = DC->getExprOperand(); + if (Op->isTypeDependent()) + return Expr::CT_Dependent; + + const RecordType *RT = Op->getType()->getAs<RecordType>(); + if (!RT) + return Expr::CT_Cannot; + + if (!cast<CXXRecordDecl>(RT->getDecl())->isPolymorphic()) + return Expr::CT_Cannot; + + if (Op->Classify(C).isPRValue()) + return Expr::CT_Cannot; + + return Expr::CT_Can; +} + +Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const { + // C++ [expr.unary.noexcept]p3: + // [Can throw] if in a potentially-evaluated context the expression would + // contain: + switch (getStmtClass()) { + case CXXThrowExprClass: + // - a potentially evaluated throw-expression + return CT_Can; + + case CXXDynamicCastExprClass: { + // - a potentially evaluated dynamic_cast expression dynamic_cast<T>(v), + // where T is a reference type, that requires a run-time check + CanThrowResult CT = CanDynamicCastThrow(cast<CXXDynamicCastExpr>(this)); + if (CT == CT_Can) + return CT; + return MergeCanThrow(CT, CanSubExprsThrow(C, this)); + } + + case CXXTypeidExprClass: + // - a potentially evaluated typeid expression applied to a glvalue + // expression whose type is a polymorphic class type + return CanTypeidThrow(C, cast<CXXTypeidExpr>(this)); + + // - a potentially evaluated call to a function, member function, function + // pointer, or member function pointer that does not have a non-throwing + // exception-specification + case CallExprClass: + case CXXOperatorCallExprClass: + case CXXMemberCallExprClass: { + CanThrowResult CT = CanCalleeThrow(cast<CallExpr>(this)->getCalleeDecl()); + if (CT == CT_Can) + return CT; + return MergeCanThrow(CT, CanSubExprsThrow(C, this)); + } + + case CXXConstructExprClass: + case CXXTemporaryObjectExprClass: { + CanThrowResult CT = CanCalleeThrow( + cast<CXXConstructExpr>(this)->getConstructor()); + if (CT == CT_Can) + return CT; + return MergeCanThrow(CT, CanSubExprsThrow(C, this)); + } + + case CXXNewExprClass: { + CanThrowResult CT = MergeCanThrow( + CanCalleeThrow(cast<CXXNewExpr>(this)->getOperatorNew()), + CanCalleeThrow(cast<CXXNewExpr>(this)->getConstructor(), + /*NullThrows*/false)); + if (CT == CT_Can) + return CT; + return MergeCanThrow(CT, CanSubExprsThrow(C, this)); + } + + case CXXDeleteExprClass: { + CanThrowResult CT = CanCalleeThrow( + cast<CXXDeleteExpr>(this)->getOperatorDelete()); + if (CT == CT_Can) + return CT; + const Expr *Arg = cast<CXXDeleteExpr>(this)->getArgument(); + // Unwrap exactly one implicit cast, which converts all pointers to void*. + if (const ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(Arg)) + Arg = Cast->getSubExpr(); + if (const PointerType *PT = Arg->getType()->getAs<PointerType>()) { + if (const RecordType *RT = PT->getPointeeType()->getAs<RecordType>()) { + CanThrowResult CT2 = CanCalleeThrow( + cast<CXXRecordDecl>(RT->getDecl())->getDestructor()); + if (CT2 == CT_Can) + return CT2; + CT = MergeCanThrow(CT, CT2); + } + } + return MergeCanThrow(CT, CanSubExprsThrow(C, this)); + } + + case CXXBindTemporaryExprClass: { + // The bound temporary has to be destroyed again, which might throw. + CanThrowResult CT = CanCalleeThrow( + cast<CXXBindTemporaryExpr>(this)->getTemporary()->getDestructor()); + if (CT == CT_Can) + return CT; + return MergeCanThrow(CT, CanSubExprsThrow(C, this)); + } + + // ObjC message sends are like function calls, but never have exception + // specs. + case ObjCMessageExprClass: + case ObjCPropertyRefExprClass: + return CT_Can; + + // Many other things have subexpressions, so we have to test those. + // Some are simple: + case ParenExprClass: + case MemberExprClass: + case CXXReinterpretCastExprClass: + case CXXConstCastExprClass: + case ConditionalOperatorClass: + case CompoundLiteralExprClass: + case ExtVectorElementExprClass: + case InitListExprClass: + case DesignatedInitExprClass: + case ParenListExprClass: + case VAArgExprClass: + case CXXDefaultArgExprClass: + case ExprWithCleanupsClass: + case ObjCIvarRefExprClass: + case ObjCIsaExprClass: + case ShuffleVectorExprClass: + return CanSubExprsThrow(C, this); + + // Some might be dependent for other reasons. + case UnaryOperatorClass: + case ArraySubscriptExprClass: + case ImplicitCastExprClass: + case CStyleCastExprClass: + case CXXStaticCastExprClass: + case CXXFunctionalCastExprClass: + case BinaryOperatorClass: + case CompoundAssignOperatorClass: { + CanThrowResult CT = isTypeDependent() ? CT_Dependent : CT_Cannot; + return MergeCanThrow(CT, CanSubExprsThrow(C, this)); + } + + // FIXME: We should handle StmtExpr, but that opens a MASSIVE can of worms. + case StmtExprClass: + return CT_Can; + + case ChooseExprClass: + if (isTypeDependent() || isValueDependent()) + return CT_Dependent; + return cast<ChooseExpr>(this)->getChosenSubExpr(C)->CanThrow(C); + + // Some expressions are always dependent. + case DependentScopeDeclRefExprClass: + case CXXUnresolvedConstructExprClass: + case CXXDependentScopeMemberExprClass: + return CT_Dependent; + + default: + // All other expressions don't have subexpressions, or else they are + // unevaluated. + return CT_Cannot; + } +} + Expr* Expr::IgnoreParens() { Expr* E = this; - while (ParenExpr* P = dyn_cast<ParenExpr>(E)) - E = P->getSubExpr(); - - return E; + while (true) { + if (ParenExpr* P = dyn_cast<ParenExpr>(E)) { + E = P->getSubExpr(); + continue; + } + if (UnaryOperator* P = dyn_cast<UnaryOperator>(E)) { + if (P->getOpcode() == UO_Extension) { + E = P->getSubExpr(); + continue; + } + } + return E; + } } /// IgnoreParenCasts - Ignore parentheses and casts. Strip off any ParenExpr @@ -1324,24 +1832,68 @@ Expr* Expr::IgnoreParens() { Expr *Expr::IgnoreParenCasts() { Expr *E = this; while (true) { - if (ParenExpr *P = dyn_cast<ParenExpr>(E)) + if (ParenExpr* P = dyn_cast<ParenExpr>(E)) { E = P->getSubExpr(); - else if (CastExpr *P = dyn_cast<CastExpr>(E)) + continue; + } + if (CastExpr *P = dyn_cast<CastExpr>(E)) { E = P->getSubExpr(); - else - return E; + continue; + } + if (UnaryOperator* P = dyn_cast<UnaryOperator>(E)) { + if (P->getOpcode() == UO_Extension) { + E = P->getSubExpr(); + continue; + } + } + return E; } } +/// IgnoreParenLValueCasts - Ignore parentheses and lvalue-to-rvalue +/// casts. This is intended purely as a temporary workaround for code +/// that hasn't yet been rewritten to do the right thing about those +/// casts, and may disappear along with the last internal use. +Expr *Expr::IgnoreParenLValueCasts() { + Expr *E = this; + while (true) { + if (ParenExpr *P = dyn_cast<ParenExpr>(E)) { + E = P->getSubExpr(); + continue; + } else if (CastExpr *P = dyn_cast<CastExpr>(E)) { + if (P->getCastKind() == CK_LValueToRValue) { + E = P->getSubExpr(); + continue; + } + } else if (UnaryOperator* P = dyn_cast<UnaryOperator>(E)) { + if (P->getOpcode() == UO_Extension) { + E = P->getSubExpr(); + continue; + } + } + break; + } + return E; +} + Expr *Expr::IgnoreParenImpCasts() { Expr *E = this; while (true) { - if (ParenExpr *P = dyn_cast<ParenExpr>(E)) + if (ParenExpr *P = dyn_cast<ParenExpr>(E)) { E = P->getSubExpr(); - else if (ImplicitCastExpr *P = dyn_cast<ImplicitCastExpr>(E)) + continue; + } + if (ImplicitCastExpr *P = dyn_cast<ImplicitCastExpr>(E)) { E = P->getSubExpr(); - else - return E; + continue; + } + if (UnaryOperator* P = dyn_cast<UnaryOperator>(E)) { + if (P->getOpcode() == UO_Extension) { + E = P->getSubExpr(); + continue; + } + } + return E; } } @@ -1366,9 +1918,9 @@ Expr *Expr::IgnoreParenNoopCasts(ASTContext &Ctx) { continue; } - if ((E->getType()->isPointerType() || + if ((E->getType()->isPointerType() || E->getType()->isIntegralType(Ctx)) && - (SE->getType()->isPointerType() || + (SE->getType()->isPointerType() || SE->getType()->isIntegralType(Ctx)) && Ctx.getTypeSize(E->getType()) == Ctx.getTypeSize(SE->getType())) { E = SE; @@ -1376,6 +1928,13 @@ Expr *Expr::IgnoreParenNoopCasts(ASTContext &Ctx) { } } + if (UnaryOperator* P = dyn_cast<UnaryOperator>(E)) { + if (P->getOpcode() == UO_Extension) { + E = P->getSubExpr(); + continue; + } + } + return E; } } @@ -1390,7 +1949,7 @@ bool Expr::isDefaultArgument() const { /// \brief Skip over any no-op casts and any temporary-binding /// expressions. -static const Expr *skipTemporaryBindingsAndNoOpCasts(const Expr *E) { +static const Expr *skipTemporaryBindingsNoOpCastsAndParens(const Expr *E) { while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) { if (ICE->getCastKind() == CK_NoOp) E = ICE->getSubExpr(); @@ -1407,50 +1966,48 @@ static const Expr *skipTemporaryBindingsAndNoOpCasts(const Expr *E) { else break; } - - return E; -} -const Expr *Expr::getTemporaryObject() const { - const Expr *E = skipTemporaryBindingsAndNoOpCasts(this); + return E->IgnoreParens(); +} - // A cast can produce a temporary object. The object's construction - // is represented as a CXXConstructExpr. - if (const CastExpr *Cast = dyn_cast<CastExpr>(E)) { - // Only user-defined and constructor conversions can produce - // temporary objects. - if (Cast->getCastKind() != CK_ConstructorConversion && - Cast->getCastKind() != CK_UserDefinedConversion) - return 0; +/// isTemporaryObject - Determines if this expression produces a +/// temporary of the given class type. +bool Expr::isTemporaryObject(ASTContext &C, const CXXRecordDecl *TempTy) const { + if (!C.hasSameUnqualifiedType(getType(), C.getTypeDeclType(TempTy))) + return false; - // Strip off temporary bindings and no-op casts. - const Expr *Sub = skipTemporaryBindingsAndNoOpCasts(Cast->getSubExpr()); + const Expr *E = skipTemporaryBindingsNoOpCastsAndParens(this); - // If this is a constructor conversion, see if we have an object - // construction. - if (Cast->getCastKind() == CK_ConstructorConversion) - return dyn_cast<CXXConstructExpr>(Sub); + // Temporaries are by definition pr-values of class type. + if (!E->Classify(C).isPRValue()) { + // In this context, property reference is a message call and is pr-value. + if (!isa<ObjCPropertyRefExpr>(E)) + return false; + } - // If this is a user-defined conversion, see if we have a call to - // a function that itself returns a temporary object. - if (Cast->getCastKind() == CK_UserDefinedConversion) - if (const CallExpr *CE = dyn_cast<CallExpr>(Sub)) - if (CE->getCallReturnType()->isRecordType()) - return CE; + // Black-list a few cases which yield pr-values of class type that don't + // refer to temporaries of that type: - return 0; + // - implicit derived-to-base conversions + if (isa<ImplicitCastExpr>(E)) { + switch (cast<ImplicitCastExpr>(E)->getCastKind()) { + case CK_DerivedToBase: + case CK_UncheckedDerivedToBase: + return false; + default: + break; + } } - // A call returning a class type returns a temporary. - if (const CallExpr *CE = dyn_cast<CallExpr>(E)) { - if (CE->getCallReturnType()->isRecordType()) - return CE; + // - member expressions (all) + if (isa<MemberExpr>(E)) + return false; - return 0; - } + // - opaque values (all) + if (isa<OpaqueValueExpr>(E)) + return false; - // Explicit temporary object constructors create temporaries. - return dyn_cast<CXXTemporaryObjectExpr>(E); + return true; } /// hasAnyTypeDependentArguments - Determines if any of the expressions @@ -1533,6 +2090,9 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const { case ParenExprClass: return cast<ParenExpr>(this)->getSubExpr() ->isConstantInitializer(Ctx, IsForRef); + case ChooseExprClass: + return cast<ChooseExpr>(this)->getChosenSubExpr(Ctx) + ->isConstantInitializer(Ctx, IsForRef); case UnaryOperatorClass: { const UnaryOperator* Exp = cast<UnaryOperator>(this); if (Exp->getOpcode() == UO_Extension) @@ -1572,11 +2132,14 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const { return isEvaluatable(Ctx); } -/// isNullPointerConstant - C99 6.3.2.3p3 - Return true if this is either an -/// integer constant expression with the value zero, or if this is one that is -/// cast to void*. -bool Expr::isNullPointerConstant(ASTContext &Ctx, - NullPointerConstantValueDependence NPC) const { +/// isNullPointerConstant - C99 6.3.2.3p3 - Return whether this is a null +/// pointer constant or not, as well as the specific kind of constant detected. +/// Null pointer constants can be integer constant expressions with the +/// value zero, casts of zero to void*, nullptr (C++0X), or __null +/// (a GNU extension). +Expr::NullPointerConstantKind +Expr::isNullPointerConstant(ASTContext &Ctx, + NullPointerConstantValueDependence NPC) const { if (isValueDependent()) { switch (NPC) { case NPC_NeverValueDependent: @@ -1584,10 +2147,13 @@ bool Expr::isNullPointerConstant(ASTContext &Ctx, // If the unthinkable happens, fall through to the safest alternative. case NPC_ValueDependentIsNull: - return isTypeDependent() || getType()->isIntegralType(Ctx); + if (isTypeDependent() || getType()->isIntegralType(Ctx)) + return NPCK_ZeroInteger; + else + return NPCK_NotNull; case NPC_ValueDependentIsNotNull: - return false; + return NPCK_NotNull; } } @@ -1616,30 +2182,61 @@ bool Expr::isNullPointerConstant(ASTContext &Ctx, return DefaultArg->getExpr()->isNullPointerConstant(Ctx, NPC); } else if (isa<GNUNullExpr>(this)) { // The GNU __null extension is always a null pointer constant. - return true; + return NPCK_GNUNull; } // C++0x nullptr_t is always a null pointer constant. if (getType()->isNullPtrType()) - return true; - + return NPCK_CXX0X_nullptr; + + if (const RecordType *UT = getType()->getAsUnionType()) + if (UT && UT->getDecl()->hasAttr<TransparentUnionAttr>()) + if (const CompoundLiteralExpr *CLE = dyn_cast<CompoundLiteralExpr>(this)){ + const Expr *InitExpr = CLE->getInitializer(); + if (const InitListExpr *ILE = dyn_cast<InitListExpr>(InitExpr)) + return ILE->getInit(0)->isNullPointerConstant(Ctx, NPC); + } // This expression must be an integer type. if (!getType()->isIntegerType() || (Ctx.getLangOptions().CPlusPlus && getType()->isEnumeralType())) - return false; + return NPCK_NotNull; // If we have an integer constant expression, we need to *evaluate* it and // test for the value 0. llvm::APSInt Result; - return isIntegerConstantExpr(Result, Ctx) && Result == 0; + bool IsNull = isIntegerConstantExpr(Result, Ctx) && Result == 0; + + return (IsNull ? NPCK_ZeroInteger : NPCK_NotNull); +} + +/// \brief If this expression is an l-value for an Objective C +/// property, find the underlying property reference expression. +const ObjCPropertyRefExpr *Expr::getObjCProperty() const { + const Expr *E = this; + while (true) { + assert((E->getValueKind() == VK_LValue && + E->getObjectKind() == OK_ObjCProperty) && + "expression is not a property reference"); + E = E->IgnoreParenCasts(); + if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) { + if (BO->getOpcode() == BO_Comma) { + E = BO->getRHS(); + continue; + } + } + + break; + } + + return cast<ObjCPropertyRefExpr>(E); } FieldDecl *Expr::getBitField() { Expr *E = this->IgnoreParens(); while (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) { - if (ICE->getValueKind() != VK_RValue && - ICE->getCastKind() == CK_NoOp) + if (ICE->getCastKind() == CK_LValueToRValue || + (ICE->getValueKind() != VK_RValue && ICE->getCastKind() == CK_NoOp)) E = ICE->getSubExpr()->IgnoreParens(); else break; @@ -1650,6 +2247,11 @@ FieldDecl *Expr::getBitField() { if (Field->isBitField()) return Field; + if (DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(E)) + if (FieldDecl *Field = dyn_cast<FieldDecl>(DeclRef->getDecl())) + if (Field->isBitField()) + return Field; + if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(E)) if (BinOp->isAssignmentOp() && BinOp->getLHS()) return BinOp->getLHS()->getBitField(); @@ -1741,21 +2343,24 @@ void ExtVectorElementExpr::getEncodedElementAccess( } ObjCMessageExpr::ObjCMessageExpr(QualType T, + ExprValueKind VK, SourceLocation LBracLoc, SourceLocation SuperLoc, bool IsInstanceSuper, QualType SuperType, Selector Sel, + SourceLocation SelLoc, ObjCMethodDecl *Method, Expr **Args, unsigned NumArgs, SourceLocation RBracLoc) - : Expr(ObjCMessageExprClass, T, /*TypeDependent=*/false, - /*ValueDependent=*/false), + : Expr(ObjCMessageExprClass, T, VK, OK_Ordinary, + /*TypeDependent=*/false, /*ValueDependent=*/false, + /*ContainsUnexpandedParameterPack=*/false), NumArgs(NumArgs), Kind(IsInstanceSuper? SuperInstance : SuperClass), HasMethod(Method != 0), SuperLoc(SuperLoc), SelectorOrMethod(reinterpret_cast<uintptr_t>(Method? Method : Sel.getAsOpaquePtr())), - LBracLoc(LBracLoc), RBracLoc(RBracLoc) + SelectorLoc(SelLoc), LBracLoc(LBracLoc), RBracLoc(RBracLoc) { setReceiverPointer(SuperType.getAsOpaquePtr()); if (NumArgs) @@ -1763,88 +2368,115 @@ ObjCMessageExpr::ObjCMessageExpr(QualType T, } ObjCMessageExpr::ObjCMessageExpr(QualType T, + ExprValueKind VK, SourceLocation LBracLoc, TypeSourceInfo *Receiver, - Selector Sel, + Selector Sel, + SourceLocation SelLoc, ObjCMethodDecl *Method, Expr **Args, unsigned NumArgs, SourceLocation RBracLoc) - : Expr(ObjCMessageExprClass, T, T->isDependentType(), - (T->isDependentType() || - hasAnyValueDependentArguments(Args, NumArgs))), + : Expr(ObjCMessageExprClass, T, VK, OK_Ordinary, T->isDependentType(), + T->isDependentType(), T->containsUnexpandedParameterPack()), NumArgs(NumArgs), Kind(Class), HasMethod(Method != 0), SelectorOrMethod(reinterpret_cast<uintptr_t>(Method? Method : Sel.getAsOpaquePtr())), - LBracLoc(LBracLoc), RBracLoc(RBracLoc) + SelectorLoc(SelLoc), LBracLoc(LBracLoc), RBracLoc(RBracLoc) { setReceiverPointer(Receiver); - if (NumArgs) - memcpy(getArgs(), Args, NumArgs * sizeof(Expr *)); + Expr **MyArgs = getArgs(); + for (unsigned I = 0; I != NumArgs; ++I) { + if (Args[I]->isTypeDependent()) + ExprBits.TypeDependent = true; + if (Args[I]->isValueDependent()) + ExprBits.ValueDependent = true; + if (Args[I]->containsUnexpandedParameterPack()) + ExprBits.ContainsUnexpandedParameterPack = true; + + MyArgs[I] = Args[I]; + } } ObjCMessageExpr::ObjCMessageExpr(QualType T, + ExprValueKind VK, SourceLocation LBracLoc, Expr *Receiver, Selector Sel, + SourceLocation SelLoc, ObjCMethodDecl *Method, Expr **Args, unsigned NumArgs, SourceLocation RBracLoc) - : Expr(ObjCMessageExprClass, T, Receiver->isTypeDependent(), - (Receiver->isTypeDependent() || - hasAnyValueDependentArguments(Args, NumArgs))), + : Expr(ObjCMessageExprClass, T, VK, OK_Ordinary, Receiver->isTypeDependent(), + Receiver->isTypeDependent(), + Receiver->containsUnexpandedParameterPack()), NumArgs(NumArgs), Kind(Instance), HasMethod(Method != 0), SelectorOrMethod(reinterpret_cast<uintptr_t>(Method? Method : Sel.getAsOpaquePtr())), - LBracLoc(LBracLoc), RBracLoc(RBracLoc) + SelectorLoc(SelLoc), LBracLoc(LBracLoc), RBracLoc(RBracLoc) { setReceiverPointer(Receiver); - if (NumArgs) - memcpy(getArgs(), Args, NumArgs * sizeof(Expr *)); + Expr **MyArgs = getArgs(); + for (unsigned I = 0; I != NumArgs; ++I) { + if (Args[I]->isTypeDependent()) + ExprBits.TypeDependent = true; + if (Args[I]->isValueDependent()) + ExprBits.ValueDependent = true; + if (Args[I]->containsUnexpandedParameterPack()) + ExprBits.ContainsUnexpandedParameterPack = true; + + MyArgs[I] = Args[I]; + } } ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T, + ExprValueKind VK, SourceLocation LBracLoc, SourceLocation SuperLoc, bool IsInstanceSuper, QualType SuperType, Selector Sel, + SourceLocation SelLoc, ObjCMethodDecl *Method, Expr **Args, unsigned NumArgs, SourceLocation RBracLoc) { unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) + NumArgs * sizeof(Expr *); void *Mem = Context.Allocate(Size, llvm::AlignOf<ObjCMessageExpr>::Alignment); - return new (Mem) ObjCMessageExpr(T, LBracLoc, SuperLoc, IsInstanceSuper, - SuperType, Sel, Method, Args, NumArgs, + return new (Mem) ObjCMessageExpr(T, VK, LBracLoc, SuperLoc, IsInstanceSuper, + SuperType, Sel, SelLoc, Method, Args,NumArgs, RBracLoc); } ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T, + ExprValueKind VK, SourceLocation LBracLoc, TypeSourceInfo *Receiver, Selector Sel, + SourceLocation SelLoc, ObjCMethodDecl *Method, Expr **Args, unsigned NumArgs, SourceLocation RBracLoc) { unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) + NumArgs * sizeof(Expr *); void *Mem = Context.Allocate(Size, llvm::AlignOf<ObjCMessageExpr>::Alignment); - return new (Mem) ObjCMessageExpr(T, LBracLoc, Receiver, Sel, Method, Args, - NumArgs, RBracLoc); + return new (Mem) ObjCMessageExpr(T, VK, LBracLoc, Receiver, Sel, SelLoc, + Method, Args, NumArgs, RBracLoc); } ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T, + ExprValueKind VK, SourceLocation LBracLoc, Expr *Receiver, - Selector Sel, + Selector Sel, + SourceLocation SelLoc, ObjCMethodDecl *Method, Expr **Args, unsigned NumArgs, SourceLocation RBracLoc) { unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) + NumArgs * sizeof(Expr *); void *Mem = Context.Allocate(Size, llvm::AlignOf<ObjCMessageExpr>::Alignment); - return new (Mem) ObjCMessageExpr(T, LBracLoc, Receiver, Sel, Method, Args, - NumArgs, RBracLoc); + return new (Mem) ObjCMessageExpr(T, VK, LBracLoc, Receiver, Sel, SelLoc, + Method, Args, NumArgs, RBracLoc); } ObjCMessageExpr *ObjCMessageExpr::CreateEmpty(ASTContext &Context, @@ -1854,7 +2486,23 @@ ObjCMessageExpr *ObjCMessageExpr::CreateEmpty(ASTContext &Context, void *Mem = Context.Allocate(Size, llvm::AlignOf<ObjCMessageExpr>::Alignment); return new (Mem) ObjCMessageExpr(EmptyShell(), NumArgs); } - + +SourceRange ObjCMessageExpr::getReceiverRange() const { + switch (getReceiverKind()) { + case Instance: + return getInstanceReceiver()->getSourceRange(); + + case Class: + return getClassReceiverTypeInfo()->getTypeLoc().getSourceRange(); + + case SuperInstance: + case SuperClass: + return getSuperLoc(); + } + + return SourceLocation(); +} + Selector ObjCMessageExpr::getSelector() const { if (HasMethod) return reinterpret_cast<const ObjCMethodDecl *>(SelectorOrMethod) @@ -1883,19 +2531,40 @@ ObjCInterfaceDecl *ObjCMessageExpr::getReceiverInterface() const { break; case SuperClass: - if (const ObjCObjectPointerType *Iface - = getSuperType()->getAs<ObjCObjectPointerType>()) - return Iface->getInterfaceDecl(); + if (const ObjCObjectType *Iface + = getSuperType()->getAs<ObjCObjectType>()) + return Iface->getInterface(); break; } return 0; } -bool ChooseExpr::isConditionTrue(ASTContext &C) const { +bool ChooseExpr::isConditionTrue(const ASTContext &C) const { return getCond()->EvaluateAsInt(C) != 0; } +ShuffleVectorExpr::ShuffleVectorExpr(ASTContext &C, Expr **args, unsigned nexpr, + QualType Type, SourceLocation BLoc, + SourceLocation RP) + : Expr(ShuffleVectorExprClass, Type, VK_RValue, OK_Ordinary, + Type->isDependentType(), Type->isDependentType(), + Type->containsUnexpandedParameterPack()), + BuiltinLoc(BLoc), RParenLoc(RP), NumExprs(nexpr) +{ + SubExprs = new (C) Stmt*[nexpr]; + for (unsigned i = 0; i < nexpr; i++) { + if (args[i]->isTypeDependent()) + ExprBits.TypeDependent = true; + if (args[i]->isValueDependent()) + ExprBits.ValueDependent = true; + if (args[i]->containsUnexpandedParameterPack()) + ExprBits.ContainsUnexpandedParameterPack = true; + + SubExprs[i] = args[i]; + } +} + void ShuffleVectorExpr::setExprs(ASTContext &C, Expr ** Exprs, unsigned NumExprs) { if (SubExprs) C.Deallocate(SubExprs); @@ -1926,13 +2595,15 @@ DesignatedInitExpr::DesignatedInitExpr(ASTContext &C, QualType Ty, unsigned NumIndexExprs, Expr *Init) : Expr(DesignatedInitExprClass, Ty, - Init->isTypeDependent(), Init->isValueDependent()), + Init->getValueKind(), Init->getObjectKind(), + Init->isTypeDependent(), Init->isValueDependent(), + Init->containsUnexpandedParameterPack()), EqualOrColonLoc(EqualOrColonLoc), GNUSyntax(GNUSyntax), NumDesignators(NumDesignators), NumSubExprs(NumIndexExprs + 1) { this->Designators = new (C) Designator[NumDesignators]; // Record the initializer itself. - child_iterator Child = child_begin(); + child_range Child = children(); *Child++ = Init; // Copy the designators and their subexpressions, computing @@ -1944,8 +2615,12 @@ DesignatedInitExpr::DesignatedInitExpr(ASTContext &C, QualType Ty, if (this->Designators[I].isArrayDesignator()) { // Compute type- and value-dependence. Expr *Index = IndexExprs[IndexIdx]; - ValueDependent = ValueDependent || - Index->isTypeDependent() || Index->isValueDependent(); + if (Index->isTypeDependent() || Index->isValueDependent()) + ExprBits.ValueDependent = true; + + // Propagate unexpanded parameter packs. + if (Index->containsUnexpandedParameterPack()) + ExprBits.ContainsUnexpandedParameterPack = true; // Copy the index expressions into permanent storage. *Child++ = IndexExprs[IndexIdx++]; @@ -1953,9 +2628,14 @@ DesignatedInitExpr::DesignatedInitExpr(ASTContext &C, QualType Ty, // Compute type- and value-dependence. Expr *Start = IndexExprs[IndexIdx]; Expr *End = IndexExprs[IndexIdx + 1]; - ValueDependent = ValueDependent || - Start->isTypeDependent() || Start->isValueDependent() || - End->isTypeDependent() || End->isValueDependent(); + if (Start->isTypeDependent() || Start->isValueDependent() || + End->isTypeDependent() || End->isValueDependent()) + ExprBits.ValueDependent = true; + + // Propagate unexpanded parameter packs. + if (Start->containsUnexpandedParameterPack() || + End->containsUnexpandedParameterPack()) + ExprBits.ContainsUnexpandedParameterPack = true; // Copy the start/end expressions into permanent storage. *Child++ = IndexExprs[IndexIdx++]; @@ -2066,14 +2746,30 @@ void DesignatedInitExpr::ExpandDesignator(ASTContext &C, unsigned Idx, ParenListExpr::ParenListExpr(ASTContext& C, SourceLocation lparenloc, Expr **exprs, unsigned nexprs, SourceLocation rparenloc) -: Expr(ParenListExprClass, QualType(), - hasAnyTypeDependentArguments(exprs, nexprs), - hasAnyValueDependentArguments(exprs, nexprs)), - NumExprs(nexprs), LParenLoc(lparenloc), RParenLoc(rparenloc) { + : Expr(ParenListExprClass, QualType(), VK_RValue, OK_Ordinary, + false, false, false), + NumExprs(nexprs), LParenLoc(lparenloc), RParenLoc(rparenloc) { Exprs = new (C) Stmt*[nexprs]; - for (unsigned i = 0; i != nexprs; ++i) + for (unsigned i = 0; i != nexprs; ++i) { + if (exprs[i]->isTypeDependent()) + ExprBits.TypeDependent = true; + if (exprs[i]->isValueDependent()) + ExprBits.ValueDependent = true; + if (exprs[i]->containsUnexpandedParameterPack()) + ExprBits.ContainsUnexpandedParameterPack = true; + Exprs[i] = exprs[i]; + } +} + +const OpaqueValueExpr *OpaqueValueExpr::findInCopyConstruct(const Expr *e) { + if (const ExprWithCleanups *ewc = dyn_cast<ExprWithCleanups>(e)) + e = ewc->getSubExpr(); + e = cast<CXXConstructExpr>(e)->getArg(0); + while (const ImplicitCastExpr *ice = dyn_cast<ImplicitCastExpr>(e)) + e = ice->getSubExpr(); + return cast<OpaqueValueExpr>(e); } //===----------------------------------------------------------------------===// @@ -2093,257 +2789,43 @@ const Expr* ConstExprIterator::operator->() const { return cast<Expr>(*I); } // Child Iterators for iterating over subexpressions/substatements //===----------------------------------------------------------------------===// -// DeclRefExpr -Stmt::child_iterator DeclRefExpr::child_begin() { return child_iterator(); } -Stmt::child_iterator DeclRefExpr::child_end() { return child_iterator(); } - -// ObjCIvarRefExpr -Stmt::child_iterator ObjCIvarRefExpr::child_begin() { return &Base; } -Stmt::child_iterator ObjCIvarRefExpr::child_end() { return &Base+1; } - -// ObjCPropertyRefExpr -Stmt::child_iterator ObjCPropertyRefExpr::child_begin() { return &Base; } -Stmt::child_iterator ObjCPropertyRefExpr::child_end() { return &Base+1; } - -// ObjCImplicitSetterGetterRefExpr -Stmt::child_iterator ObjCImplicitSetterGetterRefExpr::child_begin() { - // If this is accessing a class member, skip that entry. - if (Base) return &Base; - return &Base+1; -} -Stmt::child_iterator ObjCImplicitSetterGetterRefExpr::child_end() { - return &Base+1; -} - -// ObjCSuperExpr -Stmt::child_iterator ObjCSuperExpr::child_begin() { return child_iterator(); } -Stmt::child_iterator ObjCSuperExpr::child_end() { return child_iterator(); } - -// ObjCIsaExpr -Stmt::child_iterator ObjCIsaExpr::child_begin() { return &Base; } -Stmt::child_iterator ObjCIsaExpr::child_end() { return &Base+1; } - -// PredefinedExpr -Stmt::child_iterator PredefinedExpr::child_begin() { return child_iterator(); } -Stmt::child_iterator PredefinedExpr::child_end() { return child_iterator(); } - -// IntegerLiteral -Stmt::child_iterator IntegerLiteral::child_begin() { return child_iterator(); } -Stmt::child_iterator IntegerLiteral::child_end() { return child_iterator(); } - -// CharacterLiteral -Stmt::child_iterator CharacterLiteral::child_begin() { return child_iterator();} -Stmt::child_iterator CharacterLiteral::child_end() { return child_iterator(); } - -// FloatingLiteral -Stmt::child_iterator FloatingLiteral::child_begin() { return child_iterator(); } -Stmt::child_iterator FloatingLiteral::child_end() { return child_iterator(); } - -// ImaginaryLiteral -Stmt::child_iterator ImaginaryLiteral::child_begin() { return &Val; } -Stmt::child_iterator ImaginaryLiteral::child_end() { return &Val+1; } - -// StringLiteral -Stmt::child_iterator StringLiteral::child_begin() { return child_iterator(); } -Stmt::child_iterator StringLiteral::child_end() { return child_iterator(); } - -// ParenExpr -Stmt::child_iterator ParenExpr::child_begin() { return &Val; } -Stmt::child_iterator ParenExpr::child_end() { return &Val+1; } - -// UnaryOperator -Stmt::child_iterator UnaryOperator::child_begin() { return &Val; } -Stmt::child_iterator UnaryOperator::child_end() { return &Val+1; } - -// OffsetOfExpr -Stmt::child_iterator OffsetOfExpr::child_begin() { - return reinterpret_cast<Stmt **> (reinterpret_cast<OffsetOfNode *> (this + 1) - + NumComps); -} -Stmt::child_iterator OffsetOfExpr::child_end() { - return child_iterator(&*child_begin() + NumExprs); -} - // SizeOfAlignOfExpr -Stmt::child_iterator SizeOfAlignOfExpr::child_begin() { +Stmt::child_range SizeOfAlignOfExpr::children() { // If this is of a type and the type is a VLA type (and not a typedef), the // size expression of the VLA needs to be treated as an executable expression. // Why isn't this weirdness documented better in StmtIterator? if (isArgumentType()) { - if (VariableArrayType* T = dyn_cast<VariableArrayType>( + if (const VariableArrayType* T = dyn_cast<VariableArrayType>( getArgumentType().getTypePtr())) - return child_iterator(T); - return child_iterator(); + return child_range(child_iterator(T), child_iterator()); + return child_range(); } - return child_iterator(&Argument.Ex); -} -Stmt::child_iterator SizeOfAlignOfExpr::child_end() { - if (isArgumentType()) - return child_iterator(); - return child_iterator(&Argument.Ex + 1); -} - -// ArraySubscriptExpr -Stmt::child_iterator ArraySubscriptExpr::child_begin() { - return &SubExprs[0]; -} -Stmt::child_iterator ArraySubscriptExpr::child_end() { - return &SubExprs[0]+END_EXPR; -} - -// CallExpr -Stmt::child_iterator CallExpr::child_begin() { - return &SubExprs[0]; -} -Stmt::child_iterator CallExpr::child_end() { - return &SubExprs[0]+NumArgs+ARGS_START; -} - -// MemberExpr -Stmt::child_iterator MemberExpr::child_begin() { return &Base; } -Stmt::child_iterator MemberExpr::child_end() { return &Base+1; } - -// ExtVectorElementExpr -Stmt::child_iterator ExtVectorElementExpr::child_begin() { return &Base; } -Stmt::child_iterator ExtVectorElementExpr::child_end() { return &Base+1; } - -// CompoundLiteralExpr -Stmt::child_iterator CompoundLiteralExpr::child_begin() { return &Init; } -Stmt::child_iterator CompoundLiteralExpr::child_end() { return &Init+1; } - -// CastExpr -Stmt::child_iterator CastExpr::child_begin() { return &Op; } -Stmt::child_iterator CastExpr::child_end() { return &Op+1; } - -// BinaryOperator -Stmt::child_iterator BinaryOperator::child_begin() { - return &SubExprs[0]; -} -Stmt::child_iterator BinaryOperator::child_end() { - return &SubExprs[0]+END_EXPR; -} - -// ConditionalOperator -Stmt::child_iterator ConditionalOperator::child_begin() { - return &SubExprs[0]; -} -Stmt::child_iterator ConditionalOperator::child_end() { - return &SubExprs[0]+END_EXPR; -} - -// AddrLabelExpr -Stmt::child_iterator AddrLabelExpr::child_begin() { return child_iterator(); } -Stmt::child_iterator AddrLabelExpr::child_end() { return child_iterator(); } - -// StmtExpr -Stmt::child_iterator StmtExpr::child_begin() { return &SubStmt; } -Stmt::child_iterator StmtExpr::child_end() { return &SubStmt+1; } - -// TypesCompatibleExpr -Stmt::child_iterator TypesCompatibleExpr::child_begin() { - return child_iterator(); -} - -Stmt::child_iterator TypesCompatibleExpr::child_end() { - return child_iterator(); -} - -// ChooseExpr -Stmt::child_iterator ChooseExpr::child_begin() { return &SubExprs[0]; } -Stmt::child_iterator ChooseExpr::child_end() { return &SubExprs[0]+END_EXPR; } - -// GNUNullExpr -Stmt::child_iterator GNUNullExpr::child_begin() { return child_iterator(); } -Stmt::child_iterator GNUNullExpr::child_end() { return child_iterator(); } - -// ShuffleVectorExpr -Stmt::child_iterator ShuffleVectorExpr::child_begin() { - return &SubExprs[0]; -} -Stmt::child_iterator ShuffleVectorExpr::child_end() { - return &SubExprs[0]+NumExprs; -} - -// VAArgExpr -Stmt::child_iterator VAArgExpr::child_begin() { return &Val; } -Stmt::child_iterator VAArgExpr::child_end() { return &Val+1; } - -// InitListExpr -Stmt::child_iterator InitListExpr::child_begin() { - return InitExprs.size() ? &InitExprs[0] : 0; -} -Stmt::child_iterator InitListExpr::child_end() { - return InitExprs.size() ? &InitExprs[0] + InitExprs.size() : 0; -} - -// DesignatedInitExpr -Stmt::child_iterator DesignatedInitExpr::child_begin() { - char* Ptr = static_cast<char*>(static_cast<void *>(this)); - Ptr += sizeof(DesignatedInitExpr); - return reinterpret_cast<Stmt**>(reinterpret_cast<void**>(Ptr)); -} -Stmt::child_iterator DesignatedInitExpr::child_end() { - return child_iterator(&*child_begin() + NumSubExprs); -} - -// ImplicitValueInitExpr -Stmt::child_iterator ImplicitValueInitExpr::child_begin() { - return child_iterator(); -} - -Stmt::child_iterator ImplicitValueInitExpr::child_end() { - return child_iterator(); -} - -// ParenListExpr -Stmt::child_iterator ParenListExpr::child_begin() { - return &Exprs[0]; -} -Stmt::child_iterator ParenListExpr::child_end() { - return &Exprs[0]+NumExprs; -} - -// ObjCStringLiteral -Stmt::child_iterator ObjCStringLiteral::child_begin() { - return &String; -} -Stmt::child_iterator ObjCStringLiteral::child_end() { - return &String+1; -} - -// ObjCEncodeExpr -Stmt::child_iterator ObjCEncodeExpr::child_begin() { return child_iterator(); } -Stmt::child_iterator ObjCEncodeExpr::child_end() { return child_iterator(); } - -// ObjCSelectorExpr -Stmt::child_iterator ObjCSelectorExpr::child_begin() { - return child_iterator(); -} -Stmt::child_iterator ObjCSelectorExpr::child_end() { - return child_iterator(); -} - -// ObjCProtocolExpr -Stmt::child_iterator ObjCProtocolExpr::child_begin() { - return child_iterator(); -} -Stmt::child_iterator ObjCProtocolExpr::child_end() { - return child_iterator(); + return child_range(&Argument.Ex, &Argument.Ex + 1); } // ObjCMessageExpr -Stmt::child_iterator ObjCMessageExpr::child_begin() { +Stmt::child_range ObjCMessageExpr::children() { + Stmt **begin; if (getReceiverKind() == Instance) - return reinterpret_cast<Stmt **>(this + 1); - return getArgs(); -} -Stmt::child_iterator ObjCMessageExpr::child_end() { - return getArgs() + getNumArgs(); + begin = reinterpret_cast<Stmt **>(this + 1); + else + begin = reinterpret_cast<Stmt **>(getArgs()); + return child_range(begin, + reinterpret_cast<Stmt **>(getArgs() + getNumArgs())); } // Blocks -Stmt::child_iterator BlockExpr::child_begin() { return child_iterator(); } -Stmt::child_iterator BlockExpr::child_end() { return child_iterator(); } +BlockDeclRefExpr::BlockDeclRefExpr(VarDecl *d, QualType t, ExprValueKind VK, + SourceLocation l, bool ByRef, + bool constAdded) + : Expr(BlockDeclRefExprClass, t, VK, OK_Ordinary, false, false, + d->isParameterPack()), + D(d), Loc(l), IsByRef(ByRef), ConstQualAdded(constAdded) +{ + bool TypeDependent = false; + bool ValueDependent = false; + computeDeclRefDependence(D, getType(), TypeDependent, ValueDependent); + ExprBits.TypeDependent = TypeDependent; + ExprBits.ValueDependent = ValueDependent; +} -Stmt::child_iterator BlockDeclRefExpr::child_begin() { return child_iterator();} -Stmt::child_iterator BlockDeclRefExpr::child_end() { return child_iterator(); } diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 0a10130..28ff9fb 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -29,57 +29,18 @@ QualType CXXTypeidExpr::getTypeOperand() const { .getUnqualifiedType(); } -// CXXTypeidExpr - has child iterators if the operand is an expression -Stmt::child_iterator CXXTypeidExpr::child_begin() { - return isTypeOperand() ? child_iterator() - : reinterpret_cast<Stmt **>(&Operand); -} -Stmt::child_iterator CXXTypeidExpr::child_end() { - return isTypeOperand() ? child_iterator() - : reinterpret_cast<Stmt **>(&Operand) + 1; -} - -// CXXBoolLiteralExpr -Stmt::child_iterator CXXBoolLiteralExpr::child_begin() { - return child_iterator(); -} -Stmt::child_iterator CXXBoolLiteralExpr::child_end() { - return child_iterator(); -} - -// CXXNullPtrLiteralExpr -Stmt::child_iterator CXXNullPtrLiteralExpr::child_begin() { - return child_iterator(); -} -Stmt::child_iterator CXXNullPtrLiteralExpr::child_end() { - return child_iterator(); -} - -// CXXThisExpr -Stmt::child_iterator CXXThisExpr::child_begin() { return child_iterator(); } -Stmt::child_iterator CXXThisExpr::child_end() { return child_iterator(); } - -// CXXThrowExpr -Stmt::child_iterator CXXThrowExpr::child_begin() { return &Op; } -Stmt::child_iterator CXXThrowExpr::child_end() { - // If Op is 0, we are processing throw; which has no children. - return Op ? &Op+1 : &Op; -} - -// CXXDefaultArgExpr -Stmt::child_iterator CXXDefaultArgExpr::child_begin() { - return child_iterator(); -} -Stmt::child_iterator CXXDefaultArgExpr::child_end() { - return child_iterator(); +QualType CXXUuidofExpr::getTypeOperand() const { + assert(isTypeOperand() && "Cannot call getTypeOperand for __uuidof(expr)"); + return Operand.get<TypeSourceInfo *>()->getType().getNonReferenceType() + .getUnqualifiedType(); } // CXXScalarValueInitExpr -Stmt::child_iterator CXXScalarValueInitExpr::child_begin() { - return child_iterator(); -} -Stmt::child_iterator CXXScalarValueInitExpr::child_end() { - return child_iterator(); +SourceRange CXXScalarValueInitExpr::getSourceRange() const { + SourceLocation Start = RParenLoc; + if (TypeInfo) + Start = TypeInfo->getTypeLoc().getBeginLoc(); + return SourceRange(Start, RParenLoc); } // CXXNewExpr @@ -88,22 +49,44 @@ CXXNewExpr::CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew, SourceRange TypeIdParens, Expr *arraySize, CXXConstructorDecl *constructor, bool initializer, Expr **constructorArgs, unsigned numConsArgs, - FunctionDecl *operatorDelete, QualType ty, - SourceLocation startLoc, SourceLocation endLoc) - : Expr(CXXNewExprClass, ty, ty->isDependentType(), ty->isDependentType()), - GlobalNew(globalNew), - Initializer(initializer), SubExprs(0), OperatorNew(operatorNew), + FunctionDecl *operatorDelete, + bool usualArrayDeleteWantsSize, QualType ty, + TypeSourceInfo *AllocatedTypeInfo, + SourceLocation startLoc, SourceLocation endLoc, + SourceLocation constructorLParen, + SourceLocation constructorRParen) + : Expr(CXXNewExprClass, ty, VK_RValue, OK_Ordinary, + ty->isDependentType(), ty->isDependentType(), + ty->containsUnexpandedParameterPack()), + GlobalNew(globalNew), Initializer(initializer), + UsualArrayDeleteWantsSize(usualArrayDeleteWantsSize), + SubExprs(0), OperatorNew(operatorNew), OperatorDelete(operatorDelete), Constructor(constructor), - TypeIdParens(TypeIdParens), StartLoc(startLoc), EndLoc(endLoc) { - + AllocatedTypeInfo(AllocatedTypeInfo), TypeIdParens(TypeIdParens), + StartLoc(startLoc), EndLoc(endLoc), ConstructorLParen(constructorLParen), + ConstructorRParen(constructorRParen) { AllocateArgsArray(C, arraySize != 0, numPlaceArgs, numConsArgs); unsigned i = 0; - if (Array) + if (Array) { + if (arraySize->containsUnexpandedParameterPack()) + ExprBits.ContainsUnexpandedParameterPack = true; + SubExprs[i++] = arraySize; - for (unsigned j = 0; j < NumPlacementArgs; ++j) + } + + for (unsigned j = 0; j < NumPlacementArgs; ++j) { + if (placementArgs[j]->containsUnexpandedParameterPack()) + ExprBits.ContainsUnexpandedParameterPack = true; + SubExprs[i++] = placementArgs[j]; - for (unsigned j = 0; j < NumConstructorArgs; ++j) + } + + for (unsigned j = 0; j < NumConstructorArgs; ++j) { + if (constructorArgs[j]->containsUnexpandedParameterPack()) + ExprBits.ContainsUnexpandedParameterPack = true; + SubExprs[i++] = constructorArgs[j]; + } } void CXXNewExpr::AllocateArgsArray(ASTContext &C, bool isArray, @@ -118,27 +101,59 @@ void CXXNewExpr::AllocateArgsArray(ASTContext &C, bool isArray, } -Stmt::child_iterator CXXNewExpr::child_begin() { return &SubExprs[0]; } -Stmt::child_iterator CXXNewExpr::child_end() { - return &SubExprs[0] + Array + getNumPlacementArgs() + getNumConstructorArgs(); -} - // CXXDeleteExpr -Stmt::child_iterator CXXDeleteExpr::child_begin() { return &Argument; } -Stmt::child_iterator CXXDeleteExpr::child_end() { return &Argument+1; } +QualType CXXDeleteExpr::getDestroyedType() const { + const Expr *Arg = getArgument(); + while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) { + if (ICE->getCastKind() != CK_UserDefinedConversion && + ICE->getType()->isVoidPointerType()) + Arg = ICE->getSubExpr(); + else + break; + } + // The type-to-delete may not be a pointer if it's a dependent type. + const QualType ArgType = Arg->getType(); -// CXXPseudoDestructorExpr -Stmt::child_iterator CXXPseudoDestructorExpr::child_begin() { return &Base; } -Stmt::child_iterator CXXPseudoDestructorExpr::child_end() { - return &Base + 1; + if (ArgType->isDependentType() && !ArgType->isPointerType()) + return QualType(); + + return ArgType->getAs<PointerType>()->getPointeeType(); } +// CXXPseudoDestructorExpr PseudoDestructorTypeStorage::PseudoDestructorTypeStorage(TypeSourceInfo *Info) : Type(Info) { Location = Info->getTypeLoc().getLocalSourceRange().getBegin(); } +CXXPseudoDestructorExpr::CXXPseudoDestructorExpr(ASTContext &Context, + Expr *Base, bool isArrow, SourceLocation OperatorLoc, + NestedNameSpecifier *Qualifier, SourceRange QualifierRange, + TypeSourceInfo *ScopeType, SourceLocation ColonColonLoc, + SourceLocation TildeLoc, PseudoDestructorTypeStorage DestroyedType) + : Expr(CXXPseudoDestructorExprClass, + Context.getPointerType(Context.getFunctionType(Context.VoidTy, 0, 0, + FunctionProtoType::ExtProtoInfo())), + VK_RValue, OK_Ordinary, + /*isTypeDependent=*/(Base->isTypeDependent() || + (DestroyedType.getTypeSourceInfo() && + DestroyedType.getTypeSourceInfo()->getType()->isDependentType())), + /*isValueDependent=*/Base->isValueDependent(), + // ContainsUnexpandedParameterPack + (Base->containsUnexpandedParameterPack() || + (Qualifier && Qualifier->containsUnexpandedParameterPack()) || + (ScopeType && + ScopeType->getType()->containsUnexpandedParameterPack()) || + (DestroyedType.getTypeSourceInfo() && + DestroyedType.getTypeSourceInfo()->getType() + ->containsUnexpandedParameterPack()))), + Base(static_cast<Stmt *>(Base)), IsArrow(isArrow), + OperatorLoc(OperatorLoc), Qualifier(Qualifier), + QualifierRange(QualifierRange), + ScopeType(ScopeType), ColonColonLoc(ColonColonLoc), TildeLoc(TildeLoc), + DestroyedType(DestroyedType) { } + QualType CXXPseudoDestructorExpr::getDestroyedType() const { if (TypeSourceInfo *TInfo = DestroyedType.getTypeSourceInfo()) return TInfo->getType(); @@ -156,7 +171,7 @@ SourceRange CXXPseudoDestructorExpr::getSourceRange() const { // UnresolvedLookupExpr UnresolvedLookupExpr * -UnresolvedLookupExpr::Create(ASTContext &C, bool Dependent, +UnresolvedLookupExpr::Create(ASTContext &C, CXXRecordDecl *NamingClass, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, @@ -168,73 +183,94 @@ UnresolvedLookupExpr::Create(ASTContext &C, bool Dependent, { void *Mem = C.Allocate(sizeof(UnresolvedLookupExpr) + ExplicitTemplateArgumentList::sizeFor(Args)); - UnresolvedLookupExpr *ULE - = new (Mem) UnresolvedLookupExpr(C, - Dependent ? C.DependentTy : C.OverloadTy, - Dependent, NamingClass, - Qualifier, QualifierRange, NameInfo, - ADL, - /*Overload*/ true, - /*ExplicitTemplateArgs*/ true, - Begin, End); - - reinterpret_cast<ExplicitTemplateArgumentList*>(ULE+1)->initializeFrom(Args); - - return ULE; + return new (Mem) UnresolvedLookupExpr(C, NamingClass, + Qualifier, QualifierRange, NameInfo, + ADL, /*Overload*/ true, &Args, + Begin, End); } UnresolvedLookupExpr * -UnresolvedLookupExpr::CreateEmpty(ASTContext &C, unsigned NumTemplateArgs) { +UnresolvedLookupExpr::CreateEmpty(ASTContext &C, bool HasExplicitTemplateArgs, + unsigned NumTemplateArgs) { std::size_t size = sizeof(UnresolvedLookupExpr); - if (NumTemplateArgs != 0) + if (HasExplicitTemplateArgs) size += ExplicitTemplateArgumentList::sizeFor(NumTemplateArgs); - void *Mem = C.Allocate(size, llvm::alignof<UnresolvedLookupExpr>()); + void *Mem = C.Allocate(size, llvm::alignOf<UnresolvedLookupExpr>()); UnresolvedLookupExpr *E = new (Mem) UnresolvedLookupExpr(EmptyShell()); - E->HasExplicitTemplateArgs = NumTemplateArgs != 0; + E->HasExplicitTemplateArgs = HasExplicitTemplateArgs; return E; } -OverloadExpr::OverloadExpr(StmtClass K, ASTContext &C, QualType T, - bool Dependent, NestedNameSpecifier *Qualifier, - SourceRange QRange, +OverloadExpr::OverloadExpr(StmtClass K, ASTContext &C, + NestedNameSpecifier *Qualifier, SourceRange QRange, const DeclarationNameInfo &NameInfo, - bool HasTemplateArgs, + const TemplateArgumentListInfo *TemplateArgs, UnresolvedSetIterator Begin, - UnresolvedSetIterator End) - : Expr(K, T, Dependent, Dependent), - Results(0), NumResults(0), NameInfo(NameInfo), Qualifier(Qualifier), - QualifierRange(QRange), HasExplicitTemplateArgs(HasTemplateArgs) + UnresolvedSetIterator End, + bool KnownDependent, + bool KnownContainsUnexpandedParameterPack) + : Expr(K, C.OverloadTy, VK_LValue, OK_Ordinary, KnownDependent, + KnownDependent, + (KnownContainsUnexpandedParameterPack || + NameInfo.containsUnexpandedParameterPack() || + (Qualifier && Qualifier->containsUnexpandedParameterPack()))), + Results(0), NumResults(End - Begin), NameInfo(NameInfo), + Qualifier(Qualifier), QualifierRange(QRange), + HasExplicitTemplateArgs(TemplateArgs != 0) { - initializeResults(C, Begin, End); -} - -void OverloadExpr::initializeResults(ASTContext &C, - UnresolvedSetIterator Begin, - UnresolvedSetIterator End) { - assert(Results == 0 && "Results already initialized!"); NumResults = End - Begin; if (NumResults) { + // Determine whether this expression is type-dependent. + for (UnresolvedSetImpl::const_iterator I = Begin; I != End; ++I) { + if ((*I)->getDeclContext()->isDependentContext() || + isa<UnresolvedUsingValueDecl>(*I)) { + ExprBits.TypeDependent = true; + ExprBits.ValueDependent = true; + } + } + Results = static_cast<DeclAccessPair *>( C.Allocate(sizeof(DeclAccessPair) * NumResults, - llvm::alignof<DeclAccessPair>())); + llvm::alignOf<DeclAccessPair>())); memcpy(Results, &*Begin.getIterator(), NumResults * sizeof(DeclAccessPair)); } -} - -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; + // If we have explicit template arguments, check for dependent + // template arguments and whether they contain any unexpanded pack + // expansions. + if (TemplateArgs) { + bool Dependent = false; + bool ContainsUnexpandedParameterPack = false; + getExplicitTemplateArgs().initializeFrom(*TemplateArgs, Dependent, + ContainsUnexpandedParameterPack); + + if (Dependent) { + ExprBits.TypeDependent = true; + ExprBits.ValueDependent = true; + } + if (ContainsUnexpandedParameterPack) + ExprBits.ContainsUnexpandedParameterPack = true; + } - if (Args && TemplateSpecializationType::anyDependentTemplateArguments(*Args)) - return true; + if (isTypeDependent()) + setType(C.DependentTy); +} - return false; +void OverloadExpr::initializeResults(ASTContext &C, + UnresolvedSetIterator Begin, + UnresolvedSetIterator End) { + assert(Results == 0 && "Results already initialized!"); + NumResults = End - Begin; + if (NumResults) { + Results = static_cast<DeclAccessPair *>( + C.Allocate(sizeof(DeclAccessPair) * NumResults, + + llvm::alignOf<DeclAccessPair>())); + memcpy(Results, &*Begin.getIterator(), + NumResults * sizeof(DeclAccessPair)); + } } CXXRecordDecl *OverloadExpr::getNamingClass() const { @@ -244,21 +280,30 @@ CXXRecordDecl *OverloadExpr::getNamingClass() const { return cast<UnresolvedMemberExpr>(this)->getNamingClass(); } -Stmt::child_iterator UnresolvedLookupExpr::child_begin() { - return child_iterator(); -} -Stmt::child_iterator UnresolvedLookupExpr::child_end() { - return child_iterator(); -} -// UnaryTypeTraitExpr -Stmt::child_iterator UnaryTypeTraitExpr::child_begin() { - return child_iterator(); -} -Stmt::child_iterator UnaryTypeTraitExpr::child_end() { - return child_iterator(); +// DependentScopeDeclRefExpr +DependentScopeDeclRefExpr::DependentScopeDeclRefExpr(QualType T, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + const DeclarationNameInfo &NameInfo, + const TemplateArgumentListInfo *Args) + : Expr(DependentScopeDeclRefExprClass, T, VK_LValue, OK_Ordinary, + true, true, + (NameInfo.containsUnexpandedParameterPack() || + (Qualifier && Qualifier->containsUnexpandedParameterPack()))), + NameInfo(NameInfo), QualifierRange(QualifierRange), Qualifier(Qualifier), + HasExplicitTemplateArgs(Args != 0) +{ + if (Args) { + bool Dependent = true; + bool ContainsUnexpandedParameterPack + = ExprBits.ContainsUnexpandedParameterPack; + + reinterpret_cast<ExplicitTemplateArgumentList*>(this+1) + ->initializeFrom(*Args, Dependent, ContainsUnexpandedParameterPack); + ExprBits.ContainsUnexpandedParameterPack = ContainsUnexpandedParameterPack; + } } -// DependentScopeDeclRefExpr DependentScopeDeclRefExpr * DependentScopeDeclRefExpr::Create(ASTContext &C, NestedNameSpecifier *Qualifier, @@ -266,251 +311,46 @@ DependentScopeDeclRefExpr::Create(ASTContext &C, const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *Args) { std::size_t size = sizeof(DependentScopeDeclRefExpr); - if (Args) size += ExplicitTemplateArgumentList::sizeFor(*Args); - void *Mem = C.Allocate(size); - - DependentScopeDeclRefExpr *DRE - = new (Mem) DependentScopeDeclRefExpr(C.DependentTy, - Qualifier, QualifierRange, - NameInfo, Args != 0); - if (Args) - reinterpret_cast<ExplicitTemplateArgumentList*>(DRE+1) - ->initializeFrom(*Args); - - return DRE; + size += ExplicitTemplateArgumentList::sizeFor(*Args); + void *Mem = C.Allocate(size); + return new (Mem) DependentScopeDeclRefExpr(C.DependentTy, + Qualifier, QualifierRange, + NameInfo, Args); } DependentScopeDeclRefExpr * DependentScopeDeclRefExpr::CreateEmpty(ASTContext &C, + bool HasExplicitTemplateArgs, unsigned NumTemplateArgs) { std::size_t size = sizeof(DependentScopeDeclRefExpr); - if (NumTemplateArgs) + if (HasExplicitTemplateArgs) size += ExplicitTemplateArgumentList::sizeFor(NumTemplateArgs); void *Mem = C.Allocate(size); - - return new (Mem) DependentScopeDeclRefExpr(QualType(), 0, SourceRange(), - DeclarationNameInfo(), - NumTemplateArgs != 0); -} - -StmtIterator DependentScopeDeclRefExpr::child_begin() { - return child_iterator(); + DependentScopeDeclRefExpr *E + = new (Mem) DependentScopeDeclRefExpr(QualType(), 0, SourceRange(), + DeclarationNameInfo(), 0); + E->HasExplicitTemplateArgs = HasExplicitTemplateArgs; + return E; } -StmtIterator DependentScopeDeclRefExpr::child_end() { - return child_iterator(); -} +SourceRange CXXConstructExpr::getSourceRange() const { + if (ParenRange.isValid()) + return SourceRange(Loc, ParenRange.getEnd()); -bool UnaryTypeTraitExpr::EvaluateTrait(ASTContext& C) const { - switch(UTT) { - default: assert(false && "Unknown type trait or not implemented"); - case UTT_IsPOD: return QueriedType->isPODType(); - case UTT_IsLiteral: return QueriedType->isLiteralType(); - case UTT_IsClass: // Fallthrough - case UTT_IsUnion: - if (const RecordType *Record = QueriedType->getAs<RecordType>()) { - bool Union = Record->getDecl()->isUnion(); - return UTT == UTT_IsUnion ? Union : !Union; - } - return false; - case UTT_IsEnum: return QueriedType->isEnumeralType(); - case UTT_IsPolymorphic: - if (const RecordType *Record = QueriedType->getAs<RecordType>()) { - // Type traits are only parsed in C++, so we've got CXXRecords. - return cast<CXXRecordDecl>(Record->getDecl())->isPolymorphic(); - } - return false; - case UTT_IsAbstract: - if (const RecordType *RT = QueriedType->getAs<RecordType>()) - return cast<CXXRecordDecl>(RT->getDecl())->isAbstract(); - return false; - case UTT_IsEmpty: - if (const RecordType *Record = QueriedType->getAs<RecordType>()) { - return !Record->getDecl()->isUnion() - && cast<CXXRecordDecl>(Record->getDecl())->isEmpty(); - } - return false; - case UTT_HasTrivialConstructor: - // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: - // If __is_pod (type) is true then the trait is true, else if type is - // a cv class or union type (or array thereof) with a trivial default - // constructor ([class.ctor]) then the trait is true, else it is false. - if (QueriedType->isPODType()) - return true; - if (const RecordType *RT = - C.getBaseElementType(QueriedType)->getAs<RecordType>()) - return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialConstructor(); - return false; - case UTT_HasTrivialCopy: - // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: - // If __is_pod (type) is true or type is a reference type then - // the trait is true, else if type is a cv class or union type - // with a trivial copy constructor ([class.copy]) then the trait - // is true, else it is false. - if (QueriedType->isPODType() || QueriedType->isReferenceType()) - return true; - if (const RecordType *RT = QueriedType->getAs<RecordType>()) - return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialCopyConstructor(); - return false; - case UTT_HasTrivialAssign: - // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: - // If type is const qualified or is a reference type then the - // trait is false. Otherwise if __is_pod (type) is true then the - // trait is true, else if type is a cv class or union type with - // a trivial copy assignment ([class.copy]) then the trait is - // true, else it is false. - // Note: the const and reference restrictions are interesting, - // given that const and reference members don't prevent a class - // from having a trivial copy assignment operator (but do cause - // errors if the copy assignment operator is actually used, q.v. - // [class.copy]p12). - - if (C.getBaseElementType(QueriedType).isConstQualified()) - return false; - if (QueriedType->isPODType()) - return true; - if (const RecordType *RT = QueriedType->getAs<RecordType>()) - return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialCopyAssignment(); - return false; - case UTT_HasTrivialDestructor: - // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: - // If __is_pod (type) is true or type is a reference type - // then the trait is true, else if type is a cv class or union - // type (or array thereof) with a trivial destructor - // ([class.dtor]) then the trait is true, else it is - // false. - if (QueriedType->isPODType() || QueriedType->isReferenceType()) - return true; - if (const RecordType *RT = - C.getBaseElementType(QueriedType)->getAs<RecordType>()) - return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialDestructor(); - return false; - // TODO: Propagate nothrowness for implicitly declared special members. - case UTT_HasNothrowAssign: - // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: - // If type is const qualified or is a reference type then the - // trait is false. Otherwise if __has_trivial_assign (type) - // is true then the trait is true, else if type is a cv class - // or union type with copy assignment operators that are known - // not to throw an exception then the trait is true, else it is - // false. - if (C.getBaseElementType(QueriedType).isConstQualified()) - return false; - if (QueriedType->isReferenceType()) - return false; - if (QueriedType->isPODType()) - return true; - if (const RecordType *RT = QueriedType->getAs<RecordType>()) { - CXXRecordDecl* RD = cast<CXXRecordDecl>(RT->getDecl()); - if (RD->hasTrivialCopyAssignment()) - return true; - - bool FoundAssign = false; - bool AllNoThrow = true; - DeclarationName Name = C.DeclarationNames.getCXXOperatorName(OO_Equal); - DeclContext::lookup_const_iterator Op, OpEnd; - for (llvm::tie(Op, OpEnd) = RD->lookup(Name); - Op != OpEnd; ++Op) { - CXXMethodDecl *Operator = cast<CXXMethodDecl>(*Op); - if (Operator->isCopyAssignmentOperator()) { - FoundAssign = true; - const FunctionProtoType *CPT - = Operator->getType()->getAs<FunctionProtoType>(); - if (!CPT->hasEmptyExceptionSpec()) { - AllNoThrow = false; - break; - } - } + SourceLocation End = Loc; + for (unsigned I = getNumArgs(); I > 0; --I) { + const Expr *Arg = getArg(I-1); + if (!Arg->isDefaultArgument()) { + SourceLocation NewEnd = Arg->getLocEnd(); + if (NewEnd.isValid()) { + End = NewEnd; + break; } - - return FoundAssign && AllNoThrow; } - return false; - case UTT_HasNothrowCopy: - // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: - // If __has_trivial_copy (type) is true then the trait is true, else - // if type is a cv class or union type with copy constructors that are - // known not to throw an exception then the trait is true, else it is - // false. - if (QueriedType->isPODType() || QueriedType->isReferenceType()) - return true; - if (const RecordType *RT = QueriedType->getAs<RecordType>()) { - CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); - if (RD->hasTrivialCopyConstructor()) - return true; - - bool FoundConstructor = false; - bool AllNoThrow = true; - unsigned FoundTQs; - DeclarationName ConstructorName - = C.DeclarationNames.getCXXConstructorName( - C.getCanonicalType(QueriedType)); - DeclContext::lookup_const_iterator Con, ConEnd; - for (llvm::tie(Con, ConEnd) = RD->lookup(ConstructorName); - Con != ConEnd; ++Con) { - CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con); - if (Constructor->isCopyConstructor(FoundTQs)) { - FoundConstructor = true; - const FunctionProtoType *CPT - = Constructor->getType()->getAs<FunctionProtoType>(); - if (!CPT->hasEmptyExceptionSpec()) { - AllNoThrow = false; - break; - } - } - } - - return FoundConstructor && AllNoThrow; - } - return false; - case UTT_HasNothrowConstructor: - // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: - // If __has_trivial_constructor (type) is true then the trait is - // true, else if type is a cv class or union type (or array - // thereof) with a default constructor that is known not to - // throw an exception then the trait is true, else it is false. - if (QueriedType->isPODType()) - return true; - if (const RecordType *RT = - C.getBaseElementType(QueriedType)->getAs<RecordType>()) { - CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); - if (RD->hasTrivialConstructor()) - return true; - - if (CXXConstructorDecl *Constructor = RD->getDefaultConstructor()) { - const FunctionProtoType *CPT - = Constructor->getType()->getAs<FunctionProtoType>(); - // TODO: check whether evaluating default arguments can throw. - // For now, we'll be conservative and assume that they can throw. - if (CPT->hasEmptyExceptionSpec() && CPT->getNumArgs() == 0) - return true; - } - } - return false; - case UTT_HasVirtualDestructor: - // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: - // If type is a class type with a virtual destructor ([class.dtor]) - // then the trait is true, else it is false. - if (const RecordType *Record = QueriedType->getAs<RecordType>()) { - CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl()); - if (CXXDestructorDecl *Destructor = RD->getDestructor()) - return Destructor->isVirtual(); - } - return false; } -} -SourceRange CXXConstructExpr::getSourceRange() const { - // FIXME: Should we know where the parentheses are, if there are any? - for (std::reverse_iterator<Stmt**> I(&Args[NumArgs]), E(&Args[0]); I!=E;++I) { - // Ignore CXXDefaultExprs when computing the range, as they don't - // have a range. - if (!isa<CXXDefaultArgExpr>(*I)) - return SourceRange(Loc, (*I)->getLocEnd()); - } - - return SourceRange(Loc); + return SourceRange(Loc, End); } SourceRange CXXOperatorCallExpr::getSourceRange() const { @@ -546,6 +386,17 @@ Expr *CXXMemberCallExpr::getImplicitObjectArgument() { return 0; } +CXXRecordDecl *CXXMemberCallExpr::getRecordDecl() { + Expr* ThisArg = getImplicitObjectArgument(); + if (!ThisArg) + return 0; + + if (ThisArg->getType()->isAnyPointerType()) + return ThisArg->getType()->getPointeeType()->getAsCXXRecordDecl(); + + return ThisArg->getType()->getAsCXXRecordDecl(); +} + SourceRange CXXMemberCallExpr::getSourceRange() const { SourceLocation LocStart = getCallee()->getLocStart(); if (LocStart.isInvalid() && getNumArgs() > 0) @@ -572,15 +423,18 @@ const char *CXXNamedCastExpr::getCastName() const { } CXXStaticCastExpr *CXXStaticCastExpr::Create(ASTContext &C, QualType T, + ExprValueKind VK, CastKind K, Expr *Op, const CXXCastPath *BasePath, TypeSourceInfo *WrittenTy, - SourceLocation L) { + SourceLocation L, + SourceLocation RParenLoc) { unsigned PathSize = (BasePath ? BasePath->size() : 0); void *Buffer = C.Allocate(sizeof(CXXStaticCastExpr) + PathSize * sizeof(CXXBaseSpecifier*)); CXXStaticCastExpr *E = - new (Buffer) CXXStaticCastExpr(T, K, Op, PathSize, WrittenTy, L); + new (Buffer) CXXStaticCastExpr(T, VK, K, Op, PathSize, WrittenTy, L, + RParenLoc); if (PathSize) E->setCastPath(*BasePath); return E; } @@ -593,15 +447,18 @@ CXXStaticCastExpr *CXXStaticCastExpr::CreateEmpty(ASTContext &C, } CXXDynamicCastExpr *CXXDynamicCastExpr::Create(ASTContext &C, QualType T, + ExprValueKind VK, CastKind K, Expr *Op, const CXXCastPath *BasePath, TypeSourceInfo *WrittenTy, - SourceLocation L) { + SourceLocation L, + SourceLocation RParenLoc) { unsigned PathSize = (BasePath ? BasePath->size() : 0); void *Buffer = C.Allocate(sizeof(CXXDynamicCastExpr) + PathSize * sizeof(CXXBaseSpecifier*)); CXXDynamicCastExpr *E = - new (Buffer) CXXDynamicCastExpr(T, K, Op, PathSize, WrittenTy, L); + new (Buffer) CXXDynamicCastExpr(T, VK, K, Op, PathSize, WrittenTy, L, + RParenLoc); if (PathSize) E->setCastPath(*BasePath); return E; } @@ -614,14 +471,17 @@ CXXDynamicCastExpr *CXXDynamicCastExpr::CreateEmpty(ASTContext &C, } CXXReinterpretCastExpr * -CXXReinterpretCastExpr::Create(ASTContext &C, QualType T, CastKind K, Expr *Op, +CXXReinterpretCastExpr::Create(ASTContext &C, QualType T, ExprValueKind VK, + CastKind K, Expr *Op, const CXXCastPath *BasePath, - TypeSourceInfo *WrittenTy, SourceLocation L) { + TypeSourceInfo *WrittenTy, SourceLocation L, + SourceLocation RParenLoc) { unsigned PathSize = (BasePath ? BasePath->size() : 0); void *Buffer = C.Allocate(sizeof(CXXReinterpretCastExpr) + PathSize * sizeof(CXXBaseSpecifier*)); CXXReinterpretCastExpr *E = - new (Buffer) CXXReinterpretCastExpr(T, K, Op, PathSize, WrittenTy, L); + new (Buffer) CXXReinterpretCastExpr(T, VK, K, Op, PathSize, WrittenTy, L, + RParenLoc); if (PathSize) E->setCastPath(*BasePath); return E; } @@ -633,10 +493,12 @@ CXXReinterpretCastExpr::CreateEmpty(ASTContext &C, unsigned PathSize) { return new (Buffer) CXXReinterpretCastExpr(EmptyShell(), PathSize); } -CXXConstCastExpr *CXXConstCastExpr::Create(ASTContext &C, QualType T, Expr *Op, +CXXConstCastExpr *CXXConstCastExpr::Create(ASTContext &C, QualType T, + ExprValueKind VK, Expr *Op, TypeSourceInfo *WrittenTy, - SourceLocation L) { - return new (C) CXXConstCastExpr(T, Op, WrittenTy, L); + SourceLocation L, + SourceLocation RParenLoc) { + return new (C) CXXConstCastExpr(T, VK, Op, WrittenTy, L, RParenLoc); } CXXConstCastExpr *CXXConstCastExpr::CreateEmpty(ASTContext &C) { @@ -644,7 +506,7 @@ CXXConstCastExpr *CXXConstCastExpr::CreateEmpty(ASTContext &C) { } CXXFunctionalCastExpr * -CXXFunctionalCastExpr::Create(ASTContext &C, QualType T, +CXXFunctionalCastExpr::Create(ASTContext &C, QualType T, ExprValueKind VK, TypeSourceInfo *Written, SourceLocation L, CastKind K, Expr *Op, const CXXCastPath *BasePath, SourceLocation R) { @@ -652,7 +514,7 @@ CXXFunctionalCastExpr::Create(ASTContext &C, QualType T, void *Buffer = C.Allocate(sizeof(CXXFunctionalCastExpr) + PathSize * sizeof(CXXBaseSpecifier*)); CXXFunctionalCastExpr *E = - new (Buffer) CXXFunctionalCastExpr(T, Written, L, K, Op, PathSize, R); + new (Buffer) CXXFunctionalCastExpr(T, VK, Written, L, K, Op, PathSize, R); if (PathSize) E->setCastPath(*BasePath); return E; } @@ -689,15 +551,22 @@ CXXBindTemporaryExpr *CXXBindTemporaryExpr::Create(ASTContext &C, CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(ASTContext &C, CXXConstructorDecl *Cons, - QualType writtenTy, - SourceLocation tyBeginLoc, + TypeSourceInfo *Type, Expr **Args, unsigned NumArgs, - SourceLocation rParenLoc, + SourceRange parenRange, bool ZeroInitialization) - : CXXConstructExpr(C, CXXTemporaryObjectExprClass, writtenTy, tyBeginLoc, - Cons, false, Args, NumArgs, ZeroInitialization), - TyBeginLoc(tyBeginLoc), RParenLoc(rParenLoc) { + : CXXConstructExpr(C, CXXTemporaryObjectExprClass, + Type->getType().getNonReferenceType(), + Type->getTypeLoc().getBeginLoc(), + Cons, false, Args, NumArgs, ZeroInitialization, + CXXConstructExpr::CK_Complete, parenRange), + Type(Type) { +} + +SourceRange CXXTemporaryObjectExpr::getSourceRange() const { + return SourceRange(Type->getTypeLoc().getBeginLoc(), + getParenRange().getEnd()); } CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T, @@ -705,10 +574,11 @@ CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T, CXXConstructorDecl *D, bool Elidable, Expr **Args, unsigned NumArgs, bool ZeroInitialization, - ConstructionKind ConstructKind) { + ConstructionKind ConstructKind, + SourceRange ParenRange) { return new (C) CXXConstructExpr(C, CXXConstructExprClass, T, Loc, D, Elidable, Args, NumArgs, ZeroInitialization, - ConstructKind); + ConstructKind, ParenRange); } CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T, @@ -716,31 +586,39 @@ CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T, CXXConstructorDecl *D, bool elidable, Expr **args, unsigned numargs, bool ZeroInitialization, - ConstructionKind ConstructKind) -: Expr(SC, T, - T->isDependentType(), - (T->isDependentType() || - CallExpr::hasAnyValueDependentArguments(args, numargs))), - Constructor(D), Loc(Loc), Elidable(elidable), - ZeroInitialization(ZeroInitialization), ConstructKind(ConstructKind), - Args(0), NumArgs(numargs) + ConstructionKind ConstructKind, + SourceRange ParenRange) + : Expr(SC, T, VK_RValue, OK_Ordinary, + T->isDependentType(), T->isDependentType(), + T->containsUnexpandedParameterPack()), + Constructor(D), Loc(Loc), ParenRange(ParenRange), Elidable(elidable), + ZeroInitialization(ZeroInitialization), ConstructKind(ConstructKind), + Args(0), NumArgs(numargs) { if (NumArgs) { Args = new (C) Stmt*[NumArgs]; for (unsigned i = 0; i != NumArgs; ++i) { assert(args[i] && "NULL argument in CXXConstructExpr"); + + if (args[i]->isValueDependent()) + ExprBits.ValueDependent = true; + if (args[i]->containsUnexpandedParameterPack()) + ExprBits.ContainsUnexpandedParameterPack = true; + Args[i] = args[i]; } } } -CXXExprWithTemporaries::CXXExprWithTemporaries(ASTContext &C, - Expr *subexpr, - CXXTemporary **temps, - unsigned numtemps) - : Expr(CXXExprWithTemporariesClass, subexpr->getType(), - subexpr->isTypeDependent(), subexpr->isValueDependent()), +ExprWithCleanups::ExprWithCleanups(ASTContext &C, + Expr *subexpr, + CXXTemporary **temps, + unsigned numtemps) + : Expr(ExprWithCleanupsClass, subexpr->getType(), + subexpr->getValueKind(), subexpr->getObjectKind(), + subexpr->isTypeDependent(), subexpr->isValueDependent(), + subexpr->containsUnexpandedParameterPack()), SubExpr(subexpr), Temps(0), NumTemps(0) { if (numtemps) { setNumTemporaries(C, numtemps); @@ -749,75 +627,53 @@ CXXExprWithTemporaries::CXXExprWithTemporaries(ASTContext &C, } } -void CXXExprWithTemporaries::setNumTemporaries(ASTContext &C, unsigned N) { +void ExprWithCleanups::setNumTemporaries(ASTContext &C, unsigned N) { assert(Temps == 0 && "Cannot resize with this"); NumTemps = N; Temps = new (C) CXXTemporary*[NumTemps]; } -CXXExprWithTemporaries *CXXExprWithTemporaries::Create(ASTContext &C, - Expr *SubExpr, - CXXTemporary **Temps, - unsigned NumTemps) { - return new (C) CXXExprWithTemporaries(C, SubExpr, Temps, NumTemps); +ExprWithCleanups *ExprWithCleanups::Create(ASTContext &C, + Expr *SubExpr, + CXXTemporary **Temps, + unsigned NumTemps) { + return new (C) ExprWithCleanups(C, SubExpr, Temps, NumTemps); } -// CXXBindTemporaryExpr -Stmt::child_iterator CXXBindTemporaryExpr::child_begin() { - return &SubExpr; -} - -Stmt::child_iterator CXXBindTemporaryExpr::child_end() { - return &SubExpr + 1; -} - -// CXXConstructExpr -Stmt::child_iterator CXXConstructExpr::child_begin() { - return &Args[0]; -} -Stmt::child_iterator CXXConstructExpr::child_end() { - return &Args[0]+NumArgs; -} - -// CXXExprWithTemporaries -Stmt::child_iterator CXXExprWithTemporaries::child_begin() { - return &SubExpr; -} - -Stmt::child_iterator CXXExprWithTemporaries::child_end() { - return &SubExpr + 1; -} - -CXXUnresolvedConstructExpr::CXXUnresolvedConstructExpr( - SourceLocation TyBeginLoc, - QualType T, +CXXUnresolvedConstructExpr::CXXUnresolvedConstructExpr(TypeSourceInfo *Type, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, SourceLocation RParenLoc) - : Expr(CXXUnresolvedConstructExprClass, T.getNonReferenceType(), - T->isDependentType(), true), - TyBeginLoc(TyBeginLoc), - Type(T), + : Expr(CXXUnresolvedConstructExprClass, + Type->getType().getNonReferenceType(), + VK_LValue, OK_Ordinary, + Type->getType()->isDependentType(), true, + Type->getType()->containsUnexpandedParameterPack()), + Type(Type), LParenLoc(LParenLoc), RParenLoc(RParenLoc), NumArgs(NumArgs) { Stmt **StoredArgs = reinterpret_cast<Stmt **>(this + 1); - memcpy(StoredArgs, Args, sizeof(Expr *) * NumArgs); + for (unsigned I = 0; I != NumArgs; ++I) { + if (Args[I]->containsUnexpandedParameterPack()) + ExprBits.ContainsUnexpandedParameterPack = true; + + StoredArgs[I] = Args[I]; + } } CXXUnresolvedConstructExpr * CXXUnresolvedConstructExpr::Create(ASTContext &C, - SourceLocation TyBegin, - QualType T, + TypeSourceInfo *Type, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, SourceLocation RParenLoc) { void *Mem = C.Allocate(sizeof(CXXUnresolvedConstructExpr) + sizeof(Expr *) * NumArgs); - return new (Mem) CXXUnresolvedConstructExpr(TyBegin, T, LParenLoc, + return new (Mem) CXXUnresolvedConstructExpr(Type, LParenLoc, Args, NumArgs, RParenLoc); } @@ -829,12 +685,8 @@ CXXUnresolvedConstructExpr::CreateEmpty(ASTContext &C, unsigned NumArgs) { return new (Mem) CXXUnresolvedConstructExpr(Empty, NumArgs); } -Stmt::child_iterator CXXUnresolvedConstructExpr::child_begin() { - return child_iterator(reinterpret_cast<Stmt **>(this + 1)); -} - -Stmt::child_iterator CXXUnresolvedConstructExpr::child_end() { - return child_iterator(reinterpret_cast<Stmt **>(this + 1) + NumArgs); +SourceRange CXXUnresolvedConstructExpr::getSourceRange() const { + return SourceRange(Type->getTypeLoc().getBeginLoc(), RParenLoc); } CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C, @@ -846,17 +698,46 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C, NamedDecl *FirstQualifierFoundInScope, DeclarationNameInfo MemberNameInfo, const TemplateArgumentListInfo *TemplateArgs) - : Expr(CXXDependentScopeMemberExprClass, C.DependentTy, true, true), + : Expr(CXXDependentScopeMemberExprClass, C.DependentTy, + VK_LValue, OK_Ordinary, true, true, + ((Base && Base->containsUnexpandedParameterPack()) || + (Qualifier && Qualifier->containsUnexpandedParameterPack()) || + MemberNameInfo.containsUnexpandedParameterPack())), Base(Base), BaseType(BaseType), IsArrow(IsArrow), HasExplicitTemplateArgs(TemplateArgs != 0), OperatorLoc(OperatorLoc), Qualifier(Qualifier), QualifierRange(QualifierRange), FirstQualifierFoundInScope(FirstQualifierFoundInScope), MemberNameInfo(MemberNameInfo) { - if (TemplateArgs) - getExplicitTemplateArgs().initializeFrom(*TemplateArgs); + if (TemplateArgs) { + bool Dependent = true; + bool ContainsUnexpandedParameterPack = false; + getExplicitTemplateArgs().initializeFrom(*TemplateArgs, Dependent, + ContainsUnexpandedParameterPack); + if (ContainsUnexpandedParameterPack) + ExprBits.ContainsUnexpandedParameterPack = true; + } } +CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C, + Expr *Base, QualType BaseType, + bool IsArrow, + SourceLocation OperatorLoc, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + NamedDecl *FirstQualifierFoundInScope, + DeclarationNameInfo MemberNameInfo) + : Expr(CXXDependentScopeMemberExprClass, C.DependentTy, + VK_LValue, OK_Ordinary, true, true, + ((Base && Base->containsUnexpandedParameterPack()) || + (Qualifier && Qualifier->containsUnexpandedParameterPack()) || + MemberNameInfo.containsUnexpandedParameterPack())), + Base(Base), BaseType(BaseType), IsArrow(IsArrow), + HasExplicitTemplateArgs(false), OperatorLoc(OperatorLoc), + Qualifier(Qualifier), QualifierRange(QualifierRange), + FirstQualifierFoundInScope(FirstQualifierFoundInScope), + MemberNameInfo(MemberNameInfo) { } + CXXDependentScopeMemberExpr * CXXDependentScopeMemberExpr::Create(ASTContext &C, Expr *Base, QualType BaseType, bool IsArrow, @@ -877,7 +758,7 @@ CXXDependentScopeMemberExpr::Create(ASTContext &C, if (TemplateArgs) size += ExplicitTemplateArgumentList::sizeFor(*TemplateArgs); - void *Mem = C.Allocate(size, llvm::alignof<CXXDependentScopeMemberExpr>()); + void *Mem = C.Allocate(size, llvm::alignOf<CXXDependentScopeMemberExpr>()); return new (Mem) CXXDependentScopeMemberExpr(C, Base, BaseType, IsArrow, OperatorLoc, Qualifier, QualifierRange, @@ -887,8 +768,9 @@ CXXDependentScopeMemberExpr::Create(ASTContext &C, CXXDependentScopeMemberExpr * CXXDependentScopeMemberExpr::CreateEmpty(ASTContext &C, + bool HasExplicitTemplateArgs, unsigned NumTemplateArgs) { - if (NumTemplateArgs == 0) + if (!HasExplicitTemplateArgs) return new (C) CXXDependentScopeMemberExpr(C, 0, QualType(), 0, SourceLocation(), 0, SourceRange(), 0, @@ -896,7 +778,7 @@ CXXDependentScopeMemberExpr::CreateEmpty(ASTContext &C, std::size_t size = sizeof(CXXDependentScopeMemberExpr) + ExplicitTemplateArgumentList::sizeFor(NumTemplateArgs); - void *Mem = C.Allocate(size, llvm::alignof<CXXDependentScopeMemberExpr>()); + void *Mem = C.Allocate(size, llvm::alignOf<CXXDependentScopeMemberExpr>()); CXXDependentScopeMemberExpr *E = new (Mem) CXXDependentScopeMemberExpr(C, 0, QualType(), 0, SourceLocation(), 0, @@ -906,18 +788,7 @@ CXXDependentScopeMemberExpr::CreateEmpty(ASTContext &C, return E; } -Stmt::child_iterator CXXDependentScopeMemberExpr::child_begin() { - return child_iterator(&Base); -} - -Stmt::child_iterator CXXDependentScopeMemberExpr::child_end() { - if (isImplicitAccess()) - return child_iterator(&Base); - return child_iterator(&Base + 1); -} - -UnresolvedMemberExpr::UnresolvedMemberExpr(ASTContext &C, QualType T, - bool Dependent, +UnresolvedMemberExpr::UnresolvedMemberExpr(ASTContext &C, bool HasUnresolvedUsing, Expr *Base, QualType BaseType, bool IsArrow, @@ -928,17 +799,21 @@ UnresolvedMemberExpr::UnresolvedMemberExpr(ASTContext &C, QualType T, const TemplateArgumentListInfo *TemplateArgs, UnresolvedSetIterator Begin, UnresolvedSetIterator End) - : OverloadExpr(UnresolvedMemberExprClass, C, T, Dependent, + : OverloadExpr(UnresolvedMemberExprClass, C, Qualifier, QualifierRange, MemberNameInfo, - TemplateArgs != 0, Begin, End), + TemplateArgs, Begin, End, + // Dependent + ((Base && Base->isTypeDependent()) || + BaseType->isDependentType()), + // Contains unexpanded parameter pack + ((Base && Base->containsUnexpandedParameterPack()) || + BaseType->containsUnexpandedParameterPack())), IsArrow(IsArrow), HasUnresolvedUsing(HasUnresolvedUsing), Base(Base), BaseType(BaseType), OperatorLoc(OperatorLoc) { - if (TemplateArgs) - getExplicitTemplateArgs().initializeFrom(*TemplateArgs); } UnresolvedMemberExpr * -UnresolvedMemberExpr::Create(ASTContext &C, bool Dependent, +UnresolvedMemberExpr::Create(ASTContext &C, bool HasUnresolvedUsing, Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, @@ -952,23 +827,23 @@ UnresolvedMemberExpr::Create(ASTContext &C, bool Dependent, if (TemplateArgs) size += ExplicitTemplateArgumentList::sizeFor(*TemplateArgs); - void *Mem = C.Allocate(size, llvm::alignof<UnresolvedMemberExpr>()); + void *Mem = C.Allocate(size, llvm::alignOf<UnresolvedMemberExpr>()); return new (Mem) UnresolvedMemberExpr(C, - Dependent ? C.DependentTy : C.OverloadTy, - Dependent, HasUnresolvedUsing, Base, BaseType, + HasUnresolvedUsing, Base, BaseType, IsArrow, OperatorLoc, Qualifier, QualifierRange, MemberNameInfo, TemplateArgs, Begin, End); } UnresolvedMemberExpr * -UnresolvedMemberExpr::CreateEmpty(ASTContext &C, unsigned NumTemplateArgs) { +UnresolvedMemberExpr::CreateEmpty(ASTContext &C, bool HasExplicitTemplateArgs, + unsigned NumTemplateArgs) { std::size_t size = sizeof(UnresolvedMemberExpr); - if (NumTemplateArgs != 0) + if (HasExplicitTemplateArgs) size += ExplicitTemplateArgumentList::sizeFor(NumTemplateArgs); - void *Mem = C.Allocate(size, llvm::alignof<UnresolvedMemberExpr>()); + void *Mem = C.Allocate(size, llvm::alignOf<UnresolvedMemberExpr>()); UnresolvedMemberExpr *E = new (Mem) UnresolvedMemberExpr(EmptyShell()); - E->HasExplicitTemplateArgs = NumTemplateArgs != 0; + E->HasExplicitTemplateArgs = HasExplicitTemplateArgs; return E; } @@ -980,7 +855,7 @@ CXXRecordDecl *UnresolvedMemberExpr::getNamingClass() const { // lookup. CXXRecordDecl *Record = 0; if (getQualifier()) { - Type *T = getQualifier()->getAsType(); + const Type *T = getQualifier()->getAsType(); assert(T && "qualifier in member expression does not name type"); Record = T->getAsCXXRecordDecl(); assert(Record && "qualifier in member expression does not name record"); @@ -1001,12 +876,18 @@ CXXRecordDecl *UnresolvedMemberExpr::getNamingClass() const { return Record; } -Stmt::child_iterator UnresolvedMemberExpr::child_begin() { - return child_iterator(&Base); -} +SubstNonTypeTemplateParmPackExpr:: +SubstNonTypeTemplateParmPackExpr(QualType T, + NonTypeTemplateParmDecl *Param, + SourceLocation NameLoc, + const TemplateArgument &ArgPack) + : Expr(SubstNonTypeTemplateParmPackExprClass, T, VK_RValue, OK_Ordinary, + true, false, true), + Param(Param), Arguments(ArgPack.pack_begin()), + NumArguments(ArgPack.pack_size()), NameLoc(NameLoc) { } -Stmt::child_iterator UnresolvedMemberExpr::child_end() { - if (isImplicitAccess()) - return child_iterator(&Base); - return child_iterator(&Base + 1); +TemplateArgument SubstNonTypeTemplateParmPackExpr::getArgumentPack() const { + return TemplateArgument(Arguments, NumArguments); } + + diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp index d7e38eb..890898a 100644 --- a/lib/AST/ExprClassification.cpp +++ b/lib/AST/ExprClassification.cpp @@ -29,10 +29,27 @@ static Cl::Kinds ClassifyUnnamed(ASTContext &Ctx, QualType T); static Cl::Kinds ClassifyMemberExpr(ASTContext &Ctx, const MemberExpr *E); static Cl::Kinds ClassifyBinaryOp(ASTContext &Ctx, const BinaryOperator *E); static Cl::Kinds ClassifyConditional(ASTContext &Ctx, - const ConditionalOperator *E); + const Expr *trueExpr, + const Expr *falseExpr); static Cl::ModifiableType IsModifiable(ASTContext &Ctx, const Expr *E, Cl::Kinds Kind, SourceLocation &Loc); +static Cl::Kinds ClassifyExprValueKind(const LangOptions &Lang, + const Expr *E, + ExprValueKind Kind) { + switch (Kind) { + case VK_RValue: + return Lang.CPlusPlus && E->getType()->isRecordType() ? + Cl::CL_ClassTemporary : Cl::CL_PRValue; + case VK_LValue: + return Cl::CL_LValue; + case VK_XValue: + return Cl::CL_XValue; + } + llvm_unreachable("Invalid value category of implicit cast."); + return Cl::CL_PRValue; +} + Cl Expr::ClassifyImpl(ASTContext &Ctx, SourceLocation *Loc) const { assert(!TR->isReferenceType() && "Expressions can't have reference type."); @@ -48,6 +65,19 @@ Cl Expr::ClassifyImpl(ASTContext &Ctx, SourceLocation *Loc) const { kind = Cl::CL_Void; } + // Enable this assertion for testing. + switch (kind) { + case Cl::CL_LValue: assert(getValueKind() == VK_LValue); break; + case Cl::CL_XValue: assert(getValueKind() == VK_XValue); break; + case Cl::CL_Function: + case Cl::CL_Void: + case Cl::CL_DuplicateVectorComponents: + case Cl::CL_MemberFunction: + case Cl::CL_SubObjCPropertySetting: + case Cl::CL_ClassTemporary: + case Cl::CL_PRValue: assert(getValueKind() == VK_RValue); break; + } + Cl::ModifiableType modifiable = Cl::CM_Untested; if (Loc) modifiable = IsModifiable(Ctx, this, kind, *Loc); @@ -60,7 +90,13 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { switch (E->getStmtClass()) { // First come the expressions that are always lvalues, unconditionally. - + case Stmt::NoStmtClass: +#define ABSTRACT_STMT(Kind) +#define STMT(Kind, Base) case Expr::Kind##Class: +#define EXPR(Kind, Base) +#include "clang/AST/StmtNodes.inc" + llvm_unreachable("cannot classify a statement"); + break; case Expr::ObjCIsaExprClass: // C++ [expr.prim.general]p1: A string literal is an lvalue. case Expr::StringLiteralClass: @@ -70,20 +106,56 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::PredefinedExprClass: // Property references are lvalues case Expr::ObjCPropertyRefExprClass: - case Expr::ObjCImplicitSetterGetterRefExprClass: // C++ [expr.typeid]p1: The result of a typeid expression is an lvalue of... case Expr::CXXTypeidExprClass: // Unresolved lookups get classified as lvalues. // FIXME: Is this wise? Should they get their own kind? case Expr::UnresolvedLookupExprClass: case Expr::UnresolvedMemberExprClass: + case Expr::CXXDependentScopeMemberExprClass: + case Expr::CXXUnresolvedConstructExprClass: + case Expr::DependentScopeDeclRefExprClass: // ObjC instance variables are lvalues // FIXME: ObjC++0x might have different rules case Expr::ObjCIvarRefExprClass: + return Cl::CL_LValue; // C99 6.5.2.5p5 says that compound literals are lvalues. - // FIXME: C++ might have a different opinion. + // In C++, they're class temporaries. case Expr::CompoundLiteralExprClass: - return Cl::CL_LValue; + return Ctx.getLangOptions().CPlusPlus? Cl::CL_ClassTemporary + : Cl::CL_LValue; + + // Expressions that are prvalues. + case Expr::CXXBoolLiteralExprClass: + case Expr::CXXPseudoDestructorExprClass: + case Expr::SizeOfAlignOfExprClass: + case Expr::CXXNewExprClass: + case Expr::CXXThisExprClass: + case Expr::CXXNullPtrLiteralExprClass: + case Expr::ImaginaryLiteralClass: + case Expr::GNUNullExprClass: + case Expr::OffsetOfExprClass: + case Expr::CXXThrowExprClass: + case Expr::ShuffleVectorExprClass: + case Expr::IntegerLiteralClass: + case Expr::CharacterLiteralClass: + case Expr::AddrLabelExprClass: + case Expr::CXXDeleteExprClass: + case Expr::ImplicitValueInitExprClass: + case Expr::BlockExprClass: + case Expr::FloatingLiteralClass: + case Expr::CXXNoexceptExprClass: + case Expr::CXXScalarValueInitExprClass: + case Expr::UnaryTypeTraitExprClass: + case Expr::BinaryTypeTraitExprClass: + case Expr::ObjCSelectorExprClass: + case Expr::ObjCProtocolExprClass: + case Expr::ObjCStringLiteralClass: + case Expr::ParenListExprClass: + case Expr::InitListExprClass: + case Expr::SizeOfPackExprClass: + case Expr::SubstNonTypeTemplateParmPackExprClass: + return Cl::CL_PRValue; // Next come the complicated cases. @@ -115,11 +187,22 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { return Cl::CL_LValue; // GNU extensions, simply look through them. - case UO_Real: - case UO_Imag: case UO_Extension: return ClassifyInternal(Ctx, cast<UnaryOperator>(E)->getSubExpr()); + // Treat _Real and _Imag basically as if they were member + // expressions: l-value only if the operand is a true l-value. + case UO_Real: + case UO_Imag: { + const Expr *Op = cast<UnaryOperator>(E)->getSubExpr()->IgnoreParens(); + Cl::Kinds K = ClassifyInternal(Ctx, Op); + if (K != Cl::CL_LValue) return K; + + if (isa<ObjCPropertyRefExpr>(Op)) + return Cl::CL_SubObjCPropertySetting; + return Cl::CL_LValue; + } + // C++ [expr.pre.incr]p1: The result is the updated operand; it is an // lvalue, [...] // Not so in C. @@ -131,19 +214,15 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { return Cl::CL_PRValue; } + case Expr::OpaqueValueExprClass: + return ClassifyExprValueKind(Lang, E, + cast<OpaqueValueExpr>(E)->getValueKind()); + // Implicit casts are lvalues if they're lvalue casts. Other than that, we // only specifically record class temporaries. case Expr::ImplicitCastExprClass: - switch (cast<ImplicitCastExpr>(E)->getValueKind()) { - case VK_RValue: - return Lang.CPlusPlus && E->getType()->isRecordType() ? - Cl::CL_ClassTemporary : Cl::CL_PRValue; - case VK_LValue: - return Cl::CL_LValue; - case VK_XValue: - return Cl::CL_XValue; - } - llvm_unreachable("Invalid value category of implicit cast."); + return ClassifyExprValueKind(Lang, E, + cast<ImplicitCastExpr>(E)->getValueKind()); // C++ [expr.prim.general]p4: The presence of parentheses does not affect // whether the expression is an lvalue. @@ -160,6 +239,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::CallExprClass: case Expr::CXXOperatorCallExprClass: case Expr::CXXMemberCallExprClass: + case Expr::CUDAKernelCallExprClass: return ClassifyUnnamed(Ctx, cast<CallExpr>(E)->getCallReturnType()); // __builtin_choose_expr is equivalent to the chosen expression. @@ -180,9 +260,9 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::CXXBindTemporaryExprClass: return ClassifyInternal(Ctx, cast<CXXBindTemporaryExpr>(E)->getSubExpr()); - // And the temporary lifetime guard. - case Expr::CXXExprWithTemporariesClass: - return ClassifyInternal(Ctx, cast<CXXExprWithTemporaries>(E)->getSubExpr()); + // And the cleanups guard. + case Expr::ExprWithCleanupsClass: + return ClassifyInternal(Ctx, cast<ExprWithCleanups>(E)->getSubExpr()); // Casts depend completely on the target type. All casts work the same. case Expr::CStyleCastExprClass: @@ -195,10 +275,18 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { if (!Lang.CPlusPlus) return Cl::CL_PRValue; return ClassifyUnnamed(Ctx, cast<ExplicitCastExpr>(E)->getTypeAsWritten()); - case Expr::ConditionalOperatorClass: + case Expr::BinaryConditionalOperatorClass: { + if (!Lang.CPlusPlus) return Cl::CL_PRValue; + const BinaryConditionalOperator *co = cast<BinaryConditionalOperator>(E); + return ClassifyConditional(Ctx, co->getTrueExpr(), co->getFalseExpr()); + } + + case Expr::ConditionalOperatorClass: { // Once again, only C++ is interesting. if (!Lang.CPlusPlus) return Cl::CL_PRValue; - return ClassifyConditional(Ctx, cast<ConditionalOperator>(E)); + const ConditionalOperator *co = cast<ConditionalOperator>(E); + return ClassifyConditional(Ctx, co->getTrueExpr(), co->getFalseExpr()); + } // ObjC message sends are effectively function calls, if the target function // is known. @@ -207,17 +295,35 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { cast<ObjCMessageExpr>(E)->getMethodDecl()) { return ClassifyUnnamed(Ctx, Method->getResultType()); } - + return Cl::CL_PRValue; + // Some C++ expressions are always class temporaries. case Expr::CXXConstructExprClass: case Expr::CXXTemporaryObjectExprClass: - case Expr::CXXScalarValueInitExprClass: return Cl::CL_ClassTemporary; - // Everything we haven't handled is a prvalue. - default: + case Expr::VAArgExprClass: + return ClassifyUnnamed(Ctx, E->getType()); + + case Expr::DesignatedInitExprClass: + return ClassifyInternal(Ctx, cast<DesignatedInitExpr>(E)->getInit()); + + case Expr::StmtExprClass: { + const CompoundStmt *S = cast<StmtExpr>(E)->getSubStmt(); + if (const Expr *LastExpr = dyn_cast_or_null<Expr>(S->body_back())) + return ClassifyUnnamed(Ctx, LastExpr->getType()); return Cl::CL_PRValue; } + + case Expr::CXXUuidofExprClass: + return Cl::CL_LValue; + + case Expr::PackExpansionExprClass: + return ClassifyInternal(Ctx, cast<PackExpansionExpr>(E)->getPattern()); + } + + llvm_unreachable("unhandled expression kind in classification"); + return Cl::CL_LValue; } /// ClassifyDecl - Return the classification of an expression referencing the @@ -239,6 +345,7 @@ static Cl::Kinds ClassifyDecl(ASTContext &Ctx, const Decl *D) { islvalue = NTTParm->getType()->isReferenceType(); else islvalue = isa<VarDecl>(D) || isa<FieldDecl>(D) || + isa<IndirectFieldDecl>(D) || (Ctx.getLangOptions().CPlusPlus && (isa<FunctionDecl>(D) || isa<FunctionTemplateDecl>(D))); @@ -274,9 +381,8 @@ static Cl::Kinds ClassifyMemberExpr(ASTContext &Ctx, const MemberExpr *E) { if (E->isArrow()) return Cl::CL_LValue; // ObjC property accesses are not lvalues, but get special treatment. - Expr *Base = E->getBase(); - if (isa<ObjCPropertyRefExpr>(Base) || - isa<ObjCImplicitSetterGetterRefExpr>(Base)) + Expr *Base = E->getBase()->IgnoreParens(); + if (isa<ObjCPropertyRefExpr>(Base)) return Cl::CL_SubObjCPropertySetting; return ClassifyInternal(Ctx, Base); } @@ -301,6 +407,9 @@ static Cl::Kinds ClassifyMemberExpr(ASTContext &Ctx, const MemberExpr *E) { // *E1 is an lvalue if (E->isArrow()) return Cl::CL_LValue; + Expr *Base = E->getBase()->IgnoreParenImpCasts(); + if (isa<ObjCPropertyRefExpr>(Base)) + return Cl::CL_SubObjCPropertySetting; return ClassifyInternal(Ctx, E->getBase()); } @@ -320,8 +429,10 @@ static Cl::Kinds ClassifyBinaryOp(ASTContext &Ctx, const BinaryOperator *E) { assert(Ctx.getLangOptions().CPlusPlus && "This is only relevant for C++."); // C++ [expr.ass]p1: All [...] return an lvalue referring to the left operand. + // Except we override this for writes to ObjC properties. if (E->isAssignmentOp()) - return Cl::CL_LValue; + return (E->getLHS()->getObjectKind() == OK_ObjCProperty + ? Cl::CL_PRValue : Cl::CL_LValue); // C++ [expr.comma]p1: the result is of the same value category as its right // operand, [...]. @@ -345,13 +456,11 @@ static Cl::Kinds ClassifyBinaryOp(ASTContext &Ctx, const BinaryOperator *E) { return Cl::CL_PRValue; } -static Cl::Kinds ClassifyConditional(ASTContext &Ctx, - const ConditionalOperator *E) { +static Cl::Kinds ClassifyConditional(ASTContext &Ctx, const Expr *True, + const Expr *False) { assert(Ctx.getLangOptions().CPlusPlus && "This is only relevant for C++."); - Expr *True = E->getTrueExpr(); - Expr *False = E->getFalseExpr(); // C++ [expr.cond]p2 // If either the second or the third operand has type (cv) void, [...] // the result [...] is a prvalue. @@ -375,9 +484,10 @@ static Cl::ModifiableType IsModifiable(ASTContext &Ctx, const Expr *E, if (Kind == Cl::CL_PRValue) { // For the sake of better diagnostics, we want to specifically recognize // use of the GCC cast-as-lvalue extension. - if (const CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(E->IgnoreParens())){ - if (CE->getSubExpr()->Classify(Ctx).isLValue()) { - Loc = CE->getLParenLoc(); + if (const ExplicitCastExpr *CE = + dyn_cast<ExplicitCastExpr>(E->IgnoreParens())) { + if (CE->getSubExpr()->IgnoreParenImpCasts()->isLValue()) { + Loc = CE->getExprLoc(); return Cl::CM_LValueCast; } } @@ -401,9 +511,8 @@ static Cl::ModifiableType IsModifiable(ASTContext &Ctx, const Expr *E, // Assignment to a property in ObjC is an implicit setter access. But a // setter might not exist. - if (const ObjCImplicitSetterGetterRefExpr *Expr = - dyn_cast<ObjCImplicitSetterGetterRefExpr>(E)) { - if (Expr->getSetterMethod() == 0) + if (const ObjCPropertyRefExpr *Expr = dyn_cast<ObjCPropertyRefExpr>(E)) { + if (Expr->isImplicitProperty() && Expr->getImplicitPropertySetter() == 0) return Cl::CM_NoSetterProperty; } @@ -420,7 +529,8 @@ static Cl::ModifiableType IsModifiable(ASTContext &Ctx, const Expr *E, // Records with any const fields (recursively) are not modifiable. if (const RecordType *R = CT->getAs<RecordType>()) { - assert(!Ctx.getLangOptions().CPlusPlus && + assert((E->getObjectKind() == OK_ObjCProperty || + !Ctx.getLangOptions().CPlusPlus) && "C++ struct assignment should be resolved by the " "copy assignment operator."); if (R->hasConstFields()) @@ -430,7 +540,7 @@ static Cl::ModifiableType IsModifiable(ASTContext &Ctx, const Expr *E, return Cl::CM_Modifiable; } -Expr::isLvalueResult Expr::isLvalue(ASTContext &Ctx) const { +Expr::LValueClassification Expr::ClassifyLValue(ASTContext &Ctx) const { Classification VC = Classify(Ctx); switch (VC.getKind()) { case Cl::CL_LValue: return LV_Valid; diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 7347f5a..656bb99 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -43,12 +43,20 @@ using llvm::APFloat; /// evaluate the expression regardless of what the RHS is, but C only allows /// certain things in certain situations. struct EvalInfo { - ASTContext &Ctx; + const ASTContext &Ctx; /// EvalResult - Contains information about the evaluation. Expr::EvalResult &EvalResult; - EvalInfo(ASTContext &ctx, Expr::EvalResult& evalresult) + llvm::DenseMap<const OpaqueValueExpr*, APValue> OpaqueValues; + const APValue *getOpaqueValue(const OpaqueValueExpr *e) { + llvm::DenseMap<const OpaqueValueExpr*, APValue>::iterator + i = OpaqueValues.find(e); + if (i == OpaqueValues.end()) return 0; + return &i->second; + } + + EvalInfo(const ASTContext &ctx, Expr::EvalResult& evalresult) : Ctx(ctx), EvalResult(evalresult) {} }; @@ -73,12 +81,24 @@ namespace { APSInt &getComplexIntReal() { return IntReal; } APSInt &getComplexIntImag() { return IntImag; } - void moveInto(APValue &v) { + void moveInto(APValue &v) const { if (isComplexFloat()) v = APValue(FloatReal, FloatImag); else v = APValue(IntReal, IntImag); } + void setFrom(const APValue &v) { + assert(v.isComplexFloat() || v.isComplexInt()); + if (v.isComplexFloat()) { + makeComplexFloat(); + FloatReal = v.getComplexFloatReal(); + FloatImag = v.getComplexFloatImag(); + } else { + makeComplexInt(); + IntReal = v.getComplexIntReal(); + IntImag = v.getComplexIntImag(); + } + } }; struct LValue { @@ -88,12 +108,18 @@ namespace { Expr *getLValueBase() { return Base; } CharUnits getLValueOffset() { return Offset; } - void moveInto(APValue &v) { + void moveInto(APValue &v) const { v = APValue(Base, Offset); } + void setFrom(const APValue &v) { + assert(v.isLValue()); + Base = v.getLValueBase(); + Offset = v.getLValueOffset(); + } }; } +static bool Evaluate(EvalInfo &info, const Expr *E); static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info); static bool EvaluatePointer(const Expr *E, LValue &Result, EvalInfo &Info); static bool EvaluateInteger(const Expr *E, APSInt &Result, EvalInfo &Info); @@ -192,7 +218,7 @@ static bool HandleConversionToBool(const Expr* E, bool& Result, } static APSInt HandleFloatToIntCast(QualType DestType, QualType SrcType, - APFloat &Value, ASTContext &Ctx) { + APFloat &Value, const ASTContext &Ctx) { unsigned DestWidth = Ctx.getIntWidth(DestType); // Determine whether we are converting to unsigned or signed. bool DestSigned = DestType->isSignedIntegerType(); @@ -206,7 +232,7 @@ static APSInt HandleFloatToIntCast(QualType DestType, QualType SrcType, } static APFloat HandleFloatToFloatCast(QualType DestType, QualType SrcType, - APFloat &Value, ASTContext &Ctx) { + APFloat &Value, const ASTContext &Ctx) { bool ignored; APFloat Result = Value; Result.convert(Ctx.getFloatTypeSemantics(DestType), @@ -215,18 +241,18 @@ static APFloat HandleFloatToFloatCast(QualType DestType, QualType SrcType, } static APSInt HandleIntToIntCast(QualType DestType, QualType SrcType, - APSInt &Value, ASTContext &Ctx) { + APSInt &Value, const ASTContext &Ctx) { unsigned DestWidth = Ctx.getIntWidth(DestType); APSInt Result = Value; // Figure out if this is a truncate, extend or noop cast. // If the input is signed, do a sign extend, noop, or truncate. - Result.extOrTrunc(DestWidth); + Result = Result.extOrTrunc(DestWidth); Result.setIsUnsigned(DestType->isUnsignedIntegerType()); return Result; } static APFloat HandleIntToFloatCast(QualType DestType, QualType SrcType, - APSInt &Value, ASTContext &Ctx) { + APSInt &Value, const ASTContext &Ctx) { APFloat Result(Ctx.getFloatTypeSemantics(DestType), 1); Result.convertFromAPInt(Value, Value.isSigned(), @@ -291,8 +317,34 @@ public: if (Visit(E->getInit(i))) return true; return false; } + + bool VisitSizeOfPackExpr(SizeOfPackExpr *) { return false; } }; +class OpaqueValueEvaluation { + EvalInfo &info; + OpaqueValueExpr *opaqueValue; + +public: + OpaqueValueEvaluation(EvalInfo &info, OpaqueValueExpr *opaqueValue, + Expr *value) + : info(info), opaqueValue(opaqueValue) { + + // If evaluation fails, fail immediately. + if (!Evaluate(info, value)) { + this->opaqueValue = 0; + return; + } + info.OpaqueValues[opaqueValue] = info.EvalResult.Val; + } + + bool hasError() const { return opaqueValue == 0; } + + ~OpaqueValueEvaluation() { + if (opaqueValue) info.OpaqueValues.erase(opaqueValue); + } +}; + } // end anonymous namespace //===----------------------------------------------------------------------===// @@ -402,7 +454,7 @@ bool LValueExprEvaluator::VisitMemberExpr(MemberExpr *E) { break; } - Result.Offset += CharUnits::fromQuantity(RL.getFieldOffset(i) / 8); + Result.Offset += Info.Ctx.toCharUnitsFromBits(RL.getFieldOffset(i)); return true; } @@ -460,17 +512,20 @@ public: { return Success(E); } bool VisitCallExpr(CallExpr *E); bool VisitBlockExpr(BlockExpr *E) { - if (!E->hasBlockDeclRefExprs()) + if (!E->getBlockDecl()->hasCaptures()) return Success(E); return false; } bool VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) { return Success((Expr*)0); } + bool VisitBinaryConditionalOperator(BinaryConditionalOperator *E); bool VisitConditionalOperator(ConditionalOperator *E); bool VisitChooseExpr(ChooseExpr *E) { return Visit(E->getChosenSubExpr(Info.Ctx)); } bool VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E) { return Success((Expr*)0); } + + bool VisitOpaqueValueExpr(OpaqueValueExpr *E); // FIXME: Missing: @protocol, @selector }; } // end anonymous namespace @@ -532,35 +587,6 @@ bool PointerExprEvaluator::VisitCastExpr(CastExpr* E) { default: break; - case CK_Unknown: { - // FIXME: The handling for CK_Unknown is ugly/shouldn't be necessary! - - // Check for pointer->pointer cast - if (SubExpr->getType()->isPointerType() || - SubExpr->getType()->isObjCObjectPointerType() || - SubExpr->getType()->isNullPtrType() || - SubExpr->getType()->isBlockPointerType()) - return Visit(SubExpr); - - if (SubExpr->getType()->isIntegralOrEnumerationType()) { - APValue Value; - if (!EvaluateIntegerOrLValue(SubExpr, Value, Info)) - break; - - if (Value.isInt()) { - Value.getInt().extOrTrunc((unsigned)Info.Ctx.getTypeSize(E->getType())); - Result.Base = 0; - Result.Offset = CharUnits::fromQuantity(Value.getInt().getZExtValue()); - return true; - } else { - Result.Base = Value.getLValueBase(); - Result.Offset = Value.getLValueOffset(); - return true; - } - } - break; - } - case CK_NoOp: case CK_BitCast: case CK_LValueBitCast: @@ -568,13 +594,54 @@ bool PointerExprEvaluator::VisitCastExpr(CastExpr* E) { case CK_AnyPointerToBlockPointerCast: return Visit(SubExpr); + case CK_DerivedToBase: + case CK_UncheckedDerivedToBase: { + LValue BaseLV; + if (!EvaluatePointer(E->getSubExpr(), BaseLV, Info)) + return false; + + // Now figure out the necessary offset to add to the baseLV to get from + // the derived class to the base class. + CharUnits Offset = CharUnits::Zero(); + + QualType Ty = E->getSubExpr()->getType(); + const CXXRecordDecl *DerivedDecl = + Ty->getAs<PointerType>()->getPointeeType()->getAsCXXRecordDecl(); + + for (CastExpr::path_const_iterator PathI = E->path_begin(), + PathE = E->path_end(); PathI != PathE; ++PathI) { + const CXXBaseSpecifier *Base = *PathI; + + // FIXME: If the base is virtual, we'd need to determine the type of the + // most derived class and we don't support that right now. + if (Base->isVirtual()) + return false; + + const CXXRecordDecl *BaseDecl = Base->getType()->getAsCXXRecordDecl(); + const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(DerivedDecl); + + Offset += Layout.getBaseClassOffset(BaseDecl); + DerivedDecl = BaseDecl; + } + + Result.Base = BaseLV.getLValueBase(); + Result.Offset = BaseLV.getLValueOffset() + Offset; + return true; + } + + case CK_NullToPointer: { + Result.Base = 0; + Result.Offset = CharUnits::Zero(); + return true; + } + case CK_IntegralToPointer: { APValue Value; if (!EvaluateIntegerOrLValue(SubExpr, Value, Info)) break; if (Value.isInt()) { - Value.getInt().extOrTrunc((unsigned)Info.Ctx.getTypeSize(E->getType())); + Value.getInt() = Value.getInt().extOrTrunc((unsigned)Info.Ctx.getTypeSize(E->getType())); Result.Base = 0; Result.Offset = CharUnits::fromQuantity(Value.getInt().getZExtValue()); return true; @@ -602,6 +669,26 @@ bool PointerExprEvaluator::VisitCallExpr(CallExpr *E) { return false; } +bool PointerExprEvaluator::VisitOpaqueValueExpr(OpaqueValueExpr *e) { + const APValue *value = Info.getOpaqueValue(e); + if (!value) + return (e->getSourceExpr() ? Visit(e->getSourceExpr()) : false); + Result.setFrom(*value); + return true; +} + +bool PointerExprEvaluator:: +VisitBinaryConditionalOperator(BinaryConditionalOperator *e) { + OpaqueValueEvaluation opaque(Info, e->getOpaqueValue(), e->getCommon()); + if (opaque.hasError()) return false; + + bool cond; + if (!HandleConversionToBool(e->getCond(), cond, Info)) + return false; + + return Visit(cond ? e->getTrueExpr() : e->getFalseExpr()); +} + bool PointerExprEvaluator::VisitConditionalOperator(ConditionalOperator *E) { bool BoolResult; if (!HandleConversionToBool(E->getCond(), BoolResult, Info)) @@ -718,8 +805,7 @@ APValue VectorExprEvaluator::VisitCastExpr(const CastExpr* E) { llvm::SmallVector<APValue, 4> Elts; for (unsigned i = 0; i != NElts; ++i) { - APSInt Tmp = Init; - Tmp.extOrTrunc(EltWidth); + APSInt Tmp = Init.extOrTrunc(EltWidth); if (EltTy->isIntegerType()) Elts.push_back(APValue(Tmp)); @@ -898,15 +984,14 @@ public: bool VisitCharacterLiteral(const CharacterLiteral *E) { return Success(E->getValue(), E); } - bool VisitTypesCompatibleExpr(const TypesCompatibleExpr *E) { - // Per gcc docs "this built-in function ignores top level - // qualifiers". We need to use the canonical version to properly - // be able to strip CRV qualifiers from the type. - QualType T0 = Info.Ctx.getCanonicalType(E->getArgType1()); - QualType T1 = Info.Ctx.getCanonicalType(E->getArgType2()); - return Success(Info.Ctx.typesAreCompatible(T0.getUnqualifiedType(), - T1.getUnqualifiedType()), - E); + + bool VisitOpaqueValueExpr(OpaqueValueExpr *e) { + const APValue *value = Info.getOpaqueValue(e); + if (!value) { + if (e->getSourceExpr()) return Visit(e->getSourceExpr()); + return Error(e->getExprLoc(), diag::note_invalid_subexpr_in_ice, e); + } + return Success(value->getInt(), e); } bool CheckReferencedDecl(const Expr *E, const Decl *D); @@ -927,6 +1012,7 @@ public: bool VisitOffsetOfExpr(const OffsetOfExpr *E); bool VisitUnaryOperator(const UnaryOperator *E); bool VisitConditionalOperator(const ConditionalOperator *E); + bool VisitBinaryConditionalOperator(const BinaryConditionalOperator *E); bool VisitCastExpr(CastExpr* E); bool VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E); @@ -948,7 +1034,11 @@ public: } bool VisitUnaryTypeTraitExpr(const UnaryTypeTraitExpr *E) { - return Success(E->EvaluateTrait(Info.Ctx), E); + return Success(E->getValue(), E); + } + + bool VisitBinaryTypeTraitExpr(const BinaryTypeTraitExpr *E) { + return Success(E->getValue(), E); } bool VisitChooseExpr(const ChooseExpr *E) { @@ -958,6 +1048,9 @@ public: bool VisitUnaryReal(const UnaryOperator *E); bool VisitUnaryImag(const UnaryOperator *E); + bool VisitCXXNoexceptExpr(const CXXNoexceptExpr *E); + bool VisitSizeOfPackExpr(const SizeOfPackExpr *E); + private: CharUnits GetAlignOfExpr(const Expr *E); CharUnits GetAlignOfType(QualType T); @@ -1018,7 +1111,6 @@ bool IntExprEvaluator::CheckReferencedDecl(const Expr* E, const Decl* D) { } VD->setEvaluatedValue(APValue()); - return false; } } } @@ -1160,6 +1252,24 @@ bool IntExprEvaluator::VisitCallExpr(CallExpr *E) { case Builtin::BI__builtin_expect: return Visit(E->getArg(0)); + + case Builtin::BIstrlen: + case Builtin::BI__builtin_strlen: + // As an extension, we support strlen() and __builtin_strlen() as constant + // expressions when the argument is a string literal. + if (StringLiteral *S + = dyn_cast<StringLiteral>(E->getArg(0)->IgnoreParenImpCasts())) { + // The string literal may have embedded null characters. Find the first + // one and truncate there. + llvm::StringRef Str = S->getString(); + llvm::StringRef::size_type Pos = Str.find(0); + if (Pos != llvm::StringRef::npos) + Str = Str.substr(0, Pos); + + return Success(Str.size(), E); + } + + return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E); } } @@ -1403,12 +1513,25 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { return Error(E->getOperatorLoc(), diag::note_expr_divide_by_zero, E); return Success(Result.getInt() % RHS, E); case BO_Shl: { - // FIXME: Warn about out of range shift amounts! - unsigned SA = - (unsigned) RHS.getLimitedValue(Result.getInt().getBitWidth()-1); + // During constant-folding, a negative shift is an opposite shift. + if (RHS.isSigned() && RHS.isNegative()) { + RHS = -RHS; + goto shift_right; + } + + shift_left: + unsigned SA + = (unsigned) RHS.getLimitedValue(Result.getInt().getBitWidth()-1); return Success(Result.getInt() << SA, E); } case BO_Shr: { + // During constant-folding, a negative shift is an opposite shift. + if (RHS.isSigned() && RHS.isNegative()) { + RHS = -RHS; + goto shift_left; + } + + shift_right: unsigned SA = (unsigned) RHS.getLimitedValue(Result.getInt().getBitWidth()-1); return Success(Result.getInt() >> SA, E); @@ -1423,6 +1546,18 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { } } +bool IntExprEvaluator:: +VisitBinaryConditionalOperator(const BinaryConditionalOperator *e) { + OpaqueValueEvaluation opaque(Info, e->getOpaqueValue(), e->getCommon()); + if (opaque.hasError()) return false; + + bool cond; + if (!HandleConversionToBool(e->getCond(), cond, Info)) + return false; + + return Visit(cond ? e->getTrueExpr() : e->getFalseExpr()); +} + bool IntExprEvaluator::VisitConditionalOperator(const ConditionalOperator *E) { bool Cond; if (!HandleConversionToBool(E->getCond(), Cond, Info)) @@ -1439,12 +1574,9 @@ CharUnits IntExprEvaluator::GetAlignOfType(QualType T) { if (const ReferenceType *Ref = T->getAs<ReferenceType>()) T = Ref->getPointeeType(); - // Get information about the alignment. - unsigned CharSize = Info.Ctx.Target.getCharWidth(); - // __alignof is defined to return the preferred alignment. - return CharUnits::fromQuantity( - Info.Ctx.getPreferredTypeAlign(T.getTypePtr()) / CharSize); + return Info.Ctx.toCharUnitsFromBits( + Info.Ctx.getPreferredTypeAlign(T.getTypePtr())); } CharUnits IntExprEvaluator::GetAlignOfExpr(const Expr *E) { @@ -1527,17 +1659,9 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *E) { return false; RecordDecl *RD = RT->getDecl(); const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD); - unsigned i = 0; - // FIXME: It would be nice if we didn't have to loop here! - for (RecordDecl::field_iterator Field = RD->field_begin(), - FieldEnd = RD->field_end(); - Field != FieldEnd; (void)++Field, ++i) { - if (*Field == MemberDecl) - break; - } + unsigned i = MemberDecl->getFieldIndex(); assert(i < RL.getFieldCount() && "offsetof field in wrong type"); - Result += CharUnits::fromQuantity( - RL.getFieldOffset(i) / Info.Ctx.getCharWidth()); + Result += Info.Ctx.toCharUnitsFromBits(RL.getFieldOffset(i)); CurrentType = MemberDecl->getType().getNonReferenceType(); break; } @@ -1565,9 +1689,7 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *E) { return false; // Add the offset to the base. - Result += CharUnits::fromQuantity( - RL.getBaseClassOffset(cast<CXXRecordDecl>(BaseRT->getDecl())) - / Info.Ctx.getCharWidth()); + Result += RL.getBaseClassOffset(cast<CXXRecordDecl>(BaseRT->getDecl())); break; } } @@ -1723,6 +1845,14 @@ bool IntExprEvaluator::VisitUnaryImag(const UnaryOperator *E) { return Success(0, E); } +bool IntExprEvaluator::VisitSizeOfPackExpr(const SizeOfPackExpr *E) { + return Success(E->getPackLength(), E); +} + +bool IntExprEvaluator::VisitCXXNoexceptExpr(const CXXNoexceptExpr *E) { + return Success(E->getValue(), E); +} + //===----------------------------------------------------------------------===// // Float Evaluation //===----------------------------------------------------------------------===// @@ -1749,6 +1879,7 @@ public: bool VisitCastExpr(CastExpr *E); bool VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E); bool VisitConditionalOperator(ConditionalOperator *E); + bool VisitBinaryConditionalOperator(BinaryConditionalOperator *E); bool VisitChooseExpr(const ChooseExpr *E) { return Visit(E->getChosenSubExpr(Info.Ctx)); } @@ -1757,6 +1888,16 @@ public: bool VisitUnaryReal(const UnaryOperator *E); bool VisitUnaryImag(const UnaryOperator *E); + bool VisitDeclRefExpr(const DeclRefExpr *E); + + bool VisitOpaqueValueExpr(const OpaqueValueExpr *e) { + const APValue *value = Info.getOpaqueValue(e); + if (!value) + return (e->getSourceExpr() ? Visit(e->getSourceExpr()) : false); + Result = value->getFloat(); + return true; + } + // FIXME: Missing: array subscript of vector, member of vector, // ImplicitValueInitExpr }; @@ -1767,7 +1908,7 @@ static bool EvaluateFloat(const Expr* E, APFloat& Result, EvalInfo &Info) { return FloatExprEvaluator(Info, Result).Visit(const_cast<Expr*>(E)); } -static bool TryEvaluateBuiltinNaN(ASTContext &Context, +static bool TryEvaluateBuiltinNaN(const ASTContext &Context, QualType ResultTy, const Expr *Arg, bool SNaN, @@ -1844,6 +1985,45 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) { } } +bool FloatExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) { + const Decl *D = E->getDecl(); + if (!isa<VarDecl>(D) || isa<ParmVarDecl>(D)) return false; + const VarDecl *VD = cast<VarDecl>(D); + + // Require the qualifiers to be const and not volatile. + CanQualType T = Info.Ctx.getCanonicalType(E->getType()); + if (!T.isConstQualified() || T.isVolatileQualified()) + return false; + + const Expr *Init = VD->getAnyInitializer(); + if (!Init) return false; + + if (APValue *V = VD->getEvaluatedValue()) { + if (V->isFloat()) { + Result = V->getFloat(); + return true; + } + return false; + } + + if (VD->isEvaluatingValue()) + return false; + + VD->setEvaluatingValue(); + + Expr::EvalResult InitResult; + if (Init->Evaluate(InitResult, Info.Ctx) && !InitResult.HasSideEffects && + InitResult.Val.isFloat()) { + // Cache the evaluated value in the variable declaration. + Result = InitResult.Val.getFloat(); + VD->setEvaluatedValue(InitResult.Val); + return true; + } + + VD->setEvaluatedValue(APValue()); + return false; +} + bool FloatExprEvaluator::VisitUnaryReal(const UnaryOperator *E) { if (E->getSubExpr()->getType()->isAnyComplexType()) { ComplexValue CV; @@ -1902,6 +2082,10 @@ bool FloatExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { return true; } + // We can't evaluate pointer-to-member operations. + if (E->isPtrMemOp()) + return false; + // FIXME: Diagnostics? I really don't understand how the warnings // and errors are supposed to work. APFloat RHS(0.0); @@ -1950,7 +2134,14 @@ bool FloatExprEvaluator::VisitCastExpr(CastExpr *E) { Result, Info.Ctx); return true; } - // FIXME: Handle complex types + + if (E->getCastKind() == CK_FloatingComplexToReal) { + ComplexValue V; + if (!EvaluateComplex(SubExpr, V, Info)) + return false; + Result = V.getComplexFloatReal(); + return true; + } return false; } @@ -1960,6 +2151,18 @@ bool FloatExprEvaluator::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E) return true; } +bool FloatExprEvaluator:: +VisitBinaryConditionalOperator(BinaryConditionalOperator *e) { + OpaqueValueEvaluation opaque(Info, e->getOpaqueValue(), e->getCommon()); + if (opaque.hasError()) return false; + + bool cond; + if (!HandleConversionToBool(e->getCond(), cond, Info)) + return false; + + return Visit(cond ? e->getTrueExpr() : e->getFalseExpr()); +} + bool FloatExprEvaluator::VisitConditionalOperator(ConditionalOperator *E) { bool Cond; if (!HandleConversionToBool(E->getCond(), Cond, Info)) @@ -1997,12 +2200,21 @@ public: bool VisitCastExpr(CastExpr *E); bool VisitBinaryOperator(const BinaryOperator *E); + bool VisitUnaryOperator(const UnaryOperator *E); + bool VisitConditionalOperator(const ConditionalOperator *E); + bool VisitBinaryConditionalOperator(const BinaryConditionalOperator *E); bool VisitChooseExpr(const ChooseExpr *E) { return Visit(E->getChosenSubExpr(Info.Ctx)); } bool VisitUnaryExtension(const UnaryOperator *E) { return Visit(E->getSubExpr()); } - // FIXME Missing: unary +/-/~, binary div, ImplicitValueInitExpr, - // conditional ?:, comma + bool VisitOpaqueValueExpr(const OpaqueValueExpr *e) { + const APValue *value = Info.getOpaqueValue(e); + if (!value) + return (e->getSourceExpr() ? Visit(e->getSourceExpr()) : false); + Result.setFrom(*value); + return true; + } + // FIXME Missing: ImplicitValueInitExpr }; } // end anonymous namespace @@ -2038,99 +2250,143 @@ bool ComplexExprEvaluator::VisitImaginaryLiteral(ImaginaryLiteral *E) { } bool ComplexExprEvaluator::VisitCastExpr(CastExpr *E) { - Expr* SubExpr = E->getSubExpr(); - QualType EltType = E->getType()->getAs<ComplexType>()->getElementType(); - QualType SubType = SubExpr->getType(); - if (SubType->isRealFloatingType()) { + switch (E->getCastKind()) { + case CK_BitCast: + case CK_LValueBitCast: + case CK_BaseToDerived: + case CK_DerivedToBase: + case CK_UncheckedDerivedToBase: + case CK_Dynamic: + case CK_ToUnion: + case CK_ArrayToPointerDecay: + case CK_FunctionToPointerDecay: + case CK_NullToPointer: + case CK_NullToMemberPointer: + case CK_BaseToDerivedMemberPointer: + case CK_DerivedToBaseMemberPointer: + case CK_MemberPointerToBoolean: + case CK_ConstructorConversion: + case CK_IntegralToPointer: + case CK_PointerToIntegral: + case CK_PointerToBoolean: + case CK_ToVoid: + case CK_VectorSplat: + case CK_IntegralCast: + case CK_IntegralToBoolean: + case CK_IntegralToFloating: + case CK_FloatingToIntegral: + case CK_FloatingToBoolean: + case CK_FloatingCast: + case CK_AnyPointerToObjCPointerCast: + case CK_AnyPointerToBlockPointerCast: + case CK_ObjCObjectLValueCast: + case CK_FloatingComplexToReal: + case CK_FloatingComplexToBoolean: + case CK_IntegralComplexToReal: + case CK_IntegralComplexToBoolean: + llvm_unreachable("invalid cast kind for complex value"); + + case CK_LValueToRValue: + case CK_NoOp: + return Visit(E->getSubExpr()); + + case CK_Dependent: + case CK_GetObjCProperty: + case CK_UserDefinedConversion: + return false; + + case CK_FloatingRealToComplex: { APFloat &Real = Result.FloatReal; - if (!EvaluateFloat(SubExpr, Real, Info)) + if (!EvaluateFloat(E->getSubExpr(), Real, Info)) return false; - if (EltType->isRealFloatingType()) { - Result.makeComplexFloat(); - Real = HandleFloatToFloatCast(EltType, SubType, Real, Info.Ctx); - Result.FloatImag = APFloat(Real.getSemantics()); - return true; - } else { - Result.makeComplexInt(); - Result.IntReal = HandleFloatToIntCast(EltType, SubType, Real, Info.Ctx); - Result.IntImag = APSInt(Result.IntReal.getBitWidth(), - !Result.IntReal.isSigned()); - return true; - } - } else if (SubType->isIntegerType()) { + Result.makeComplexFloat(); + Result.FloatImag = APFloat(Real.getSemantics()); + return true; + } + + case CK_FloatingComplexCast: { + if (!Visit(E->getSubExpr())) + return false; + + QualType To = E->getType()->getAs<ComplexType>()->getElementType(); + QualType From + = E->getSubExpr()->getType()->getAs<ComplexType>()->getElementType(); + + Result.FloatReal + = HandleFloatToFloatCast(To, From, Result.FloatReal, Info.Ctx); + Result.FloatImag + = HandleFloatToFloatCast(To, From, Result.FloatImag, Info.Ctx); + return true; + } + + case CK_FloatingComplexToIntegralComplex: { + if (!Visit(E->getSubExpr())) + return false; + + QualType To = E->getType()->getAs<ComplexType>()->getElementType(); + QualType From + = E->getSubExpr()->getType()->getAs<ComplexType>()->getElementType(); + Result.makeComplexInt(); + Result.IntReal = HandleFloatToIntCast(To, From, Result.FloatReal, Info.Ctx); + Result.IntImag = HandleFloatToIntCast(To, From, Result.FloatImag, Info.Ctx); + return true; + } + + case CK_IntegralRealToComplex: { APSInt &Real = Result.IntReal; - if (!EvaluateInteger(SubExpr, Real, Info)) + if (!EvaluateInteger(E->getSubExpr(), Real, Info)) return false; - if (EltType->isRealFloatingType()) { - Result.makeComplexFloat(); - Result.FloatReal - = HandleIntToFloatCast(EltType, SubType, Real, Info.Ctx); - Result.FloatImag = APFloat(Result.FloatReal.getSemantics()); - return true; - } else { - Result.makeComplexInt(); - Real = HandleIntToIntCast(EltType, SubType, Real, Info.Ctx); - Result.IntImag = APSInt(Real.getBitWidth(), !Real.isSigned()); - return true; - } - } else if (const ComplexType *CT = SubType->getAs<ComplexType>()) { - if (!Visit(SubExpr)) + Result.makeComplexInt(); + Result.IntImag = APSInt(Real.getBitWidth(), !Real.isSigned()); + return true; + } + + case CK_IntegralComplexCast: { + if (!Visit(E->getSubExpr())) return false; - QualType SrcType = CT->getElementType(); + QualType To = E->getType()->getAs<ComplexType>()->getElementType(); + QualType From + = E->getSubExpr()->getType()->getAs<ComplexType>()->getElementType(); - if (Result.isComplexFloat()) { - if (EltType->isRealFloatingType()) { - Result.makeComplexFloat(); - Result.FloatReal = HandleFloatToFloatCast(EltType, SrcType, - Result.FloatReal, - Info.Ctx); - Result.FloatImag = HandleFloatToFloatCast(EltType, SrcType, - Result.FloatImag, - Info.Ctx); - return true; - } else { - Result.makeComplexInt(); - Result.IntReal = HandleFloatToIntCast(EltType, SrcType, - Result.FloatReal, - Info.Ctx); - Result.IntImag = HandleFloatToIntCast(EltType, SrcType, - Result.FloatImag, - Info.Ctx); - return true; - } - } else { - assert(Result.isComplexInt() && "Invalid evaluate result."); - if (EltType->isRealFloatingType()) { - Result.makeComplexFloat(); - Result.FloatReal = HandleIntToFloatCast(EltType, SrcType, - Result.IntReal, - Info.Ctx); - Result.FloatImag = HandleIntToFloatCast(EltType, SrcType, - Result.IntImag, - Info.Ctx); - return true; - } else { - Result.makeComplexInt(); - Result.IntReal = HandleIntToIntCast(EltType, SrcType, - Result.IntReal, - Info.Ctx); - Result.IntImag = HandleIntToIntCast(EltType, SrcType, - Result.IntImag, - Info.Ctx); - return true; - } - } + Result.IntReal = HandleIntToIntCast(To, From, Result.IntReal, Info.Ctx); + Result.IntImag = HandleIntToIntCast(To, From, Result.IntImag, Info.Ctx); + return true; + } + + case CK_IntegralComplexToFloatingComplex: { + if (!Visit(E->getSubExpr())) + return false; + + QualType To = E->getType()->getAs<ComplexType>()->getElementType(); + QualType From + = E->getSubExpr()->getType()->getAs<ComplexType>()->getElementType(); + Result.makeComplexFloat(); + Result.FloatReal = HandleIntToFloatCast(To, From, Result.IntReal, Info.Ctx); + Result.FloatImag = HandleIntToFloatCast(To, From, Result.IntImag, Info.Ctx); + return true; + } } - // FIXME: Handle more casts. + llvm_unreachable("unknown cast resulting in complex value"); return false; } bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { + if (E->getOpcode() == BO_Comma) { + if (!Visit(E->getRHS())) + return false; + + // If we can't evaluate the LHS, it might have side effects; + // conservatively mark it. + if (!E->getLHS()->isEvaluatable(Info.Ctx)) + Info.EvalResult.HasSideEffects = true; + + return true; + } if (!Visit(E->getLHS())) return false; @@ -2195,29 +2451,122 @@ bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { LHS.getComplexIntImag() * RHS.getComplexIntReal()); } break; + case BO_Div: + if (Result.isComplexFloat()) { + ComplexValue LHS = Result; + APFloat &LHS_r = LHS.getComplexFloatReal(); + APFloat &LHS_i = LHS.getComplexFloatImag(); + APFloat &RHS_r = RHS.getComplexFloatReal(); + APFloat &RHS_i = RHS.getComplexFloatImag(); + APFloat &Res_r = Result.getComplexFloatReal(); + APFloat &Res_i = Result.getComplexFloatImag(); + + APFloat Den = RHS_r; + Den.multiply(RHS_r, APFloat::rmNearestTiesToEven); + APFloat Tmp = RHS_i; + Tmp.multiply(RHS_i, APFloat::rmNearestTiesToEven); + Den.add(Tmp, APFloat::rmNearestTiesToEven); + + Res_r = LHS_r; + Res_r.multiply(RHS_r, APFloat::rmNearestTiesToEven); + Tmp = LHS_i; + Tmp.multiply(RHS_i, APFloat::rmNearestTiesToEven); + Res_r.add(Tmp, APFloat::rmNearestTiesToEven); + Res_r.divide(Den, APFloat::rmNearestTiesToEven); + + Res_i = LHS_i; + Res_i.multiply(RHS_r, APFloat::rmNearestTiesToEven); + Tmp = LHS_r; + Tmp.multiply(RHS_i, APFloat::rmNearestTiesToEven); + Res_i.subtract(Tmp, APFloat::rmNearestTiesToEven); + Res_i.divide(Den, APFloat::rmNearestTiesToEven); + } else { + if (RHS.getComplexIntReal() == 0 && RHS.getComplexIntImag() == 0) { + // FIXME: what about diagnostics? + return false; + } + ComplexValue LHS = Result; + APSInt Den = RHS.getComplexIntReal() * RHS.getComplexIntReal() + + RHS.getComplexIntImag() * RHS.getComplexIntImag(); + Result.getComplexIntReal() = + (LHS.getComplexIntReal() * RHS.getComplexIntReal() + + LHS.getComplexIntImag() * RHS.getComplexIntImag()) / Den; + Result.getComplexIntImag() = + (LHS.getComplexIntImag() * RHS.getComplexIntReal() - + LHS.getComplexIntReal() * RHS.getComplexIntImag()) / Den; + } + break; } return true; } +bool ComplexExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { + // Get the operand value into 'Result'. + if (!Visit(E->getSubExpr())) + return false; + + switch (E->getOpcode()) { + default: + // FIXME: what about diagnostics? + return false; + case UO_Extension: + return true; + case UO_Plus: + // The result is always just the subexpr. + return true; + case UO_Minus: + if (Result.isComplexFloat()) { + Result.getComplexFloatReal().changeSign(); + Result.getComplexFloatImag().changeSign(); + } + else { + Result.getComplexIntReal() = -Result.getComplexIntReal(); + Result.getComplexIntImag() = -Result.getComplexIntImag(); + } + return true; + case UO_Not: + if (Result.isComplexFloat()) + Result.getComplexFloatImag().changeSign(); + else + Result.getComplexIntImag() = -Result.getComplexIntImag(); + return true; + } +} + +bool ComplexExprEvaluator:: +VisitBinaryConditionalOperator(const BinaryConditionalOperator *e) { + OpaqueValueEvaluation opaque(Info, e->getOpaqueValue(), e->getCommon()); + if (opaque.hasError()) return false; + + bool cond; + if (!HandleConversionToBool(e->getCond(), cond, Info)) + return false; + + return Visit(cond ? e->getTrueExpr() : e->getFalseExpr()); +} + +bool ComplexExprEvaluator::VisitConditionalOperator(const ConditionalOperator *E) { + bool Cond; + if (!HandleConversionToBool(E->getCond(), Cond, Info)) + return false; + + return Visit(Cond ? E->getTrueExpr() : E->getFalseExpr()); +} + //===----------------------------------------------------------------------===// // Top level Expr::Evaluate method. //===----------------------------------------------------------------------===// -/// Evaluate - Return true if this is a constant which we can fold using -/// any crazy technique (that has nothing to do with language standards) that -/// we want to. If this function returns true, it returns the folded constant -/// in Result. -bool Expr::Evaluate(EvalResult &Result, ASTContext &Ctx) const { - const Expr *E = this; - EvalInfo Info(Ctx, Result); +static bool Evaluate(EvalInfo &Info, const Expr *E) { if (E->getType()->isVectorType()) { if (!EvaluateVector(E, Info.EvalResult.Val, Info)) return false; } else if (E->getType()->isIntegerType()) { if (!IntExprEvaluator(Info, Info.EvalResult.Val).Visit(const_cast<Expr*>(E))) return false; - if (Result.Val.isLValue() && !IsGlobalLValue(Result.Val.getLValueBase())) + if (Info.EvalResult.Val.isLValue() && + !IsGlobalLValue(Info.EvalResult.Val.getLValueBase())) return false; } else if (E->getType()->hasPointerRepresentation()) { LValue LV; @@ -2243,14 +2592,24 @@ bool Expr::Evaluate(EvalResult &Result, ASTContext &Ctx) const { return true; } -bool Expr::EvaluateAsBooleanCondition(bool &Result, ASTContext &Ctx) const { +/// Evaluate - Return true if this is a constant which we can fold using +/// any crazy technique (that has nothing to do with language standards) that +/// we want to. If this function returns true, it returns the folded constant +/// in Result. +bool Expr::Evaluate(EvalResult &Result, const ASTContext &Ctx) const { + EvalInfo Info(Ctx, Result); + return ::Evaluate(Info, this); +} + +bool Expr::EvaluateAsBooleanCondition(bool &Result, + const ASTContext &Ctx) const { EvalResult Scratch; EvalInfo Info(Ctx, Scratch); return HandleConversionToBool(this, Result, Info); } -bool Expr::EvaluateAsLValue(EvalResult &Result, ASTContext &Ctx) const { +bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx) const { EvalInfo Info(Ctx, Result); LValue LV; @@ -2263,7 +2622,8 @@ bool Expr::EvaluateAsLValue(EvalResult &Result, ASTContext &Ctx) const { return false; } -bool Expr::EvaluateAsAnyLValue(EvalResult &Result, ASTContext &Ctx) const { +bool Expr::EvaluateAsAnyLValue(EvalResult &Result, + const ASTContext &Ctx) const { EvalInfo Info(Ctx, Result); LValue LV; @@ -2276,21 +2636,21 @@ bool Expr::EvaluateAsAnyLValue(EvalResult &Result, ASTContext &Ctx) const { /// isEvaluatable - Call Evaluate to see if this expression can be constant /// folded, but discard the result. -bool Expr::isEvaluatable(ASTContext &Ctx) const { +bool Expr::isEvaluatable(const ASTContext &Ctx) const { EvalResult Result; return Evaluate(Result, Ctx) && !Result.HasSideEffects; } -bool Expr::HasSideEffects(ASTContext &Ctx) const { +bool Expr::HasSideEffects(const ASTContext &Ctx) const { Expr::EvalResult Result; EvalInfo Info(Ctx, Result); return HasSideEffect(Info).Visit(const_cast<Expr*>(this)); } -APSInt Expr::EvaluateAsInt(ASTContext &Ctx) const { +APSInt Expr::EvaluateAsInt(const ASTContext &Ctx) const { EvalResult EvalResult; bool Result = Evaluate(EvalResult, Ctx); - Result = Result; + (void)Result; assert(Result && "Could not evaluate expression"); assert(EvalResult.Val.isInt() && "Expression did not evaluate to integer"); @@ -2358,6 +2718,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { } switch (E->getStmtClass()) { +#define ABSTRACT_STMT(Node) #define STMT(Node, Base) case Expr::Node##Class: #define EXPR(Node, Base) #include "clang/AST/StmtNodes.inc" @@ -2378,8 +2739,10 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::AddrLabelExprClass: case Expr::StmtExprClass: case Expr::CXXMemberCallExprClass: + case Expr::CUDAKernelCallExprClass: case Expr::CXXDynamicCastExprClass: case Expr::CXXTypeidExprClass: + case Expr::CXXUuidofExprClass: case Expr::CXXNullPtrLiteralExprClass: case Expr::CXXThisExprClass: case Expr::CXXThrowExprClass: @@ -2390,7 +2753,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::DependentScopeDeclRefExprClass: case Expr::CXXConstructExprClass: case Expr::CXXBindTemporaryExprClass: - case Expr::CXXExprWithTemporariesClass: + case Expr::ExprWithCleanupsClass: case Expr::CXXTemporaryObjectExprClass: case Expr::CXXUnresolvedConstructExprClass: case Expr::CXXDependentScopeMemberExprClass: @@ -2402,15 +2765,17 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::ObjCProtocolExprClass: case Expr::ObjCIvarRefExprClass: case Expr::ObjCPropertyRefExprClass: - case Expr::ObjCImplicitSetterGetterRefExprClass: - case Expr::ObjCSuperExprClass: case Expr::ObjCIsaExprClass: case Expr::ShuffleVectorExprClass: case Expr::BlockExprClass: case Expr::BlockDeclRefExprClass: case Expr::NoStmtClass: + case Expr::OpaqueValueExprClass: + case Expr::PackExpansionExprClass: + case Expr::SubstNonTypeTemplateParmPackExprClass: return ICEDiag(2, E->getLocStart()); + case Expr::SizeOfPackExprClass: case Expr::GNUNullExprClass: // GCC considers the GNU __null value to be an integral constant expression. return NoDiag(); @@ -2421,8 +2786,9 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::CharacterLiteralClass: case Expr::CXXBoolLiteralExprClass: case Expr::CXXScalarValueInitExprClass: - case Expr::TypesCompatibleExprClass: case Expr::UnaryTypeTraitExprClass: + case Expr::BinaryTypeTraitExprClass: + case Expr::CXXNoexceptExprClass: return NoDiag(); case Expr::CallExprClass: case Expr::CXXOperatorCallExprClass: { @@ -2619,6 +2985,17 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { return NoDiag(); return ICEDiag(2, E->getLocStart()); } + case Expr::BinaryConditionalOperatorClass: { + const BinaryConditionalOperator *Exp = cast<BinaryConditionalOperator>(E); + ICEDiag CommonResult = CheckICE(Exp->getCommon(), Ctx); + if (CommonResult.Val == 2) return CommonResult; + ICEDiag FalseResult = CheckICE(Exp->getFalseExpr(), Ctx); + if (FalseResult.Val == 2) return FalseResult; + if (CommonResult.Val == 1) return CommonResult; + if (FalseResult.Val == 1 && + Exp->getCommon()->EvaluateAsInt(Ctx) == 0) return NoDiag(); + return FalseResult; + } case Expr::ConditionalOperatorClass: { const ConditionalOperator *Exp = cast<ConditionalOperator>(E); // If the condition (ignoring parens) is a __builtin_constant_p call, diff --git a/lib/AST/FullExpr.cpp b/lib/AST/FullExpr.cpp deleted file mode 100644 index 93ee8d1..0000000 --- a/lib/AST/FullExpr.cpp +++ /dev/null @@ -1,45 +0,0 @@ -//===--- FullExpr.cpp - C++ full expression class ---------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the FullExpr interface, to be used for type safe handling -// of full expressions. -// -// Full expressions are described in C++ [intro.execution]p12. -// -//===----------------------------------------------------------------------===// - -#include "clang/AST/ASTContext.h" -#include "clang/AST/FullExpr.h" -#include "clang/AST/Expr.h" -#include "clang/AST/ExprCXX.h" -#include "llvm/Support/AlignOf.h" -using namespace clang; - -FullExpr FullExpr::Create(ASTContext &Context, Expr *SubExpr, - CXXTemporary **Temporaries, unsigned NumTemporaries) { - FullExpr E; - - if (!NumTemporaries) { - E.SubExpr = SubExpr; - return E; - } - - unsigned Size = sizeof(FullExpr) - + sizeof(CXXTemporary *) * NumTemporaries; - - unsigned Align = llvm::AlignOf<ExprAndTemporaries>::Alignment; - ExprAndTemporaries *ET = - static_cast<ExprAndTemporaries *>(Context.Allocate(Size, Align)); - - ET->SubExpr = SubExpr; - std::copy(Temporaries, Temporaries + NumTemporaries, ET->temps_begin()); - - return E; -} - diff --git a/lib/AST/InheritViz.cpp b/lib/AST/InheritViz.cpp index c47a9da..533a232 100644 --- a/lib/AST/InheritViz.cpp +++ b/lib/AST/InheritViz.cpp @@ -17,6 +17,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/TypeOrdering.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/GraphWriter.h" #include "llvm/Support/raw_ostream.h" #include <map> @@ -135,34 +136,28 @@ InheritanceHierarchyWriter::WriteNodeReference(QualType Type, /// class using GraphViz. void CXXRecordDecl::viewInheritance(ASTContext& Context) const { QualType Self = Context.getTypeDeclType(const_cast<CXXRecordDecl *>(this)); - std::string ErrMsg; - sys::Path Filename = sys::Path::GetTemporaryDirectory(&ErrMsg); - if (Filename.isEmpty()) { - llvm::errs() << "Error: " << ErrMsg << "\n"; - return; - } - Filename.appendComponent(Self.getAsString() + ".dot"); - if (Filename.makeUnique(true,&ErrMsg)) { - llvm::errs() << "Error: " << ErrMsg << "\n"; + // Create temp directory + SmallString<128> Filename; + int FileFD = 0; + if (error_code ec = sys::fs::unique_file( + "clang-class-inheritance-hierarchy-%%-%%-%%-%%-" + + Self.getAsString() + ".dot", + FileFD, Filename)) { + errs() << "Error creating temporary output file: " << ec.message() << '\n'; return; } - llvm::errs() << "Writing '" << Filename.c_str() << "'... "; + llvm::errs() << "Writing '" << Filename << "'... "; - llvm::raw_fd_ostream O(Filename.c_str(), ErrMsg); + llvm::raw_fd_ostream O(FileFD, true); + InheritanceHierarchyWriter Writer(Context, O); + Writer.WriteGraph(Self); - if (ErrMsg.empty()) { - InheritanceHierarchyWriter Writer(Context, O); - Writer.WriteGraph(Self); - llvm::errs() << " done. \n"; + llvm::errs() << " done. \n"; + O.close(); - O.close(); - - // Display the graph - DisplayGraph(Filename); - } else { - llvm::errs() << "error opening file for writing!\n"; - } + // Display the graph + DisplayGraph(sys::Path(Filename)); } } diff --git a/lib/AST/ItaniumCXXABI.cpp b/lib/AST/ItaniumCXXABI.cpp index c3fa466..bed02b4 100644 --- a/lib/AST/ItaniumCXXABI.cpp +++ b/lib/AST/ItaniumCXXABI.cpp @@ -19,7 +19,10 @@ #include "CXXABI.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/RecordLayout.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/Type.h" +#include "clang/Basic/TargetInfo.h" using namespace clang; @@ -35,6 +38,24 @@ public: if (Pointee->isFunctionType()) return 2; return 1; } + + CallingConv getDefaultMethodCallConv() const { + return CC_C; + } + + // We cheat and just check that the class has a vtable pointer, and that it's + // only big enough to have a vtable pointer and nothing more (or less). + bool isNearlyEmpty(const CXXRecordDecl *RD) const { + + // Check that the class has a vtable pointer. + if (!RD->isDynamicClass()) + return false; + + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + CharUnits PointerSize = + Context.toCharUnitsFromBits(Context.Target.getPointerWidth(0)); + return Layout.getNonVirtualSize() == PointerSize; + } }; class ARMCXXABI : public ItaniumCXXABI { diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp new file mode 100644 index 0000000..d66c374 --- /dev/null +++ b/lib/AST/ItaniumMangle.cpp @@ -0,0 +1,2705 @@ +//===--- ItaniumMangle.cpp - Itanium C++ Name Mangling ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Implements C++ name mangling according to the Itanium C++ ABI, +// which is used in GCC 3.2 and newer (and many compilers that are +// ABI-compatible with GCC): +// +// http://www.codesourcery.com/public/cxx-abi/abi.html +// +//===----------------------------------------------------------------------===// +#include "clang/AST/Mangle.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/ExprCXX.h" +#include "clang/Basic/ABI.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/ErrorHandling.h" + +#define MANGLE_CHECKER 0 + +#if MANGLE_CHECKER +#include <cxxabi.h> +#endif + +using namespace clang; + +namespace { + +static const CXXRecordDecl *GetLocalClassDecl(const NamedDecl *ND) { + const DeclContext *DC = dyn_cast<DeclContext>(ND); + if (!DC) + DC = ND->getDeclContext(); + while (!DC->isNamespace() && !DC->isTranslationUnit()) { + if (isa<FunctionDecl>(DC->getParent())) + return dyn_cast<CXXRecordDecl>(DC); + DC = DC->getParent(); + } + return 0; +} + +static const CXXMethodDecl *getStructor(const CXXMethodDecl *MD) { + assert((isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD)) && + "Passed in decl is not a ctor or dtor!"); + + if (const TemplateDecl *TD = MD->getPrimaryTemplate()) { + MD = cast<CXXMethodDecl>(TD->getTemplatedDecl()); + + assert((isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD)) && + "Templated decl is not a ctor or dtor!"); + } + + return MD; +} + +static const unsigned UnknownArity = ~0U; + +class ItaniumMangleContext : public MangleContext { + llvm::DenseMap<const TagDecl *, uint64_t> AnonStructIds; + unsigned Discriminator; + llvm::DenseMap<const NamedDecl*, unsigned> Uniquifier; + +public: + explicit ItaniumMangleContext(ASTContext &Context, + Diagnostic &Diags) + : MangleContext(Context, Diags) { } + + uint64_t getAnonymousStructId(const TagDecl *TD) { + std::pair<llvm::DenseMap<const TagDecl *, + uint64_t>::iterator, bool> Result = + AnonStructIds.insert(std::make_pair(TD, AnonStructIds.size())); + return Result.first->second; + } + + void startNewFunction() { + MangleContext::startNewFunction(); + mangleInitDiscriminator(); + } + + /// @name Mangler Entry Points + /// @{ + + bool shouldMangleDeclName(const NamedDecl *D); + void mangleName(const NamedDecl *D, llvm::raw_ostream &); + void mangleThunk(const CXXMethodDecl *MD, + const ThunkInfo &Thunk, + llvm::raw_ostream &); + void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type, + const ThisAdjustment &ThisAdjustment, + llvm::raw_ostream &); + void mangleReferenceTemporary(const VarDecl *D, + llvm::raw_ostream &); + void mangleCXXVTable(const CXXRecordDecl *RD, + llvm::raw_ostream &); + void mangleCXXVTT(const CXXRecordDecl *RD, + llvm::raw_ostream &); + void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset, + const CXXRecordDecl *Type, + llvm::raw_ostream &); + void mangleCXXRTTI(QualType T, llvm::raw_ostream &); + void mangleCXXRTTIName(QualType T, llvm::raw_ostream &); + void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type, + llvm::raw_ostream &); + void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type, + llvm::raw_ostream &); + + void mangleItaniumGuardVariable(const VarDecl *D, llvm::raw_ostream &); + + void mangleInitDiscriminator() { + Discriminator = 0; + } + + bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) { + unsigned &discriminator = Uniquifier[ND]; + if (!discriminator) + discriminator = ++Discriminator; + if (discriminator == 1) + return false; + disc = discriminator-2; + return true; + } + /// @} +}; + +/// CXXNameMangler - Manage the mangling of a single name. +class CXXNameMangler { + ItaniumMangleContext &Context; + llvm::raw_ostream &Out; + + const CXXMethodDecl *Structor; + unsigned StructorType; + + /// SeqID - The next subsitution sequence number. + unsigned SeqID; + + llvm::DenseMap<uintptr_t, unsigned> Substitutions; + + ASTContext &getASTContext() const { return Context.getASTContext(); } + +public: + CXXNameMangler(ItaniumMangleContext &C, llvm::raw_ostream &Out_) + : Context(C), Out(Out_), Structor(0), StructorType(0), SeqID(0) { } + CXXNameMangler(ItaniumMangleContext &C, llvm::raw_ostream &Out_, + const CXXConstructorDecl *D, CXXCtorType Type) + : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type), + SeqID(0) { } + CXXNameMangler(ItaniumMangleContext &C, llvm::raw_ostream &Out_, + const CXXDestructorDecl *D, CXXDtorType Type) + : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type), + SeqID(0) { } + +#if MANGLE_CHECKER + ~CXXNameMangler() { + if (Out.str()[0] == '\01') + return; + + int status = 0; + char *result = abi::__cxa_demangle(Out.str().str().c_str(), 0, 0, &status); + assert(status == 0 && "Could not demangle mangled name!"); + free(result); + } +#endif + llvm::raw_ostream &getStream() { return Out; } + + void mangle(const NamedDecl *D, llvm::StringRef Prefix = "_Z"); + void mangleCallOffset(int64_t NonVirtual, int64_t Virtual); + void mangleNumber(const llvm::APSInt &I); + void mangleNumber(int64_t Number); + void mangleFloat(const llvm::APFloat &F); + void mangleFunctionEncoding(const FunctionDecl *FD); + void mangleName(const NamedDecl *ND); + void mangleType(QualType T); + void mangleNameOrStandardSubstitution(const NamedDecl *ND); + +private: + bool mangleSubstitution(const NamedDecl *ND); + bool mangleSubstitution(QualType T); + bool mangleSubstitution(TemplateName Template); + bool mangleSubstitution(uintptr_t Ptr); + + bool mangleStandardSubstitution(const NamedDecl *ND); + + void addSubstitution(const NamedDecl *ND) { + ND = cast<NamedDecl>(ND->getCanonicalDecl()); + + addSubstitution(reinterpret_cast<uintptr_t>(ND)); + } + void addSubstitution(QualType T); + void addSubstitution(TemplateName Template); + void addSubstitution(uintptr_t Ptr); + + void mangleUnresolvedScope(NestedNameSpecifier *Qualifier); + void mangleUnresolvedName(NestedNameSpecifier *Qualifier, + DeclarationName Name, + unsigned KnownArity = UnknownArity); + + void mangleName(const TemplateDecl *TD, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs); + void mangleUnqualifiedName(const NamedDecl *ND) { + mangleUnqualifiedName(ND, ND->getDeclName(), UnknownArity); + } + void mangleUnqualifiedName(const NamedDecl *ND, DeclarationName Name, + unsigned KnownArity); + void mangleUnscopedName(const NamedDecl *ND); + void mangleUnscopedTemplateName(const TemplateDecl *ND); + void mangleUnscopedTemplateName(TemplateName); + void mangleSourceName(const IdentifierInfo *II); + void mangleLocalName(const NamedDecl *ND); + void mangleNestedName(const NamedDecl *ND, const DeclContext *DC, + bool NoFunction=false); + void mangleNestedName(const TemplateDecl *TD, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs); + void manglePrefix(const DeclContext *DC, bool NoFunction=false); + void mangleTemplatePrefix(const TemplateDecl *ND); + void mangleTemplatePrefix(TemplateName Template); + void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity); + void mangleQualifiers(Qualifiers Quals); + void mangleRefQualifier(RefQualifierKind RefQualifier); + + void mangleObjCMethodName(const ObjCMethodDecl *MD); + + // Declare manglers for every type class. +#define ABSTRACT_TYPE(CLASS, PARENT) +#define NON_CANONICAL_TYPE(CLASS, PARENT) +#define TYPE(CLASS, PARENT) void mangleType(const CLASS##Type *T); +#include "clang/AST/TypeNodes.def" + + void mangleType(const TagType*); + void mangleType(TemplateName); + void mangleBareFunctionType(const FunctionType *T, + bool MangleReturnType); + void mangleNeonVectorType(const VectorType *T); + + void mangleIntegerLiteral(QualType T, const llvm::APSInt &Value); + void mangleMemberExpr(const Expr *Base, bool IsArrow, + NestedNameSpecifier *Qualifier, + DeclarationName Name, + unsigned KnownArity); + void mangleExpression(const Expr *E, unsigned Arity = UnknownArity); + void mangleCXXCtorType(CXXCtorType T); + void mangleCXXDtorType(CXXDtorType T); + + void mangleTemplateArgs(const ExplicitTemplateArgumentList &TemplateArgs); + void mangleTemplateArgs(TemplateName Template, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs); + void mangleTemplateArgs(const TemplateParameterList &PL, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs); + void mangleTemplateArgs(const TemplateParameterList &PL, + const TemplateArgumentList &AL); + void mangleTemplateArg(const NamedDecl *P, const TemplateArgument &A); + + void mangleTemplateParameter(unsigned Index); +}; + +} + +static bool isInCLinkageSpecification(const Decl *D) { + D = D->getCanonicalDecl(); + for (const DeclContext *DC = D->getDeclContext(); + !DC->isTranslationUnit(); DC = DC->getParent()) { + if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC)) + return Linkage->getLanguage() == LinkageSpecDecl::lang_c; + } + + return false; +} + +bool ItaniumMangleContext::shouldMangleDeclName(const NamedDecl *D) { + // In C, functions with no attributes never need to be mangled. Fastpath them. + if (!getASTContext().getLangOptions().CPlusPlus && !D->hasAttrs()) + return false; + + // Any decl can be declared with __asm("foo") on it, and this takes precedence + // over all other naming in the .o file. + if (D->hasAttr<AsmLabelAttr>()) + return true; + + // Clang's "overloadable" attribute extension to C/C++ implies name mangling + // (always) as does passing a C++ member function and a function + // whose name is not a simple identifier. + const FunctionDecl *FD = dyn_cast<FunctionDecl>(D); + if (FD && (FD->hasAttr<OverloadableAttr>() || isa<CXXMethodDecl>(FD) || + !FD->getDeclName().isIdentifier())) + return true; + + // Otherwise, no mangling is done outside C++ mode. + if (!getASTContext().getLangOptions().CPlusPlus) + return false; + + // Variables at global scope with non-internal linkage are not mangled + if (!FD) { + const DeclContext *DC = D->getDeclContext(); + // Check for extern variable declared locally. + if (DC->isFunctionOrMethod() && D->hasLinkage()) + while (!DC->isNamespace() && !DC->isTranslationUnit()) + DC = DC->getParent(); + if (DC->isTranslationUnit() && D->getLinkage() != InternalLinkage) + return false; + } + + // Class members are always mangled. + if (D->getDeclContext()->isRecord()) + return true; + + // C functions and "main" are not mangled. + if ((FD && FD->isMain()) || isInCLinkageSpecification(D)) + return false; + + return true; +} + +void CXXNameMangler::mangle(const NamedDecl *D, llvm::StringRef Prefix) { + // Any decl can be declared with __asm("foo") on it, and this takes precedence + // over all other naming in the .o file. + if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>()) { + // If we have an asm name, then we use it as the mangling. + + // Adding the prefix can cause problems when one file has a "foo" and + // another has a "\01foo". That is known to happen on ELF with the + // tricks normally used for producing aliases (PR9177). Fortunately the + // llvm mangler on ELF is a nop, so we can just avoid adding the \01 + // marker. + llvm::StringRef UserLabelPrefix = + getASTContext().Target.getUserLabelPrefix(); + if (!UserLabelPrefix.empty()) + Out << '\01'; // LLVM IR Marker for __asm("foo") + + Out << ALA->getLabel(); + return; + } + + // <mangled-name> ::= _Z <encoding> + // ::= <data name> + // ::= <special-name> + Out << Prefix; + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) + mangleFunctionEncoding(FD); + else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) + mangleName(VD); + else + mangleName(cast<FieldDecl>(D)); +} + +void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) { + // <encoding> ::= <function name> <bare-function-type> + mangleName(FD); + + // Don't mangle in the type if this isn't a decl we should typically mangle. + if (!Context.shouldMangleDeclName(FD)) + return; + + // Whether the mangling of a function type includes the return type depends on + // the context and the nature of the function. The rules for deciding whether + // the return type is included are: + // + // 1. Template functions (names or types) have return types encoded, with + // the exceptions listed below. + // 2. Function types not appearing as part of a function name mangling, + // e.g. parameters, pointer types, etc., have return type encoded, with the + // exceptions listed below. + // 3. Non-template function names do not have return types encoded. + // + // The exceptions mentioned in (1) and (2) above, for which the return type is + // never included, are + // 1. Constructors. + // 2. Destructors. + // 3. Conversion operator functions, e.g. operator int. + bool MangleReturnType = false; + if (FunctionTemplateDecl *PrimaryTemplate = FD->getPrimaryTemplate()) { + if (!(isa<CXXConstructorDecl>(FD) || isa<CXXDestructorDecl>(FD) || + isa<CXXConversionDecl>(FD))) + MangleReturnType = true; + + // Mangle the type of the primary template. + FD = PrimaryTemplate->getTemplatedDecl(); + } + + // Do the canonicalization out here because parameter types can + // undergo additional canonicalization (e.g. array decay). + const FunctionType *FT + = cast<FunctionType>(Context.getASTContext() + .getCanonicalType(FD->getType())); + + mangleBareFunctionType(FT, MangleReturnType); +} + +static const DeclContext *IgnoreLinkageSpecDecls(const DeclContext *DC) { + while (isa<LinkageSpecDecl>(DC)) { + DC = DC->getParent(); + } + + return DC; +} + +/// isStd - Return whether a given namespace is the 'std' namespace. +static bool isStd(const NamespaceDecl *NS) { + if (!IgnoreLinkageSpecDecls(NS->getParent())->isTranslationUnit()) + return false; + + const IdentifierInfo *II = NS->getOriginalNamespace()->getIdentifier(); + return II && II->isStr("std"); +} + +// isStdNamespace - Return whether a given decl context is a toplevel 'std' +// namespace. +static bool isStdNamespace(const DeclContext *DC) { + if (!DC->isNamespace()) + return false; + + return isStd(cast<NamespaceDecl>(DC)); +} + +static const TemplateDecl * +isTemplate(const NamedDecl *ND, const TemplateArgumentList *&TemplateArgs) { + // Check if we have a function template. + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)){ + if (const TemplateDecl *TD = FD->getPrimaryTemplate()) { + TemplateArgs = FD->getTemplateSpecializationArgs(); + return TD; + } + } + + // Check if we have a class template. + if (const ClassTemplateSpecializationDecl *Spec = + dyn_cast<ClassTemplateSpecializationDecl>(ND)) { + TemplateArgs = &Spec->getTemplateArgs(); + return Spec->getSpecializedTemplate(); + } + + return 0; +} + +void CXXNameMangler::mangleName(const NamedDecl *ND) { + // <name> ::= <nested-name> + // ::= <unscoped-name> + // ::= <unscoped-template-name> <template-args> + // ::= <local-name> + // + const DeclContext *DC = ND->getDeclContext(); + + // If this is an extern variable declared locally, the relevant DeclContext + // is that of the containing namespace, or the translation unit. + if (isa<FunctionDecl>(DC) && ND->hasLinkage()) + while (!DC->isNamespace() && !DC->isTranslationUnit()) + DC = DC->getParent(); + else if (GetLocalClassDecl(ND)) { + mangleLocalName(ND); + return; + } + + while (isa<LinkageSpecDecl>(DC)) + DC = DC->getParent(); + + if (DC->isTranslationUnit() || isStdNamespace(DC)) { + // Check if we have a template. + const TemplateArgumentList *TemplateArgs = 0; + if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) { + mangleUnscopedTemplateName(TD); + TemplateParameterList *TemplateParameters = TD->getTemplateParameters(); + mangleTemplateArgs(*TemplateParameters, *TemplateArgs); + return; + } + + mangleUnscopedName(ND); + return; + } + + if (isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC)) { + mangleLocalName(ND); + return; + } + + mangleNestedName(ND, DC); +} +void CXXNameMangler::mangleName(const TemplateDecl *TD, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs) { + const DeclContext *DC = IgnoreLinkageSpecDecls(TD->getDeclContext()); + + if (DC->isTranslationUnit() || isStdNamespace(DC)) { + mangleUnscopedTemplateName(TD); + TemplateParameterList *TemplateParameters = TD->getTemplateParameters(); + mangleTemplateArgs(*TemplateParameters, TemplateArgs, NumTemplateArgs); + } else { + mangleNestedName(TD, TemplateArgs, NumTemplateArgs); + } +} + +void CXXNameMangler::mangleUnscopedName(const NamedDecl *ND) { + // <unscoped-name> ::= <unqualified-name> + // ::= St <unqualified-name> # ::std:: + if (isStdNamespace(ND->getDeclContext())) + Out << "St"; + + mangleUnqualifiedName(ND); +} + +void CXXNameMangler::mangleUnscopedTemplateName(const TemplateDecl *ND) { + // <unscoped-template-name> ::= <unscoped-name> + // ::= <substitution> + if (mangleSubstitution(ND)) + return; + + // <template-template-param> ::= <template-param> + if (const TemplateTemplateParmDecl *TTP + = dyn_cast<TemplateTemplateParmDecl>(ND)) { + mangleTemplateParameter(TTP->getIndex()); + return; + } + + mangleUnscopedName(ND->getTemplatedDecl()); + addSubstitution(ND); +} + +void CXXNameMangler::mangleUnscopedTemplateName(TemplateName Template) { + // <unscoped-template-name> ::= <unscoped-name> + // ::= <substitution> + if (TemplateDecl *TD = Template.getAsTemplateDecl()) + return mangleUnscopedTemplateName(TD); + + if (mangleSubstitution(Template)) + return; + + // FIXME: How to cope with operators here? + DependentTemplateName *Dependent = Template.getAsDependentTemplateName(); + assert(Dependent && "Not a dependent template name?"); + if (!Dependent->isIdentifier()) { + // FIXME: We can't possibly know the arity of the operator here! + Diagnostic &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Error, + "cannot mangle dependent operator name"); + Diags.Report(DiagID); + return; + } + + mangleSourceName(Dependent->getIdentifier()); + addSubstitution(Template); +} + +void CXXNameMangler::mangleFloat(const llvm::APFloat &F) { + // TODO: avoid this copy with careful stream management. + llvm::SmallString<20> Buffer; + F.bitcastToAPInt().toString(Buffer, 16, false); + Out.write(Buffer.data(), Buffer.size()); +} + +void CXXNameMangler::mangleNumber(const llvm::APSInt &Value) { + if (Value.isSigned() && Value.isNegative()) { + Out << 'n'; + Value.abs().print(Out, true); + } else + Value.print(Out, Value.isSigned()); +} + +void CXXNameMangler::mangleNumber(int64_t Number) { + // <number> ::= [n] <non-negative decimal integer> + if (Number < 0) { + Out << 'n'; + Number = -Number; + } + + Out << Number; +} + +void CXXNameMangler::mangleCallOffset(int64_t NonVirtual, int64_t Virtual) { + // <call-offset> ::= h <nv-offset> _ + // ::= v <v-offset> _ + // <nv-offset> ::= <offset number> # non-virtual base override + // <v-offset> ::= <offset number> _ <virtual offset number> + // # virtual base override, with vcall offset + if (!Virtual) { + Out << 'h'; + mangleNumber(NonVirtual); + Out << '_'; + return; + } + + Out << 'v'; + mangleNumber(NonVirtual); + Out << '_'; + mangleNumber(Virtual); + Out << '_'; +} + +void CXXNameMangler::mangleUnresolvedScope(NestedNameSpecifier *Qualifier) { + Qualifier = getASTContext().getCanonicalNestedNameSpecifier(Qualifier); + switch (Qualifier->getKind()) { + case NestedNameSpecifier::Global: + // nothing + break; + case NestedNameSpecifier::Namespace: + mangleName(Qualifier->getAsNamespace()); + break; + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: { + const Type *QTy = Qualifier->getAsType(); + + if (const TemplateSpecializationType *TST = + dyn_cast<TemplateSpecializationType>(QTy)) { + if (!mangleSubstitution(QualType(TST, 0))) { + mangleTemplatePrefix(TST->getTemplateName()); + + // FIXME: GCC does not appear to mangle the template arguments when + // the template in question is a dependent template name. Should we + // emulate that badness? + mangleTemplateArgs(TST->getTemplateName(), TST->getArgs(), + TST->getNumArgs()); + addSubstitution(QualType(TST, 0)); + } + } else { + // We use the QualType mangle type variant here because it handles + // substitutions. + mangleType(QualType(QTy, 0)); + } + } + break; + case NestedNameSpecifier::Identifier: + // Member expressions can have these without prefixes. + if (Qualifier->getPrefix()) + mangleUnresolvedScope(Qualifier->getPrefix()); + mangleSourceName(Qualifier->getAsIdentifier()); + break; + } +} + +/// Mangles a name which was not resolved to a specific entity. +void CXXNameMangler::mangleUnresolvedName(NestedNameSpecifier *Qualifier, + DeclarationName Name, + unsigned KnownArity) { + if (Qualifier) + mangleUnresolvedScope(Qualifier); + // FIXME: ambiguity of unqualified lookup with :: + + mangleUnqualifiedName(0, Name, KnownArity); +} + +static const FieldDecl *FindFirstNamedDataMember(const RecordDecl *RD) { + assert(RD->isAnonymousStructOrUnion() && + "Expected anonymous struct or union!"); + + for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); + I != E; ++I) { + const FieldDecl *FD = *I; + + if (FD->getIdentifier()) + return FD; + + if (const RecordType *RT = FD->getType()->getAs<RecordType>()) { + if (const FieldDecl *NamedDataMember = + FindFirstNamedDataMember(RT->getDecl())) + return NamedDataMember; + } + } + + // We didn't find a named data member. + return 0; +} + +void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, + DeclarationName Name, + unsigned KnownArity) { + // <unqualified-name> ::= <operator-name> + // ::= <ctor-dtor-name> + // ::= <source-name> + switch (Name.getNameKind()) { + case DeclarationName::Identifier: { + if (const IdentifierInfo *II = Name.getAsIdentifierInfo()) { + // We must avoid conflicts between internally- and externally- + // linked variable declaration names in the same TU. + // This naming convention is the same as that followed by GCC, though it + // shouldn't actually matter. + if (ND && isa<VarDecl>(ND) && ND->getLinkage() == InternalLinkage && + ND->getDeclContext()->isFileContext()) + Out << 'L'; + + mangleSourceName(II); + break; + } + + // Otherwise, an anonymous entity. We must have a declaration. + assert(ND && "mangling empty name without declaration"); + + if (const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(ND)) { + if (NS->isAnonymousNamespace()) { + // This is how gcc mangles these names. + Out << "12_GLOBAL__N_1"; + break; + } + } + + if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) { + // We must have an anonymous union or struct declaration. + const RecordDecl *RD = + cast<RecordDecl>(VD->getType()->getAs<RecordType>()->getDecl()); + + // Itanium C++ ABI 5.1.2: + // + // For the purposes of mangling, the name of an anonymous union is + // considered to be the name of the first named data member found by a + // pre-order, depth-first, declaration-order walk of the data members of + // the anonymous union. If there is no such data member (i.e., if all of + // the data members in the union are unnamed), then there is no way for + // a program to refer to the anonymous union, and there is therefore no + // need to mangle its name. + const FieldDecl *FD = FindFirstNamedDataMember(RD); + + // It's actually possible for various reasons for us to get here + // with an empty anonymous struct / union. Fortunately, it + // doesn't really matter what name we generate. + if (!FD) break; + assert(FD->getIdentifier() && "Data member name isn't an identifier!"); + + mangleSourceName(FD->getIdentifier()); + break; + } + + // We must have an anonymous struct. + const TagDecl *TD = cast<TagDecl>(ND); + if (const TypedefDecl *D = TD->getTypedefForAnonDecl()) { + assert(TD->getDeclContext() == D->getDeclContext() && + "Typedef should not be in another decl context!"); + assert(D->getDeclName().getAsIdentifierInfo() && + "Typedef was not named!"); + mangleSourceName(D->getDeclName().getAsIdentifierInfo()); + break; + } + + // Get a unique id for the anonymous struct. + uint64_t AnonStructId = Context.getAnonymousStructId(TD); + + // Mangle it as a source name in the form + // [n] $_<id> + // where n is the length of the string. + llvm::SmallString<8> Str; + Str += "$_"; + Str += llvm::utostr(AnonStructId); + + Out << Str.size(); + Out << Str.str(); + break; + } + + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + assert(false && "Can't mangle Objective-C selector names here!"); + break; + + case DeclarationName::CXXConstructorName: + if (ND == Structor) + // If the named decl is the C++ constructor we're mangling, use the type + // we were given. + mangleCXXCtorType(static_cast<CXXCtorType>(StructorType)); + else + // Otherwise, use the complete constructor name. This is relevant if a + // class with a constructor is declared within a constructor. + mangleCXXCtorType(Ctor_Complete); + break; + + case DeclarationName::CXXDestructorName: + if (ND == Structor) + // If the named decl is the C++ destructor we're mangling, use the type we + // were given. + mangleCXXDtorType(static_cast<CXXDtorType>(StructorType)); + else + // Otherwise, use the complete destructor name. This is relevant if a + // class with a destructor is declared within a destructor. + mangleCXXDtorType(Dtor_Complete); + break; + + case DeclarationName::CXXConversionFunctionName: + // <operator-name> ::= cv <type> # (cast) + Out << "cv"; + mangleType(Context.getASTContext().getCanonicalType(Name.getCXXNameType())); + break; + + case DeclarationName::CXXOperatorName: { + unsigned Arity; + if (ND) { + Arity = cast<FunctionDecl>(ND)->getNumParams(); + + // If we have a C++ member function, we need to include the 'this' pointer. + // FIXME: This does not make sense for operators that are static, but their + // names stay the same regardless of the arity (operator new for instance). + if (isa<CXXMethodDecl>(ND)) + Arity++; + } else + Arity = KnownArity; + + mangleOperatorName(Name.getCXXOverloadedOperator(), Arity); + break; + } + + case DeclarationName::CXXLiteralOperatorName: + // FIXME: This mangling is not yet official. + Out << "li"; + mangleSourceName(Name.getCXXLiteralIdentifier()); + break; + + case DeclarationName::CXXUsingDirective: + assert(false && "Can't mangle a using directive name!"); + break; + } +} + +void CXXNameMangler::mangleSourceName(const IdentifierInfo *II) { + // <source-name> ::= <positive length number> <identifier> + // <number> ::= [n] <non-negative decimal integer> + // <identifier> ::= <unqualified source code identifier> + Out << II->getLength() << II->getName(); +} + +void CXXNameMangler::mangleNestedName(const NamedDecl *ND, + const DeclContext *DC, + bool NoFunction) { + // <nested-name> + // ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E + // ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix> + // <template-args> E + + Out << 'N'; + if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(ND)) { + mangleQualifiers(Qualifiers::fromCVRMask(Method->getTypeQualifiers())); + mangleRefQualifier(Method->getRefQualifier()); + } + + // Check if we have a template. + const TemplateArgumentList *TemplateArgs = 0; + if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) { + mangleTemplatePrefix(TD); + TemplateParameterList *TemplateParameters = TD->getTemplateParameters(); + mangleTemplateArgs(*TemplateParameters, *TemplateArgs); + } + else { + manglePrefix(DC, NoFunction); + mangleUnqualifiedName(ND); + } + + Out << 'E'; +} +void CXXNameMangler::mangleNestedName(const TemplateDecl *TD, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs) { + // <nested-name> ::= N [<CV-qualifiers>] <template-prefix> <template-args> E + + Out << 'N'; + + mangleTemplatePrefix(TD); + TemplateParameterList *TemplateParameters = TD->getTemplateParameters(); + mangleTemplateArgs(*TemplateParameters, TemplateArgs, NumTemplateArgs); + + Out << 'E'; +} + +void CXXNameMangler::mangleLocalName(const NamedDecl *ND) { + // <local-name> := Z <function encoding> E <entity name> [<discriminator>] + // := Z <function encoding> E s [<discriminator>] + // <discriminator> := _ <non-negative number> + const DeclContext *DC = ND->getDeclContext(); + Out << 'Z'; + + if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(DC)) { + mangleObjCMethodName(MD); + } else if (const CXXRecordDecl *RD = GetLocalClassDecl(ND)) { + mangleFunctionEncoding(cast<FunctionDecl>(RD->getDeclContext())); + Out << 'E'; + + // Mangle the name relative to the closest enclosing function. + if (ND == RD) // equality ok because RD derived from ND above + mangleUnqualifiedName(ND); + else + mangleNestedName(ND, DC, true /*NoFunction*/); + + unsigned disc; + if (Context.getNextDiscriminator(RD, disc)) { + if (disc < 10) + Out << '_' << disc; + else + Out << "__" << disc << '_'; + } + + return; + } + else + mangleFunctionEncoding(cast<FunctionDecl>(DC)); + + Out << 'E'; + mangleUnqualifiedName(ND); +} + +void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) { + // <prefix> ::= <prefix> <unqualified-name> + // ::= <template-prefix> <template-args> + // ::= <template-param> + // ::= # empty + // ::= <substitution> + + while (isa<LinkageSpecDecl>(DC)) + DC = DC->getParent(); + + if (DC->isTranslationUnit()) + return; + + if (const BlockDecl *Block = dyn_cast<BlockDecl>(DC)) { + manglePrefix(DC->getParent(), NoFunction); + llvm::SmallString<64> Name; + llvm::raw_svector_ostream NameStream(Name); + Context.mangleBlock(Block, NameStream); + NameStream.flush(); + Out << Name.size() << Name; + return; + } + + if (mangleSubstitution(cast<NamedDecl>(DC))) + return; + + // Check if we have a template. + const TemplateArgumentList *TemplateArgs = 0; + if (const TemplateDecl *TD = isTemplate(cast<NamedDecl>(DC), TemplateArgs)) { + mangleTemplatePrefix(TD); + TemplateParameterList *TemplateParameters = TD->getTemplateParameters(); + mangleTemplateArgs(*TemplateParameters, *TemplateArgs); + } + else if(NoFunction && (isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC))) + return; + else if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(DC)) + mangleObjCMethodName(Method); + else { + manglePrefix(DC->getParent(), NoFunction); + mangleUnqualifiedName(cast<NamedDecl>(DC)); + } + + addSubstitution(cast<NamedDecl>(DC)); +} + +void CXXNameMangler::mangleTemplatePrefix(TemplateName Template) { + // <template-prefix> ::= <prefix> <template unqualified-name> + // ::= <template-param> + // ::= <substitution> + if (TemplateDecl *TD = Template.getAsTemplateDecl()) + return mangleTemplatePrefix(TD); + + if (QualifiedTemplateName *Qualified = Template.getAsQualifiedTemplateName()) + mangleUnresolvedScope(Qualified->getQualifier()); + + if (OverloadedTemplateStorage *Overloaded + = Template.getAsOverloadedTemplate()) { + mangleUnqualifiedName(0, (*Overloaded->begin())->getDeclName(), + UnknownArity); + return; + } + + DependentTemplateName *Dependent = Template.getAsDependentTemplateName(); + assert(Dependent && "Unknown template name kind?"); + mangleUnresolvedScope(Dependent->getQualifier()); + mangleUnscopedTemplateName(Template); +} + +void CXXNameMangler::mangleTemplatePrefix(const TemplateDecl *ND) { + // <template-prefix> ::= <prefix> <template unqualified-name> + // ::= <template-param> + // ::= <substitution> + // <template-template-param> ::= <template-param> + // <substitution> + + if (mangleSubstitution(ND)) + return; + + // <template-template-param> ::= <template-param> + if (const TemplateTemplateParmDecl *TTP + = dyn_cast<TemplateTemplateParmDecl>(ND)) { + mangleTemplateParameter(TTP->getIndex()); + return; + } + + manglePrefix(ND->getDeclContext()); + mangleUnqualifiedName(ND->getTemplatedDecl()); + addSubstitution(ND); +} + +/// Mangles a template name under the production <type>. Required for +/// template template arguments. +/// <type> ::= <class-enum-type> +/// ::= <template-param> +/// ::= <substitution> +void CXXNameMangler::mangleType(TemplateName TN) { + if (mangleSubstitution(TN)) + return; + + TemplateDecl *TD = 0; + + switch (TN.getKind()) { + case TemplateName::QualifiedTemplate: + TD = TN.getAsQualifiedTemplateName()->getTemplateDecl(); + goto HaveDecl; + + case TemplateName::Template: + TD = TN.getAsTemplateDecl(); + goto HaveDecl; + + HaveDecl: + if (isa<TemplateTemplateParmDecl>(TD)) + mangleTemplateParameter(cast<TemplateTemplateParmDecl>(TD)->getIndex()); + else + mangleName(TD); + break; + + case TemplateName::OverloadedTemplate: + llvm_unreachable("can't mangle an overloaded template name as a <type>"); + break; + + case TemplateName::DependentTemplate: { + const DependentTemplateName *Dependent = TN.getAsDependentTemplateName(); + assert(Dependent->isIdentifier()); + + // <class-enum-type> ::= <name> + // <name> ::= <nested-name> + mangleUnresolvedScope(Dependent->getQualifier()); + mangleSourceName(Dependent->getIdentifier()); + break; + } + + case TemplateName::SubstTemplateTemplateParmPack: { + SubstTemplateTemplateParmPackStorage *SubstPack + = TN.getAsSubstTemplateTemplateParmPack(); + mangleTemplateParameter(SubstPack->getParameterPack()->getIndex()); + break; + } + } + + addSubstitution(TN); +} + +void +CXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity) { + switch (OO) { + // <operator-name> ::= nw # new + case OO_New: Out << "nw"; break; + // ::= na # new[] + case OO_Array_New: Out << "na"; break; + // ::= dl # delete + case OO_Delete: Out << "dl"; break; + // ::= da # delete[] + case OO_Array_Delete: Out << "da"; break; + // ::= ps # + (unary) + // ::= pl # + (binary or unknown) + case OO_Plus: + Out << (Arity == 1? "ps" : "pl"); break; + // ::= ng # - (unary) + // ::= mi # - (binary or unknown) + case OO_Minus: + Out << (Arity == 1? "ng" : "mi"); break; + // ::= ad # & (unary) + // ::= an # & (binary or unknown) + case OO_Amp: + Out << (Arity == 1? "ad" : "an"); break; + // ::= de # * (unary) + // ::= ml # * (binary or unknown) + case OO_Star: + // Use binary when unknown. + Out << (Arity == 1? "de" : "ml"); break; + // ::= co # ~ + case OO_Tilde: Out << "co"; break; + // ::= dv # / + case OO_Slash: Out << "dv"; break; + // ::= rm # % + case OO_Percent: Out << "rm"; break; + // ::= or # | + case OO_Pipe: Out << "or"; break; + // ::= eo # ^ + case OO_Caret: Out << "eo"; break; + // ::= aS # = + case OO_Equal: Out << "aS"; break; + // ::= pL # += + case OO_PlusEqual: Out << "pL"; break; + // ::= mI # -= + case OO_MinusEqual: Out << "mI"; break; + // ::= mL # *= + case OO_StarEqual: Out << "mL"; break; + // ::= dV # /= + case OO_SlashEqual: Out << "dV"; break; + // ::= rM # %= + case OO_PercentEqual: Out << "rM"; break; + // ::= aN # &= + case OO_AmpEqual: Out << "aN"; break; + // ::= oR # |= + case OO_PipeEqual: Out << "oR"; break; + // ::= eO # ^= + case OO_CaretEqual: Out << "eO"; break; + // ::= ls # << + case OO_LessLess: Out << "ls"; break; + // ::= rs # >> + case OO_GreaterGreater: Out << "rs"; break; + // ::= lS # <<= + case OO_LessLessEqual: Out << "lS"; break; + // ::= rS # >>= + case OO_GreaterGreaterEqual: Out << "rS"; break; + // ::= eq # == + case OO_EqualEqual: Out << "eq"; break; + // ::= ne # != + case OO_ExclaimEqual: Out << "ne"; break; + // ::= lt # < + case OO_Less: Out << "lt"; break; + // ::= gt # > + case OO_Greater: Out << "gt"; break; + // ::= le # <= + case OO_LessEqual: Out << "le"; break; + // ::= ge # >= + case OO_GreaterEqual: Out << "ge"; break; + // ::= nt # ! + case OO_Exclaim: Out << "nt"; break; + // ::= aa # && + case OO_AmpAmp: Out << "aa"; break; + // ::= oo # || + case OO_PipePipe: Out << "oo"; break; + // ::= pp # ++ + case OO_PlusPlus: Out << "pp"; break; + // ::= mm # -- + case OO_MinusMinus: Out << "mm"; break; + // ::= cm # , + case OO_Comma: Out << "cm"; break; + // ::= pm # ->* + case OO_ArrowStar: Out << "pm"; break; + // ::= pt # -> + case OO_Arrow: Out << "pt"; break; + // ::= cl # () + case OO_Call: Out << "cl"; break; + // ::= ix # [] + case OO_Subscript: Out << "ix"; break; + + // ::= qu # ? + // The conditional operator can't be overloaded, but we still handle it when + // mangling expressions. + case OO_Conditional: Out << "qu"; break; + + case OO_None: + case NUM_OVERLOADED_OPERATORS: + assert(false && "Not an overloaded operator"); + break; + } +} + +void CXXNameMangler::mangleQualifiers(Qualifiers Quals) { + // <CV-qualifiers> ::= [r] [V] [K] # restrict (C99), volatile, const + if (Quals.hasRestrict()) + Out << 'r'; + if (Quals.hasVolatile()) + Out << 'V'; + if (Quals.hasConst()) + Out << 'K'; + + if (Quals.hasAddressSpace()) { + // Extension: + // + // <type> ::= U <address-space-number> + // + // where <address-space-number> is a source name consisting of 'AS' + // followed by the address space <number>. + llvm::SmallString<64> ASString; + ASString = "AS" + llvm::utostr_32(Quals.getAddressSpace()); + Out << 'U' << ASString.size() << ASString; + } + + // FIXME: For now, just drop all extension qualifiers on the floor. +} + +void CXXNameMangler::mangleRefQualifier(RefQualifierKind RefQualifier) { + // <ref-qualifier> ::= R # lvalue reference + // ::= O # rvalue-reference + // Proposal to Itanium C++ ABI list on 1/26/11 + switch (RefQualifier) { + case RQ_None: + break; + + case RQ_LValue: + Out << 'R'; + break; + + case RQ_RValue: + Out << 'O'; + break; + } +} + +void CXXNameMangler::mangleObjCMethodName(const ObjCMethodDecl *MD) { + Context.mangleObjCMethodName(MD, Out); +} + +void CXXNameMangler::mangleType(QualType nonCanon) { + // Only operate on the canonical type! + QualType canon = nonCanon.getCanonicalType(); + + SplitQualType split = canon.split(); + Qualifiers quals = split.second; + const Type *ty = split.first; + + bool isSubstitutable = quals || !isa<BuiltinType>(ty); + if (isSubstitutable && mangleSubstitution(canon)) + return; + + // If we're mangling a qualified array type, push the qualifiers to + // the element type. + if (quals && isa<ArrayType>(ty)) { + ty = Context.getASTContext().getAsArrayType(canon); + quals = Qualifiers(); + + // Note that we don't update canon: we want to add the + // substitution at the canonical type. + } + + if (quals) { + mangleQualifiers(quals); + // Recurse: even if the qualified type isn't yet substitutable, + // the unqualified type might be. + mangleType(QualType(ty, 0)); + } else { + switch (ty->getTypeClass()) { +#define ABSTRACT_TYPE(CLASS, PARENT) +#define NON_CANONICAL_TYPE(CLASS, PARENT) \ + case Type::CLASS: \ + llvm_unreachable("can't mangle non-canonical type " #CLASS "Type"); \ + return; +#define TYPE(CLASS, PARENT) \ + case Type::CLASS: \ + mangleType(static_cast<const CLASS##Type*>(ty)); \ + break; +#include "clang/AST/TypeNodes.def" + } + } + + // Add the substitution. + if (isSubstitutable) + addSubstitution(canon); +} + +void CXXNameMangler::mangleNameOrStandardSubstitution(const NamedDecl *ND) { + if (!mangleStandardSubstitution(ND)) + mangleName(ND); +} + +void CXXNameMangler::mangleType(const BuiltinType *T) { + // <type> ::= <builtin-type> + // <builtin-type> ::= v # void + // ::= w # wchar_t + // ::= b # bool + // ::= c # char + // ::= a # signed char + // ::= h # unsigned char + // ::= s # short + // ::= t # unsigned short + // ::= i # int + // ::= j # unsigned int + // ::= l # long + // ::= m # unsigned long + // ::= x # long long, __int64 + // ::= y # unsigned long long, __int64 + // ::= n # __int128 + // UNSUPPORTED: ::= o # unsigned __int128 + // ::= f # float + // ::= d # double + // ::= e # long double, __float80 + // UNSUPPORTED: ::= g # __float128 + // UNSUPPORTED: ::= Dd # IEEE 754r decimal floating point (64 bits) + // UNSUPPORTED: ::= De # IEEE 754r decimal floating point (128 bits) + // UNSUPPORTED: ::= Df # IEEE 754r decimal floating point (32 bits) + // UNSUPPORTED: ::= Dh # IEEE 754r half-precision floating point (16 bits) + // ::= Di # char32_t + // ::= Ds # char16_t + // ::= Dn # std::nullptr_t (i.e., decltype(nullptr)) + // ::= u <source-name> # vendor extended type + switch (T->getKind()) { + case BuiltinType::Void: Out << 'v'; break; + case BuiltinType::Bool: Out << 'b'; break; + case BuiltinType::Char_U: case BuiltinType::Char_S: Out << 'c'; break; + case BuiltinType::UChar: Out << 'h'; break; + case BuiltinType::UShort: Out << 't'; break; + case BuiltinType::UInt: Out << 'j'; break; + case BuiltinType::ULong: Out << 'm'; break; + case BuiltinType::ULongLong: Out << 'y'; break; + case BuiltinType::UInt128: Out << 'o'; break; + case BuiltinType::SChar: Out << 'a'; break; + case BuiltinType::WChar_S: + case BuiltinType::WChar_U: Out << 'w'; break; + case BuiltinType::Char16: Out << "Ds"; break; + case BuiltinType::Char32: Out << "Di"; break; + case BuiltinType::Short: Out << 's'; break; + case BuiltinType::Int: Out << 'i'; break; + case BuiltinType::Long: Out << 'l'; break; + case BuiltinType::LongLong: Out << 'x'; break; + case BuiltinType::Int128: Out << 'n'; break; + case BuiltinType::Float: Out << 'f'; break; + case BuiltinType::Double: Out << 'd'; break; + case BuiltinType::LongDouble: Out << 'e'; break; + case BuiltinType::NullPtr: Out << "Dn"; break; + + case BuiltinType::Overload: + case BuiltinType::Dependent: + assert(false && + "Overloaded and dependent types shouldn't get to name mangling"); + break; + case BuiltinType::ObjCId: Out << "11objc_object"; break; + case BuiltinType::ObjCClass: Out << "10objc_class"; break; + case BuiltinType::ObjCSel: Out << "13objc_selector"; break; + } +} + +// <type> ::= <function-type> +// <function-type> ::= F [Y] <bare-function-type> E +void CXXNameMangler::mangleType(const FunctionProtoType *T) { + Out << 'F'; + // FIXME: We don't have enough information in the AST to produce the 'Y' + // encoding for extern "C" function types. + mangleBareFunctionType(T, /*MangleReturnType=*/true); + Out << 'E'; +} +void CXXNameMangler::mangleType(const FunctionNoProtoType *T) { + llvm_unreachable("Can't mangle K&R function prototypes"); +} +void CXXNameMangler::mangleBareFunctionType(const FunctionType *T, + bool MangleReturnType) { + // We should never be mangling something without a prototype. + const FunctionProtoType *Proto = cast<FunctionProtoType>(T); + + // <bare-function-type> ::= <signature type>+ + if (MangleReturnType) + mangleType(Proto->getResultType()); + + if (Proto->getNumArgs() == 0 && !Proto->isVariadic()) { + // <builtin-type> ::= v # void + Out << 'v'; + return; + } + + for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(), + ArgEnd = Proto->arg_type_end(); + Arg != ArgEnd; ++Arg) + mangleType(*Arg); + + // <builtin-type> ::= z # ellipsis + if (Proto->isVariadic()) + Out << 'z'; +} + +// <type> ::= <class-enum-type> +// <class-enum-type> ::= <name> +void CXXNameMangler::mangleType(const UnresolvedUsingType *T) { + mangleName(T->getDecl()); +} + +// <type> ::= <class-enum-type> +// <class-enum-type> ::= <name> +void CXXNameMangler::mangleType(const EnumType *T) { + mangleType(static_cast<const TagType*>(T)); +} +void CXXNameMangler::mangleType(const RecordType *T) { + mangleType(static_cast<const TagType*>(T)); +} +void CXXNameMangler::mangleType(const TagType *T) { + mangleName(T->getDecl()); +} + +// <type> ::= <array-type> +// <array-type> ::= A <positive dimension number> _ <element type> +// ::= A [<dimension expression>] _ <element type> +void CXXNameMangler::mangleType(const ConstantArrayType *T) { + Out << 'A' << T->getSize() << '_'; + mangleType(T->getElementType()); +} +void CXXNameMangler::mangleType(const VariableArrayType *T) { + Out << 'A'; + // decayed vla types (size 0) will just be skipped. + if (T->getSizeExpr()) + mangleExpression(T->getSizeExpr()); + Out << '_'; + mangleType(T->getElementType()); +} +void CXXNameMangler::mangleType(const DependentSizedArrayType *T) { + Out << 'A'; + mangleExpression(T->getSizeExpr()); + Out << '_'; + mangleType(T->getElementType()); +} +void CXXNameMangler::mangleType(const IncompleteArrayType *T) { + Out << "A_"; + mangleType(T->getElementType()); +} + +// <type> ::= <pointer-to-member-type> +// <pointer-to-member-type> ::= M <class type> <member type> +void CXXNameMangler::mangleType(const MemberPointerType *T) { + Out << 'M'; + mangleType(QualType(T->getClass(), 0)); + QualType PointeeType = T->getPointeeType(); + if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(PointeeType)) { + mangleQualifiers(Qualifiers::fromCVRMask(FPT->getTypeQuals())); + mangleRefQualifier(FPT->getRefQualifier()); + mangleType(FPT); + + // Itanium C++ ABI 5.1.8: + // + // The type of a non-static member function is considered to be different, + // for the purposes of substitution, from the type of a namespace-scope or + // static member function whose type appears similar. The types of two + // non-static member functions are considered to be different, for the + // purposes of substitution, if the functions are members of different + // classes. In other words, for the purposes of substitution, the class of + // which the function is a member is considered part of the type of + // function. + + // We increment the SeqID here to emulate adding an entry to the + // substitution table. We can't actually add it because we don't want this + // particular function type to be substituted. + ++SeqID; + } else + mangleType(PointeeType); +} + +// <type> ::= <template-param> +void CXXNameMangler::mangleType(const TemplateTypeParmType *T) { + mangleTemplateParameter(T->getIndex()); +} + +// <type> ::= <template-param> +void CXXNameMangler::mangleType(const SubstTemplateTypeParmPackType *T) { + mangleTemplateParameter(T->getReplacedParameter()->getIndex()); +} + +// <type> ::= P <type> # pointer-to +void CXXNameMangler::mangleType(const PointerType *T) { + Out << 'P'; + mangleType(T->getPointeeType()); +} +void CXXNameMangler::mangleType(const ObjCObjectPointerType *T) { + Out << 'P'; + mangleType(T->getPointeeType()); +} + +// <type> ::= R <type> # reference-to +void CXXNameMangler::mangleType(const LValueReferenceType *T) { + Out << 'R'; + mangleType(T->getPointeeType()); +} + +// <type> ::= O <type> # rvalue reference-to (C++0x) +void CXXNameMangler::mangleType(const RValueReferenceType *T) { + Out << 'O'; + mangleType(T->getPointeeType()); +} + +// <type> ::= C <type> # complex pair (C 2000) +void CXXNameMangler::mangleType(const ComplexType *T) { + Out << 'C'; + mangleType(T->getElementType()); +} + +// ARM's ABI for Neon vector types specifies that they should be mangled as +// if they are structs (to match ARM's initial implementation). The +// vector type must be one of the special types predefined by ARM. +void CXXNameMangler::mangleNeonVectorType(const VectorType *T) { + QualType EltType = T->getElementType(); + assert(EltType->isBuiltinType() && "Neon vector element not a BuiltinType"); + const char *EltName = 0; + if (T->getVectorKind() == VectorType::NeonPolyVector) { + switch (cast<BuiltinType>(EltType)->getKind()) { + case BuiltinType::SChar: EltName = "poly8_t"; break; + case BuiltinType::Short: EltName = "poly16_t"; break; + default: llvm_unreachable("unexpected Neon polynomial vector element type"); + } + } else { + switch (cast<BuiltinType>(EltType)->getKind()) { + case BuiltinType::SChar: EltName = "int8_t"; break; + case BuiltinType::UChar: EltName = "uint8_t"; break; + case BuiltinType::Short: EltName = "int16_t"; break; + case BuiltinType::UShort: EltName = "uint16_t"; break; + case BuiltinType::Int: EltName = "int32_t"; break; + case BuiltinType::UInt: EltName = "uint32_t"; break; + case BuiltinType::LongLong: EltName = "int64_t"; break; + case BuiltinType::ULongLong: EltName = "uint64_t"; break; + case BuiltinType::Float: EltName = "float32_t"; break; + default: llvm_unreachable("unexpected Neon vector element type"); + } + } + const char *BaseName = 0; + unsigned BitSize = (T->getNumElements() * + getASTContext().getTypeSize(EltType)); + if (BitSize == 64) + BaseName = "__simd64_"; + else { + assert(BitSize == 128 && "Neon vector type not 64 or 128 bits"); + BaseName = "__simd128_"; + } + Out << strlen(BaseName) + strlen(EltName); + Out << BaseName << EltName; +} + +// GNU extension: vector types +// <type> ::= <vector-type> +// <vector-type> ::= Dv <positive dimension number> _ +// <extended element type> +// ::= Dv [<dimension expression>] _ <element type> +// <extended element type> ::= <element type> +// ::= p # AltiVec vector pixel +void CXXNameMangler::mangleType(const VectorType *T) { + if ((T->getVectorKind() == VectorType::NeonVector || + T->getVectorKind() == VectorType::NeonPolyVector)) { + mangleNeonVectorType(T); + return; + } + Out << "Dv" << T->getNumElements() << '_'; + if (T->getVectorKind() == VectorType::AltiVecPixel) + Out << 'p'; + else if (T->getVectorKind() == VectorType::AltiVecBool) + Out << 'b'; + else + mangleType(T->getElementType()); +} +void CXXNameMangler::mangleType(const ExtVectorType *T) { + mangleType(static_cast<const VectorType*>(T)); +} +void CXXNameMangler::mangleType(const DependentSizedExtVectorType *T) { + Out << "Dv"; + mangleExpression(T->getSizeExpr()); + Out << '_'; + mangleType(T->getElementType()); +} + +void CXXNameMangler::mangleType(const PackExpansionType *T) { + // <type> ::= Dp <type> # pack expansion (C++0x) + Out << "Dp"; + mangleType(T->getPattern()); +} + +void CXXNameMangler::mangleType(const ObjCInterfaceType *T) { + mangleSourceName(T->getDecl()->getIdentifier()); +} + +void CXXNameMangler::mangleType(const ObjCObjectType *T) { + // We don't allow overloading by different protocol qualification, + // so mangling them isn't necessary. + mangleType(T->getBaseType()); +} + +void CXXNameMangler::mangleType(const BlockPointerType *T) { + Out << "U13block_pointer"; + mangleType(T->getPointeeType()); +} + +void CXXNameMangler::mangleType(const InjectedClassNameType *T) { + // Mangle injected class name types as if the user had written the + // specialization out fully. It may not actually be possible to see + // this mangling, though. + mangleType(T->getInjectedSpecializationType()); +} + +void CXXNameMangler::mangleType(const TemplateSpecializationType *T) { + if (TemplateDecl *TD = T->getTemplateName().getAsTemplateDecl()) { + mangleName(TD, T->getArgs(), T->getNumArgs()); + } else { + if (mangleSubstitution(QualType(T, 0))) + return; + + mangleTemplatePrefix(T->getTemplateName()); + + // FIXME: GCC does not appear to mangle the template arguments when + // the template in question is a dependent template name. Should we + // emulate that badness? + mangleTemplateArgs(T->getTemplateName(), T->getArgs(), T->getNumArgs()); + addSubstitution(QualType(T, 0)); + } +} + +void CXXNameMangler::mangleType(const DependentNameType *T) { + // Typename types are always nested + Out << 'N'; + mangleUnresolvedScope(T->getQualifier()); + mangleSourceName(T->getIdentifier()); + Out << 'E'; +} + +void CXXNameMangler::mangleType(const DependentTemplateSpecializationType *T) { + // Dependently-scoped template types are always nested + Out << 'N'; + + // TODO: avoid making this TemplateName. + TemplateName Prefix = + getASTContext().getDependentTemplateName(T->getQualifier(), + T->getIdentifier()); + mangleTemplatePrefix(Prefix); + + // FIXME: GCC does not appear to mangle the template arguments when + // the template in question is a dependent template name. Should we + // emulate that badness? + mangleTemplateArgs(Prefix, T->getArgs(), T->getNumArgs()); + Out << 'E'; +} + +void CXXNameMangler::mangleType(const TypeOfType *T) { + // FIXME: this is pretty unsatisfactory, but there isn't an obvious + // "extension with parameters" mangling. + Out << "u6typeof"; +} + +void CXXNameMangler::mangleType(const TypeOfExprType *T) { + // FIXME: this is pretty unsatisfactory, but there isn't an obvious + // "extension with parameters" mangling. + Out << "u6typeof"; +} + +void CXXNameMangler::mangleType(const DecltypeType *T) { + Expr *E = T->getUnderlyingExpr(); + + // type ::= Dt <expression> E # decltype of an id-expression + // # or class member access + // ::= DT <expression> E # decltype of an expression + + // This purports to be an exhaustive list of id-expressions and + // class member accesses. Note that we do not ignore parentheses; + // parentheses change the semantics of decltype for these + // expressions (and cause the mangler to use the other form). + if (isa<DeclRefExpr>(E) || + isa<MemberExpr>(E) || + isa<UnresolvedLookupExpr>(E) || + isa<DependentScopeDeclRefExpr>(E) || + isa<CXXDependentScopeMemberExpr>(E) || + isa<UnresolvedMemberExpr>(E)) + Out << "Dt"; + else + Out << "DT"; + mangleExpression(E); + Out << 'E'; +} + +void CXXNameMangler::mangleType(const AutoType *T) { + QualType D = T->getDeducedType(); + assert(!D.isNull() && "can't mangle undeduced auto type"); + mangleType(D); +} + +void CXXNameMangler::mangleIntegerLiteral(QualType T, + const llvm::APSInt &Value) { + // <expr-primary> ::= L <type> <value number> E # integer literal + Out << 'L'; + + mangleType(T); + if (T->isBooleanType()) { + // Boolean values are encoded as 0/1. + Out << (Value.getBoolValue() ? '1' : '0'); + } else { + mangleNumber(Value); + } + Out << 'E'; + +} + +/// Mangles a member expression. Implicit accesses are not handled, +/// but that should be okay, because you shouldn't be able to +/// make an implicit access in a function template declaration. +void CXXNameMangler::mangleMemberExpr(const Expr *Base, + bool IsArrow, + NestedNameSpecifier *Qualifier, + DeclarationName Member, + unsigned Arity) { + // gcc-4.4 uses 'dt' for dot expressions, which is reasonable. + // OTOH, gcc also mangles the name as an expression. + Out << (IsArrow ? "pt" : "dt"); + mangleExpression(Base); + mangleUnresolvedName(Qualifier, Member, Arity); +} + +void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) { + // <expression> ::= <unary operator-name> <expression> + // ::= <binary operator-name> <expression> <expression> + // ::= <trinary operator-name> <expression> <expression> <expression> + // ::= cl <expression>* E # call + // ::= cv <type> expression # conversion with one argument + // ::= cv <type> _ <expression>* E # conversion with a different number of arguments + // ::= st <type> # sizeof (a type) + // ::= at <type> # alignof (a type) + // ::= <template-param> + // ::= <function-param> + // ::= sr <type> <unqualified-name> # dependent name + // ::= sr <type> <unqualified-name> <template-args> # dependent template-id + // ::= sZ <template-param> # size of a parameter pack + // ::= sZ <function-param> # size of a function parameter pack + // ::= <expr-primary> + // <expr-primary> ::= L <type> <value number> E # integer literal + // ::= L <type <value float> E # floating literal + // ::= L <mangled-name> E # external name + switch (E->getStmtClass()) { + case Expr::NoStmtClass: +#define ABSTRACT_STMT(Type) +#define EXPR(Type, Base) +#define STMT(Type, Base) \ + case Expr::Type##Class: +#include "clang/AST/StmtNodes.inc" + // fallthrough + + // These all can only appear in local or variable-initialization + // contexts and so should never appear in a mangling. + case Expr::AddrLabelExprClass: + case Expr::BlockDeclRefExprClass: + case Expr::CXXThisExprClass: + case Expr::DesignatedInitExprClass: + case Expr::ImplicitValueInitExprClass: + case Expr::InitListExprClass: + case Expr::ParenListExprClass: + case Expr::CXXScalarValueInitExprClass: + llvm_unreachable("unexpected statement kind"); + break; + + // FIXME: invent manglings for all these. + case Expr::BlockExprClass: + case Expr::CXXPseudoDestructorExprClass: + case Expr::ChooseExprClass: + case Expr::CompoundLiteralExprClass: + case Expr::ExtVectorElementExprClass: + case Expr::ObjCEncodeExprClass: + case Expr::ObjCIsaExprClass: + case Expr::ObjCIvarRefExprClass: + case Expr::ObjCMessageExprClass: + case Expr::ObjCPropertyRefExprClass: + case Expr::ObjCProtocolExprClass: + case Expr::ObjCSelectorExprClass: + case Expr::ObjCStringLiteralClass: + case Expr::OffsetOfExprClass: + case Expr::PredefinedExprClass: + case Expr::ShuffleVectorExprClass: + case Expr::StmtExprClass: + case Expr::UnaryTypeTraitExprClass: + case Expr::BinaryTypeTraitExprClass: + case Expr::VAArgExprClass: + case Expr::CXXUuidofExprClass: + case Expr::CXXNoexceptExprClass: + case Expr::CUDAKernelCallExprClass: { + // As bad as this diagnostic is, it's better than crashing. + Diagnostic &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Error, + "cannot yet mangle expression type %0"); + Diags.Report(E->getExprLoc(), DiagID) + << E->getStmtClassName() << E->getSourceRange(); + break; + } + + // Even gcc-4.5 doesn't mangle this. + case Expr::BinaryConditionalOperatorClass: { + Diagnostic &Diags = Context.getDiags(); + unsigned DiagID = + Diags.getCustomDiagID(Diagnostic::Error, + "?: operator with omitted middle operand cannot be mangled"); + Diags.Report(E->getExprLoc(), DiagID) + << E->getStmtClassName() << E->getSourceRange(); + break; + } + + // These are used for internal purposes and cannot be meaningfully mangled. + case Expr::OpaqueValueExprClass: + llvm_unreachable("cannot mangle opaque value; mangling wrong thing?"); + + case Expr::CXXDefaultArgExprClass: + mangleExpression(cast<CXXDefaultArgExpr>(E)->getExpr(), Arity); + break; + + case Expr::CXXMemberCallExprClass: // fallthrough + case Expr::CallExprClass: { + const CallExpr *CE = cast<CallExpr>(E); + Out << "cl"; + mangleExpression(CE->getCallee(), CE->getNumArgs()); + for (unsigned I = 0, N = CE->getNumArgs(); I != N; ++I) + mangleExpression(CE->getArg(I)); + Out << 'E'; + break; + } + + case Expr::CXXNewExprClass: { + // Proposal from David Vandervoorde, 2010.06.30 + const CXXNewExpr *New = cast<CXXNewExpr>(E); + if (New->isGlobalNew()) Out << "gs"; + Out << (New->isArray() ? "na" : "nw"); + for (CXXNewExpr::const_arg_iterator I = New->placement_arg_begin(), + E = New->placement_arg_end(); I != E; ++I) + mangleExpression(*I); + Out << '_'; + mangleType(New->getAllocatedType()); + if (New->hasInitializer()) { + Out << "pi"; + for (CXXNewExpr::const_arg_iterator I = New->constructor_arg_begin(), + E = New->constructor_arg_end(); I != E; ++I) + mangleExpression(*I); + } + Out << 'E'; + break; + } + + case Expr::MemberExprClass: { + const MemberExpr *ME = cast<MemberExpr>(E); + mangleMemberExpr(ME->getBase(), ME->isArrow(), + ME->getQualifier(), ME->getMemberDecl()->getDeclName(), + Arity); + break; + } + + case Expr::UnresolvedMemberExprClass: { + const UnresolvedMemberExpr *ME = cast<UnresolvedMemberExpr>(E); + mangleMemberExpr(ME->getBase(), ME->isArrow(), + ME->getQualifier(), ME->getMemberName(), + Arity); + if (ME->hasExplicitTemplateArgs()) + mangleTemplateArgs(ME->getExplicitTemplateArgs()); + break; + } + + case Expr::CXXDependentScopeMemberExprClass: { + const CXXDependentScopeMemberExpr *ME + = cast<CXXDependentScopeMemberExpr>(E); + mangleMemberExpr(ME->getBase(), ME->isArrow(), + ME->getQualifier(), ME->getMember(), + Arity); + if (ME->hasExplicitTemplateArgs()) + mangleTemplateArgs(ME->getExplicitTemplateArgs()); + break; + } + + case Expr::UnresolvedLookupExprClass: { + // The ABI doesn't cover how to mangle overload sets, so we mangle + // using something as close as possible to the original lookup + // expression. + const UnresolvedLookupExpr *ULE = cast<UnresolvedLookupExpr>(E); + mangleUnresolvedName(ULE->getQualifier(), ULE->getName(), Arity); + if (ULE->hasExplicitTemplateArgs()) + mangleTemplateArgs(ULE->getExplicitTemplateArgs()); + break; + } + + case Expr::CXXUnresolvedConstructExprClass: { + const CXXUnresolvedConstructExpr *CE = cast<CXXUnresolvedConstructExpr>(E); + unsigned N = CE->arg_size(); + + Out << "cv"; + mangleType(CE->getType()); + if (N != 1) Out << '_'; + for (unsigned I = 0; I != N; ++I) mangleExpression(CE->getArg(I)); + if (N != 1) Out << 'E'; + break; + } + + case Expr::CXXTemporaryObjectExprClass: + case Expr::CXXConstructExprClass: { + const CXXConstructExpr *CE = cast<CXXConstructExpr>(E); + unsigned N = CE->getNumArgs(); + + Out << "cv"; + mangleType(CE->getType()); + if (N != 1) Out << '_'; + for (unsigned I = 0; I != N; ++I) mangleExpression(CE->getArg(I)); + if (N != 1) Out << 'E'; + break; + } + + case Expr::SizeOfAlignOfExprClass: { + const SizeOfAlignOfExpr *SAE = cast<SizeOfAlignOfExpr>(E); + if (SAE->isSizeOf()) Out << 's'; + else Out << 'a'; + if (SAE->isArgumentType()) { + Out << 't'; + mangleType(SAE->getArgumentType()); + } else { + Out << 'z'; + mangleExpression(SAE->getArgumentExpr()); + } + break; + } + + case Expr::CXXThrowExprClass: { + const CXXThrowExpr *TE = cast<CXXThrowExpr>(E); + + // Proposal from David Vandervoorde, 2010.06.30 + if (TE->getSubExpr()) { + Out << "tw"; + mangleExpression(TE->getSubExpr()); + } else { + Out << "tr"; + } + break; + } + + case Expr::CXXTypeidExprClass: { + const CXXTypeidExpr *TIE = cast<CXXTypeidExpr>(E); + + // Proposal from David Vandervoorde, 2010.06.30 + if (TIE->isTypeOperand()) { + Out << "ti"; + mangleType(TIE->getTypeOperand()); + } else { + Out << "te"; + mangleExpression(TIE->getExprOperand()); + } + break; + } + + case Expr::CXXDeleteExprClass: { + const CXXDeleteExpr *DE = cast<CXXDeleteExpr>(E); + + // Proposal from David Vandervoorde, 2010.06.30 + if (DE->isGlobalDelete()) Out << "gs"; + Out << (DE->isArrayForm() ? "da" : "dl"); + mangleExpression(DE->getArgument()); + break; + } + + case Expr::UnaryOperatorClass: { + const UnaryOperator *UO = cast<UnaryOperator>(E); + mangleOperatorName(UnaryOperator::getOverloadedOperator(UO->getOpcode()), + /*Arity=*/1); + mangleExpression(UO->getSubExpr()); + break; + } + + case Expr::ArraySubscriptExprClass: { + const ArraySubscriptExpr *AE = cast<ArraySubscriptExpr>(E); + + // Array subscript is treated as a syntactically wierd form of + // binary operator. + Out << "ix"; + mangleExpression(AE->getLHS()); + mangleExpression(AE->getRHS()); + break; + } + + case Expr::CompoundAssignOperatorClass: // fallthrough + case Expr::BinaryOperatorClass: { + const BinaryOperator *BO = cast<BinaryOperator>(E); + mangleOperatorName(BinaryOperator::getOverloadedOperator(BO->getOpcode()), + /*Arity=*/2); + mangleExpression(BO->getLHS()); + mangleExpression(BO->getRHS()); + break; + } + + case Expr::ConditionalOperatorClass: { + const ConditionalOperator *CO = cast<ConditionalOperator>(E); + mangleOperatorName(OO_Conditional, /*Arity=*/3); + mangleExpression(CO->getCond()); + mangleExpression(CO->getLHS(), Arity); + mangleExpression(CO->getRHS(), Arity); + break; + } + + case Expr::ImplicitCastExprClass: { + mangleExpression(cast<ImplicitCastExpr>(E)->getSubExpr(), Arity); + break; + } + + case Expr::CStyleCastExprClass: + case Expr::CXXStaticCastExprClass: + case Expr::CXXDynamicCastExprClass: + case Expr::CXXReinterpretCastExprClass: + case Expr::CXXConstCastExprClass: + case Expr::CXXFunctionalCastExprClass: { + const ExplicitCastExpr *ECE = cast<ExplicitCastExpr>(E); + Out << "cv"; + mangleType(ECE->getType()); + mangleExpression(ECE->getSubExpr()); + break; + } + + case Expr::CXXOperatorCallExprClass: { + const CXXOperatorCallExpr *CE = cast<CXXOperatorCallExpr>(E); + unsigned NumArgs = CE->getNumArgs(); + mangleOperatorName(CE->getOperator(), /*Arity=*/NumArgs); + // Mangle the arguments. + for (unsigned i = 0; i != NumArgs; ++i) + mangleExpression(CE->getArg(i)); + break; + } + + case Expr::ParenExprClass: + mangleExpression(cast<ParenExpr>(E)->getSubExpr(), Arity); + break; + + case Expr::DeclRefExprClass: { + const NamedDecl *D = cast<DeclRefExpr>(E)->getDecl(); + + switch (D->getKind()) { + default: + // <expr-primary> ::= L <mangled-name> E # external name + Out << 'L'; + mangle(D, "_Z"); + Out << 'E'; + break; + + case Decl::EnumConstant: { + const EnumConstantDecl *ED = cast<EnumConstantDecl>(D); + mangleIntegerLiteral(ED->getType(), ED->getInitVal()); + break; + } + + case Decl::NonTypeTemplateParm: { + const NonTypeTemplateParmDecl *PD = cast<NonTypeTemplateParmDecl>(D); + mangleTemplateParameter(PD->getIndex()); + break; + } + + } + + break; + } + + case Expr::SubstNonTypeTemplateParmPackExprClass: + mangleTemplateParameter( + cast<SubstNonTypeTemplateParmPackExpr>(E)->getParameterPack()->getIndex()); + break; + + case Expr::DependentScopeDeclRefExprClass: { + const DependentScopeDeclRefExpr *DRE = cast<DependentScopeDeclRefExpr>(E); + NestedNameSpecifier *NNS = DRE->getQualifier(); + const Type *QTy = NNS->getAsType(); + + // When we're dealing with a nested-name-specifier that has just a + // dependent identifier in it, mangle that as a typename. FIXME: + // It isn't clear that we ever actually want to have such a + // nested-name-specifier; why not just represent it as a typename type? + if (!QTy && NNS->getAsIdentifier() && NNS->getPrefix()) { + QTy = getASTContext().getDependentNameType(ETK_Typename, + NNS->getPrefix(), + NNS->getAsIdentifier()) + .getTypePtr(); + } + assert(QTy && "Qualifier was not type!"); + + // ::= sr <type> <unqualified-name> # dependent name + // ::= sr <type> <unqualified-name> <template-args> # dependent template-id + Out << "sr"; + mangleType(QualType(QTy, 0)); + mangleUnqualifiedName(0, DRE->getDeclName(), Arity); + if (DRE->hasExplicitTemplateArgs()) + mangleTemplateArgs(DRE->getExplicitTemplateArgs()); + + break; + } + + case Expr::CXXBindTemporaryExprClass: + mangleExpression(cast<CXXBindTemporaryExpr>(E)->getSubExpr()); + break; + + case Expr::ExprWithCleanupsClass: + mangleExpression(cast<ExprWithCleanups>(E)->getSubExpr(), Arity); + break; + + case Expr::FloatingLiteralClass: { + const FloatingLiteral *FL = cast<FloatingLiteral>(E); + Out << 'L'; + mangleType(FL->getType()); + mangleFloat(FL->getValue()); + Out << 'E'; + break; + } + + case Expr::CharacterLiteralClass: + Out << 'L'; + mangleType(E->getType()); + Out << cast<CharacterLiteral>(E)->getValue(); + Out << 'E'; + break; + + case Expr::CXXBoolLiteralExprClass: + Out << "Lb"; + Out << (cast<CXXBoolLiteralExpr>(E)->getValue() ? '1' : '0'); + Out << 'E'; + break; + + case Expr::IntegerLiteralClass: { + llvm::APSInt Value(cast<IntegerLiteral>(E)->getValue()); + if (E->getType()->isSignedIntegerType()) + Value.setIsSigned(true); + mangleIntegerLiteral(E->getType(), Value); + break; + } + + case Expr::ImaginaryLiteralClass: { + const ImaginaryLiteral *IE = cast<ImaginaryLiteral>(E); + // Mangle as if a complex literal. + // Proposal from David Vandevoorde, 2010.06.30. + Out << 'L'; + mangleType(E->getType()); + if (const FloatingLiteral *Imag = + dyn_cast<FloatingLiteral>(IE->getSubExpr())) { + // Mangle a floating-point zero of the appropriate type. + mangleFloat(llvm::APFloat(Imag->getValue().getSemantics())); + Out << '_'; + mangleFloat(Imag->getValue()); + } else { + Out << "0_"; + llvm::APSInt Value(cast<IntegerLiteral>(IE->getSubExpr())->getValue()); + if (IE->getSubExpr()->getType()->isSignedIntegerType()) + Value.setIsSigned(true); + mangleNumber(Value); + } + Out << 'E'; + break; + } + + case Expr::StringLiteralClass: { + // Revised proposal from David Vandervoorde, 2010.07.15. + Out << 'L'; + assert(isa<ConstantArrayType>(E->getType())); + mangleType(E->getType()); + Out << 'E'; + break; + } + + case Expr::GNUNullExprClass: + // FIXME: should this really be mangled the same as nullptr? + // fallthrough + + case Expr::CXXNullPtrLiteralExprClass: { + // Proposal from David Vandervoorde, 2010.06.30, as + // modified by ABI list discussion. + Out << "LDnE"; + break; + } + + case Expr::PackExpansionExprClass: + Out << "sp"; + mangleExpression(cast<PackExpansionExpr>(E)->getPattern()); + break; + + case Expr::SizeOfPackExprClass: { + Out << "sZ"; + const NamedDecl *Pack = cast<SizeOfPackExpr>(E)->getPack(); + if (const TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Pack)) + mangleTemplateParameter(TTP->getIndex()); + else if (const NonTypeTemplateParmDecl *NTTP + = dyn_cast<NonTypeTemplateParmDecl>(Pack)) + mangleTemplateParameter(NTTP->getIndex()); + else if (const TemplateTemplateParmDecl *TempTP + = dyn_cast<TemplateTemplateParmDecl>(Pack)) + mangleTemplateParameter(TempTP->getIndex()); + else { + // Note: proposed by Mike Herrick on 11/30/10 + // <expression> ::= sZ <function-param> # size of function parameter pack + Diagnostic &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Error, + "cannot mangle sizeof...(function parameter pack)"); + Diags.Report(DiagID); + return; + } + } + } +} + +void CXXNameMangler::mangleCXXCtorType(CXXCtorType T) { + // <ctor-dtor-name> ::= C1 # complete object constructor + // ::= C2 # base object constructor + // ::= C3 # complete object allocating constructor + // + switch (T) { + case Ctor_Complete: + Out << "C1"; + break; + case Ctor_Base: + Out << "C2"; + break; + case Ctor_CompleteAllocating: + Out << "C3"; + break; + } +} + +void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) { + // <ctor-dtor-name> ::= D0 # deleting destructor + // ::= D1 # complete object destructor + // ::= D2 # base object destructor + // + switch (T) { + case Dtor_Deleting: + Out << "D0"; + break; + case Dtor_Complete: + Out << "D1"; + break; + case Dtor_Base: + Out << "D2"; + break; + } +} + +void CXXNameMangler::mangleTemplateArgs( + const ExplicitTemplateArgumentList &TemplateArgs) { + // <template-args> ::= I <template-arg>+ E + Out << 'I'; + for (unsigned I = 0, E = TemplateArgs.NumTemplateArgs; I != E; ++I) + mangleTemplateArg(0, TemplateArgs.getTemplateArgs()[I].getArgument()); + Out << 'E'; +} + +void CXXNameMangler::mangleTemplateArgs(TemplateName Template, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs) { + if (TemplateDecl *TD = Template.getAsTemplateDecl()) + return mangleTemplateArgs(*TD->getTemplateParameters(), TemplateArgs, + NumTemplateArgs); + + // <template-args> ::= I <template-arg>+ E + Out << 'I'; + for (unsigned i = 0; i != NumTemplateArgs; ++i) + mangleTemplateArg(0, TemplateArgs[i]); + Out << 'E'; +} + +void CXXNameMangler::mangleTemplateArgs(const TemplateParameterList &PL, + const TemplateArgumentList &AL) { + // <template-args> ::= I <template-arg>+ E + Out << 'I'; + for (unsigned i = 0, e = AL.size(); i != e; ++i) + mangleTemplateArg(PL.getParam(i), AL[i]); + Out << 'E'; +} + +void CXXNameMangler::mangleTemplateArgs(const TemplateParameterList &PL, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs) { + // <template-args> ::= I <template-arg>+ E + Out << 'I'; + for (unsigned i = 0; i != NumTemplateArgs; ++i) + mangleTemplateArg(PL.getParam(i), TemplateArgs[i]); + Out << 'E'; +} + +void CXXNameMangler::mangleTemplateArg(const NamedDecl *P, + const TemplateArgument &A) { + // <template-arg> ::= <type> # type or template + // ::= X <expression> E # expression + // ::= <expr-primary> # simple expressions + // ::= J <template-arg>* E # argument pack + // ::= sp <expression> # pack expansion of (C++0x) + switch (A.getKind()) { + case TemplateArgument::Null: + llvm_unreachable("Cannot mangle NULL template argument"); + + case TemplateArgument::Type: + mangleType(A.getAsType()); + break; + case TemplateArgument::Template: + // This is mangled as <type>. + mangleType(A.getAsTemplate()); + break; + case TemplateArgument::TemplateExpansion: + // <type> ::= Dp <type> # pack expansion (C++0x) + Out << "Dp"; + mangleType(A.getAsTemplateOrTemplatePattern()); + break; + case TemplateArgument::Expression: + Out << 'X'; + mangleExpression(A.getAsExpr()); + Out << 'E'; + break; + case TemplateArgument::Integral: + mangleIntegerLiteral(A.getIntegralType(), *A.getAsIntegral()); + break; + case TemplateArgument::Declaration: { + assert(P && "Missing template parameter for declaration argument"); + // <expr-primary> ::= L <mangled-name> E # external name + + // Clang produces AST's where pointer-to-member-function expressions + // and pointer-to-function expressions are represented as a declaration not + // an expression. We compensate for it here to produce the correct mangling. + NamedDecl *D = cast<NamedDecl>(A.getAsDecl()); + const NonTypeTemplateParmDecl *Parameter = cast<NonTypeTemplateParmDecl>(P); + bool compensateMangling = D->isCXXClassMember() && + !Parameter->getType()->isReferenceType(); + if (compensateMangling) { + Out << 'X'; + mangleOperatorName(OO_Amp, 1); + } + + Out << 'L'; + // References to external entities use the mangled name; if the name would + // not normally be manged then mangle it as unqualified. + // + // FIXME: The ABI specifies that external names here should have _Z, but + // gcc leaves this off. + if (compensateMangling) + mangle(D, "_Z"); + else + mangle(D, "Z"); + Out << 'E'; + + if (compensateMangling) + Out << 'E'; + + break; + } + + case TemplateArgument::Pack: { + // Note: proposal by Mike Herrick on 12/20/10 + Out << 'J'; + for (TemplateArgument::pack_iterator PA = A.pack_begin(), + PAEnd = A.pack_end(); + PA != PAEnd; ++PA) + mangleTemplateArg(P, *PA); + Out << 'E'; + } + } +} + +void CXXNameMangler::mangleTemplateParameter(unsigned Index) { + // <template-param> ::= T_ # first template parameter + // ::= T <parameter-2 non-negative number> _ + if (Index == 0) + Out << "T_"; + else + Out << 'T' << (Index - 1) << '_'; +} + +// <substitution> ::= S <seq-id> _ +// ::= S_ +bool CXXNameMangler::mangleSubstitution(const NamedDecl *ND) { + // Try one of the standard substitutions first. + if (mangleStandardSubstitution(ND)) + return true; + + ND = cast<NamedDecl>(ND->getCanonicalDecl()); + return mangleSubstitution(reinterpret_cast<uintptr_t>(ND)); +} + +bool CXXNameMangler::mangleSubstitution(QualType T) { + if (!T.getCVRQualifiers()) { + if (const RecordType *RT = T->getAs<RecordType>()) + return mangleSubstitution(RT->getDecl()); + } + + uintptr_t TypePtr = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr()); + + return mangleSubstitution(TypePtr); +} + +bool CXXNameMangler::mangleSubstitution(TemplateName Template) { + if (TemplateDecl *TD = Template.getAsTemplateDecl()) + return mangleSubstitution(TD); + + Template = Context.getASTContext().getCanonicalTemplateName(Template); + return mangleSubstitution( + reinterpret_cast<uintptr_t>(Template.getAsVoidPointer())); +} + +bool CXXNameMangler::mangleSubstitution(uintptr_t Ptr) { + llvm::DenseMap<uintptr_t, unsigned>::iterator I = Substitutions.find(Ptr); + if (I == Substitutions.end()) + return false; + + unsigned SeqID = I->second; + if (SeqID == 0) + Out << "S_"; + else { + SeqID--; + + // <seq-id> is encoded in base-36, using digits and upper case letters. + char Buffer[10]; + char *BufferPtr = llvm::array_endof(Buffer); + + if (SeqID == 0) *--BufferPtr = '0'; + + while (SeqID) { + assert(BufferPtr > Buffer && "Buffer overflow!"); + + char c = static_cast<char>(SeqID % 36); + + *--BufferPtr = (c < 10 ? '0' + c : 'A' + c - 10); + SeqID /= 36; + } + + Out << 'S' + << llvm::StringRef(BufferPtr, llvm::array_endof(Buffer)-BufferPtr) + << '_'; + } + + return true; +} + +static bool isCharType(QualType T) { + if (T.isNull()) + return false; + + return T->isSpecificBuiltinType(BuiltinType::Char_S) || + T->isSpecificBuiltinType(BuiltinType::Char_U); +} + +/// isCharSpecialization - Returns whether a given type is a template +/// specialization of a given name with a single argument of type char. +static bool isCharSpecialization(QualType T, const char *Name) { + if (T.isNull()) + return false; + + const RecordType *RT = T->getAs<RecordType>(); + if (!RT) + return false; + + const ClassTemplateSpecializationDecl *SD = + dyn_cast<ClassTemplateSpecializationDecl>(RT->getDecl()); + if (!SD) + return false; + + if (!isStdNamespace(SD->getDeclContext())) + return false; + + const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs(); + if (TemplateArgs.size() != 1) + return false; + + if (!isCharType(TemplateArgs[0].getAsType())) + return false; + + return SD->getIdentifier()->getName() == Name; +} + +template <std::size_t StrLen> +static bool isStreamCharSpecialization(const ClassTemplateSpecializationDecl*SD, + const char (&Str)[StrLen]) { + if (!SD->getIdentifier()->isStr(Str)) + return false; + + const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs(); + if (TemplateArgs.size() != 2) + return false; + + if (!isCharType(TemplateArgs[0].getAsType())) + return false; + + if (!isCharSpecialization(TemplateArgs[1].getAsType(), "char_traits")) + return false; + + return true; +} + +bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) { + // <substitution> ::= St # ::std:: + if (const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(ND)) { + if (isStd(NS)) { + Out << "St"; + return true; + } + } + + if (const ClassTemplateDecl *TD = dyn_cast<ClassTemplateDecl>(ND)) { + if (!isStdNamespace(TD->getDeclContext())) + return false; + + // <substitution> ::= Sa # ::std::allocator + if (TD->getIdentifier()->isStr("allocator")) { + Out << "Sa"; + return true; + } + + // <<substitution> ::= Sb # ::std::basic_string + if (TD->getIdentifier()->isStr("basic_string")) { + Out << "Sb"; + return true; + } + } + + if (const ClassTemplateSpecializationDecl *SD = + dyn_cast<ClassTemplateSpecializationDecl>(ND)) { + if (!isStdNamespace(SD->getDeclContext())) + return false; + + // <substitution> ::= Ss # ::std::basic_string<char, + // ::std::char_traits<char>, + // ::std::allocator<char> > + if (SD->getIdentifier()->isStr("basic_string")) { + const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs(); + + if (TemplateArgs.size() != 3) + return false; + + if (!isCharType(TemplateArgs[0].getAsType())) + return false; + + if (!isCharSpecialization(TemplateArgs[1].getAsType(), "char_traits")) + return false; + + if (!isCharSpecialization(TemplateArgs[2].getAsType(), "allocator")) + return false; + + Out << "Ss"; + return true; + } + + // <substitution> ::= Si # ::std::basic_istream<char, + // ::std::char_traits<char> > + if (isStreamCharSpecialization(SD, "basic_istream")) { + Out << "Si"; + return true; + } + + // <substitution> ::= So # ::std::basic_ostream<char, + // ::std::char_traits<char> > + if (isStreamCharSpecialization(SD, "basic_ostream")) { + Out << "So"; + return true; + } + + // <substitution> ::= Sd # ::std::basic_iostream<char, + // ::std::char_traits<char> > + if (isStreamCharSpecialization(SD, "basic_iostream")) { + Out << "Sd"; + return true; + } + } + return false; +} + +void CXXNameMangler::addSubstitution(QualType T) { + if (!T.getCVRQualifiers()) { + if (const RecordType *RT = T->getAs<RecordType>()) { + addSubstitution(RT->getDecl()); + return; + } + } + + uintptr_t TypePtr = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr()); + addSubstitution(TypePtr); +} + +void CXXNameMangler::addSubstitution(TemplateName Template) { + if (TemplateDecl *TD = Template.getAsTemplateDecl()) + return addSubstitution(TD); + + Template = Context.getASTContext().getCanonicalTemplateName(Template); + addSubstitution(reinterpret_cast<uintptr_t>(Template.getAsVoidPointer())); +} + +void CXXNameMangler::addSubstitution(uintptr_t Ptr) { + assert(!Substitutions.count(Ptr) && "Substitution already exists!"); + Substitutions[Ptr] = SeqID++; +} + +// + +/// \brief Mangles the name of the declaration D and emits that name to the +/// given output stream. +/// +/// If the declaration D requires a mangled name, this routine will emit that +/// mangled name to \p os and return true. Otherwise, \p os will be unchanged +/// and this routine will return false. In this case, the caller should just +/// emit the identifier of the declaration (\c D->getIdentifier()) as its +/// name. +void ItaniumMangleContext::mangleName(const NamedDecl *D, + llvm::raw_ostream &Out) { + assert((isa<FunctionDecl>(D) || isa<VarDecl>(D)) && + "Invalid mangleName() call, argument is not a variable or function!"); + assert(!isa<CXXConstructorDecl>(D) && !isa<CXXDestructorDecl>(D) && + "Invalid mangleName() call on 'structor decl!"); + + PrettyStackTraceDecl CrashInfo(D, SourceLocation(), + getASTContext().getSourceManager(), + "Mangling declaration"); + + CXXNameMangler Mangler(*this, Out); + return Mangler.mangle(D); +} + +void ItaniumMangleContext::mangleCXXCtor(const CXXConstructorDecl *D, + CXXCtorType Type, + llvm::raw_ostream &Out) { + CXXNameMangler Mangler(*this, Out, D, Type); + Mangler.mangle(D); +} + +void ItaniumMangleContext::mangleCXXDtor(const CXXDestructorDecl *D, + CXXDtorType Type, + llvm::raw_ostream &Out) { + CXXNameMangler Mangler(*this, Out, D, Type); + Mangler.mangle(D); +} + +void ItaniumMangleContext::mangleThunk(const CXXMethodDecl *MD, + const ThunkInfo &Thunk, + llvm::raw_ostream &Out) { + // <special-name> ::= T <call-offset> <base encoding> + // # base is the nominal target function of thunk + // <special-name> ::= Tc <call-offset> <call-offset> <base encoding> + // # base is the nominal target function of thunk + // # first call-offset is 'this' adjustment + // # second call-offset is result adjustment + + assert(!isa<CXXDestructorDecl>(MD) && + "Use mangleCXXDtor for destructor decls!"); + CXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "_ZT"; + if (!Thunk.Return.isEmpty()) + Mangler.getStream() << 'c'; + + // Mangle the 'this' pointer adjustment. + Mangler.mangleCallOffset(Thunk.This.NonVirtual, Thunk.This.VCallOffsetOffset); + + // Mangle the return pointer adjustment if there is one. + if (!Thunk.Return.isEmpty()) + Mangler.mangleCallOffset(Thunk.Return.NonVirtual, + Thunk.Return.VBaseOffsetOffset); + + Mangler.mangleFunctionEncoding(MD); +} + +void +ItaniumMangleContext::mangleCXXDtorThunk(const CXXDestructorDecl *DD, + CXXDtorType Type, + const ThisAdjustment &ThisAdjustment, + llvm::raw_ostream &Out) { + // <special-name> ::= T <call-offset> <base encoding> + // # base is the nominal target function of thunk + CXXNameMangler Mangler(*this, Out, DD, Type); + Mangler.getStream() << "_ZT"; + + // Mangle the 'this' pointer adjustment. + Mangler.mangleCallOffset(ThisAdjustment.NonVirtual, + ThisAdjustment.VCallOffsetOffset); + + Mangler.mangleFunctionEncoding(DD); +} + +/// mangleGuardVariable - Returns the mangled name for a guard variable +/// for the passed in VarDecl. +void ItaniumMangleContext::mangleItaniumGuardVariable(const VarDecl *D, + llvm::raw_ostream &Out) { + // <special-name> ::= GV <object name> # Guard variable for one-time + // # initialization + CXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "_ZGV"; + Mangler.mangleName(D); +} + +void ItaniumMangleContext::mangleReferenceTemporary(const VarDecl *D, + llvm::raw_ostream &Out) { + // We match the GCC mangling here. + // <special-name> ::= GR <object name> + CXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "_ZGR"; + Mangler.mangleName(D); +} + +void ItaniumMangleContext::mangleCXXVTable(const CXXRecordDecl *RD, + llvm::raw_ostream &Out) { + // <special-name> ::= TV <type> # virtual table + CXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "_ZTV"; + Mangler.mangleNameOrStandardSubstitution(RD); +} + +void ItaniumMangleContext::mangleCXXVTT(const CXXRecordDecl *RD, + llvm::raw_ostream &Out) { + // <special-name> ::= TT <type> # VTT structure + CXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "_ZTT"; + Mangler.mangleNameOrStandardSubstitution(RD); +} + +void ItaniumMangleContext::mangleCXXCtorVTable(const CXXRecordDecl *RD, + int64_t Offset, + const CXXRecordDecl *Type, + llvm::raw_ostream &Out) { + // <special-name> ::= TC <type> <offset number> _ <base type> + CXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "_ZTC"; + Mangler.mangleNameOrStandardSubstitution(RD); + Mangler.getStream() << Offset; + Mangler.getStream() << '_'; + Mangler.mangleNameOrStandardSubstitution(Type); +} + +void ItaniumMangleContext::mangleCXXRTTI(QualType Ty, + llvm::raw_ostream &Out) { + // <special-name> ::= TI <type> # typeinfo structure + assert(!Ty.hasQualifiers() && "RTTI info cannot have top-level qualifiers"); + CXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "_ZTI"; + Mangler.mangleType(Ty); +} + +void ItaniumMangleContext::mangleCXXRTTIName(QualType Ty, + llvm::raw_ostream &Out) { + // <special-name> ::= TS <type> # typeinfo name (null terminated byte string) + CXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "_ZTS"; + Mangler.mangleType(Ty); +} + +MangleContext *clang::createItaniumMangleContext(ASTContext &Context, + Diagnostic &Diags) { + return new ItaniumMangleContext(Context, Diags); +} diff --git a/lib/AST/Mangle.cpp b/lib/AST/Mangle.cpp new file mode 100644 index 0000000..3a0b909 --- /dev/null +++ b/lib/AST/Mangle.cpp @@ -0,0 +1,135 @@ +//===--- Mangle.cpp - Mangle C++ Names --------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Implements generic name mangling support for blocks and Objective-C. +// +//===----------------------------------------------------------------------===// +#include "clang/AST/Mangle.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/ExprCXX.h" +#include "clang/Basic/ABI.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/ErrorHandling.h" + +#define MANGLE_CHECKER 0 + +#if MANGLE_CHECKER +#include <cxxabi.h> +#endif + +using namespace clang; + +// FIXME: For blocks we currently mimic GCC's mangling scheme, which leaves +// much to be desired. Come up with a better mangling scheme. + +namespace { + +static void mangleFunctionBlock(MangleContext &Context, + llvm::StringRef Outer, + const BlockDecl *BD, + llvm::raw_ostream &Out) { + Out << "__" << Outer << "_block_invoke_" << Context.getBlockId(BD, true); +} + +static void checkMangleDC(const DeclContext *DC, const BlockDecl *BD) { +#ifndef NDEBUG + const DeclContext *ExpectedDC = BD->getDeclContext(); + while (isa<BlockDecl>(ExpectedDC) || isa<EnumDecl>(ExpectedDC)) + ExpectedDC = ExpectedDC->getParent(); + assert(DC == ExpectedDC && "Given decl context did not match expected!"); +#endif +} + +} + +void MangleContext::mangleGlobalBlock(const BlockDecl *BD, + llvm::raw_ostream &Out) { + Out << "__block_global_" << getBlockId(BD, false); +} + +void MangleContext::mangleCtorBlock(const CXXConstructorDecl *CD, + CXXCtorType CT, const BlockDecl *BD, + llvm::raw_ostream &ResStream) { + checkMangleDC(CD, BD); + llvm::SmallString<64> Buffer; + llvm::raw_svector_ostream Out(Buffer); + mangleCXXCtor(CD, CT, Out); + Out.flush(); + mangleFunctionBlock(*this, Buffer, BD, ResStream); +} + +void MangleContext::mangleDtorBlock(const CXXDestructorDecl *DD, + CXXDtorType DT, const BlockDecl *BD, + llvm::raw_ostream &ResStream) { + checkMangleDC(DD, BD); + llvm::SmallString<64> Buffer; + llvm::raw_svector_ostream Out(Buffer); + mangleCXXDtor(DD, DT, Out); + Out.flush(); + mangleFunctionBlock(*this, Buffer, BD, ResStream); +} + +void MangleContext::mangleBlock(const DeclContext *DC, const BlockDecl *BD, + llvm::raw_ostream &Out) { + assert(!isa<CXXConstructorDecl>(DC) && !isa<CXXDestructorDecl>(DC)); + checkMangleDC(DC, BD); + + llvm::SmallString<64> Buffer; + llvm::raw_svector_ostream Stream(Buffer); + if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(DC)) { + mangleObjCMethodName(Method, Stream); + } else { + const NamedDecl *ND = cast<NamedDecl>(DC); + if (IdentifierInfo *II = ND->getIdentifier()) + Stream << II->getName(); + else { + // FIXME: We were doing a mangleUnqualifiedName() before, but that's + // a private member of a class that will soon itself be private to the + // Itanium C++ ABI object. What should we do now? Right now, I'm just + // calling the mangleName() method on the MangleContext; is there a + // better way? + mangleName(ND, Stream); + } + } + Stream.flush(); + mangleFunctionBlock(*this, Buffer, BD, Out); +} + +void MangleContext::mangleObjCMethodName(const ObjCMethodDecl *MD, + llvm::raw_ostream &Out) { + llvm::SmallString<64> Name; + llvm::raw_svector_ostream OS(Name); + + const ObjCContainerDecl *CD = + dyn_cast<ObjCContainerDecl>(MD->getDeclContext()); + assert (CD && "Missing container decl in GetNameForMethod"); + OS << (MD->isInstanceMethod() ? '-' : '+') << '[' << CD->getName(); + if (const ObjCCategoryImplDecl *CID = dyn_cast<ObjCCategoryImplDecl>(CD)) + OS << '(' << CID << ')'; + OS << ' ' << MD->getSelector().getAsString() << ']'; + + Out << OS.str().size() << OS.str(); +} + +void MangleContext::mangleBlock(const BlockDecl *BD, + llvm::raw_ostream &Out) { + const DeclContext *DC = BD->getDeclContext(); + while (isa<BlockDecl>(DC) || isa<EnumDecl>(DC)) + DC = DC->getParent(); + if (DC->isFunctionOrMethod()) + mangleBlock(DC, BD, Out); + else + mangleGlobalBlock(BD, Out); +} diff --git a/lib/AST/MicrosoftCXXABI.cpp b/lib/AST/MicrosoftCXXABI.cpp index 87b7767..4de93bb 100644 --- a/lib/AST/MicrosoftCXXABI.cpp +++ b/lib/AST/MicrosoftCXXABI.cpp @@ -14,8 +14,10 @@ #include "CXXABI.h" #include "clang/AST/ASTContext.h" -#include "clang/AST/Type.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/RecordLayout.h" +#include "clang/AST/Type.h" +#include "clang/Basic/TargetInfo.h" using namespace clang; @@ -26,6 +28,27 @@ public: MicrosoftCXXABI(ASTContext &Ctx) : Context(Ctx) { } unsigned getMemberPointerSize(const MemberPointerType *MPT) const; + + CallingConv getDefaultMethodCallConv() const { + if (Context.Target.getTriple().getArch() == llvm::Triple::x86) + return CC_X86ThisCall; + else + return CC_C; + } + + bool isNearlyEmpty(const CXXRecordDecl *RD) const { + // FIXME: Audit the corners + if (!RD->isDynamicClass()) + return false; + + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + + // In the Microsoft ABI, classes can have one or two vtable pointers. + CharUnits PointerSize = + Context.toCharUnitsFromBits(Context.Target.getPointerWidth(0)); + return Layout.getNonVirtualSize() == PointerSize || + Layout.getNonVirtualSize() == PointerSize * 2; + } }; } diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp new file mode 100644 index 0000000..4bf7f23 --- /dev/null +++ b/lib/AST/MicrosoftMangle.cpp @@ -0,0 +1,1188 @@ +//===--- MicrosoftMangle.cpp - Microsoft Visual C++ Name Mangling ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This provides C++ name mangling targetting the Microsoft Visual C++ ABI. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/Mangle.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/CharUnits.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/ExprCXX.h" +#include "clang/Basic/ABI.h" + +using namespace clang; + +namespace { + +/// MicrosoftCXXNameMangler - Manage the mangling of a single name for the +/// Microsoft Visual C++ ABI. +class MicrosoftCXXNameMangler { + MangleContext &Context; + llvm::raw_ostream &Out; + + ASTContext &getASTContext() const { return Context.getASTContext(); } + +public: + MicrosoftCXXNameMangler(MangleContext &C, llvm::raw_ostream &Out_) + : Context(C), Out(Out_) { } + + void mangle(const NamedDecl *D, llvm::StringRef Prefix = "?"); + void mangleName(const NamedDecl *ND); + void mangleFunctionEncoding(const FunctionDecl *FD); + void mangleVariableEncoding(const VarDecl *VD); + void mangleNumber(int64_t Number); + void mangleType(QualType T); + +private: + void mangleUnqualifiedName(const NamedDecl *ND) { + mangleUnqualifiedName(ND, ND->getDeclName()); + } + void mangleUnqualifiedName(const NamedDecl *ND, DeclarationName Name); + void mangleSourceName(const IdentifierInfo *II); + void manglePostfix(const DeclContext *DC, bool NoFunction=false); + void mangleOperatorName(OverloadedOperatorKind OO); + void mangleQualifiers(Qualifiers Quals, bool IsMember); + + void mangleObjCMethodName(const ObjCMethodDecl *MD); + + // Declare manglers for every type class. +#define ABSTRACT_TYPE(CLASS, PARENT) +#define NON_CANONICAL_TYPE(CLASS, PARENT) +#define TYPE(CLASS, PARENT) void mangleType(const CLASS##Type *T); +#include "clang/AST/TypeNodes.def" + + void mangleType(const TagType*); + void mangleType(const FunctionType *T, const FunctionDecl *D, + bool IsStructor, bool IsInstMethod); + void mangleType(const ArrayType *T, bool IsGlobal); + void mangleExtraDimensions(QualType T); + void mangleFunctionClass(const FunctionDecl *FD); + void mangleCallingConvention(const FunctionType *T, bool IsInstMethod = false); + void mangleThrowSpecification(const FunctionProtoType *T); + +}; + +/// MicrosoftMangleContext - Overrides the default MangleContext for the +/// Microsoft Visual C++ ABI. +class MicrosoftMangleContext : public MangleContext { +public: + MicrosoftMangleContext(ASTContext &Context, + Diagnostic &Diags) : MangleContext(Context, Diags) { } + virtual bool shouldMangleDeclName(const NamedDecl *D); + virtual void mangleName(const NamedDecl *D, llvm::raw_ostream &Out); + virtual void mangleThunk(const CXXMethodDecl *MD, + const ThunkInfo &Thunk, + llvm::raw_ostream &); + virtual void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type, + const ThisAdjustment &ThisAdjustment, + llvm::raw_ostream &); + virtual void mangleCXXVTable(const CXXRecordDecl *RD, + llvm::raw_ostream &); + virtual void mangleCXXVTT(const CXXRecordDecl *RD, + llvm::raw_ostream &); + virtual void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset, + const CXXRecordDecl *Type, + llvm::raw_ostream &); + virtual void mangleCXXRTTI(QualType T, llvm::raw_ostream &); + virtual void mangleCXXRTTIName(QualType T, llvm::raw_ostream &); + virtual void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type, + llvm::raw_ostream &); + virtual void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type, + llvm::raw_ostream &); + virtual void mangleReferenceTemporary(const clang::VarDecl *, + llvm::raw_ostream &); +}; + +} + +static bool isInCLinkageSpecification(const Decl *D) { + D = D->getCanonicalDecl(); + for (const DeclContext *DC = D->getDeclContext(); + !DC->isTranslationUnit(); DC = DC->getParent()) { + if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC)) + return Linkage->getLanguage() == LinkageSpecDecl::lang_c; + } + + return false; +} + +bool MicrosoftMangleContext::shouldMangleDeclName(const NamedDecl *D) { + // In C, functions with no attributes never need to be mangled. Fastpath them. + if (!getASTContext().getLangOptions().CPlusPlus && !D->hasAttrs()) + return false; + + // Any decl can be declared with __asm("foo") on it, and this takes precedence + // over all other naming in the .o file. + if (D->hasAttr<AsmLabelAttr>()) + return true; + + // Clang's "overloadable" attribute extension to C/C++ implies name mangling + // (always) as does passing a C++ member function and a function + // whose name is not a simple identifier. + const FunctionDecl *FD = dyn_cast<FunctionDecl>(D); + if (FD && (FD->hasAttr<OverloadableAttr>() || isa<CXXMethodDecl>(FD) || + !FD->getDeclName().isIdentifier())) + return true; + + // Otherwise, no mangling is done outside C++ mode. + if (!getASTContext().getLangOptions().CPlusPlus) + return false; + + // Variables at global scope with internal linkage are not mangled. + if (!FD) { + const DeclContext *DC = D->getDeclContext(); + if (DC->isTranslationUnit() && D->getLinkage() == InternalLinkage) + return false; + } + + // C functions and "main" are not mangled. + if ((FD && FD->isMain()) || isInCLinkageSpecification(D)) + return false; + + return true; +} + +void MicrosoftCXXNameMangler::mangle(const NamedDecl *D, + llvm::StringRef Prefix) { + // MSVC doesn't mangle C++ names the same way it mangles extern "C" names. + // Therefore it's really important that we don't decorate the + // name with leading underscores or leading/trailing at signs. So, emit a + // asm marker at the start so we get the name right. + Out << '\01'; // LLVM IR Marker for __asm("foo") + + // Any decl can be declared with __asm("foo") on it, and this takes precedence + // over all other naming in the .o file. + if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>()) { + // If we have an asm name, then we use it as the mangling. + Out << ALA->getLabel(); + return; + } + + // <mangled-name> ::= ? <name> <type-encoding> + Out << Prefix; + mangleName(D); + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) + mangleFunctionEncoding(FD); + else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) + mangleVariableEncoding(VD); + // TODO: Fields? Can MSVC even mangle them? +} + +void MicrosoftCXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) { + // <type-encoding> ::= <function-class> <function-type> + + // Don't mangle in the type if this isn't a decl we should typically mangle. + if (!Context.shouldMangleDeclName(FD)) + return; + + // We should never ever see a FunctionNoProtoType at this point. + // We don't even know how to mangle their types anyway :). + const FunctionProtoType *FT = cast<FunctionProtoType>(FD->getType()); + + bool InStructor = false, InInstMethod = false; + const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD); + if (MD) { + if (MD->isInstance()) + InInstMethod = true; + if (isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD)) + InStructor = true; + } + + // First, the function class. + mangleFunctionClass(FD); + + mangleType(FT, FD, InStructor, InInstMethod); +} + +void MicrosoftCXXNameMangler::mangleVariableEncoding(const VarDecl *VD) { + // <type-encoding> ::= <storage-class> <variable-type> + // <storage-class> ::= 0 # private static member + // ::= 1 # protected static member + // ::= 2 # public static member + // ::= 3 # global + // ::= 4 # static local + + // The first character in the encoding (after the name) is the storage class. + if (VD->isStaticDataMember()) { + // If it's a static member, it also encodes the access level. + switch (VD->getAccess()) { + default: + case AS_private: Out << '0'; break; + case AS_protected: Out << '1'; break; + case AS_public: Out << '2'; break; + } + } + else if (!VD->isStaticLocal()) + Out << '3'; + else + Out << '4'; + // Now mangle the type. + // <variable-type> ::= <type> <cvr-qualifiers> + // ::= <type> A # pointers, references, arrays + // Pointers and references are odd. The type of 'int * const foo;' gets + // mangled as 'QAHA' instead of 'PAHB', for example. + QualType Ty = VD->getType(); + if (Ty->isPointerType() || Ty->isReferenceType()) { + mangleType(Ty); + Out << 'A'; + } else if (Ty->isArrayType()) { + // Global arrays are funny, too. + mangleType(cast<ArrayType>(Ty.getTypePtr()), true); + Out << 'A'; + } else { + mangleType(Ty.getLocalUnqualifiedType()); + mangleQualifiers(Ty.getLocalQualifiers(), false); + } +} + +void MicrosoftCXXNameMangler::mangleName(const NamedDecl *ND) { + // <name> ::= <unscoped-name> {[<named-scope>]+ | [<nested-name>]}? @ + const DeclContext *DC = ND->getDeclContext(); + + // Always start with the unqualified name. + mangleUnqualifiedName(ND); + + // If this is an extern variable declared locally, the relevant DeclContext + // is that of the containing namespace, or the translation unit. + if (isa<FunctionDecl>(DC) && ND->hasLinkage()) + while (!DC->isNamespace() && !DC->isTranslationUnit()) + DC = DC->getParent(); + + manglePostfix(DC); + + // Terminate the whole name with an '@'. + Out << '@'; +} + +void MicrosoftCXXNameMangler::mangleNumber(int64_t Number) { + // <number> ::= [?] <decimal digit> # <= 9 + // ::= [?] <hex digit>+ @ # > 9; A = 0, B = 1, etc... + if (Number < 0) { + Out << '?'; + Number = -Number; + } + if (Number >= 1 && Number <= 10) { + Out << Number-1; + } else { + // We have to build up the encoding in reverse order, so it will come + // out right when we write it out. + char Encoding[16]; + char *EndPtr = Encoding+sizeof(Encoding); + char *CurPtr = EndPtr; + while (Number) { + *--CurPtr = 'A' + (Number % 16); + Number /= 16; + } + Out.write(CurPtr, EndPtr-CurPtr); + Out << '@'; + } +} + +void +MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, + DeclarationName Name) { + // <unqualified-name> ::= <operator-name> + // ::= <ctor-dtor-name> + // ::= <source-name> + switch (Name.getNameKind()) { + case DeclarationName::Identifier: { + if (const IdentifierInfo *II = Name.getAsIdentifierInfo()) { + mangleSourceName(II); + break; + } + + // Otherwise, an anonymous entity. We must have a declaration. + assert(ND && "mangling empty name without declaration"); + + if (const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(ND)) { + if (NS->isAnonymousNamespace()) { + Out << "?A"; + break; + } + } + + // We must have an anonymous struct. + const TagDecl *TD = cast<TagDecl>(ND); + if (const TypedefDecl *D = TD->getTypedefForAnonDecl()) { + assert(TD->getDeclContext() == D->getDeclContext() && + "Typedef should not be in another decl context!"); + assert(D->getDeclName().getAsIdentifierInfo() && + "Typedef was not named!"); + mangleSourceName(D->getDeclName().getAsIdentifierInfo()); + break; + } + + // When VC encounters an anonymous type with no tag and no typedef, + // it literally emits '<unnamed-tag>'. + Out << "<unnamed-tag>"; + break; + } + + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + assert(false && "Can't mangle Objective-C selector names here!"); + break; + + case DeclarationName::CXXConstructorName: + assert(false && "Can't mangle constructors yet!"); + break; + + case DeclarationName::CXXDestructorName: + assert(false && "Can't mangle destructors yet!"); + break; + + case DeclarationName::CXXConversionFunctionName: + // <operator-name> ::= ?B # (cast) + // The target type is encoded as the return type. + Out << "?B"; + break; + + case DeclarationName::CXXOperatorName: + mangleOperatorName(Name.getCXXOverloadedOperator()); + break; + + case DeclarationName::CXXLiteralOperatorName: + // FIXME: Was this added in VS2010? Does MS even know how to mangle this? + assert(false && "Don't know how to mangle literal operators yet!"); + break; + + case DeclarationName::CXXUsingDirective: + assert(false && "Can't mangle a using directive name!"); + break; + } +} + +void MicrosoftCXXNameMangler::manglePostfix(const DeclContext *DC, + bool NoFunction) { + // <postfix> ::= <unqualified-name> [<postfix>] + // ::= <template-postfix> <template-args> [<postfix>] + // ::= <template-param> + // ::= <substitution> [<postfix>] + + if (!DC) return; + + while (isa<LinkageSpecDecl>(DC)) + DC = DC->getParent(); + + if (DC->isTranslationUnit()) + return; + + if (const BlockDecl *BD = dyn_cast<BlockDecl>(DC)) { + Context.mangleBlock(BD, Out); + Out << '@'; + return manglePostfix(DC->getParent(), NoFunction); + } + + if (NoFunction && (isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC))) + return; + else if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(DC)) + mangleObjCMethodName(Method); + else { + mangleUnqualifiedName(cast<NamedDecl>(DC)); + manglePostfix(DC->getParent(), NoFunction); + } +} + +void MicrosoftCXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO) { + switch (OO) { + // ?0 # constructor + // ?1 # destructor + // <operator-name> ::= ?2 # new + case OO_New: Out << "?2"; break; + // <operator-name> ::= ?3 # delete + case OO_Delete: Out << "?3"; break; + // <operator-name> ::= ?4 # = + case OO_Equal: Out << "?4"; break; + // <operator-name> ::= ?5 # >> + case OO_GreaterGreater: Out << "?5"; break; + // <operator-name> ::= ?6 # << + case OO_LessLess: Out << "?6"; break; + // <operator-name> ::= ?7 # ! + case OO_Exclaim: Out << "?7"; break; + // <operator-name> ::= ?8 # == + case OO_EqualEqual: Out << "?8"; break; + // <operator-name> ::= ?9 # != + case OO_ExclaimEqual: Out << "?9"; break; + // <operator-name> ::= ?A # [] + case OO_Subscript: Out << "?A"; break; + // ?B # conversion + // <operator-name> ::= ?C # -> + case OO_Arrow: Out << "?C"; break; + // <operator-name> ::= ?D # * + case OO_Star: Out << "?D"; break; + // <operator-name> ::= ?E # ++ + case OO_PlusPlus: Out << "?E"; break; + // <operator-name> ::= ?F # -- + case OO_MinusMinus: Out << "?F"; break; + // <operator-name> ::= ?G # - + case OO_Minus: Out << "?G"; break; + // <operator-name> ::= ?H # + + case OO_Plus: Out << "?H"; break; + // <operator-name> ::= ?I # & + case OO_Amp: Out << "?I"; break; + // <operator-name> ::= ?J # ->* + case OO_ArrowStar: Out << "?J"; break; + // <operator-name> ::= ?K # / + case OO_Slash: Out << "?K"; break; + // <operator-name> ::= ?L # % + case OO_Percent: Out << "?L"; break; + // <operator-name> ::= ?M # < + case OO_Less: Out << "?M"; break; + // <operator-name> ::= ?N # <= + case OO_LessEqual: Out << "?N"; break; + // <operator-name> ::= ?O # > + case OO_Greater: Out << "?O"; break; + // <operator-name> ::= ?P # >= + case OO_GreaterEqual: Out << "?P"; break; + // <operator-name> ::= ?Q # , + case OO_Comma: Out << "?Q"; break; + // <operator-name> ::= ?R # () + case OO_Call: Out << "?R"; break; + // <operator-name> ::= ?S # ~ + case OO_Tilde: Out << "?S"; break; + // <operator-name> ::= ?T # ^ + case OO_Caret: Out << "?T"; break; + // <operator-name> ::= ?U # | + case OO_Pipe: Out << "?U"; break; + // <operator-name> ::= ?V # && + case OO_AmpAmp: Out << "?V"; break; + // <operator-name> ::= ?W # || + case OO_PipePipe: Out << "?W"; break; + // <operator-name> ::= ?X # *= + case OO_StarEqual: Out << "?X"; break; + // <operator-name> ::= ?Y # += + case OO_PlusEqual: Out << "?Y"; break; + // <operator-name> ::= ?Z # -= + case OO_MinusEqual: Out << "?Z"; break; + // <operator-name> ::= ?_0 # /= + case OO_SlashEqual: Out << "?_0"; break; + // <operator-name> ::= ?_1 # %= + case OO_PercentEqual: Out << "?_1"; break; + // <operator-name> ::= ?_2 # >>= + case OO_GreaterGreaterEqual: Out << "?_2"; break; + // <operator-name> ::= ?_3 # <<= + case OO_LessLessEqual: Out << "?_3"; break; + // <operator-name> ::= ?_4 # &= + case OO_AmpEqual: Out << "?_4"; break; + // <operator-name> ::= ?_5 # |= + case OO_PipeEqual: Out << "?_5"; break; + // <operator-name> ::= ?_6 # ^= + case OO_CaretEqual: Out << "?_6"; break; + // ?_7 # vftable + // ?_8 # vbtable + // ?_9 # vcall + // ?_A # typeof + // ?_B # local static guard + // ?_C # string + // ?_D # vbase destructor + // ?_E # vector deleting destructor + // ?_F # default constructor closure + // ?_G # scalar deleting destructor + // ?_H # vector constructor iterator + // ?_I # vector destructor iterator + // ?_J # vector vbase constructor iterator + // ?_K # virtual displacement map + // ?_L # eh vector constructor iterator + // ?_M # eh vector destructor iterator + // ?_N # eh vector vbase constructor iterator + // ?_O # copy constructor closure + // ?_P<name> # udt returning <name> + // ?_Q # <unknown> + // ?_R0 # RTTI Type Descriptor + // ?_R1 # RTTI Base Class Descriptor at (a,b,c,d) + // ?_R2 # RTTI Base Class Array + // ?_R3 # RTTI Class Hierarchy Descriptor + // ?_R4 # RTTI Complete Object Locator + // ?_S # local vftable + // ?_T # local vftable constructor closure + // <operator-name> ::= ?_U # new[] + case OO_Array_New: Out << "?_U"; break; + // <operator-name> ::= ?_V # delete[] + case OO_Array_Delete: Out << "?_V"; break; + + case OO_Conditional: + assert(false && "Don't know how to mangle ?:"); + break; + + case OO_None: + case NUM_OVERLOADED_OPERATORS: + assert(false && "Not an overloaded operator"); + break; + } +} + +void MicrosoftCXXNameMangler::mangleSourceName(const IdentifierInfo *II) { + // <source name> ::= <identifier> @ + Out << II->getName() << '@'; +} + +void MicrosoftCXXNameMangler::mangleObjCMethodName(const ObjCMethodDecl *MD) { + Context.mangleObjCMethodName(MD, Out); +} + +void MicrosoftCXXNameMangler::mangleQualifiers(Qualifiers Quals, + bool IsMember) { + // <cvr-qualifiers> ::= [E] [F] [I] <base-cvr-qualifiers> + // 'E' means __ptr64 (32-bit only); 'F' means __unaligned (32/64-bit only); + // 'I' means __restrict (32/64-bit). + // Note that the MSVC __restrict keyword isn't the same as the C99 restrict + // keyword! + // <base-cvr-qualifiers> ::= A # near + // ::= B # near const + // ::= C # near volatile + // ::= D # near const volatile + // ::= E # far (16-bit) + // ::= F # far const (16-bit) + // ::= G # far volatile (16-bit) + // ::= H # far const volatile (16-bit) + // ::= I # huge (16-bit) + // ::= J # huge const (16-bit) + // ::= K # huge volatile (16-bit) + // ::= L # huge const volatile (16-bit) + // ::= M <basis> # based + // ::= N <basis> # based const + // ::= O <basis> # based volatile + // ::= P <basis> # based const volatile + // ::= Q # near member + // ::= R # near const member + // ::= S # near volatile member + // ::= T # near const volatile member + // ::= U # far member (16-bit) + // ::= V # far const member (16-bit) + // ::= W # far volatile member (16-bit) + // ::= X # far const volatile member (16-bit) + // ::= Y # huge member (16-bit) + // ::= Z # huge const member (16-bit) + // ::= 0 # huge volatile member (16-bit) + // ::= 1 # huge const volatile member (16-bit) + // ::= 2 <basis> # based member + // ::= 3 <basis> # based const member + // ::= 4 <basis> # based volatile member + // ::= 5 <basis> # based const volatile member + // ::= 6 # near function (pointers only) + // ::= 7 # far function (pointers only) + // ::= 8 # near method (pointers only) + // ::= 9 # far method (pointers only) + // ::= _A <basis> # based function (pointers only) + // ::= _B <basis> # based function (far?) (pointers only) + // ::= _C <basis> # based method (pointers only) + // ::= _D <basis> # based method (far?) (pointers only) + // ::= _E # block (Clang) + // <basis> ::= 0 # __based(void) + // ::= 1 # __based(segment)? + // ::= 2 <name> # __based(name) + // ::= 3 # ? + // ::= 4 # ? + // ::= 5 # not really based + if (!IsMember) { + if (!Quals.hasVolatile()) { + if (!Quals.hasConst()) + Out << 'A'; + else + Out << 'B'; + } else { + if (!Quals.hasConst()) + Out << 'C'; + else + Out << 'D'; + } + } else { + if (!Quals.hasVolatile()) { + if (!Quals.hasConst()) + Out << 'Q'; + else + Out << 'R'; + } else { + if (!Quals.hasConst()) + Out << 'S'; + else + Out << 'T'; + } + } + + // FIXME: For now, just drop all extension qualifiers on the floor. +} + +void MicrosoftCXXNameMangler::mangleType(QualType T) { + // Only operate on the canonical type! + T = getASTContext().getCanonicalType(T); + + Qualifiers Quals = T.getLocalQualifiers(); + if (Quals) { + // We have to mangle these now, while we still have enough information. + // <pointer-cvr-qualifiers> ::= P # pointer + // ::= Q # const pointer + // ::= R # volatile pointer + // ::= S # const volatile pointer + if (T->isAnyPointerType() || T->isMemberPointerType() || + T->isBlockPointerType()) { + if (!Quals.hasVolatile()) + Out << 'Q'; + else { + if (!Quals.hasConst()) + Out << 'R'; + else + Out << 'S'; + } + } else + // Just emit qualifiers like normal. + // NB: When we mangle a pointer/reference type, and the pointee + // type has no qualifiers, the lack of qualifier gets mangled + // in there. + mangleQualifiers(Quals, false); + } else if (T->isAnyPointerType() || T->isMemberPointerType() || + T->isBlockPointerType()) { + Out << 'P'; + } + switch (T->getTypeClass()) { +#define ABSTRACT_TYPE(CLASS, PARENT) +#define NON_CANONICAL_TYPE(CLASS, PARENT) \ +case Type::CLASS: \ +llvm_unreachable("can't mangle non-canonical type " #CLASS "Type"); \ +return; +#define TYPE(CLASS, PARENT) \ +case Type::CLASS: \ +mangleType(static_cast<const CLASS##Type*>(T.getTypePtr())); \ +break; +#include "clang/AST/TypeNodes.def" + } +} + +void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T) { + // <type> ::= <builtin-type> + // <builtin-type> ::= X # void + // ::= C # signed char + // ::= D # char + // ::= E # unsigned char + // ::= F # short + // ::= G # unsigned short (or wchar_t if it's not a builtin) + // ::= H # int + // ::= I # unsigned int + // ::= J # long + // ::= K # unsigned long + // L # <none> + // ::= M # float + // ::= N # double + // ::= O # long double (__float80 is mangled differently) + // ::= _D # __int8 (yup, it's a distinct type in MSVC) + // ::= _E # unsigned __int8 + // ::= _F # __int16 + // ::= _G # unsigned __int16 + // ::= _H # __int32 + // ::= _I # unsigned __int32 + // ::= _J # long long, __int64 + // ::= _K # unsigned long long, __int64 + // ::= _L # __int128 + // ::= _M # unsigned __int128 + // ::= _N # bool + // _O # <array in parameter> + // ::= _T # __float80 (Intel) + // ::= _W # wchar_t + // ::= _Z # __float80 (Digital Mars) + switch (T->getKind()) { + case BuiltinType::Void: Out << 'X'; break; + case BuiltinType::SChar: Out << 'C'; break; + case BuiltinType::Char_U: case BuiltinType::Char_S: Out << 'D'; break; + case BuiltinType::UChar: Out << 'E'; break; + case BuiltinType::Short: Out << 'F'; break; + case BuiltinType::UShort: Out << 'G'; break; + case BuiltinType::Int: Out << 'H'; break; + case BuiltinType::UInt: Out << 'I'; break; + case BuiltinType::Long: Out << 'J'; break; + case BuiltinType::ULong: Out << 'K'; break; + case BuiltinType::Float: Out << 'M'; break; + case BuiltinType::Double: Out << 'N'; break; + // TODO: Determine size and mangle accordingly + case BuiltinType::LongDouble: Out << 'O'; break; + // TODO: __int8 and friends + case BuiltinType::LongLong: Out << "_J"; break; + case BuiltinType::ULongLong: Out << "_K"; break; + case BuiltinType::Int128: Out << "_L"; break; + case BuiltinType::UInt128: Out << "_M"; break; + case BuiltinType::Bool: Out << "_N"; break; + case BuiltinType::WChar_S: + case BuiltinType::WChar_U: Out << "_W"; break; + + case BuiltinType::Overload: + case BuiltinType::Dependent: + assert(false && + "Overloaded and dependent types shouldn't get to name mangling"); + break; + case BuiltinType::ObjCId: Out << "PAUobjc_object@@"; break; + case BuiltinType::ObjCClass: Out << "PAUobjc_class@@"; break; + case BuiltinType::ObjCSel: Out << "PAUobjc_selector@@"; break; + + case BuiltinType::Char16: + case BuiltinType::Char32: + case BuiltinType::NullPtr: + assert(false && "Don't know how to mangle this type"); + break; + } +} + +// <type> ::= <function-type> +void MicrosoftCXXNameMangler::mangleType(const FunctionProtoType *T) { + // Structors only appear in decls, so at this point we know it's not a + // structor type. + // I'll probably have mangleType(MemberPointerType) call the mangleType() + // method directly. + mangleType(T, NULL, false, false); +} +void MicrosoftCXXNameMangler::mangleType(const FunctionNoProtoType *T) { + llvm_unreachable("Can't mangle K&R function prototypes"); +} + +void MicrosoftCXXNameMangler::mangleType(const FunctionType *T, + const FunctionDecl *D, + bool IsStructor, + bool IsInstMethod) { + // <function-type> ::= <this-cvr-qualifiers> <calling-convention> + // <return-type> <argument-list> <throw-spec> + const FunctionProtoType *Proto = cast<FunctionProtoType>(T); + + // If this is a C++ instance method, mangle the CVR qualifiers for the + // this pointer. + if (IsInstMethod) + mangleQualifiers(Qualifiers::fromCVRMask(Proto->getTypeQuals()), false); + + mangleCallingConvention(T, IsInstMethod); + + // <return-type> ::= <type> + // ::= @ # structors (they have no declared return type) + if (IsStructor) + Out << '@'; + else + mangleType(Proto->getResultType()); + + // <argument-list> ::= X # void + // ::= <type>+ @ + // ::= <type>* Z # varargs + if (Proto->getNumArgs() == 0 && !Proto->isVariadic()) { + Out << 'X'; + } else { + if (D) { + // If we got a decl, use the "types-as-written" to make sure arrays + // get mangled right. + for (FunctionDecl::param_const_iterator Parm = D->param_begin(), + ParmEnd = D->param_end(); + Parm != ParmEnd; ++Parm) + mangleType((*Parm)->getTypeSourceInfo()->getType()); + } else { + for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(), + ArgEnd = Proto->arg_type_end(); + Arg != ArgEnd; ++Arg) + mangleType(*Arg); + } + // <builtin-type> ::= Z # ellipsis + if (Proto->isVariadic()) + Out << 'Z'; + else + Out << '@'; + } + + mangleThrowSpecification(Proto); +} + +void MicrosoftCXXNameMangler::mangleFunctionClass(const FunctionDecl *FD) { + // <function-class> ::= A # private: near + // ::= B # private: far + // ::= C # private: static near + // ::= D # private: static far + // ::= E # private: virtual near + // ::= F # private: virtual far + // ::= G # private: thunk near + // ::= H # private: thunk far + // ::= I # protected: near + // ::= J # protected: far + // ::= K # protected: static near + // ::= L # protected: static far + // ::= M # protected: virtual near + // ::= N # protected: virtual far + // ::= O # protected: thunk near + // ::= P # protected: thunk far + // ::= Q # public: near + // ::= R # public: far + // ::= S # public: static near + // ::= T # public: static far + // ::= U # public: virtual near + // ::= V # public: virtual far + // ::= W # public: thunk near + // ::= X # public: thunk far + // ::= Y # global near + // ::= Z # global far + if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) { + switch (MD->getAccess()) { + default: + case AS_private: + if (MD->isStatic()) + Out << 'C'; + else if (MD->isVirtual()) + Out << 'E'; + else + Out << 'A'; + break; + case AS_protected: + if (MD->isStatic()) + Out << 'K'; + else if (MD->isVirtual()) + Out << 'M'; + else + Out << 'I'; + break; + case AS_public: + if (MD->isStatic()) + Out << 'S'; + else if (MD->isVirtual()) + Out << 'U'; + else + Out << 'Q'; + } + } else + Out << 'Y'; +} +void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T, + bool IsInstMethod) { + // <calling-convention> ::= A # __cdecl + // ::= B # __export __cdecl + // ::= C # __pascal + // ::= D # __export __pascal + // ::= E # __thiscall + // ::= F # __export __thiscall + // ::= G # __stdcall + // ::= H # __export __stdcall + // ::= I # __fastcall + // ::= J # __export __fastcall + // The 'export' calling conventions are from a bygone era + // (*cough*Win16*cough*) when functions were declared for export with + // that keyword. (It didn't actually export them, it just made them so + // that they could be in a DLL and somebody from another module could call + // them.) + CallingConv CC = T->getCallConv(); + if (CC == CC_Default) + CC = IsInstMethod ? getASTContext().getDefaultMethodCallConv() : CC_C; + switch (CC) { + case CC_Default: + case CC_C: Out << 'A'; break; + case CC_X86Pascal: Out << 'C'; break; + case CC_X86ThisCall: Out << 'E'; break; + case CC_X86StdCall: Out << 'G'; break; + case CC_X86FastCall: Out << 'I'; break; + } +} +void MicrosoftCXXNameMangler::mangleThrowSpecification( + const FunctionProtoType *FT) { + // <throw-spec> ::= Z # throw(...) (default) + // ::= @ # throw() or __declspec/__attribute__((nothrow)) + // ::= <type>+ + // NOTE: Since the Microsoft compiler ignores throw specifications, they are + // all actually mangled as 'Z'. (They're ignored because their associated + // functionality isn't implemented, and probably never will be.) + Out << 'Z'; +} + +void MicrosoftCXXNameMangler::mangleType(const UnresolvedUsingType *T) { + assert(false && "Don't know how to mangle UnresolvedUsingTypes yet!"); +} + +// <type> ::= <union-type> | <struct-type> | <class-type> | <enum-type> +// <union-type> ::= T <name> +// <struct-type> ::= U <name> +// <class-type> ::= V <name> +// <enum-type> ::= W <size> <name> +void MicrosoftCXXNameMangler::mangleType(const EnumType *T) { + mangleType(static_cast<const TagType*>(T)); +} +void MicrosoftCXXNameMangler::mangleType(const RecordType *T) { + mangleType(static_cast<const TagType*>(T)); +} +void MicrosoftCXXNameMangler::mangleType(const TagType *T) { + switch (T->getDecl()->getTagKind()) { + case TTK_Union: + Out << 'T'; + break; + case TTK_Struct: + Out << 'U'; + break; + case TTK_Class: + Out << 'V'; + break; + case TTK_Enum: + Out << 'W'; + Out << getASTContext().getTypeSizeInChars( + cast<EnumDecl>(T->getDecl())->getIntegerType()).getQuantity(); + break; + } + mangleName(T->getDecl()); +} + +// <type> ::= <array-type> +// <array-type> ::= P <cvr-qualifiers> [Y <dimension-count> <dimension>+] +// <element-type> # as global +// ::= Q <cvr-qualifiers> [Y <dimension-count> <dimension>+] +// <element-type> # as param +// It's supposed to be the other way around, but for some strange reason, it +// isn't. Today this behavior is retained for the sole purpose of backwards +// compatibility. +void MicrosoftCXXNameMangler::mangleType(const ArrayType *T, bool IsGlobal) { + // This isn't a recursive mangling, so now we have to do it all in this + // one call. + if (IsGlobal) + Out << 'P'; + else + Out << 'Q'; + mangleExtraDimensions(T->getElementType()); +} +void MicrosoftCXXNameMangler::mangleType(const ConstantArrayType *T) { + mangleType(static_cast<const ArrayType *>(T), false); +} +void MicrosoftCXXNameMangler::mangleType(const VariableArrayType *T) { + mangleType(static_cast<const ArrayType *>(T), false); +} +void MicrosoftCXXNameMangler::mangleType(const DependentSizedArrayType *T) { + mangleType(static_cast<const ArrayType *>(T), false); +} +void MicrosoftCXXNameMangler::mangleType(const IncompleteArrayType *T) { + mangleType(static_cast<const ArrayType *>(T), false); +} +void MicrosoftCXXNameMangler::mangleExtraDimensions(QualType ElementTy) { + llvm::SmallVector<llvm::APInt, 3> Dimensions; + for (;;) { + if (ElementTy->isConstantArrayType()) { + const ConstantArrayType *CAT = + static_cast<const ConstantArrayType *>(ElementTy.getTypePtr()); + Dimensions.push_back(CAT->getSize()); + ElementTy = CAT->getElementType(); + } else if (ElementTy->isVariableArrayType()) { + assert(false && "Don't know how to mangle VLAs!"); + } else if (ElementTy->isDependentSizedArrayType()) { + // The dependent expression has to be folded into a constant (TODO). + assert(false && "Don't know how to mangle dependent-sized arrays!"); + } else if (ElementTy->isIncompleteArrayType()) continue; + else break; + } + mangleQualifiers(ElementTy.getQualifiers(), false); + // If there are any additional dimensions, mangle them now. + if (Dimensions.size() > 0) { + Out << 'Y'; + // <dimension-count> ::= <number> # number of extra dimensions + mangleNumber(Dimensions.size()); + for (unsigned Dim = 0; Dim < Dimensions.size(); ++Dim) { + mangleNumber(Dimensions[Dim].getLimitedValue()); + } + } + mangleType(ElementTy.getLocalUnqualifiedType()); +} + +// <type> ::= <pointer-to-member-type> +// <pointer-to-member-type> ::= <pointer-cvr-qualifiers> <cvr-qualifiers> +// <class name> <type> +void MicrosoftCXXNameMangler::mangleType(const MemberPointerType *T) { + QualType PointeeType = T->getPointeeType(); + if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(PointeeType)) { + Out << '8'; + mangleName(cast<RecordType>(T->getClass())->getDecl()); + mangleType(FPT, NULL, false, true); + } else { + mangleQualifiers(PointeeType.getQualifiers(), true); + mangleName(cast<RecordType>(T->getClass())->getDecl()); + mangleType(PointeeType.getLocalUnqualifiedType()); + } +} + +void MicrosoftCXXNameMangler::mangleType(const TemplateTypeParmType *T) { + assert(false && "Don't know how to mangle TemplateTypeParmTypes yet!"); +} + +void MicrosoftCXXNameMangler::mangleType( + const SubstTemplateTypeParmPackType *T) { + assert(false && + "Don't know how to mangle SubstTemplateTypeParmPackTypes yet!"); +} + +// <type> ::= <pointer-type> +// <pointer-type> ::= <pointer-cvr-qualifiers> <cvr-qualifiers> <type> +void MicrosoftCXXNameMangler::mangleType(const PointerType *T) { + QualType PointeeTy = T->getPointeeType(); + if (PointeeTy->isArrayType()) { + // Pointers to arrays are mangled like arrays. + mangleExtraDimensions(T->getPointeeType()); + } else if (PointeeTy->isFunctionType()) { + // Function pointers are special. + Out << '6'; + mangleType(static_cast<const FunctionType *>(PointeeTy.getTypePtr()), + NULL, false, false); + } else { + if (!PointeeTy.hasQualifiers()) + // Lack of qualifiers is mangled as 'A'. + Out << 'A'; + mangleType(PointeeTy); + } +} +void MicrosoftCXXNameMangler::mangleType(const ObjCObjectPointerType *T) { + // Object pointers never have qualifiers. + Out << 'A'; + mangleType(T->getPointeeType()); +} + +// <type> ::= <reference-type> +// <reference-type> ::= A <cvr-qualifiers> <type> +void MicrosoftCXXNameMangler::mangleType(const LValueReferenceType *T) { + Out << 'A'; + QualType PointeeTy = T->getPointeeType(); + if (!PointeeTy.hasQualifiers()) + // Lack of qualifiers is mangled as 'A'. + Out << 'A'; + mangleType(PointeeTy); +} + +void MicrosoftCXXNameMangler::mangleType(const RValueReferenceType *T) { + assert(false && "Don't know how to mangle RValueReferenceTypes yet!"); +} + +void MicrosoftCXXNameMangler::mangleType(const ComplexType *T) { + assert(false && "Don't know how to mangle ComplexTypes yet!"); +} + +void MicrosoftCXXNameMangler::mangleType(const VectorType *T) { + assert(false && "Don't know how to mangle VectorTypes yet!"); +} +void MicrosoftCXXNameMangler::mangleType(const ExtVectorType *T) { + assert(false && "Don't know how to mangle ExtVectorTypes yet!"); +} +void MicrosoftCXXNameMangler::mangleType(const DependentSizedExtVectorType *T) { + assert(false && "Don't know how to mangle DependentSizedExtVectorTypes yet!"); +} + +void MicrosoftCXXNameMangler::mangleType(const ObjCInterfaceType *T) { + // ObjC interfaces have structs underlying them. + Out << 'U'; + mangleName(T->getDecl()); +} + +void MicrosoftCXXNameMangler::mangleType(const ObjCObjectType *T) { + // We don't allow overloading by different protocol qualification, + // so mangling them isn't necessary. + mangleType(T->getBaseType()); +} + +void MicrosoftCXXNameMangler::mangleType(const BlockPointerType *T) { + Out << "_E"; + mangleType(T->getPointeeType()); +} + +void MicrosoftCXXNameMangler::mangleType(const InjectedClassNameType *T) { + assert(false && "Don't know how to mangle InjectedClassNameTypes yet!"); +} + +void MicrosoftCXXNameMangler::mangleType(const TemplateSpecializationType *T) { + assert(false && "Don't know how to mangle TemplateSpecializationTypes yet!"); +} + +void MicrosoftCXXNameMangler::mangleType(const DependentNameType *T) { + assert(false && "Don't know how to mangle DependentNameTypes yet!"); +} + +void MicrosoftCXXNameMangler::mangleType( + const DependentTemplateSpecializationType *T) { + assert(false && + "Don't know how to mangle DependentTemplateSpecializationTypes yet!"); +} + +void MicrosoftCXXNameMangler::mangleType(const PackExpansionType *T) { + assert(false && "Don't know how to mangle PackExpansionTypes yet!"); +} + +void MicrosoftCXXNameMangler::mangleType(const TypeOfType *T) { + assert(false && "Don't know how to mangle TypeOfTypes yet!"); +} + +void MicrosoftCXXNameMangler::mangleType(const TypeOfExprType *T) { + assert(false && "Don't know how to mangle TypeOfExprTypes yet!"); +} + +void MicrosoftCXXNameMangler::mangleType(const DecltypeType *T) { + assert(false && "Don't know how to mangle DecltypeTypes yet!"); +} + +void MicrosoftCXXNameMangler::mangleType(const AutoType *T) { + assert(false && "Don't know how to mangle AutoTypes yet!"); +} + +void MicrosoftMangleContext::mangleName(const NamedDecl *D, + llvm::raw_ostream &Out) { + assert((isa<FunctionDecl>(D) || isa<VarDecl>(D)) && + "Invalid mangleName() call, argument is not a variable or function!"); + assert(!isa<CXXConstructorDecl>(D) && !isa<CXXDestructorDecl>(D) && + "Invalid mangleName() call on 'structor decl!"); + + PrettyStackTraceDecl CrashInfo(D, SourceLocation(), + getASTContext().getSourceManager(), + "Mangling declaration"); + + MicrosoftCXXNameMangler Mangler(*this, Out); + return Mangler.mangle(D); +} +void MicrosoftMangleContext::mangleThunk(const CXXMethodDecl *MD, + const ThunkInfo &Thunk, + llvm::raw_ostream &) { + assert(false && "Can't yet mangle thunks!"); +} +void MicrosoftMangleContext::mangleCXXDtorThunk(const CXXDestructorDecl *DD, + CXXDtorType Type, + const ThisAdjustment &, + llvm::raw_ostream &) { + assert(false && "Can't yet mangle destructor thunks!"); +} +void MicrosoftMangleContext::mangleCXXVTable(const CXXRecordDecl *RD, + llvm::raw_ostream &) { + assert(false && "Can't yet mangle virtual tables!"); +} +void MicrosoftMangleContext::mangleCXXVTT(const CXXRecordDecl *RD, + llvm::raw_ostream &) { + llvm_unreachable("The MS C++ ABI does not have virtual table tables!"); +} +void MicrosoftMangleContext::mangleCXXCtorVTable(const CXXRecordDecl *RD, + int64_t Offset, + const CXXRecordDecl *Type, + llvm::raw_ostream &) { + llvm_unreachable("The MS C++ ABI does not have constructor vtables!"); +} +void MicrosoftMangleContext::mangleCXXRTTI(QualType T, + llvm::raw_ostream &) { + assert(false && "Can't yet mangle RTTI!"); +} +void MicrosoftMangleContext::mangleCXXRTTIName(QualType T, + llvm::raw_ostream &) { + assert(false && "Can't yet mangle RTTI names!"); +} +void MicrosoftMangleContext::mangleCXXCtor(const CXXConstructorDecl *D, + CXXCtorType Type, + llvm::raw_ostream &) { + assert(false && "Can't yet mangle constructors!"); +} +void MicrosoftMangleContext::mangleCXXDtor(const CXXDestructorDecl *D, + CXXDtorType Type, + llvm::raw_ostream &) { + assert(false && "Can't yet mangle destructors!"); +} +void MicrosoftMangleContext::mangleReferenceTemporary(const clang::VarDecl *, + llvm::raw_ostream &) { + assert(false && "Can't yet mangle reference temporaries!"); +} + +MangleContext *clang::createMicrosoftMangleContext(ASTContext &Context, + Diagnostic &Diags) { + return new MicrosoftMangleContext(Context, Diags); +} diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp index 212def8..650321d 100644 --- a/lib/AST/NestedNameSpecifier.cpp +++ b/lib/AST/NestedNameSpecifier.cpp @@ -22,7 +22,7 @@ using namespace clang; NestedNameSpecifier * -NestedNameSpecifier::FindOrInsert(ASTContext &Context, +NestedNameSpecifier::FindOrInsert(const ASTContext &Context, const NestedNameSpecifier &Mockup) { llvm::FoldingSetNodeID ID; Mockup.Profile(ID); @@ -39,8 +39,8 @@ NestedNameSpecifier::FindOrInsert(ASTContext &Context, } NestedNameSpecifier * -NestedNameSpecifier::Create(ASTContext &Context, NestedNameSpecifier *Prefix, - IdentifierInfo *II) { +NestedNameSpecifier::Create(const ASTContext &Context, + NestedNameSpecifier *Prefix, IdentifierInfo *II) { assert(II && "Identifier cannot be NULL"); assert((!Prefix || Prefix->isDependent()) && "Prefix must be dependent"); @@ -52,8 +52,8 @@ NestedNameSpecifier::Create(ASTContext &Context, NestedNameSpecifier *Prefix, } NestedNameSpecifier * -NestedNameSpecifier::Create(ASTContext &Context, NestedNameSpecifier *Prefix, - NamespaceDecl *NS) { +NestedNameSpecifier::Create(const ASTContext &Context, + NestedNameSpecifier *Prefix, NamespaceDecl *NS) { assert(NS && "Namespace cannot be NULL"); assert((!Prefix || (Prefix->getAsType() == 0 && Prefix->getAsIdentifier() == 0)) && @@ -66,18 +66,19 @@ NestedNameSpecifier::Create(ASTContext &Context, NestedNameSpecifier *Prefix, } NestedNameSpecifier * -NestedNameSpecifier::Create(ASTContext &Context, NestedNameSpecifier *Prefix, - bool Template, Type *T) { +NestedNameSpecifier::Create(const ASTContext &Context, + NestedNameSpecifier *Prefix, + bool Template, const Type *T) { assert(T && "Type cannot be NULL"); NestedNameSpecifier Mockup; Mockup.Prefix.setPointer(Prefix); Mockup.Prefix.setInt(Template? TypeSpecWithTemplate : TypeSpec); - Mockup.Specifier = T; + Mockup.Specifier = const_cast<Type*>(T); return FindOrInsert(Context, Mockup); } NestedNameSpecifier * -NestedNameSpecifier::Create(ASTContext &Context, IdentifierInfo *II) { +NestedNameSpecifier::Create(const ASTContext &Context, IdentifierInfo *II) { assert(II && "Identifier cannot be NULL"); NestedNameSpecifier Mockup; Mockup.Prefix.setPointer(0); @@ -86,7 +87,8 @@ NestedNameSpecifier::Create(ASTContext &Context, IdentifierInfo *II) { return FindOrInsert(Context, Mockup); } -NestedNameSpecifier *NestedNameSpecifier::GlobalSpecifier(ASTContext &Context) { +NestedNameSpecifier * +NestedNameSpecifier::GlobalSpecifier(const ASTContext &Context) { if (!Context.GlobalNestedNameSpecifier) Context.GlobalNestedNameSpecifier = new (Context, 4) NestedNameSpecifier(); return Context.GlobalNestedNameSpecifier; @@ -113,6 +115,24 @@ bool NestedNameSpecifier::isDependent() const { return false; } +bool NestedNameSpecifier::containsUnexpandedParameterPack() const { + switch (getKind()) { + case Identifier: + return getPrefix() && getPrefix()->containsUnexpandedParameterPack(); + + case Namespace: + case Global: + return false; + + case TypeSpec: + case TypeSpecWithTemplate: + return getAsType()->containsUnexpandedParameterPack(); + } + + // Necessary to suppress a GCC warning. + return false; +} + /// \brief Print this nested name specifier to the given output /// stream. void @@ -139,7 +159,7 @@ NestedNameSpecifier::print(llvm::raw_ostream &OS, case TypeSpec: { std::string TypeStr; - Type *T = getAsType(); + const Type *T = getAsType(); PrintingPolicy InnerPolicy(Policy); InnerPolicy.SuppressScope = true; diff --git a/lib/AST/ParentMap.cpp b/lib/AST/ParentMap.cpp index 5fe873a..eca351a 100644 --- a/lib/AST/ParentMap.cpp +++ b/lib/AST/ParentMap.cpp @@ -21,7 +21,7 @@ using namespace clang; typedef llvm::DenseMap<Stmt*, Stmt*> MapTy; static void BuildParentMap(MapTy& M, Stmt* S) { - for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I!=E; ++I) + for (Stmt::child_range I = S->children(); I; ++I) if (*I) { M[*I] = S; BuildParentMap(M, *I); @@ -40,6 +40,12 @@ ParentMap::~ParentMap() { delete (MapTy*) Impl; } +void ParentMap::addStmt(Stmt* S) { + if (S) { + BuildParentMap(*(MapTy*) Impl, S); + } +} + Stmt* ParentMap::getParent(Stmt* S) const { MapTy* M = (MapTy*) Impl; MapTy::iterator I = M->find(S); @@ -51,6 +57,15 @@ Stmt *ParentMap::getParentIgnoreParens(Stmt *S) const { return S; } +Stmt *ParentMap::getParentIgnoreParenCasts(Stmt *S) const { + do { + S = getParent(S); + } + while (S && (isa<ParenExpr>(S) || isa<CastExpr>(S))); + + return S; +} + bool ParentMap::isConsumedExpr(Expr* E) const { Stmt *P = getParent(E); Stmt *DirectChild = E; diff --git a/lib/AST/RecordLayout.cpp b/lib/AST/RecordLayout.cpp index 4d9c516..035c48f 100644 --- a/lib/AST/RecordLayout.cpp +++ b/lib/AST/RecordLayout.cpp @@ -27,9 +27,10 @@ void ASTRecordLayout::Destroy(ASTContext &Ctx) { Ctx.Deallocate(this); } -ASTRecordLayout::ASTRecordLayout(ASTContext &Ctx, uint64_t size, unsigned alignment, - unsigned datasize, const uint64_t *fieldoffsets, - unsigned fieldcount) +ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx, CharUnits size, + CharUnits alignment, CharUnits datasize, + const uint64_t *fieldoffsets, + unsigned fieldcount) : Size(size), DataSize(datasize), FieldOffsets(0), Alignment(alignment), FieldCount(fieldcount), CXXInfo(0) { if (FieldCount > 0) { @@ -39,16 +40,16 @@ ASTRecordLayout::ASTRecordLayout(ASTContext &Ctx, uint64_t size, unsigned alignm } // Constructor for C++ records. -ASTRecordLayout::ASTRecordLayout(ASTContext &Ctx, - uint64_t size, unsigned alignment, - uint64_t datasize, +ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx, + CharUnits size, CharUnits alignment, + CharUnits datasize, const uint64_t *fieldoffsets, unsigned fieldcount, - uint64_t nonvirtualsize, - unsigned nonvirtualalign, - uint64_t SizeOfLargestEmptySubobject, + CharUnits nonvirtualsize, + CharUnits nonvirtualalign, + CharUnits SizeOfLargestEmptySubobject, const CXXRecordDecl *PrimaryBase, - bool PrimaryBaseIsVirtual, + bool IsPrimaryBaseVirtual, const BaseOffsetsMapTy& BaseOffsets, const BaseOffsetsMapTy& VBaseOffsets) : Size(size), DataSize(datasize), FieldOffsets(0), Alignment(alignment), @@ -59,7 +60,8 @@ ASTRecordLayout::ASTRecordLayout(ASTContext &Ctx, memcpy(FieldOffsets, fieldoffsets, FieldCount * sizeof(*FieldOffsets)); } - CXXInfo->PrimaryBase = PrimaryBaseInfo(PrimaryBase, PrimaryBaseIsVirtual); + CXXInfo->PrimaryBase.setPointer(PrimaryBase); + CXXInfo->PrimaryBase.setInt(IsPrimaryBaseVirtual); CXXInfo->NonVirtualSize = nonvirtualsize; CXXInfo->NonVirtualAlign = nonvirtualalign; CXXInfo->SizeOfLargestEmptySubobject = SizeOfLargestEmptySubobject; @@ -68,11 +70,11 @@ ASTRecordLayout::ASTRecordLayout(ASTContext &Ctx, #ifndef NDEBUG if (const CXXRecordDecl *PrimaryBase = getPrimaryBase()) { - if (getPrimaryBaseWasVirtual()) - assert(getVBaseClassOffset(PrimaryBase) == 0 && + if (isPrimaryBaseVirtual()) + assert(getVBaseClassOffset(PrimaryBase).isZero() && "Primary virtual base must be at offset 0!"); else - assert(getBaseClassOffset(PrimaryBase) == 0 && + assert(getBaseClassOffsetInBits(PrimaryBase) == 0 && "Primary base must be at offset 0!"); } #endif diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index 13fae29..cf14eba 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -8,12 +8,14 @@ //===----------------------------------------------------------------------===// #include "clang/AST/Attr.h" +#include "clang/AST/CXXInheritance.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" #include "clang/AST/RecordLayout.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Sema/SemaDiagnostic.h" #include "llvm/Support/Format.h" #include "llvm/ADT/SmallSet.h" #include "llvm/Support/MathExtras.h" @@ -55,62 +57,71 @@ struct BaseSubobjectInfo { /// EmptySubobjectMap - Keeps track of which empty subobjects exist at different /// offsets while laying out a C++ class. class EmptySubobjectMap { - ASTContext &Context; - + const ASTContext &Context; + uint64_t CharWidth; + /// Class - The class whose empty entries we're keeping track of. const CXXRecordDecl *Class; /// EmptyClassOffsets - A map from offsets to empty record decls. typedef llvm::SmallVector<const CXXRecordDecl *, 1> ClassVectorTy; - typedef llvm::DenseMap<uint64_t, ClassVectorTy> EmptyClassOffsetsMapTy; + typedef llvm::DenseMap<CharUnits, ClassVectorTy> EmptyClassOffsetsMapTy; EmptyClassOffsetsMapTy EmptyClassOffsets; /// MaxEmptyClassOffset - The highest offset known to contain an empty /// base subobject. - uint64_t MaxEmptyClassOffset; + CharUnits MaxEmptyClassOffset; /// ComputeEmptySubobjectSizes - Compute the size of the largest base or /// member subobject that is empty. void ComputeEmptySubobjectSizes(); - void AddSubobjectAtOffset(const CXXRecordDecl *RD, uint64_t Offset); + void AddSubobjectAtOffset(const CXXRecordDecl *RD, CharUnits Offset); void UpdateEmptyBaseSubobjects(const BaseSubobjectInfo *Info, - uint64_t Offset, bool PlacingEmptyBase); + CharUnits Offset, bool PlacingEmptyBase); void UpdateEmptyFieldSubobjects(const CXXRecordDecl *RD, const CXXRecordDecl *Class, - uint64_t Offset); - void UpdateEmptyFieldSubobjects(const FieldDecl *FD, uint64_t Offset); + CharUnits Offset); + void UpdateEmptyFieldSubobjects(const FieldDecl *FD, CharUnits Offset); /// AnyEmptySubobjectsBeyondOffset - Returns whether there are any empty /// subobjects beyond the given offset. - bool AnyEmptySubobjectsBeyondOffset(uint64_t Offset) const { + bool AnyEmptySubobjectsBeyondOffset(CharUnits Offset) const { return Offset <= MaxEmptyClassOffset; } + CharUnits + getFieldOffset(const ASTRecordLayout &Layout, unsigned FieldNo) const { + uint64_t FieldOffset = Layout.getFieldOffset(FieldNo); + assert(FieldOffset % CharWidth == 0 && + "Field offset not at char boundary!"); + + return Context.toCharUnitsFromBits(FieldOffset); + } + protected: - bool CanPlaceSubobjectAtOffset(const CXXRecordDecl *RD, - uint64_t Offset) const; + bool CanPlaceSubobjectAtOffset(const CXXRecordDecl *RD, + CharUnits Offset) const; bool CanPlaceBaseSubobjectAtOffset(const BaseSubobjectInfo *Info, - uint64_t Offset); + CharUnits Offset); bool CanPlaceFieldSubobjectAtOffset(const CXXRecordDecl *RD, const CXXRecordDecl *Class, - uint64_t Offset) const; + CharUnits Offset) const; bool CanPlaceFieldSubobjectAtOffset(const FieldDecl *FD, - uint64_t Offset) const; + CharUnits Offset) const; public: /// This holds the size of the largest empty subobject (either a base /// or a member). Will be zero if the record being built doesn't contain /// any empty classes. - uint64_t SizeOfLargestEmptySubobject; + CharUnits SizeOfLargestEmptySubobject; - EmptySubobjectMap(ASTContext &Context, const CXXRecordDecl *Class) - : Context(Context), Class(Class), MaxEmptyClassOffset(0), - SizeOfLargestEmptySubobject(0) { + EmptySubobjectMap(const ASTContext &Context, const CXXRecordDecl *Class) + : Context(Context), CharWidth(Context.getCharWidth()), Class(Class) { ComputeEmptySubobjectSizes(); } @@ -119,11 +130,11 @@ public: /// Returns false if placing the record will result in two components /// (direct or indirect) of the same type having the same offset. bool CanPlaceBaseAtOffset(const BaseSubobjectInfo *Info, - uint64_t Offset); + CharUnits Offset); /// CanPlaceFieldAtOffset - Return whether a field can be placed at the given /// offset. - bool CanPlaceFieldAtOffset(const FieldDecl *FD, uint64_t Offset); + bool CanPlaceFieldAtOffset(const FieldDecl *FD, CharUnits Offset); }; void EmptySubobjectMap::ComputeEmptySubobjectSizes() { @@ -133,7 +144,7 @@ void EmptySubobjectMap::ComputeEmptySubobjectSizes() { const CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); - uint64_t EmptySize = 0; + CharUnits EmptySize; const ASTRecordLayout &Layout = Context.getASTRecordLayout(BaseDecl); if (BaseDecl->isEmpty()) { // If the class decl is empty, get its size. @@ -143,8 +154,8 @@ void EmptySubobjectMap::ComputeEmptySubobjectSizes() { EmptySize = Layout.getSizeOfLargestEmptySubobject(); } - SizeOfLargestEmptySubobject = std::max(SizeOfLargestEmptySubobject, - EmptySize); + if (EmptySize > SizeOfLargestEmptySubobject) + SizeOfLargestEmptySubobject = EmptySize; } // Check the fields. @@ -159,7 +170,7 @@ void EmptySubobjectMap::ComputeEmptySubobjectSizes() { if (!RT) continue; - uint64_t EmptySize = 0; + CharUnits EmptySize; const CXXRecordDecl *MemberDecl = cast<CXXRecordDecl>(RT->getDecl()); const ASTRecordLayout &Layout = Context.getASTRecordLayout(MemberDecl); if (MemberDecl->isEmpty()) { @@ -170,14 +181,14 @@ void EmptySubobjectMap::ComputeEmptySubobjectSizes() { EmptySize = Layout.getSizeOfLargestEmptySubobject(); } - SizeOfLargestEmptySubobject = std::max(SizeOfLargestEmptySubobject, - EmptySize); + if (EmptySize > SizeOfLargestEmptySubobject) + SizeOfLargestEmptySubobject = EmptySize; } } bool EmptySubobjectMap::CanPlaceSubobjectAtOffset(const CXXRecordDecl *RD, - uint64_t Offset) const { + CharUnits Offset) const { // We only need to check empty bases. if (!RD->isEmpty()) return true; @@ -195,24 +206,27 @@ EmptySubobjectMap::CanPlaceSubobjectAtOffset(const CXXRecordDecl *RD, } void EmptySubobjectMap::AddSubobjectAtOffset(const CXXRecordDecl *RD, - uint64_t Offset) { + CharUnits Offset) { // We only care about empty bases. if (!RD->isEmpty()) return; + // If we have empty structures inside an union, we can assign both + // the same offset. Just avoid pushing them twice in the list. ClassVectorTy& Classes = EmptyClassOffsets[Offset]; - assert(std::find(Classes.begin(), Classes.end(), RD) == Classes.end() && - "Duplicate empty class detected!"); - + if (std::find(Classes.begin(), Classes.end(), RD) != Classes.end()) + return; + Classes.push_back(RD); // Update the empty class offset. - MaxEmptyClassOffset = std::max(MaxEmptyClassOffset, Offset); + if (Offset > MaxEmptyClassOffset) + MaxEmptyClassOffset = Offset; } bool -EmptySubobjectMap::CanPlaceBaseSubobjectAtOffset(const BaseSubobjectInfo *Info, - uint64_t Offset) { +EmptySubobjectMap::CanPlaceBaseSubobjectAtOffset(const BaseSubobjectInfo *Info, + CharUnits Offset) { // We don't have to keep looking past the maximum offset that's known to // contain an empty class. if (!AnyEmptySubobjectsBeyondOffset(Offset)) @@ -228,7 +242,7 @@ EmptySubobjectMap::CanPlaceBaseSubobjectAtOffset(const BaseSubobjectInfo *Info, if (Base->IsVirtual) continue; - uint64_t BaseOffset = Offset + Layout.getBaseClassOffset(Base->Class); + CharUnits BaseOffset = Offset + Layout.getBaseClassOffset(Base->Class); if (!CanPlaceBaseSubobjectAtOffset(Base, BaseOffset)) return false; @@ -248,8 +262,10 @@ EmptySubobjectMap::CanPlaceBaseSubobjectAtOffset(const BaseSubobjectInfo *Info, for (CXXRecordDecl::field_iterator I = Info->Class->field_begin(), E = Info->Class->field_end(); I != E; ++I, ++FieldNo) { const FieldDecl *FD = *I; - - uint64_t FieldOffset = Offset + Layout.getFieldOffset(FieldNo); + if (FD->isBitField()) + continue; + + CharUnits FieldOffset = Offset + getFieldOffset(Layout, FieldNo); if (!CanPlaceFieldSubobjectAtOffset(FD, FieldOffset)) return false; } @@ -258,7 +274,7 @@ EmptySubobjectMap::CanPlaceBaseSubobjectAtOffset(const BaseSubobjectInfo *Info, } void EmptySubobjectMap::UpdateEmptyBaseSubobjects(const BaseSubobjectInfo *Info, - uint64_t Offset, + CharUnits Offset, bool PlacingEmptyBase) { if (!PlacingEmptyBase && Offset >= SizeOfLargestEmptySubobject) { // We know that the only empty subobjects that can conflict with empty @@ -278,7 +294,7 @@ void EmptySubobjectMap::UpdateEmptyBaseSubobjects(const BaseSubobjectInfo *Info, if (Base->IsVirtual) continue; - uint64_t BaseOffset = Offset + Layout.getBaseClassOffset(Base->Class); + CharUnits BaseOffset = Offset + Layout.getBaseClassOffset(Base->Class); UpdateEmptyBaseSubobjects(Base, BaseOffset, PlacingEmptyBase); } @@ -295,17 +311,19 @@ void EmptySubobjectMap::UpdateEmptyBaseSubobjects(const BaseSubobjectInfo *Info, for (CXXRecordDecl::field_iterator I = Info->Class->field_begin(), E = Info->Class->field_end(); I != E; ++I, ++FieldNo) { const FieldDecl *FD = *I; + if (FD->isBitField()) + continue; - uint64_t FieldOffset = Offset + Layout.getFieldOffset(FieldNo); + CharUnits FieldOffset = Offset + getFieldOffset(Layout, FieldNo); UpdateEmptyFieldSubobjects(FD, FieldOffset); } } bool EmptySubobjectMap::CanPlaceBaseAtOffset(const BaseSubobjectInfo *Info, - uint64_t Offset) { + CharUnits Offset) { // If we know this class doesn't have any empty subobjects we don't need to // bother checking. - if (!SizeOfLargestEmptySubobject) + if (SizeOfLargestEmptySubobject.isZero()) return true; if (!CanPlaceBaseSubobjectAtOffset(Info, Offset)) @@ -320,7 +338,7 @@ bool EmptySubobjectMap::CanPlaceBaseAtOffset(const BaseSubobjectInfo *Info, bool EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const CXXRecordDecl *RD, const CXXRecordDecl *Class, - uint64_t Offset) const { + CharUnits Offset) const { // We don't have to keep looking past the maximum offset that's known to // contain an empty class. if (!AnyEmptySubobjectsBeyondOffset(Offset)) @@ -340,7 +358,7 @@ EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const CXXRecordDecl *RD, const CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); - uint64_t BaseOffset = Offset + Layout.getBaseClassOffset(BaseDecl); + CharUnits BaseOffset = Offset + Layout.getBaseClassOffset(BaseDecl); if (!CanPlaceFieldSubobjectAtOffset(BaseDecl, Class, BaseOffset)) return false; } @@ -352,7 +370,7 @@ EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const CXXRecordDecl *RD, const CXXRecordDecl *VBaseDecl = cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); - uint64_t VBaseOffset = Offset + Layout.getVBaseClassOffset(VBaseDecl); + CharUnits VBaseOffset = Offset + Layout.getVBaseClassOffset(VBaseDecl); if (!CanPlaceFieldSubobjectAtOffset(VBaseDecl, Class, VBaseOffset)) return false; } @@ -363,8 +381,10 @@ EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const CXXRecordDecl *RD, for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); I != E; ++I, ++FieldNo) { const FieldDecl *FD = *I; - - uint64_t FieldOffset = Offset + Layout.getFieldOffset(FieldNo); + if (FD->isBitField()) + continue; + + CharUnits FieldOffset = Offset + getFieldOffset(Layout, FieldNo); if (!CanPlaceFieldSubobjectAtOffset(FD, FieldOffset)) return false; @@ -373,8 +393,9 @@ EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const CXXRecordDecl *RD, return true; } -bool EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const FieldDecl *FD, - uint64_t Offset) const { +bool +EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const FieldDecl *FD, + CharUnits Offset) const { // We don't have to keep looking past the maximum offset that's known to // contain an empty class. if (!AnyEmptySubobjectsBeyondOffset(Offset)) @@ -397,7 +418,7 @@ bool EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const FieldDecl *FD, const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); uint64_t NumElements = Context.getConstantArrayElementCount(AT); - uint64_t ElementOffset = Offset; + CharUnits ElementOffset = Offset; for (uint64_t I = 0; I != NumElements; ++I) { // We don't have to keep looking past the maximum offset that's known to // contain an empty class. @@ -415,7 +436,8 @@ bool EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const FieldDecl *FD, } bool -EmptySubobjectMap::CanPlaceFieldAtOffset(const FieldDecl *FD, uint64_t Offset) { +EmptySubobjectMap::CanPlaceFieldAtOffset(const FieldDecl *FD, + CharUnits Offset) { if (!CanPlaceFieldSubobjectAtOffset(FD, Offset)) return false; @@ -427,7 +449,7 @@ EmptySubobjectMap::CanPlaceFieldAtOffset(const FieldDecl *FD, uint64_t Offset) { void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const CXXRecordDecl *RD, const CXXRecordDecl *Class, - uint64_t Offset) { + CharUnits Offset) { // We know that the only empty subobjects that can conflict with empty // field subobjects are subobjects of empty bases that can be placed at offset // zero. Because of this, we only need to keep track of empty field @@ -449,7 +471,7 @@ void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const CXXRecordDecl *RD, const CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); - uint64_t BaseOffset = Offset + Layout.getBaseClassOffset(BaseDecl); + CharUnits BaseOffset = Offset + Layout.getBaseClassOffset(BaseDecl); UpdateEmptyFieldSubobjects(BaseDecl, Class, BaseOffset); } @@ -460,7 +482,7 @@ void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const CXXRecordDecl *RD, const CXXRecordDecl *VBaseDecl = cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); - uint64_t VBaseOffset = Offset + Layout.getVBaseClassOffset(VBaseDecl); + CharUnits VBaseOffset = Offset + Layout.getVBaseClassOffset(VBaseDecl); UpdateEmptyFieldSubobjects(VBaseDecl, Class, VBaseOffset); } } @@ -470,15 +492,17 @@ void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const CXXRecordDecl *RD, for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); I != E; ++I, ++FieldNo) { const FieldDecl *FD = *I; - - uint64_t FieldOffset = Offset + Layout.getFieldOffset(FieldNo); + if (FD->isBitField()) + continue; + + CharUnits FieldOffset = Offset + getFieldOffset(Layout, FieldNo); UpdateEmptyFieldSubobjects(FD, FieldOffset); } } void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const FieldDecl *FD, - uint64_t Offset) { + CharUnits Offset) { QualType T = FD->getType(); if (const RecordType *RT = T->getAs<RecordType>()) { const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); @@ -497,7 +521,7 @@ void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const FieldDecl *FD, const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); uint64_t NumElements = Context.getConstantArrayElementCount(AT); - uint64_t ElementOffset = Offset; + CharUnits ElementOffset = Offset; for (uint64_t I = 0; I != NumElements; ++I) { // We know that the only empty subobjects that can conflict with empty @@ -519,7 +543,7 @@ protected: // FIXME: Remove this and make the appropriate fields public. friend class clang::ASTContext; - ASTContext &Context; + const ASTContext &Context; EmptySubobjectMap *EmptySubobjects; @@ -527,7 +551,10 @@ protected: uint64_t Size; /// Alignment - The current alignment of the record layout. - unsigned Alignment; + CharUnits Alignment; + + /// \brief The alignment if attribute packed is not used. + CharUnits UnpackedAlignment; llvm::SmallVector<uint64_t, 16> FieldOffsets; @@ -545,13 +572,13 @@ protected: /// MaxFieldAlignment - The maximum allowed field alignment. This is set by /// #pragma pack. - unsigned MaxFieldAlignment; + CharUnits MaxFieldAlignment; /// DataSize - The data size of the record being laid out. uint64_t DataSize; - uint64_t NonVirtualSize; - unsigned NonVirtualAlignment; + CharUnits NonVirtualSize; + CharUnits NonVirtualAlignment; /// PrimaryBase - the primary base class (if one exists) of the class /// we're laying out. @@ -561,7 +588,7 @@ protected: /// out is virtual. bool PrimaryBaseIsVirtual; - typedef llvm::DenseMap<const CXXRecordDecl *, uint64_t> BaseOffsetsMapTy; + typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsetsMapTy; /// Bases - base classes and their offsets in the record. BaseOffsetsMapTy Bases; @@ -571,7 +598,7 @@ protected: /// IndirectPrimaryBases - Virtual base classes, direct or indirect, that are /// primary base classes for some other direct or indirect base class. - llvm::SmallSet<const CXXRecordDecl*, 32> IndirectPrimaryBases; + CXXIndirectPrimaryBaseSet IndirectPrimaryBases; /// FirstNearlyEmptyVBase - The first nearly empty virtual base class in /// inheritance graph order. Used for determining the primary base class. @@ -581,11 +608,14 @@ protected: /// avoid visiting virtual bases more than once. llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBases; - RecordLayoutBuilder(ASTContext &Context, EmptySubobjectMap *EmptySubobjects) - : Context(Context), EmptySubobjects(EmptySubobjects), Size(0), Alignment(8), - Packed(false), IsUnion(false), IsMac68kAlign(false), - UnfilledBitsInLastByte(0), MaxFieldAlignment(0), DataSize(0), - NonVirtualSize(0), NonVirtualAlignment(8), PrimaryBase(0), + RecordLayoutBuilder(const ASTContext &Context, EmptySubobjectMap + *EmptySubobjects) + : Context(Context), EmptySubobjects(EmptySubobjects), Size(0), + Alignment(CharUnits::One()), UnpackedAlignment(Alignment), + Packed(false), IsUnion(false), IsMac68kAlign(false), + UnfilledBitsInLastByte(0), MaxFieldAlignment(CharUnits::Zero()), + DataSize(0), NonVirtualSize(CharUnits::Zero()), + NonVirtualAlignment(CharUnits::One()), PrimaryBase(0), PrimaryBaseIsVirtual(false), FirstNearlyEmptyVBase(0) { } void Layout(const RecordDecl *D); @@ -594,7 +624,8 @@ protected: void LayoutFields(const RecordDecl *D); void LayoutField(const FieldDecl *D); - void LayoutWideBitField(uint64_t FieldSize, uint64_t TypeSize); + void LayoutWideBitField(uint64_t FieldSize, uint64_t TypeSize, + bool FieldPacked, const FieldDecl *D); void LayoutBitField(const FieldDecl *D); /// BaseSubobjectInfoAllocator - Allocator for BaseSubobjectInfo objects. @@ -628,13 +659,6 @@ protected: virtual uint64_t GetVirtualPointersSize(const CXXRecordDecl *RD) const; - /// IdentifyPrimaryBases - Identify all virtual base classes, direct or - /// indirect, that are primary base classes for some other direct or indirect - /// base class. - void IdentifyPrimaryBases(const CXXRecordDecl *RD); - - virtual bool IsNearlyEmpty(const CXXRecordDecl *RD) const; - /// LayoutNonVirtualBases - Determines the primary base class (if any) and /// lays it out. Will then proceed to lay out all non-virtual base clasess. void LayoutNonVirtualBases(const CXXRecordDecl *RD); @@ -642,8 +666,8 @@ protected: /// LayoutNonVirtualBase - Lays out a single non-virtual base. void LayoutNonVirtualBase(const BaseSubobjectInfo *Base); - void AddPrimaryVirtualBaseOffsets(const BaseSubobjectInfo *Info, - uint64_t Offset); + void AddPrimaryVirtualBaseOffsets(const BaseSubobjectInfo *Info, + CharUnits Offset); /// LayoutVirtualBases - Lays out all the virtual bases. void LayoutVirtualBases(const CXXRecordDecl *RD, @@ -653,17 +677,26 @@ protected: void LayoutVirtualBase(const BaseSubobjectInfo *Base); /// LayoutBase - Will lay out a base and return the offset where it was - /// placed, in bits. - uint64_t LayoutBase(const BaseSubobjectInfo *Base); + /// placed, in chars. + CharUnits LayoutBase(const BaseSubobjectInfo *Base); /// InitializeLayout - Initialize record layout for the given record decl. void InitializeLayout(const Decl *D); /// FinishLayout - Finalize record layout. Adjust record size based on the /// alignment. - void FinishLayout(); + void FinishLayout(const NamedDecl *D); + + void UpdateAlignment(CharUnits NewAlignment, CharUnits UnpackedNewAlignment); + void UpdateAlignment(CharUnits NewAlignment) { + UpdateAlignment(NewAlignment, NewAlignment); + } + + void CheckFieldPadding(uint64_t Offset, uint64_t UnpaddedOffset, + uint64_t UnpackedOffset, unsigned UnpackedAlign, + bool isPacked, const FieldDecl *D); - void UpdateAlignment(unsigned NewAlignment); + DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID); RecordLayoutBuilder(const RecordLayoutBuilder&); // DO NOT IMPLEMENT void operator=(const RecordLayoutBuilder&); // DO NOT IMPLEMENT @@ -674,42 +707,6 @@ public: }; } // end anonymous namespace -/// IsNearlyEmpty - Indicates when a class has a vtable pointer, but -/// no other data. -bool RecordLayoutBuilder::IsNearlyEmpty(const CXXRecordDecl *RD) const { - // FIXME: Audit the corners - if (!RD->isDynamicClass()) - return false; - const ASTRecordLayout &BaseInfo = Context.getASTRecordLayout(RD); - if (BaseInfo.getNonVirtualSize() == Context.Target.getPointerWidth(0)) - return true; - return false; -} - -void RecordLayoutBuilder::IdentifyPrimaryBases(const CXXRecordDecl *RD) { - const ASTRecordLayout::PrimaryBaseInfo &BaseInfo = - Context.getASTRecordLayout(RD).getPrimaryBaseInfo(); - - // If the record has a primary base class that is virtual, add it to the set - // of primary bases. - if (BaseInfo.isVirtual()) - IndirectPrimaryBases.insert(BaseInfo.getBase()); - - // Now traverse all bases and find primary bases for them. - for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), - e = RD->bases_end(); i != e; ++i) { - assert(!i->getType()->isDependentType() && - "Cannot layout class with dependent bases."); - const CXXRecordDecl *Base = - cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); - - // Only bases with virtual bases participate in computing the - // indirect primary virtual base classes. - if (Base->getNumVBases()) - IdentifyPrimaryBases(Base); - } -} - void RecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD) { for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), @@ -721,7 +718,7 @@ RecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD) { cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); // Check if this is a nearly empty virtual base. - if (I->isVirtual() && IsNearlyEmpty(Base)) { + if (I->isVirtual() && Context.isNearlyEmpty(Base)) { // If it's not an indirect primary base, then we've found our primary // base. if (!IndirectPrimaryBases.count(Base)) { @@ -754,14 +751,7 @@ void RecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) { // Compute all the primary virtual bases for all of our direct and // indirect bases, and record all their primary virtual base classes. - for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), - e = RD->bases_end(); i != e; ++i) { - assert(!i->getType()->isDependentType() && - "Cannot lay out class with dependent bases."); - const CXXRecordDecl *Base = - cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); - IdentifyPrimaryBases(Base); - } + RD->getIndirectPrimaryBases(IndirectPrimaryBases); // If the record has a dynamic base class, attempt to choose a primary base // class. It is the first (in direct base class order) non-virtual dynamic @@ -809,8 +799,18 @@ void RecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) { Size += GetVirtualPointersSize(RD); DataSize = Size; + CharUnits UnpackedBaseAlign = + Context.toCharUnitsFromBits(Context.Target.getPointerAlign(0)); + CharUnits BaseAlign = (Packed) ? CharUnits::One() : UnpackedBaseAlign; + + // The maximum field alignment overrides base align. + if (!MaxFieldAlignment.isZero()) { + BaseAlign = std::min(BaseAlign, MaxFieldAlignment); + UnpackedBaseAlign = std::min(UnpackedBaseAlign, MaxFieldAlignment); + } + // Update the alignment. - UpdateAlignment(Context.Target.getPointerAlign(0)); + UpdateAlignment(BaseAlign, UnpackedBaseAlign); } BaseSubobjectInfo * @@ -845,7 +845,7 @@ RecordLayoutBuilder::ComputeBaseSubobjectInfo(const CXXRecordDecl *RD, // Check if this base has a primary virtual base. if (RD->getNumVBases()) { const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - if (Layout.getPrimaryBaseWasVirtual()) { + if (Layout.isPrimaryBaseVirtual()) { // This base does have a primary virtual base. PrimaryVirtualBase = Layout.getPrimaryBase(); assert(PrimaryVirtualBase && "Didn't have a primary virtual base!"); @@ -977,7 +977,7 @@ RecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) { void RecordLayoutBuilder::LayoutNonVirtualBase(const BaseSubobjectInfo *Base) { // Layout the base. - uint64_t Offset = LayoutBase(Base); + CharUnits Offset = LayoutBase(Base); // Add its base class offset. assert(!Bases.count(Base->Class) && "base offset already exists!"); @@ -988,7 +988,7 @@ void RecordLayoutBuilder::LayoutNonVirtualBase(const BaseSubobjectInfo *Base) { void RecordLayoutBuilder::AddPrimaryVirtualBaseOffsets(const BaseSubobjectInfo *Info, - uint64_t Offset) { + CharUnits Offset) { // This base isn't interesting, it has no virtual bases. if (!Info->Class->getNumVBases()) return; @@ -1016,7 +1016,7 @@ RecordLayoutBuilder::AddPrimaryVirtualBaseOffsets(const BaseSubobjectInfo *Info, if (Base->IsVirtual) continue; - uint64_t BaseOffset = Offset + Layout.getBaseClassOffset(Base->Class); + CharUnits BaseOffset = Offset + Layout.getBaseClassOffset(Base->Class); AddPrimaryVirtualBaseOffsets(Base, BaseOffset); } } @@ -1033,7 +1033,7 @@ RecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD, } else { const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); PrimaryBase = Layout.getPrimaryBase(); - PrimaryBaseIsVirtual = Layout.getPrimaryBaseWasVirtual(); + PrimaryBaseIsVirtual = Layout.isPrimaryBaseVirtual(); } for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), @@ -1074,7 +1074,7 @@ void RecordLayoutBuilder::LayoutVirtualBase(const BaseSubobjectInfo *Base) { assert(!Base->Derived && "Trying to lay out a primary virtual base!"); // Layout the base. - uint64_t Offset = LayoutBase(Base); + CharUnits Offset = LayoutBase(Base); // Add its base class offset. assert(!VBases.count(Base->Class) && "vbase offset already exists!"); @@ -1083,38 +1083,48 @@ void RecordLayoutBuilder::LayoutVirtualBase(const BaseSubobjectInfo *Base) { AddPrimaryVirtualBaseOffsets(Base, Offset); } -uint64_t RecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) { +CharUnits RecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) { const ASTRecordLayout &Layout = Context.getASTRecordLayout(Base->Class); // If we have an empty base class, try to place it at offset 0. if (Base->Class->isEmpty() && - EmptySubobjects->CanPlaceBaseAtOffset(Base, 0)) { - Size = std::max(Size, Layout.getSize()); + EmptySubobjects->CanPlaceBaseAtOffset(Base, CharUnits::Zero())) { + uint64_t RecordSizeInBits = Context.toBits(Layout.getSize()); + Size = std::max(Size, RecordSizeInBits); - return 0; + return CharUnits::Zero(); } - unsigned BaseAlign = Layout.getNonVirtualAlign(); + CharUnits UnpackedBaseAlign = Layout.getNonVirtualAlign(); + CharUnits BaseAlign = (Packed) ? CharUnits::One() : UnpackedBaseAlign; + + // The maximum field alignment overrides base align. + if (!MaxFieldAlignment.isZero()) { + BaseAlign = std::min(BaseAlign, MaxFieldAlignment); + UnpackedBaseAlign = std::min(UnpackedBaseAlign, MaxFieldAlignment); + } // Round up the current record size to the base's alignment boundary. - uint64_t Offset = llvm::RoundUpToAlignment(DataSize, BaseAlign); + uint64_t Offset = + llvm::RoundUpToAlignment(DataSize, Context.toBits(BaseAlign)); // Try to place the base. - while (!EmptySubobjects->CanPlaceBaseAtOffset(Base, Offset)) - Offset += BaseAlign; + while (!EmptySubobjects->CanPlaceBaseAtOffset(Base, + Context.toCharUnitsFromBits(Offset))) + Offset += Context.toBits(BaseAlign); if (!Base->Class->isEmpty()) { // Update the data size. - DataSize = Offset + Layout.getNonVirtualSize(); + DataSize = Offset + Context.toBits(Layout.getNonVirtualSize()); Size = std::max(Size, DataSize); } else - Size = std::max(Size, Offset + Layout.getSize()); + Size = std::max(Size, Offset + Context.toBits(Layout.getSize())); // Remember max struct/class alignment. - UpdateAlignment(BaseAlign); + UpdateAlignment(BaseAlign, UnpackedBaseAlign); - return Offset; + return Context.toCharUnitsFromBits(Offset); } void RecordLayoutBuilder::InitializeLayout(const Decl *D) { @@ -1129,14 +1139,14 @@ void RecordLayoutBuilder::InitializeLayout(const Decl *D) { // to bit-fields, but gcc appears not to follow that. if (D->hasAttr<AlignMac68kAttr>()) { IsMac68kAlign = true; - MaxFieldAlignment = 2 * 8; - Alignment = 2 * 8; + MaxFieldAlignment = CharUnits::fromQuantity(2); + Alignment = CharUnits::fromQuantity(2); } else { if (const MaxFieldAlignmentAttr *MFAA = D->getAttr<MaxFieldAlignmentAttr>()) - MaxFieldAlignment = MFAA->getAlignment(); + MaxFieldAlignment = Context.toCharUnitsFromBits(MFAA->getAlignment()); if (unsigned MaxAlign = D->getMaxAlignment()) - UpdateAlignment(MaxAlign); + UpdateAlignment(Context.toCharUnitsFromBits(MaxAlign)); } } @@ -1146,7 +1156,7 @@ void RecordLayoutBuilder::Layout(const RecordDecl *D) { // Finally, round the size of the total struct up to the alignment of the // struct itself. - FinishLayout(); + FinishLayout(D); } void RecordLayoutBuilder::Layout(const CXXRecordDecl *RD) { @@ -1157,7 +1167,7 @@ void RecordLayoutBuilder::Layout(const CXXRecordDecl *RD) { LayoutFields(RD); - NonVirtualSize = Size; + NonVirtualSize = Context.toCharUnitsFromBits(Size); NonVirtualAlignment = Alignment; // Lay out the virtual bases and add the primary virtual base offsets. @@ -1167,7 +1177,7 @@ void RecordLayoutBuilder::Layout(const CXXRecordDecl *RD) { // Finally, round the size of the total struct up to the alignment of the // struct itself. - FinishLayout(); + FinishLayout(RD); #ifndef NDEBUG // Check that we have base offsets for all bases. @@ -1201,7 +1211,7 @@ void RecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D) { // We start laying out ivars not at the end of the superclass // structure, but at the next byte following the last field. - Size = llvm::RoundUpToAlignment(SL.getDataSize(), 8); + Size = Context.toBits(SL.getDataSize()); DataSize = Size; } @@ -1215,7 +1225,7 @@ void RecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D) { // Finally, round the size of the total struct up to the alignment of the // struct itself. - FinishLayout(); + FinishLayout(D); } void RecordLayoutBuilder::LayoutFields(const RecordDecl *D) { @@ -1227,7 +1237,9 @@ void RecordLayoutBuilder::LayoutFields(const RecordDecl *D) { } void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize, - uint64_t TypeSize) { + uint64_t TypeSize, + bool FieldPacked, + const FieldDecl *D) { assert(Context.getLangOptions().CPlusPlus && "Can only have wide bit-fields in C++!"); @@ -1258,6 +1270,7 @@ void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize, UnfilledBitsInLastByte = 0; uint64_t FieldOffset; + uint64_t UnpaddedFieldOffset = DataSize - UnfilledBitsInLastByte; if (IsUnion) { DataSize = std::max(DataSize, FieldSize); @@ -1276,16 +1289,20 @@ void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize, // Place this field at the current location. FieldOffsets.push_back(FieldOffset); + CheckFieldPadding(FieldOffset, UnpaddedFieldOffset, FieldOffset, + TypeAlign, FieldPacked, D); + // Update the size. Size = std::max(Size, DataSize); // Remember max struct/class alignment. - UpdateAlignment(TypeAlign); + UpdateAlignment(Context.toCharUnitsFromBits(TypeAlign)); } void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { bool FieldPacked = Packed || D->hasAttr<PackedAttr>(); - uint64_t FieldOffset = IsUnion ? 0 : (DataSize - UnfilledBitsInLastByte); + uint64_t UnpaddedFieldOffset = DataSize - UnfilledBitsInLastByte; + uint64_t FieldOffset = IsUnion ? 0 : UnpaddedFieldOffset; uint64_t FieldSize = D->getBitWidth()->EvaluateAsInt(Context).getZExtValue(); std::pair<uint64_t, unsigned> FieldInfo = Context.getTypeInfo(D->getType()); @@ -1293,29 +1310,48 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { unsigned FieldAlign = FieldInfo.second; if (FieldSize > TypeSize) { - LayoutWideBitField(FieldSize, TypeSize); + LayoutWideBitField(FieldSize, TypeSize, FieldPacked, D); return; } + // The align if the field is not packed. This is to check if the attribute + // was unnecessary (-Wpacked). + unsigned UnpackedFieldAlign = FieldAlign; + uint64_t UnpackedFieldOffset = FieldOffset; + if (!Context.Target.useBitFieldTypeAlignment()) + UnpackedFieldAlign = 1; + if (FieldPacked || !Context.Target.useBitFieldTypeAlignment()) FieldAlign = 1; FieldAlign = std::max(FieldAlign, D->getMaxAlignment()); + UnpackedFieldAlign = std::max(UnpackedFieldAlign, D->getMaxAlignment()); // The maximum field alignment overrides the aligned attribute. - if (MaxFieldAlignment) - FieldAlign = std::min(FieldAlign, MaxFieldAlignment); + if (!MaxFieldAlignment.isZero()) { + unsigned MaxFieldAlignmentInBits = Context.toBits(MaxFieldAlignment); + FieldAlign = std::min(FieldAlign, MaxFieldAlignmentInBits); + UnpackedFieldAlign = std::min(UnpackedFieldAlign, MaxFieldAlignmentInBits); + } // Check if we need to add padding to give the field the correct alignment. if (FieldSize == 0 || (FieldOffset & (FieldAlign-1)) + FieldSize > TypeSize) FieldOffset = llvm::RoundUpToAlignment(FieldOffset, FieldAlign); + if (FieldSize == 0 || + (UnpackedFieldOffset & (UnpackedFieldAlign-1)) + FieldSize > TypeSize) + UnpackedFieldOffset = llvm::RoundUpToAlignment(UnpackedFieldOffset, + UnpackedFieldAlign); + // Padding members don't affect overall alignment. if (!D->getIdentifier()) - FieldAlign = 1; + FieldAlign = UnpackedFieldAlign = 1; // Place this field at the current location. FieldOffsets.push_back(FieldOffset); + CheckFieldPadding(FieldOffset, UnpaddedFieldOffset, UnpackedFieldOffset, + UnpackedFieldAlign, FieldPacked, D); + // Update DataSize to include the last byte containing (part of) the bitfield. if (IsUnion) { // FIXME: I think FieldSize should be TypeSize here. @@ -1331,7 +1367,8 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { Size = std::max(Size, DataSize); // Remember max struct/class alignment. - UpdateAlignment(FieldAlign); + UpdateAlignment(Context.toCharUnitsFromBits(FieldAlign), + Context.toCharUnitsFromBits(UnpackedFieldAlign)); } void RecordLayoutBuilder::LayoutField(const FieldDecl *D) { @@ -1340,42 +1377,74 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) { return; } + uint64_t UnpaddedFieldOffset = DataSize - UnfilledBitsInLastByte; + // Reset the unfilled bits. UnfilledBitsInLastByte = 0; bool FieldPacked = Packed || D->hasAttr<PackedAttr>(); - uint64_t FieldOffset = IsUnion ? 0 : DataSize; - uint64_t FieldSize; - unsigned FieldAlign; + CharUnits FieldOffset = + IsUnion ? CharUnits::Zero() : Context.toCharUnitsFromBits(DataSize); + CharUnits FieldSize; + CharUnits FieldAlign; if (D->getType()->isIncompleteArrayType()) { // This is a flexible array member; we can't directly // query getTypeInfo about these, so we figure it out here. // Flexible array members don't have any size, but they // have to be aligned appropriately for their element type. - FieldSize = 0; + FieldSize = CharUnits::Zero(); const ArrayType* ATy = Context.getAsArrayType(D->getType()); - FieldAlign = Context.getTypeAlign(ATy->getElementType()); + FieldAlign = Context.getTypeAlignInChars(ATy->getElementType()); } else if (const ReferenceType *RT = D->getType()->getAs<ReferenceType>()) { unsigned AS = RT->getPointeeType().getAddressSpace(); - FieldSize = Context.Target.getPointerWidth(AS); - FieldAlign = Context.Target.getPointerAlign(AS); + FieldSize = + Context.toCharUnitsFromBits(Context.Target.getPointerWidth(AS)); + FieldAlign = + Context.toCharUnitsFromBits(Context.Target.getPointerAlign(AS)); } else { - std::pair<uint64_t, unsigned> FieldInfo = Context.getTypeInfo(D->getType()); + std::pair<CharUnits, CharUnits> FieldInfo = + Context.getTypeInfoInChars(D->getType()); FieldSize = FieldInfo.first; FieldAlign = FieldInfo.second; + + if (Context.getLangOptions().MSBitfields) { + // If MS bitfield layout is required, figure out what type is being + // laid out and align the field to the width of that type. + + // Resolve all typedefs down to their base type and round up the field + // alignment if necessary. + QualType T = Context.getBaseElementType(D->getType()); + if (const BuiltinType *BTy = T->getAs<BuiltinType>()) { + CharUnits TypeSize = Context.getTypeSizeInChars(BTy); + if (TypeSize > FieldAlign) + FieldAlign = TypeSize; + } + } } + // The align if the field is not packed. This is to check if the attribute + // was unnecessary (-Wpacked). + CharUnits UnpackedFieldAlign = FieldAlign; + CharUnits UnpackedFieldOffset = FieldOffset; + if (FieldPacked) - FieldAlign = 8; - FieldAlign = std::max(FieldAlign, D->getMaxAlignment()); + FieldAlign = CharUnits::One(); + CharUnits MaxAlignmentInChars = + Context.toCharUnitsFromBits(D->getMaxAlignment()); + FieldAlign = std::max(FieldAlign, MaxAlignmentInChars); + UnpackedFieldAlign = std::max(UnpackedFieldAlign, MaxAlignmentInChars); // The maximum field alignment overrides the aligned attribute. - if (MaxFieldAlignment) + if (!MaxFieldAlignment.isZero()) { FieldAlign = std::min(FieldAlign, MaxFieldAlignment); + UnpackedFieldAlign = std::min(UnpackedFieldAlign, MaxFieldAlignment); + } // Round up the current record size to the field's alignment boundary. - FieldOffset = llvm::RoundUpToAlignment(FieldOffset, FieldAlign); + FieldOffset = FieldOffset.RoundUpToAlignment(FieldAlign); + UnpackedFieldOffset = + UnpackedFieldOffset.RoundUpToAlignment(UnpackedFieldAlign); if (!IsUnion && EmptySubobjects) { // Check if we can place the field at this offset. @@ -1386,41 +1455,130 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) { } // Place this field at the current location. - FieldOffsets.push_back(FieldOffset); + FieldOffsets.push_back(Context.toBits(FieldOffset)); + + CheckFieldPadding(Context.toBits(FieldOffset), UnpaddedFieldOffset, + Context.toBits(UnpackedFieldOffset), + Context.toBits(UnpackedFieldAlign), FieldPacked, D); // Reserve space for this field. + uint64_t FieldSizeInBits = Context.toBits(FieldSize); if (IsUnion) - Size = std::max(Size, FieldSize); + Size = std::max(Size, FieldSizeInBits); else - Size = FieldOffset + FieldSize; + Size = Context.toBits(FieldOffset) + FieldSizeInBits; // Update the data size. DataSize = Size; // Remember max struct/class alignment. - UpdateAlignment(FieldAlign); + UpdateAlignment(FieldAlign, UnpackedFieldAlign); } -void RecordLayoutBuilder::FinishLayout() { +void RecordLayoutBuilder::FinishLayout(const NamedDecl *D) { // In C++, records cannot be of size 0. - if (Context.getLangOptions().CPlusPlus && Size == 0) - Size = 8; + if (Context.getLangOptions().CPlusPlus && Size == 0) { + if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) { + // Compatibility with gcc requires a class (pod or non-pod) + // which is not empty but of size 0; such as having fields of + // array of zero-length, remains of Size 0 + if (RD->isEmpty()) + Size = 8; + } + else + Size = 8; + } // Finally, round the size of the record up to the alignment of the // record itself. - Size = llvm::RoundUpToAlignment(Size, Alignment); + uint64_t UnpaddedSize = Size - UnfilledBitsInLastByte; + uint64_t UnpackedSize = + llvm::RoundUpToAlignment(Size, Context.toBits(UnpackedAlignment)); + Size = llvm::RoundUpToAlignment(Size, Context.toBits(Alignment)); + + unsigned CharBitNum = Context.Target.getCharWidth(); + if (const RecordDecl *RD = dyn_cast<RecordDecl>(D)) { + // Warn if padding was introduced to the struct/class/union. + if (Size > UnpaddedSize) { + unsigned PadSize = Size - UnpaddedSize; + bool InBits = true; + if (PadSize % CharBitNum == 0) { + PadSize = PadSize / CharBitNum; + InBits = false; + } + Diag(RD->getLocation(), diag::warn_padded_struct_size) + << Context.getTypeDeclType(RD) + << PadSize + << (InBits ? 1 : 0) /*(byte|bit)*/ << (PadSize > 1); // plural or not + } + + // Warn if we packed it unnecessarily. If the alignment is 1 byte don't + // bother since there won't be alignment issues. + if (Packed && UnpackedAlignment > CharUnits::One() && Size == UnpackedSize) + Diag(D->getLocation(), diag::warn_unnecessary_packed) + << Context.getTypeDeclType(RD); + } } -void RecordLayoutBuilder::UpdateAlignment(unsigned NewAlignment) { +void RecordLayoutBuilder::UpdateAlignment(CharUnits NewAlignment, + CharUnits UnpackedNewAlignment) { // The alignment is not modified when using 'mac68k' alignment. if (IsMac68kAlign) return; - if (NewAlignment <= Alignment) + if (NewAlignment > Alignment) { + assert(llvm::isPowerOf2_32(NewAlignment.getQuantity() && + "Alignment not a power of 2")); + Alignment = NewAlignment; + } + + if (UnpackedNewAlignment > UnpackedAlignment) { + assert(llvm::isPowerOf2_32(UnpackedNewAlignment.getQuantity() && + "Alignment not a power of 2")); + UnpackedAlignment = UnpackedNewAlignment; + } +} + +void RecordLayoutBuilder::CheckFieldPadding(uint64_t Offset, + uint64_t UnpaddedOffset, + uint64_t UnpackedOffset, + unsigned UnpackedAlign, + bool isPacked, + const FieldDecl *D) { + // We let objc ivars without warning, objc interfaces generally are not used + // for padding tricks. + if (isa<ObjCIvarDecl>(D)) return; - assert(llvm::isPowerOf2_32(NewAlignment && "Alignment not a power of 2")); + unsigned CharBitNum = Context.Target.getCharWidth(); - Alignment = NewAlignment; + // Warn if padding was introduced to the struct/class. + if (!IsUnion && Offset > UnpaddedOffset) { + unsigned PadSize = Offset - UnpaddedOffset; + bool InBits = true; + if (PadSize % CharBitNum == 0) { + PadSize = PadSize / CharBitNum; + InBits = false; + } + if (D->getIdentifier()) + Diag(D->getLocation(), diag::warn_padded_struct_field) + << (D->getParent()->isStruct() ? 0 : 1) // struct|class + << Context.getTypeDeclType(D->getParent()) + << PadSize + << (InBits ? 1 : 0) /*(byte|bit)*/ << (PadSize > 1) // plural or not + << D->getIdentifier(); + else + Diag(D->getLocation(), diag::warn_padded_struct_anon_field) + << (D->getParent()->isStruct() ? 0 : 1) // struct|class + << Context.getTypeDeclType(D->getParent()) + << PadSize + << (InBits ? 1 : 0) /*(byte|bit)*/ << (PadSize > 1); // plural or not + } + + // Warn if we packed it unnecessarily. If the alignment is 1 byte don't + // bother since there won't be alignment issues. + if (isPacked && UnpackedAlign > CharBitNum && Offset == UnpackedOffset) + Diag(D->getLocation(), diag::warn_unnecessary_packed) + << D->getIdentifier(); } const CXXMethodDecl * @@ -1435,6 +1593,13 @@ RecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) { if (RD->isInAnonymousNamespace()) return 0; + // Template instantiations don't have key functions,see Itanium C++ ABI 5.2.6. + // Same behavior as GCC. + TemplateSpecializationKind TSK = RD->getTemplateSpecializationKind(); + if (TSK == TSK_ImplicitInstantiation || + TSK == TSK_ExplicitInstantiationDefinition) + return 0; + for (CXXRecordDecl::method_iterator I = RD->method_begin(), E = RD->method_end(); I != E; ++I) { const CXXMethodDecl *MD = *I; @@ -1463,26 +1628,21 @@ RecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) { return 0; } -// This class implements layout specific to the Microsoft ABI. -class MSRecordLayoutBuilder: public RecordLayoutBuilder { -public: - MSRecordLayoutBuilder(ASTContext& Ctx, EmptySubobjectMap *EmptySubobjects): - RecordLayoutBuilder(Ctx, EmptySubobjects) {} - - virtual bool IsNearlyEmpty(const CXXRecordDecl *RD) const; - virtual uint64_t GetVirtualPointersSize(const CXXRecordDecl *RD) const; -}; +DiagnosticBuilder +RecordLayoutBuilder::Diag(SourceLocation Loc, unsigned DiagID) { + return Context.getDiagnostics().Report(Loc, DiagID); +} -bool MSRecordLayoutBuilder::IsNearlyEmpty(const CXXRecordDecl *RD) const { - // FIXME: Audit the corners - if (!RD->isDynamicClass()) - return false; - const ASTRecordLayout &BaseInfo = Context.getASTRecordLayout(RD); - // In the Microsoft ABI, classes can have one or two vtable pointers. - if (BaseInfo.getNonVirtualSize() == Context.Target.getPointerWidth(0) || - BaseInfo.getNonVirtualSize() == Context.Target.getPointerWidth(0) * 2) - return true; - return false; +namespace { + // This class implements layout specific to the Microsoft ABI. + class MSRecordLayoutBuilder : public RecordLayoutBuilder { + public: + MSRecordLayoutBuilder(const ASTContext& Ctx, + EmptySubobjectMap *EmptySubobjects) : + RecordLayoutBuilder(Ctx, EmptySubobjects) {} + + virtual uint64_t GetVirtualPointersSize(const CXXRecordDecl *RD) const; + }; } uint64_t @@ -1497,7 +1657,8 @@ MSRecordLayoutBuilder::GetVirtualPointersSize(const CXXRecordDecl *RD) const { /// getASTRecordLayout - Get or compute information about the layout of the /// specified record (struct/union/class), which indicates its size and field /// position information. -const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) { +const ASTRecordLayout & +ASTContext::getASTRecordLayout(const RecordDecl *D) const { D = D->getDefinition(); assert(D && "Cannot get layout of forward declarations!"); @@ -1531,12 +1692,16 @@ const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) { // FIXME: This should be done in FinalizeLayout. uint64_t DataSize = IsPODForThePurposeOfLayout ? Builder->Size : Builder->DataSize; - uint64_t NonVirtualSize = - IsPODForThePurposeOfLayout ? DataSize : Builder->NonVirtualSize; + CharUnits NonVirtualSize = + IsPODForThePurposeOfLayout ? + toCharUnitsFromBits(DataSize) : Builder->NonVirtualSize; + CharUnits RecordSize = toCharUnitsFromBits(Builder->Size); NewEntry = - new (*this) ASTRecordLayout(*this, Builder->Size, Builder->Alignment, - DataSize, Builder->FieldOffsets.data(), + new (*this) ASTRecordLayout(*this, RecordSize, + Builder->Alignment, + toCharUnitsFromBits(DataSize), + Builder->FieldOffsets.data(), Builder->FieldOffsets.size(), NonVirtualSize, Builder->NonVirtualAlignment, @@ -1548,9 +1713,12 @@ const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) { RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0); Builder.Layout(D); + CharUnits RecordSize = toCharUnitsFromBits(Builder.Size); + NewEntry = - new (*this) ASTRecordLayout(*this, Builder.Size, Builder.Alignment, - Builder.Size, + new (*this) ASTRecordLayout(*this, RecordSize, + Builder.Alignment, + toCharUnitsFromBits(Builder.Size), Builder.FieldOffsets.data(), Builder.FieldOffsets.size()); } @@ -1572,9 +1740,6 @@ const CXXMethodDecl *ASTContext::getKeyFunction(const CXXRecordDecl *RD) { const CXXMethodDecl *&Entry = KeyFunctions[RD]; if (!Entry) Entry = RecordLayoutBuilder::ComputeKeyFunction(RD); - else - assert(Entry == RecordLayoutBuilder::ComputeKeyFunction(RD) && - "Key function changed!"); return Entry; } @@ -1586,7 +1751,7 @@ const CXXMethodDecl *ASTContext::getKeyFunction(const CXXRecordDecl *RD) { /// implementation. This may differ by including synthesized ivars. const ASTRecordLayout & ASTContext::getObjCLayout(const ObjCInterfaceDecl *D, - const ObjCImplementationDecl *Impl) { + const ObjCImplementationDecl *Impl) const { assert(!D->isForwardDecl() && "Invalid interface decl!"); // Look up this layout, if already laid out, return what we have. @@ -1609,9 +1774,12 @@ ASTContext::getObjCLayout(const ObjCInterfaceDecl *D, RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0); Builder.Layout(D); + CharUnits RecordSize = toCharUnitsFromBits(Builder.Size); + const ASTRecordLayout *NewEntry = - new (*this) ASTRecordLayout(*this, Builder.Size, Builder.Alignment, - Builder.DataSize, + new (*this) ASTRecordLayout(*this, RecordSize, + Builder.Alignment, + toCharUnitsFromBits(Builder.DataSize), Builder.FieldOffsets.data(), Builder.FieldOffsets.size()); @@ -1621,18 +1789,18 @@ ASTContext::getObjCLayout(const ObjCInterfaceDecl *D, } static void PrintOffset(llvm::raw_ostream &OS, - uint64_t Offset, unsigned IndentLevel) { - OS << llvm::format("%4d | ", Offset); + CharUnits Offset, unsigned IndentLevel) { + OS << llvm::format("%4d | ", Offset.getQuantity()); OS.indent(IndentLevel * 2); } static void DumpCXXRecordLayout(llvm::raw_ostream &OS, - const CXXRecordDecl *RD, ASTContext &C, - uint64_t Offset, + const CXXRecordDecl *RD, const ASTContext &C, + CharUnits Offset, unsigned IndentLevel, const char* Description, bool IncludeVirtualBases) { - const ASTRecordLayout &Info = C.getASTRecordLayout(RD); + const ASTRecordLayout &Layout = C.getASTRecordLayout(RD); PrintOffset(OS, Offset, IndentLevel); OS << C.getTypeDeclType(const_cast<CXXRecordDecl *>(RD)).getAsString(); @@ -1644,7 +1812,7 @@ static void DumpCXXRecordLayout(llvm::raw_ostream &OS, IndentLevel++; - const CXXRecordDecl *PrimaryBase = Info.getPrimaryBase(); + const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); // Vtable pointer. if (RD->isDynamicClass() && !PrimaryBase) { @@ -1662,7 +1830,7 @@ static void DumpCXXRecordLayout(llvm::raw_ostream &OS, const CXXRecordDecl *Base = cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); - uint64_t BaseOffset = Offset + Info.getBaseClassOffset(Base) / 8; + CharUnits BaseOffset = Offset + Layout.getBaseClassOffset(Base); DumpCXXRecordLayout(OS, Base, C, BaseOffset, IndentLevel, Base == PrimaryBase ? "(primary base)" : "(base)", @@ -1674,7 +1842,8 @@ static void DumpCXXRecordLayout(llvm::raw_ostream &OS, for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); I != E; ++I, ++FieldNo) { const FieldDecl *Field = *I; - uint64_t FieldOffset = Offset + Info.getFieldOffset(FieldNo) / 8; + CharUnits FieldOffset = Offset + + C.toCharUnitsFromBits(Layout.getFieldOffset(FieldNo)); if (const RecordType *RT = Field->getType()->getAs<RecordType>()) { if (const CXXRecordDecl *D = dyn_cast<CXXRecordDecl>(RT->getDecl())) { @@ -1699,27 +1868,27 @@ static void DumpCXXRecordLayout(llvm::raw_ostream &OS, const CXXRecordDecl *VBase = cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); - uint64_t VBaseOffset = Offset + Info.getVBaseClassOffset(VBase) / 8; + CharUnits VBaseOffset = Offset + Layout.getVBaseClassOffset(VBase); DumpCXXRecordLayout(OS, VBase, C, VBaseOffset, IndentLevel, VBase == PrimaryBase ? "(primary virtual base)" : "(virtual base)", /*IncludeVirtualBases=*/false); } - OS << " sizeof=" << Info.getSize() / 8; - OS << ", dsize=" << Info.getDataSize() / 8; - OS << ", align=" << Info.getAlignment() / 8 << '\n'; - OS << " nvsize=" << Info.getNonVirtualSize() / 8; - OS << ", nvalign=" << Info.getNonVirtualAlign() / 8 << '\n'; + OS << " sizeof=" << Layout.getSize().getQuantity(); + OS << ", dsize=" << Layout.getDataSize().getQuantity(); + OS << ", align=" << Layout.getAlignment().getQuantity() << '\n'; + OS << " nvsize=" << Layout.getNonVirtualSize().getQuantity(); + OS << ", nvalign=" << Layout.getNonVirtualAlign().getQuantity() << '\n'; OS << '\n'; } void ASTContext::DumpRecordLayout(const RecordDecl *RD, - llvm::raw_ostream &OS) { + llvm::raw_ostream &OS) const { const ASTRecordLayout &Info = getASTRecordLayout(RD); if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) - return DumpCXXRecordLayout(OS, CXXRD, *this, 0, 0, 0, + return DumpCXXRecordLayout(OS, CXXRD, *this, CharUnits(), 0, 0, /*IncludeVirtualBases=*/true); OS << "Type: " << getTypeDeclType(RD).getAsString() << "\n"; @@ -1727,9 +1896,9 @@ void ASTContext::DumpRecordLayout(const RecordDecl *RD, RD->dump(); OS << "\nLayout: "; OS << "<ASTRecordLayout\n"; - OS << " Size:" << Info.getSize() << "\n"; - OS << " DataSize:" << Info.getDataSize() << "\n"; - OS << " Alignment:" << Info.getAlignment() << "\n"; + OS << " Size:" << toBits(Info.getSize()) << "\n"; + OS << " DataSize:" << toBits(Info.getDataSize()) << "\n"; + OS << " Alignment:" << toBits(Info.getAlignment()) << "\n"; OS << " FieldOffsets: ["; for (unsigned i = 0, e = Info.getFieldCount(); i != e; ++i) { if (i) OS << ", "; diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index fc88981..7e73f02 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -46,7 +46,7 @@ static StmtClassNameTable &getStmtInfoTableEntry(Stmt::StmtClass E) { } const char *Stmt::getStmtClassName() const { - return getStmtInfoTableEntry((StmtClass)sClass).Name; + return getStmtInfoTableEntry((StmtClass) StmtBits.sClass).Name; } void Stmt::PrintStats() { @@ -84,17 +84,84 @@ bool Stmt::CollectingStats(bool Enable) { return StatSwitch; } +namespace { + struct good {}; + struct bad {}; + + // These silly little functions have to be static inline to suppress + // unused warnings, and they have to be defined to suppress other + // warnings. + static inline good is_good(good) { return good(); } + + typedef Stmt::child_range children_t(); + template <class T> good implements_children(children_t T::*) { + return good(); + } + static inline bad implements_children(children_t Stmt::*) { + return bad(); + } + + typedef SourceRange getSourceRange_t() const; + template <class T> good implements_getSourceRange(getSourceRange_t T::*) { + return good(); + } + static inline bad implements_getSourceRange(getSourceRange_t Stmt::*) { + return bad(); + } + +#define ASSERT_IMPLEMENTS_children(type) \ + (void) sizeof(is_good(implements_children(&type::children))) +#define ASSERT_IMPLEMENTS_getSourceRange(type) \ + (void) sizeof(is_good(implements_getSourceRange(&type::getSourceRange))) +} + +/// Check whether the various Stmt classes implement their member +/// functions. +static inline void check_implementations() { +#define ABSTRACT_STMT(type) +#define STMT(type, base) \ + ASSERT_IMPLEMENTS_children(type); \ + ASSERT_IMPLEMENTS_getSourceRange(type); +#include "clang/AST/StmtNodes.inc" +} + +Stmt::child_range Stmt::children() { + switch (getStmtClass()) { + case Stmt::NoStmtClass: llvm_unreachable("statement without class"); +#define ABSTRACT_STMT(type) +#define STMT(type, base) \ + case Stmt::type##Class: \ + return static_cast<type*>(this)->children(); +#include "clang/AST/StmtNodes.inc" + } + llvm_unreachable("unknown statement kind!"); + return child_range(); +} + +SourceRange Stmt::getSourceRange() const { + switch (getStmtClass()) { + case Stmt::NoStmtClass: llvm_unreachable("statement without class"); +#define ABSTRACT_STMT(type) +#define STMT(type, base) \ + case Stmt::type##Class: \ + return static_cast<const type*>(this)->getSourceRange(); +#include "clang/AST/StmtNodes.inc" + } + llvm_unreachable("unknown statement kind!"); + return SourceRange(); +} + void CompoundStmt::setStmts(ASTContext &C, Stmt **Stmts, unsigned NumStmts) { if (this->Body) C.Deallocate(Body); - this->NumStmts = NumStmts; + this->CompoundStmtBits.NumStmts = NumStmts; Body = new (C) Stmt*[NumStmts]; memcpy(Body, Stmts, sizeof(Stmt *) * NumStmts); } const char *LabelStmt::getName() const { - return getID()->getNameStart(); + return getDecl()->getIdentifier()->getNameStart(); } // This is defined here to avoid polluting Stmt.h with importing Expr.h @@ -106,7 +173,7 @@ SourceRange ReturnStmt::getSourceRange() const { } bool Stmt::hasImplicitControlFlow() const { - switch (sClass) { + switch (StmtBits.sClass) { default: return false; @@ -416,7 +483,7 @@ ObjCAtTryStmt *ObjCAtTryStmt::Create(ASTContext &Context, Stmt *atFinallyStmt) { unsigned Size = sizeof(ObjCAtTryStmt) + (1 + NumCatchStmts + (atFinallyStmt != 0)) * sizeof(Stmt *); - void *Mem = Context.Allocate(Size, llvm::alignof<ObjCAtTryStmt>()); + void *Mem = Context.Allocate(Size, llvm::alignOf<ObjCAtTryStmt>()); return new (Mem) ObjCAtTryStmt(atTryLoc, atTryStmt, CatchStmts, NumCatchStmts, atFinallyStmt); } @@ -426,7 +493,7 @@ ObjCAtTryStmt *ObjCAtTryStmt::CreateEmpty(ASTContext &Context, bool HasFinally) { unsigned Size = sizeof(ObjCAtTryStmt) + (1 + NumCatchStmts + HasFinally) * sizeof(Stmt *); - void *Mem = Context.Allocate(Size, llvm::alignof<ObjCAtTryStmt>()); + void *Mem = Context.Allocate(Size, llvm::alignOf<ObjCAtTryStmt>()); return new (Mem) ObjCAtTryStmt(EmptyShell(), NumCatchStmts, HasFinally); } @@ -448,7 +515,7 @@ CXXTryStmt *CXXTryStmt::Create(ASTContext &C, SourceLocation tryLoc, std::size_t Size = sizeof(CXXTryStmt); Size += ((numHandlers + 1) * sizeof(Stmt)); - void *Mem = C.Allocate(Size, llvm::alignof<CXXTryStmt>()); + void *Mem = C.Allocate(Size, llvm::alignOf<CXXTryStmt>()); return new (Mem) CXXTryStmt(tryLoc, tryBlock, handlers, numHandlers); } @@ -457,7 +524,7 @@ CXXTryStmt *CXXTryStmt::Create(ASTContext &C, EmptyShell Empty, std::size_t Size = sizeof(CXXTryStmt); Size += ((numHandlers + 1) * sizeof(Stmt)); - void *Mem = C.Allocate(Size, llvm::alignof<CXXTryStmt>()); + void *Mem = C.Allocate(Size, llvm::alignOf<CXXTryStmt>()); return new (Mem) CXXTryStmt(Empty, numHandlers); } @@ -530,7 +597,7 @@ void ForStmt::setConditionVariable(ASTContext &C, VarDecl *V) { } SwitchStmt::SwitchStmt(ASTContext &C, VarDecl *Var, Expr *cond) - : Stmt(SwitchStmtClass), FirstCase(0) + : Stmt(SwitchStmtClass), FirstCase(0), AllEnumCasesCovered(0) { setConditionVariable(C, Var); SubExprs[COND] = reinterpret_cast<Stmt*>(cond); @@ -556,6 +623,11 @@ void SwitchStmt::setConditionVariable(ASTContext &C, VarDecl *V) { V->getSourceRange().getEnd()); } +Stmt *SwitchCase::getSubStmt() { + if (isa<CaseStmt>(this)) return cast<CaseStmt>(this)->getSubStmt(); + return cast<DefaultStmt>(this)->getSubStmt(); +} + WhileStmt::WhileStmt(ASTContext &C, VarDecl *Var, Expr *cond, Stmt *body, SourceLocation WL) : Stmt(WhileStmtClass) @@ -585,101 +657,13 @@ void WhileStmt::setConditionVariable(ASTContext &C, VarDecl *V) { V->getSourceRange().getEnd()); } -//===----------------------------------------------------------------------===// -// Child Iterators for iterating over subexpressions/substatements -//===----------------------------------------------------------------------===// - -// DeclStmt -Stmt::child_iterator DeclStmt::child_begin() { - return StmtIterator(DG.begin(), DG.end()); -} - -Stmt::child_iterator DeclStmt::child_end() { - return StmtIterator(DG.end(), DG.end()); -} - -// NullStmt -Stmt::child_iterator NullStmt::child_begin() { return child_iterator(); } -Stmt::child_iterator NullStmt::child_end() { return child_iterator(); } - -// CompoundStmt -Stmt::child_iterator CompoundStmt::child_begin() { return &Body[0]; } -Stmt::child_iterator CompoundStmt::child_end() { return &Body[0]+NumStmts; } - -// CaseStmt -Stmt::child_iterator CaseStmt::child_begin() { return &SubExprs[0]; } -Stmt::child_iterator CaseStmt::child_end() { return &SubExprs[END_EXPR]; } - -// DefaultStmt -Stmt::child_iterator DefaultStmt::child_begin() { return &SubStmt; } -Stmt::child_iterator DefaultStmt::child_end() { return &SubStmt+1; } - -// LabelStmt -Stmt::child_iterator LabelStmt::child_begin() { return &SubStmt; } -Stmt::child_iterator LabelStmt::child_end() { return &SubStmt+1; } - -// IfStmt -Stmt::child_iterator IfStmt::child_begin() { - return &SubExprs[0]; -} -Stmt::child_iterator IfStmt::child_end() { - return &SubExprs[0]+END_EXPR; -} - -// SwitchStmt -Stmt::child_iterator SwitchStmt::child_begin() { - return &SubExprs[0]; -} -Stmt::child_iterator SwitchStmt::child_end() { - return &SubExprs[0]+END_EXPR; -} - -// WhileStmt -Stmt::child_iterator WhileStmt::child_begin() { - return &SubExprs[0]; -} -Stmt::child_iterator WhileStmt::child_end() { - return &SubExprs[0]+END_EXPR; -} - -// DoStmt -Stmt::child_iterator DoStmt::child_begin() { return &SubExprs[0]; } -Stmt::child_iterator DoStmt::child_end() { return &SubExprs[0]+END_EXPR; } - -// ForStmt -Stmt::child_iterator ForStmt::child_begin() { - return &SubExprs[0]; -} -Stmt::child_iterator ForStmt::child_end() { - return &SubExprs[0]+END_EXPR; -} - -// ObjCForCollectionStmt -Stmt::child_iterator ObjCForCollectionStmt::child_begin() { - return &SubExprs[0]; -} -Stmt::child_iterator ObjCForCollectionStmt::child_end() { - return &SubExprs[0]+END_EXPR; -} - -// GotoStmt -Stmt::child_iterator GotoStmt::child_begin() { return child_iterator(); } -Stmt::child_iterator GotoStmt::child_end() { return child_iterator(); } - // IndirectGotoStmt -Expr* IndirectGotoStmt::getTarget() { return cast<Expr>(Target); } -const Expr* IndirectGotoStmt::getTarget() const { return cast<Expr>(Target); } - -Stmt::child_iterator IndirectGotoStmt::child_begin() { return &Target; } -Stmt::child_iterator IndirectGotoStmt::child_end() { return &Target+1; } - -// ContinueStmt -Stmt::child_iterator ContinueStmt::child_begin() { return child_iterator(); } -Stmt::child_iterator ContinueStmt::child_end() { return child_iterator(); } - -// BreakStmt -Stmt::child_iterator BreakStmt::child_begin() { return child_iterator(); } -Stmt::child_iterator BreakStmt::child_end() { return child_iterator(); } +LabelDecl *IndirectGotoStmt::getConstantTarget() { + if (AddrLabelExpr *E = + dyn_cast<AddrLabelExpr>(getTarget()->IgnoreParenImpCasts())) + return E->getLabel(); + return 0; +} // ReturnStmt const Expr* ReturnStmt::getRetValue() const { @@ -688,69 +672,3 @@ const Expr* ReturnStmt::getRetValue() const { Expr* ReturnStmt::getRetValue() { return cast_or_null<Expr>(RetExpr); } - -Stmt::child_iterator ReturnStmt::child_begin() { - return &RetExpr; -} -Stmt::child_iterator ReturnStmt::child_end() { - return RetExpr ? &RetExpr+1 : &RetExpr; -} - -// AsmStmt -Stmt::child_iterator AsmStmt::child_begin() { - return NumOutputs + NumInputs == 0 ? 0 : &Exprs[0]; -} -Stmt::child_iterator AsmStmt::child_end() { - return NumOutputs + NumInputs == 0 ? 0 : &Exprs[0] + NumOutputs + NumInputs; -} - -// ObjCAtCatchStmt -Stmt::child_iterator ObjCAtCatchStmt::child_begin() { return &Body; } -Stmt::child_iterator ObjCAtCatchStmt::child_end() { return &Body + 1; } - -// ObjCAtFinallyStmt -Stmt::child_iterator ObjCAtFinallyStmt::child_begin() { return &AtFinallyStmt; } -Stmt::child_iterator ObjCAtFinallyStmt::child_end() { return &AtFinallyStmt+1; } - -// ObjCAtTryStmt -Stmt::child_iterator ObjCAtTryStmt::child_begin() { return getStmts(); } - -Stmt::child_iterator ObjCAtTryStmt::child_end() { - return getStmts() + 1 + NumCatchStmts + HasFinally; -} - -// ObjCAtThrowStmt -Stmt::child_iterator ObjCAtThrowStmt::child_begin() { - return &Throw; -} - -Stmt::child_iterator ObjCAtThrowStmt::child_end() { - return &Throw+1; -} - -// ObjCAtSynchronizedStmt -Stmt::child_iterator ObjCAtSynchronizedStmt::child_begin() { - return &SubStmts[0]; -} - -Stmt::child_iterator ObjCAtSynchronizedStmt::child_end() { - return &SubStmts[0]+END_EXPR; -} - -// CXXCatchStmt -Stmt::child_iterator CXXCatchStmt::child_begin() { - return &HandlerBlock; -} - -Stmt::child_iterator CXXCatchStmt::child_end() { - return &HandlerBlock + 1; -} - -// CXXTryStmt -Stmt::child_iterator CXXTryStmt::child_begin() { - return reinterpret_cast<Stmt **>(this + 1); -} - -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 5c236a4..846bd4c 100644 --- a/lib/AST/StmtDumper.cpp +++ b/lib/AST/StmtDumper.cpp @@ -59,19 +59,12 @@ namespace { Visit(S); // Print out children. - Stmt::child_iterator CI = S->child_begin(), CE = S->child_end(); - if (CI != CE) { - while (CI != CE) { + Stmt::child_range CI = S->children(); + if (CI) { + while (CI) { OS << '\n'; DumpSubTree(*CI++); } - if (const ConditionalOperator *CO = - dyn_cast<ConditionalOperator>(S)) { - if (CO->getSAVE()) { - OS << '\n'; - DumpSubTree(CO->getSAVE()); - } - } } } OS << ')'; @@ -90,25 +83,44 @@ namespace { } void DumpType(QualType T) { - OS << "'" << T.getAsString() << "'"; + SplitQualType T_split = T.split(); + OS << "'" << QualType::getAsString(T_split) << "'"; if (!T.isNull()) { // If the type is sugared, also dump a (shallow) desugared type. - QualType Simplified = T.getDesugaredType(); - if (Simplified != T) - OS << ":'" << Simplified.getAsString() << "'"; + SplitQualType D_split = T.getSplitDesugaredType(); + if (T_split != D_split) + OS << ":'" << QualType::getAsString(D_split) << "'"; } } + void DumpDeclRef(Decl *node); void DumpStmt(const Stmt *Node) { Indent(); OS << "(" << Node->getStmtClassName() << " " << (void*)Node; DumpSourceRange(Node); } + void DumpValueKind(ExprValueKind K) { + switch (K) { + case VK_RValue: break; + case VK_LValue: OS << " lvalue"; break; + case VK_XValue: OS << " xvalue"; break; + } + } + void DumpObjectKind(ExprObjectKind K) { + switch (K) { + case OK_Ordinary: break; + case OK_BitField: OS << " bitfield"; break; + case OK_ObjCProperty: OS << " objcproperty"; break; + case OK_VectorComponent: OS << " vectorcomponent"; break; + } + } void DumpExpr(const Expr *Node) { DumpStmt(Node); OS << ' '; DumpType(Node->getType()); + DumpValueKind(Node->getValueKind()); + DumpObjectKind(Node->getObjectKind()); } void DumpSourceRange(const Stmt *Node); void DumpLocation(SourceLocation Loc); @@ -122,7 +134,6 @@ namespace { // Exprs void VisitExpr(Expr *Node); void VisitCastExpr(CastExpr *Node); - void VisitImplicitCastExpr(ImplicitCastExpr *Node); void VisitDeclRefExpr(DeclRefExpr *Node); void VisitPredefinedExpr(PredefinedExpr *Node); void VisitCharacterLiteral(CharacterLiteral *Node); @@ -136,7 +147,7 @@ namespace { void VisitBinaryOperator(BinaryOperator *Node); void VisitCompoundAssignOperator(CompoundAssignOperator *Node); void VisitAddrLabelExpr(AddrLabelExpr *Node); - void VisitTypesCompatibleExpr(TypesCompatibleExpr *Node); + void VisitBlockExpr(BlockExpr *Node); // C++ void VisitCXXNamedCastExpr(CXXNamedCastExpr *Node); @@ -145,7 +156,7 @@ namespace { void VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node); void VisitCXXConstructExpr(CXXConstructExpr *Node); void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node); - void VisitCXXExprWithTemporaries(CXXExprWithTemporaries *Node); + void VisitExprWithCleanups(ExprWithCleanups *Node); void VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node); void DumpCXXTemporary(CXXTemporary *Temporary); @@ -156,10 +167,7 @@ namespace { void VisitObjCSelectorExpr(ObjCSelectorExpr *Node); void VisitObjCProtocolExpr(ObjCProtocolExpr *Node); void VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node); - void VisitObjCImplicitSetterGetterRefExpr( - ObjCImplicitSetterGetterRefExpr *Node); void VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node); - void VisitObjCSuperExpr(ObjCSuperExpr *Node); }; } @@ -170,15 +178,15 @@ namespace { void StmtDumper::DumpLocation(SourceLocation Loc) { SourceLocation SpellingLoc = SM->getSpellingLoc(Loc); - if (SpellingLoc.isInvalid()) { - OS << "<invalid sloc>"; - return; - } - // The general format we print out is filename:line:col, but we drop pieces // that haven't changed since the last loc printed. PresumedLoc PLoc = SM->getPresumedLoc(SpellingLoc); + if (PLoc.isInvalid()) { + OS << "<invalid sloc>"; + return; + } + if (strcmp(PLoc.getFilename(), LastLocFilename) != 0) { OS << PLoc.getFilename() << ':' << PLoc.getLine() << ':' << PLoc.getColumn(); @@ -274,6 +282,8 @@ void StmtDumper::DumpDeclarator(Decl *D) { UD->getTargetNestedNameDecl()->print(OS, PrintingPolicy(UD->getASTContext().getLangOptions())); OS << ";\""; + } else if (LabelDecl *LD = dyn_cast<LabelDecl>(D)) { + OS << "label " << LD->getNameAsString(); } else { assert(0 && "Unexpected decl"); } @@ -345,39 +355,25 @@ void StmtDumper::VisitCastExpr(CastExpr *Node) { OS << ">"; } -void StmtDumper::VisitImplicitCastExpr(ImplicitCastExpr *Node) { - VisitCastExpr(Node); - switch (Node->getValueKind()) { - case VK_LValue: - OS << " lvalue"; - break; - case VK_XValue: - OS << " xvalue"; - break; - case VK_RValue: - break; - } -} - void StmtDumper::VisitDeclRefExpr(DeclRefExpr *Node) { DumpExpr(Node); OS << " "; - switch (Node->getDecl()->getKind()) { - default: OS << "Decl"; break; - case Decl::Function: OS << "FunctionDecl"; break; - case Decl::Var: OS << "Var"; break; - case Decl::ParmVar: OS << "ParmVar"; break; - case Decl::EnumConstant: OS << "EnumConstant"; break; - case Decl::Typedef: OS << "Typedef"; break; - case Decl::Record: OS << "Record"; break; - case Decl::Enum: OS << "Enum"; break; - case Decl::CXXRecord: OS << "CXXRecord"; break; - case Decl::ObjCInterface: OS << "ObjCInterface"; break; - case Decl::ObjCClass: OS << "ObjCClass"; break; + DumpDeclRef(Node->getDecl()); +} + +void StmtDumper::DumpDeclRef(Decl *d) { + OS << d->getDeclKindName() << ' ' << (void*) d; + + if (NamedDecl *nd = dyn_cast<NamedDecl>(d)) { + OS << " '"; + nd->getDeclName().printName(OS); + OS << "'"; } - OS << "='" << Node->getDecl() << "' " << (void*)Node->getDecl(); + if (ValueDecl *vd = dyn_cast<ValueDecl>(d)) { + OS << ' '; DumpType(vd->getType()); + } } void StmtDumper::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node) { @@ -475,6 +471,30 @@ void StmtDumper::VisitCompoundAssignOperator(CompoundAssignOperator *Node) { DumpType(Node->getComputationResultType()); } +void StmtDumper::VisitBlockExpr(BlockExpr *Node) { + DumpExpr(Node); + + IndentLevel++; + BlockDecl *block = Node->getBlockDecl(); + if (block->capturesCXXThis()) { + OS << '\n'; Indent(); OS << "(capture this)"; + } + for (BlockDecl::capture_iterator + i = block->capture_begin(), e = block->capture_end(); i != e; ++i) { + OS << '\n'; + Indent(); + OS << "(capture "; + if (i->isByRef()) OS << "byref "; + if (i->isNested()) OS << "nested "; + DumpDeclRef(i->getVariable()); + if (i->hasCopyExpr()) DumpSubTree(i->getCopyExpr()); + OS << ")"; + } + IndentLevel--; + + DumpSubTree(block->getBody()); +} + // GNU extensions. void StmtDumper::VisitAddrLabelExpr(AddrLabelExpr *Node) { @@ -483,14 +503,6 @@ void StmtDumper::VisitAddrLabelExpr(AddrLabelExpr *Node) { << " " << (void*)Node->getLabel(); } -void StmtDumper::VisitTypesCompatibleExpr(TypesCompatibleExpr *Node) { - DumpExpr(Node); - OS << " "; - DumpType(Node->getArgType1()); - OS << " "; - DumpType(Node->getArgType2()); -} - //===----------------------------------------------------------------------===// // C++ Expressions //===----------------------------------------------------------------------===// @@ -535,7 +547,7 @@ void StmtDumper::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node) { DumpCXXTemporary(Node->getTemporary()); } -void StmtDumper::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *Node) { +void StmtDumper::VisitExprWithCleanups(ExprWithCleanups *Node) { DumpExpr(Node); ++IndentLevel; for (unsigned i = 0, e = Node->getNumTemporaries(); i != e; ++i) { @@ -606,29 +618,25 @@ void StmtDumper::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) { void StmtDumper::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) { DumpExpr(Node); + if (Node->isImplicitProperty()) { + OS << " Kind=MethodRef Getter=\""; + if (Node->getImplicitPropertyGetter()) + OS << Node->getImplicitPropertyGetter()->getSelector().getAsString(); + else + OS << "(null)"; - OS << " Kind=PropertyRef Property=\"" << Node->getProperty() << '"'; -} - -void StmtDumper::VisitObjCImplicitSetterGetterRefExpr( - ObjCImplicitSetterGetterRefExpr *Node) { - DumpExpr(Node); - - ObjCMethodDecl *Getter = Node->getGetterMethod(); - ObjCMethodDecl *Setter = Node->getSetterMethod(); - OS << " Kind=MethodRef Getter=\"" - << Getter->getSelector().getAsString() - << "\" Setter=\""; - if (Setter) - OS << Setter->getSelector().getAsString(); - else - OS << "(null)"; - OS << "\""; -} + OS << "\" Setter=\""; + if (ObjCMethodDecl *Setter = Node->getImplicitPropertySetter()) + OS << Setter->getSelector().getAsString(); + else + OS << "(null)"; + OS << "\""; + } else { + OS << " Kind=PropertyRef Property=\"" << Node->getExplicitProperty() << '"'; + } -void StmtDumper::VisitObjCSuperExpr(ObjCSuperExpr *Node) { - DumpExpr(Node); - OS << " super"; + if (Node->isSuperReceiver()) + OS << " super"; } //===----------------------------------------------------------------------===// diff --git a/lib/AST/StmtIterator.cpp b/lib/AST/StmtIterator.cpp index 7fc7c96..9a7265a 100644 --- a/lib/AST/StmtIterator.cpp +++ b/lib/AST/StmtIterator.cpp @@ -18,9 +18,9 @@ using namespace clang; // FIXME: Add support for dependent-sized array types in C++? // Does it even make sense to build a CFG for an uninstantiated template? -static inline VariableArrayType* FindVA(Type* t) { - while (ArrayType* vt = dyn_cast<ArrayType>(t)) { - if (VariableArrayType* vat = dyn_cast<VariableArrayType>(vt)) +static inline const VariableArrayType *FindVA(const Type* t) { + while (const ArrayType *vt = dyn_cast<ArrayType>(t)) { + if (const VariableArrayType *vat = dyn_cast<VariableArrayType>(vt)) if (vat->getSizeExpr()) return vat; @@ -33,7 +33,7 @@ static inline VariableArrayType* FindVA(Type* t) { void StmtIteratorBase::NextVA() { assert (getVAPtr()); - VariableArrayType* p = getVAPtr(); + const VariableArrayType *p = getVAPtr(); p = FindVA(p->getElementType().getTypePtr()); setVAPtr(p); @@ -90,7 +90,7 @@ void StmtIteratorBase::NextDecl(bool ImmediateAdvance) { bool StmtIteratorBase::HandleDecl(Decl* D) { if (VarDecl* VD = dyn_cast<VarDecl>(D)) { - if (VariableArrayType* VAPtr = FindVA(VD->getType().getTypePtr())) { + if (const VariableArrayType* VAPtr = FindVA(VD->getType().getTypePtr())) { setVAPtr(VAPtr); return true; } @@ -99,7 +99,7 @@ bool StmtIteratorBase::HandleDecl(Decl* D) { return true; } else if (TypedefDecl* TD = dyn_cast<TypedefDecl>(D)) { - if (VariableArrayType* VAPtr = + if (const VariableArrayType* VAPtr = FindVA(TD->getUnderlyingType().getTypePtr())) { setVAPtr(VAPtr); return true; @@ -124,16 +124,16 @@ StmtIteratorBase::StmtIteratorBase(Decl** dgi, Decl** dge) NextDecl(false); } -StmtIteratorBase::StmtIteratorBase(VariableArrayType* t) +StmtIteratorBase::StmtIteratorBase(const VariableArrayType* t) : stmt(0), decl(0), RawVAPtr(SizeOfTypeVAMode) { RawVAPtr |= reinterpret_cast<uintptr_t>(t); } Stmt*& StmtIteratorBase::GetDeclExpr() const { - if (VariableArrayType* VAPtr = getVAPtr()) { + if (const VariableArrayType* VAPtr = getVAPtr()) { assert (VAPtr->SizeExpr); - return VAPtr->SizeExpr; + return const_cast<Stmt*&>(VAPtr->SizeExpr); } assert (inDecl() || inDeclGroup()); diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 5236a66..1cdd220 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -15,9 +15,11 @@ #include "clang/AST/StmtVisitor.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/PrettyPrinter.h" #include "llvm/Support/Format.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" using namespace clang; //===----------------------------------------------------------------------===// @@ -63,6 +65,7 @@ namespace { void PrintRawDeclStmt(DeclStmt *S); void PrintRawIfStmt(IfStmt *If); void PrintRawCXXCatchStmt(CXXCatchStmt *Catch); + void PrintCallArgs(CallExpr *E); void PrintExpr(Expr *E) { if (E) @@ -83,10 +86,10 @@ namespace { else StmtVisitor<StmtPrinter>::Visit(S); } - void VisitStmt(Stmt *Node) ATTRIBUTE_UNUSED { + void VisitStmt(Stmt *Node) LLVM_ATTRIBUTE_UNUSED { Indent() << "<<unknown stmt type>>\n"; } - void VisitExpr(Expr *Node) ATTRIBUTE_UNUSED { + void VisitExpr(Expr *Node) LLVM_ATTRIBUTE_UNUSED { OS << "<<unknown expr type>>"; } void VisitCXXNamedCastExpr(CXXNamedCastExpr *Node); @@ -217,10 +220,6 @@ void StmtPrinter::VisitSwitchStmt(SwitchStmt *Node) { } } -void StmtPrinter::VisitSwitchCase(SwitchCase*) { - assert(0 && "SwitchCase is an abstract class"); -} - void StmtPrinter::VisitWhileStmt(WhileStmt *Node) { Indent() << "while ("; PrintExpr(Node->getCond()); @@ -479,7 +478,8 @@ void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) { void StmtPrinter::VisitDependentScopeDeclRefExpr( DependentScopeDeclRefExpr *Node) { - Node->getQualifier()->print(OS, Policy); + if (NestedNameSpecifier *Qualifier = Node->getQualifier()) + Qualifier->print(OS, Policy); OS << Node->getNameInfo(); if (Node->hasExplicitTemplateArgs()) OS << TemplateSpecializationType::PrintTemplateArgumentList( @@ -508,22 +508,17 @@ void StmtPrinter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) { } void StmtPrinter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) { - if (Node->getBase()) { + if (Node->isSuperReceiver()) + OS << "super."; + else if (Node->getBase()) { PrintExpr(Node->getBase()); OS << "."; } - OS << Node->getProperty()->getName(); -} - -void StmtPrinter::VisitObjCImplicitSetterGetterRefExpr( - ObjCImplicitSetterGetterRefExpr *Node) { - if (Node->getBase()) { - PrintExpr(Node->getBase()); - OS << "."; - } - if (Node->getGetterMethod()) - OS << Node->getGetterMethod(); + if (Node->isImplicitProperty()) + OS << Node->getImplicitPropertyGetter()->getSelector().getAsString(); + else + OS << Node->getExplicitProperty()->getName(); } void StmtPrinter::VisitPredefinedExpr(PredefinedExpr *Node) { @@ -727,9 +722,7 @@ void StmtPrinter::VisitArraySubscriptExpr(ArraySubscriptExpr *Node) { OS << "]"; } -void StmtPrinter::VisitCallExpr(CallExpr *Call) { - PrintExpr(Call->getCallee()); - OS << "("; +void StmtPrinter::PrintCallArgs(CallExpr *Call) { for (unsigned i = 0, e = Call->getNumArgs(); i != e; ++i) { if (isa<CXXDefaultArgExpr>(Call->getArg(i))) { // Don't print any defaulted arguments @@ -739,6 +732,12 @@ void StmtPrinter::VisitCallExpr(CallExpr *Call) { if (i) OS << ", "; PrintExpr(Call->getArg(i)); } +} + +void StmtPrinter::VisitCallExpr(CallExpr *Call) { + PrintExpr(Call->getCallee()); + OS << "("; + PrintCallArgs(Call); OS << ")"; } void StmtPrinter::VisitMemberExpr(MemberExpr *Node) { @@ -793,21 +792,20 @@ void StmtPrinter::VisitCompoundAssignOperator(CompoundAssignOperator *Node) { } void StmtPrinter::VisitConditionalOperator(ConditionalOperator *Node) { PrintExpr(Node->getCond()); - - if (Node->getLHS()) { - OS << " ? "; - PrintExpr(Node->getLHS()); - OS << " : "; - } - else { // Handle GCC extension where LHS can be NULL. - OS << " ?: "; - } - + OS << " ? "; + PrintExpr(Node->getLHS()); + OS << " : "; PrintExpr(Node->getRHS()); } // GNU extensions. +void +StmtPrinter::VisitBinaryConditionalOperator(BinaryConditionalOperator *Node) { + PrintExpr(Node->getCommon()); + OS << " ?: "; + PrintExpr(Node->getFalseExpr()); +} void StmtPrinter::VisitAddrLabelExpr(AddrLabelExpr *Node) { OS << "&&" << Node->getLabel()->getName(); } @@ -818,12 +816,6 @@ void StmtPrinter::VisitStmtExpr(StmtExpr *E) { OS << ")"; } -void StmtPrinter::VisitTypesCompatibleExpr(TypesCompatibleExpr *Node) { - OS << "__builtin_types_compatible_p("; - OS << Node->getArgType1().getAsString(Policy) << ","; - OS << Node->getArgType2().getAsString(Policy) << ")"; -} - void StmtPrinter::VisitChooseExpr(ChooseExpr *Node) { OS << "__builtin_choose_expr("; PrintExpr(Node->getCond()); @@ -968,6 +960,15 @@ void StmtPrinter::VisitCXXMemberCallExpr(CXXMemberCallExpr *Node) { VisitCallExpr(cast<CallExpr>(Node)); } +void StmtPrinter::VisitCUDAKernelCallExpr(CUDAKernelCallExpr *Node) { + PrintExpr(Node->getCallee()); + OS << "<<<"; + PrintCallArgs(Node->getConfig()); + OS << ">>>("; + PrintCallArgs(Node); + OS << ")"; +} + void StmtPrinter::VisitCXXNamedCastExpr(CXXNamedCastExpr *Node) { OS << Node->getCastName() << '<'; OS << Node->getTypeAsWritten().getAsString(Policy) << ">("; @@ -1001,6 +1002,16 @@ void StmtPrinter::VisitCXXTypeidExpr(CXXTypeidExpr *Node) { OS << ")"; } +void StmtPrinter::VisitCXXUuidofExpr(CXXUuidofExpr *Node) { + OS << "__uuidof("; + if (Node->isTypeOperand()) { + OS << Node->getTypeOperand().getAsString(Policy); + } else { + PrintExpr(Node->getExprOperand()); + } + OS << ")"; +} + void StmtPrinter::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) { OS << (Node->getValue() ? "true" : "false"); } @@ -1051,7 +1062,10 @@ void StmtPrinter::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *Node) { } void StmtPrinter::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *Node) { - OS << Node->getType().getAsString(Policy) << "()"; + if (TypeSourceInfo *TSInfo = Node->getTypeSourceInfo()) + OS << TSInfo->getType().getAsString(Policy) << "()"; + else + OS << Node->getType().getAsString(Policy) << "()"; } void StmtPrinter::VisitCXXNewExpr(CXXNewExpr *E) { @@ -1123,17 +1137,18 @@ void StmtPrinter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) { } void StmtPrinter::VisitCXXConstructExpr(CXXConstructExpr *E) { - // FIXME. For now we just print a trivial constructor call expression, - // constructing its first argument object. - if (E->getNumArgs() == 1) { - CXXConstructorDecl *CD = E->getConstructor(); - if (CD->isTrivial()) - PrintExpr(E->getArg(0)); + for (unsigned i = 0, e = E->getNumArgs(); i != e; ++i) { + if (isa<CXXDefaultArgExpr>(E->getArg(i))) { + // Don't print any defaulted arguments + break; + } + + if (i) OS << ", "; + PrintExpr(E->getArg(i)); } - // Nothing to print. } -void StmtPrinter::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E) { +void StmtPrinter::VisitExprWithCleanups(ExprWithCleanups *E) { // Just forward to the sub expression. PrintExpr(E->getSubExpr()); } @@ -1197,7 +1212,7 @@ void StmtPrinter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *Node) { static const char *getTypeTraitName(UnaryTypeTrait UTT) { switch (UTT) { - default: assert(false && "Unknown type trait"); + default: llvm_unreachable("Unknown unary type trait"); case UTT_HasNothrowAssign: return "__has_nothrow_assign"; case UTT_HasNothrowCopy: return "__has_nothrow_copy"; case UTT_HasNothrowConstructor: return "__has_nothrow_constructor"; @@ -1214,6 +1229,16 @@ static const char *getTypeTraitName(UnaryTypeTrait UTT) { case UTT_IsPolymorphic: return "__is_polymorphic"; case UTT_IsUnion: return "__is_union"; } + return ""; +} + +static const char *getTypeTraitName(BinaryTypeTrait BTT) { + switch (BTT) { + case BTT_IsBaseOf: return "__is_base_of"; + case BTT_TypeCompatible: return "__builtin_types_compatible_p"; + case BTT_IsConvertibleTo: return "__is_convertible_to"; + } + return ""; } void StmtPrinter::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) { @@ -1221,6 +1246,32 @@ void StmtPrinter::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) { << E->getQueriedType().getAsString(Policy) << ")"; } +void StmtPrinter::VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E) { + OS << getTypeTraitName(E->getTrait()) << "(" + << E->getLhsType().getAsString(Policy) << "," + << E->getRhsType().getAsString(Policy) << ")"; +} + +void StmtPrinter::VisitCXXNoexceptExpr(CXXNoexceptExpr *E) { + OS << "noexcept("; + PrintExpr(E->getOperand()); + OS << ")"; +} + +void StmtPrinter::VisitPackExpansionExpr(PackExpansionExpr *E) { + PrintExpr(E->getPattern()); + OS << "..."; +} + +void StmtPrinter::VisitSizeOfPackExpr(SizeOfPackExpr *E) { + OS << "sizeof...(" << E->getPack()->getNameAsString() << ")"; +} + +void StmtPrinter::VisitSubstNonTypeTemplateParmPackExpr( + SubstNonTypeTemplateParmPackExpr *Node) { + OS << Node->getParameterPack()->getNameAsString(); +} + // Obj-C void StmtPrinter::VisitObjCStringLiteral(ObjCStringLiteral *Node) { @@ -1260,7 +1311,7 @@ void StmtPrinter::VisitObjCMessageExpr(ObjCMessageExpr *Mess) { OS << ' '; Selector selector = Mess->getSelector(); if (selector.isUnarySelector()) { - OS << selector.getIdentifierInfoForSlot(0)->getName(); + OS << selector.getNameForSlot(0); } else { for (unsigned i = 0, e = Mess->getNumArgs(); i != e; ++i) { if (i < selector.getNumArgs()) { @@ -1278,9 +1329,6 @@ void StmtPrinter::VisitObjCMessageExpr(ObjCMessageExpr *Mess) { OS << "]"; } -void StmtPrinter::VisitObjCSuperExpr(ObjCSuperExpr *) { - OS << "super"; -} void StmtPrinter::VisitBlockExpr(BlockExpr *Node) { BlockDecl *BD = Node->getBlockDecl(); @@ -1313,6 +1361,9 @@ void StmtPrinter::VisitBlockExpr(BlockExpr *Node) { void StmtPrinter::VisitBlockDeclRefExpr(BlockDeclRefExpr *Node) { OS << Node->getDecl(); } + +void StmtPrinter::VisitOpaqueValueExpr(OpaqueValueExpr *Node) {} + //===----------------------------------------------------------------------===// // Stmt method implementations //===----------------------------------------------------------------------===// diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index 78a336d..b540011 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -25,11 +25,11 @@ using namespace clang; namespace { class StmtProfiler : public StmtVisitor<StmtProfiler> { llvm::FoldingSetNodeID &ID; - ASTContext &Context; + const ASTContext &Context; bool Canonical; public: - StmtProfiler(llvm::FoldingSetNodeID &ID, ASTContext &Context, + StmtProfiler(llvm::FoldingSetNodeID &ID, const ASTContext &Context, bool Canonical) : ID(ID), Context(Context), Canonical(Canonical) { } @@ -68,8 +68,7 @@ namespace { void StmtProfiler::VisitStmt(Stmt *S) { ID.AddInteger(S->getStmtClass()); - for (Stmt::child_iterator C = S->child_begin(), CEnd = S->child_end(); - C != CEnd; ++C) + for (Stmt::child_range C = S->children(); C; ++C) Visit(*C); } @@ -102,7 +101,7 @@ void StmtProfiler::VisitDefaultStmt(DefaultStmt *S) { void StmtProfiler::VisitLabelStmt(LabelStmt *S) { VisitStmt(S); - VisitName(S->getID()); + VisitDecl(S->getDecl()); } void StmtProfiler::VisitIfStmt(IfStmt *S) { @@ -130,7 +129,7 @@ void StmtProfiler::VisitForStmt(ForStmt *S) { void StmtProfiler::VisitGotoStmt(GotoStmt *S) { VisitStmt(S); - VisitName(S->getLabel()->getID()); + VisitDecl(S->getLabel()); } void StmtProfiler::VisitIndirectGotoStmt(IndirectGotoStmt *S) { @@ -350,19 +349,17 @@ void StmtProfiler::VisitConditionalOperator(ConditionalOperator *S) { VisitExpr(S); } -void StmtProfiler::VisitAddrLabelExpr(AddrLabelExpr *S) { +void StmtProfiler::VisitBinaryConditionalOperator(BinaryConditionalOperator *S){ VisitExpr(S); - VisitName(S->getLabel()->getID()); } -void StmtProfiler::VisitStmtExpr(StmtExpr *S) { +void StmtProfiler::VisitAddrLabelExpr(AddrLabelExpr *S) { VisitExpr(S); + VisitDecl(S->getLabel()); } -void StmtProfiler::VisitTypesCompatibleExpr(TypesCompatibleExpr *S) { +void StmtProfiler::VisitStmtExpr(StmtExpr *S) { VisitExpr(S); - VisitType(S->getArgType1()); - VisitType(S->getArgType2()); } void StmtProfiler::VisitShuffleVectorExpr(ShuffleVectorExpr *S) { @@ -431,8 +428,6 @@ void StmtProfiler::VisitBlockDeclRefExpr(BlockDeclRefExpr *S) { VisitDecl(S->getDecl()); ID.AddBoolean(S->isByRef()); ID.AddBoolean(S->isConstQualAdded()); - if (S->getCopyConstructorExpr()) - Visit(S->getCopyConstructorExpr()); } static Stmt::StmtClass DecodeOperatorCall(CXXOperatorCallExpr *S, @@ -652,6 +647,10 @@ void StmtProfiler::VisitCXXMemberCallExpr(CXXMemberCallExpr *S) { VisitCallExpr(S); } +void StmtProfiler::VisitCUDAKernelCallExpr(CUDAKernelCallExpr *S) { + VisitCallExpr(S); +} + void StmtProfiler::VisitCXXNamedCastExpr(CXXNamedCastExpr *S) { VisitExplicitCastExpr(S); } @@ -687,6 +686,12 @@ void StmtProfiler::VisitCXXTypeidExpr(CXXTypeidExpr *S) { VisitType(S->getTypeOperand()); } +void StmtProfiler::VisitCXXUuidofExpr(CXXUuidofExpr *S) { + VisitExpr(S); + if (S->isTypeOperand()) + VisitType(S->getTypeOperand()); +} + void StmtProfiler::VisitCXXThisExpr(CXXThisExpr *S) { VisitExpr(S); } @@ -774,6 +779,13 @@ void StmtProfiler::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *S) { VisitType(S->getQueriedType()); } +void StmtProfiler::VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *S) { + VisitExpr(S); + ID.AddInteger(S->getTrait()); + VisitType(S->getLhsType()); + VisitType(S->getRhsType()); +} + void StmtProfiler::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *S) { VisitExpr(S); @@ -784,11 +796,8 @@ StmtProfiler::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *S) { VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs()); } -void StmtProfiler::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *S) { +void StmtProfiler::VisitExprWithCleanups(ExprWithCleanups *S) { VisitExpr(S); - for (unsigned I = 0, N = S->getNumTemporaries(); I != N; ++I) - VisitDecl( - const_cast<CXXDestructorDecl *>(S->getTemporary(I)->getDestructor())); } void @@ -824,6 +833,30 @@ void StmtProfiler::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *S) { VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs()); } +void StmtProfiler::VisitCXXNoexceptExpr(CXXNoexceptExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitPackExpansionExpr(PackExpansionExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitSizeOfPackExpr(SizeOfPackExpr *S) { + VisitExpr(S); + VisitDecl(S->getPack()); +} + +void StmtProfiler::VisitSubstNonTypeTemplateParmPackExpr( + SubstNonTypeTemplateParmPackExpr *S) { + VisitExpr(S); + VisitDecl(S->getParameterPack()); + VisitTemplateArgument(S->getArgumentPack()); +} + +void StmtProfiler::VisitOpaqueValueExpr(OpaqueValueExpr *E) { + VisitExpr(E); +} + void StmtProfiler::VisitObjCStringLiteral(ObjCStringLiteral *S) { VisitExpr(S); } @@ -852,15 +885,16 @@ void StmtProfiler::VisitObjCIvarRefExpr(ObjCIvarRefExpr *S) { void StmtProfiler::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *S) { VisitExpr(S); - VisitDecl(S->getProperty()); -} - -void StmtProfiler::VisitObjCImplicitSetterGetterRefExpr( - ObjCImplicitSetterGetterRefExpr *S) { - VisitExpr(S); - VisitDecl(S->getGetterMethod()); - VisitDecl(S->getSetterMethod()); - VisitDecl(S->getInterfaceDecl()); + if (S->isImplicitProperty()) { + VisitDecl(S->getImplicitPropertyGetter()); + VisitDecl(S->getImplicitPropertySetter()); + } else { + VisitDecl(S->getExplicitProperty()); + } + if (S->isSuperReceiver()) { + ID.AddBoolean(S->isSuperReceiver()); + VisitType(S->getSuperReceiverType()); + } } void StmtProfiler::VisitObjCMessageExpr(ObjCMessageExpr *S) { @@ -869,10 +903,6 @@ void StmtProfiler::VisitObjCMessageExpr(ObjCMessageExpr *S) { VisitDecl(S->getMethodDecl()); } -void StmtProfiler::VisitObjCSuperExpr(ObjCSuperExpr *S) { - VisitExpr(S); -} - void StmtProfiler::VisitObjCIsaExpr(ObjCIsaExpr *S) { VisitExpr(S); ID.AddBoolean(S->isArrow()); @@ -885,6 +915,7 @@ void StmtProfiler::VisitDecl(Decl *D) { if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) { ID.AddInteger(NTTP->getDepth()); ID.AddInteger(NTTP->getIndex()); + ID.AddBoolean(NTTP->isParameterPack()); VisitType(NTTP->getType()); return; } @@ -902,6 +933,7 @@ void StmtProfiler::VisitDecl(Decl *D) { if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(D)) { ID.AddInteger(TTP->getDepth()); ID.AddInteger(TTP->getIndex()); + ID.AddBoolean(TTP->isParameterPack()); return; } } @@ -952,7 +984,8 @@ void StmtProfiler::VisitTemplateArgument(const TemplateArgument &Arg) { break; case TemplateArgument::Template: - VisitTemplateName(Arg.getAsTemplate()); + case TemplateArgument::TemplateExpansion: + VisitTemplateName(Arg.getAsTemplateOrTemplatePattern()); break; case TemplateArgument::Declaration: @@ -976,7 +1009,7 @@ void StmtProfiler::VisitTemplateArgument(const TemplateArgument &Arg) { } } -void Stmt::Profile(llvm::FoldingSetNodeID &ID, ASTContext &Context, +void Stmt::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, bool Canonical) { StmtProfiler Profiler(ID, Context, Canonical); Profiler.Visit(this); diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp index a3bf145..5ab5f46 100644 --- a/lib/AST/TemplateBase.cpp +++ b/lib/AST/TemplateBase.cpp @@ -12,41 +12,172 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ADT/FoldingSet.h" #include "clang/AST/TemplateBase.h" +#include "clang/AST/ASTContext.h" #include "clang/AST/DeclBase.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/Type.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/Diagnostic.h" +#include "llvm/ADT/FoldingSet.h" +#include <algorithm> +#include <cctype> +#include <iomanip> +#include <sstream> using namespace clang; +/// \brief Print a template integral argument value. +/// +/// \param TemplArg the TemplateArgument instance to print. +/// +/// \param Out the raw_ostream instance to use for printing. +static void printIntegral(const TemplateArgument &TemplArg, + llvm::raw_ostream &Out) { + const ::clang::Type *T = TemplArg.getIntegralType().getTypePtr(); + const llvm::APSInt *Val = TemplArg.getAsIntegral(); + + if (T->isBooleanType()) { + Out << (Val->getBoolValue() ? "true" : "false"); + } else if (T->isCharType()) { + char Ch = Val->getSExtValue(); + if (std::isprint(Ch)) { + Out << "'"; + if (Ch == '\'' || Ch == '\\') + Out << '\\'; + Out << Ch << "'"; + } else { + std::ostringstream Str; + Str << std::setw(2) << std::setfill('0') << std::hex << (int)Ch; + Out << "'\\x" << Str.str() << "'"; + } + } else { + Out << Val->toString(10); + } +} + //===----------------------------------------------------------------------===// // TemplateArgument Implementation //===----------------------------------------------------------------------===// -/// \brief Construct a template argument pack. -void TemplateArgument::setArgumentPack(TemplateArgument *args, unsigned NumArgs, - bool CopyArgs) { - assert(isNull() && "Must call setArgumentPack on a null argument"); +TemplateArgument TemplateArgument::CreatePackCopy(ASTContext &Context, + const TemplateArgument *Args, + unsigned NumArgs) { + if (NumArgs == 0) + return TemplateArgument(0, 0); + + TemplateArgument *Storage = new (Context) TemplateArgument [NumArgs]; + std::copy(Args, Args + NumArgs, Storage); + return TemplateArgument(Storage, NumArgs); +} + +bool TemplateArgument::isDependent() const { + switch (getKind()) { + case Null: + assert(false && "Should not have a NULL template argument"); + return false; + + case Type: + return getAsType()->isDependentType(); + + case Template: + return getAsTemplate().isDependent(); + + case TemplateExpansion: + return true; + + case Declaration: + if (DeclContext *DC = dyn_cast<DeclContext>(getAsDecl())) + return DC->isDependentContext(); + return getAsDecl()->getDeclContext()->isDependentContext(); + + case Integral: + // Never dependent + return false; + + case Expression: + return (getAsExpr()->isTypeDependent() || getAsExpr()->isValueDependent()); + + case Pack: + for (pack_iterator P = pack_begin(), PEnd = pack_end(); P != PEnd; ++P) { + if (P->isDependent()) + return true; + } + + return false; + } + + return false; +} + +bool TemplateArgument::isPackExpansion() const { + switch (getKind()) { + case Null: + case Declaration: + case Integral: + case Pack: + case Template: + return false; + + case TemplateExpansion: + return true; + + case Type: + return isa<PackExpansionType>(getAsType()); + + case Expression: + return isa<PackExpansionExpr>(getAsExpr()); + } + + return false; +} + +bool TemplateArgument::containsUnexpandedParameterPack() const { + switch (getKind()) { + case Null: + case Declaration: + case Integral: + case TemplateExpansion: + break; + + case Type: + if (getAsType()->containsUnexpandedParameterPack()) + return true; + break; + + case Template: + if (getAsTemplate().containsUnexpandedParameterPack()) + return true; + break; + + case Expression: + if (getAsExpr()->containsUnexpandedParameterPack()) + return true; + break; - Kind = Pack; - Args.NumArgs = NumArgs; - Args.CopyArgs = CopyArgs; - if (!Args.CopyArgs) { - Args.Args = args; - return; + case Pack: + for (pack_iterator P = pack_begin(), PEnd = pack_end(); P != PEnd; ++P) + if (P->containsUnexpandedParameterPack()) + return true; + + break; } - // FIXME: Allocate in ASTContext - Args.Args = new TemplateArgument[NumArgs]; - for (unsigned I = 0; I != Args.NumArgs; ++I) - Args.Args[I] = args[I]; + return false; +} + +llvm::Optional<unsigned> TemplateArgument::getNumTemplateExpansions() const { + assert(Kind == TemplateExpansion); + if (TemplateArg.NumExpansions) + return TemplateArg.NumExpansions - 1; + + return llvm::Optional<unsigned>(); } void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID, - ASTContext &Context) const { + const ASTContext &Context) const { ID.AddInteger(Kind); switch (Kind) { case Null: @@ -61,18 +192,22 @@ void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID, break; case Template: + case TemplateExpansion: { + TemplateName Template = getAsTemplateOrTemplatePattern(); if (TemplateTemplateParmDecl *TTP = dyn_cast_or_null<TemplateTemplateParmDecl>( - getAsTemplate().getAsTemplateDecl())) { + Template.getAsTemplateDecl())) { ID.AddBoolean(true); ID.AddInteger(TTP->getDepth()); ID.AddInteger(TTP->getPosition()); + ID.AddBoolean(TTP->isParameterPack()); } else { ID.AddBoolean(false); - ID.AddPointer(Context.getCanonicalTemplateName(getAsTemplate()) - .getAsVoidPointer()); + ID.AddPointer(Context.getCanonicalTemplateName(Template) + .getAsVoidPointer()); } break; + } case Integral: getAsIntegral()->Profile(ID); @@ -97,8 +232,9 @@ bool TemplateArgument::structurallyEquals(const TemplateArgument &Other) const { case Null: case Type: case Declaration: + case Expression: case Template: - case Expression: + case TemplateExpansion: return TypeOrValue == Other.TypeOrValue; case Integral: @@ -117,10 +253,102 @@ bool TemplateArgument::structurallyEquals(const TemplateArgument &Other) const { return false; } +TemplateArgument TemplateArgument::getPackExpansionPattern() const { + assert(isPackExpansion()); + + switch (getKind()) { + case Type: + return getAsType()->getAs<PackExpansionType>()->getPattern(); + + case Expression: + return cast<PackExpansionExpr>(getAsExpr())->getPattern(); + + case TemplateExpansion: + return TemplateArgument(getAsTemplateOrTemplatePattern()); + + case Declaration: + case Integral: + case Pack: + case Null: + case Template: + return TemplateArgument(); + } + + return TemplateArgument(); +} + +void TemplateArgument::print(const PrintingPolicy &Policy, + llvm::raw_ostream &Out) const { + switch (getKind()) { + case Null: + Out << "<no value>"; + break; + + case Type: { + std::string TypeStr; + getAsType().getAsStringInternal(TypeStr, Policy); + Out << TypeStr; + break; + } + + case Declaration: { + bool Unnamed = true; + if (NamedDecl *ND = dyn_cast_or_null<NamedDecl>(getAsDecl())) { + if (ND->getDeclName()) { + Unnamed = false; + Out << ND->getNameAsString(); + } + } + + if (Unnamed) { + Out << "<anonymous>"; + } + break; + } + + case Template: + getAsTemplate().print(Out, Policy); + break; + + case TemplateExpansion: + getAsTemplateOrTemplatePattern().print(Out, Policy); + Out << "..."; + break; + + case Integral: { + printIntegral(*this, Out); + break; + } + + case Expression: + getAsExpr()->printPretty(Out, 0, Policy); + break; + + case Pack: + Out << "<"; + bool First = true; + for (TemplateArgument::pack_iterator P = pack_begin(), PEnd = pack_end(); + P != PEnd; ++P) { + if (First) + First = false; + else + Out << ", "; + + P->print(Policy, Out); + } + Out << ">"; + break; + } +} + //===----------------------------------------------------------------------===// // TemplateArgumentLoc Implementation //===----------------------------------------------------------------------===// +TemplateArgumentLocInfo::TemplateArgumentLocInfo() { + memset(this, 0, sizeof(TemplateArgumentLocInfo)); +} + SourceRange TemplateArgumentLoc::getSourceRange() const { switch (Argument.getKind()) { case TemplateArgument::Expression: @@ -137,10 +365,16 @@ SourceRange TemplateArgumentLoc::getSourceRange() const { case TemplateArgument::Template: if (getTemplateQualifierRange().isValid()) - return SourceRange(getTemplateQualifierRange().getBegin(), + return SourceRange(getTemplateQualifierRange().getBegin(), getTemplateNameLoc()); return SourceRange(getTemplateNameLoc()); + case TemplateArgument::TemplateExpansion: + if (getTemplateQualifierRange().isValid()) + return SourceRange(getTemplateQualifierRange().getBegin(), + getTemplateEllipsisLoc()); + return SourceRange(getTemplateNameLoc(), getTemplateEllipsisLoc()); + case TemplateArgument::Integral: case TemplateArgument::Pack: case TemplateArgument::Null: @@ -151,6 +385,68 @@ SourceRange TemplateArgumentLoc::getSourceRange() const { return SourceRange(); } +TemplateArgumentLoc +TemplateArgumentLoc::getPackExpansionPattern(SourceLocation &Ellipsis, + llvm::Optional<unsigned> &NumExpansions, + ASTContext &Context) const { + assert(Argument.isPackExpansion()); + + switch (Argument.getKind()) { + case TemplateArgument::Type: { + // FIXME: We shouldn't ever have to worry about missing + // type-source info! + TypeSourceInfo *ExpansionTSInfo = getTypeSourceInfo(); + if (!ExpansionTSInfo) + ExpansionTSInfo = Context.getTrivialTypeSourceInfo( + getArgument().getAsType(), + Ellipsis); + PackExpansionTypeLoc Expansion + = cast<PackExpansionTypeLoc>(ExpansionTSInfo->getTypeLoc()); + Ellipsis = Expansion.getEllipsisLoc(); + + TypeLoc Pattern = Expansion.getPatternLoc(); + NumExpansions = Expansion.getTypePtr()->getNumExpansions(); + + // FIXME: This is horrible. We know where the source location data is for + // the pattern, and we have the pattern's type, but we are forced to copy + // them into an ASTContext because TypeSourceInfo bundles them together + // and TemplateArgumentLoc traffics in TypeSourceInfo pointers. + TypeSourceInfo *PatternTSInfo + = Context.CreateTypeSourceInfo(Pattern.getType(), + Pattern.getFullDataSize()); + memcpy(PatternTSInfo->getTypeLoc().getOpaqueData(), + Pattern.getOpaqueData(), Pattern.getFullDataSize()); + return TemplateArgumentLoc(TemplateArgument(Pattern.getType()), + PatternTSInfo); + } + + case TemplateArgument::Expression: { + PackExpansionExpr *Expansion + = cast<PackExpansionExpr>(Argument.getAsExpr()); + Expr *Pattern = Expansion->getPattern(); + Ellipsis = Expansion->getEllipsisLoc(); + NumExpansions = Expansion->getNumExpansions(); + return TemplateArgumentLoc(Pattern, Pattern); + } + + case TemplateArgument::TemplateExpansion: + Ellipsis = getTemplateEllipsisLoc(); + NumExpansions = Argument.getNumTemplateExpansions(); + return TemplateArgumentLoc(Argument.getPackExpansionPattern(), + getTemplateQualifierRange(), + getTemplateNameLoc()); + + case TemplateArgument::Declaration: + case TemplateArgument::Template: + case TemplateArgument::Integral: + case TemplateArgument::Pack: + case TemplateArgument::Null: + return TemplateArgumentLoc(); + } + + return TemplateArgumentLoc(); +} + const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB, const TemplateArgument &Arg) { switch (Arg.getKind()) { @@ -170,7 +466,10 @@ const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB, case TemplateArgument::Template: return DB << Arg.getAsTemplate(); - + + case TemplateArgument::TemplateExpansion: + return DB << Arg.getAsTemplateOrTemplatePattern() << "..."; + case TemplateArgument::Expression: { // This shouldn't actually ever happen, so it's okay that we're // regurgitating an expression here. @@ -184,9 +483,16 @@ const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB, return DB << OS.str(); } - case TemplateArgument::Pack: - // FIXME: Format arguments in a list! - return DB << "<parameter pack>"; + case TemplateArgument::Pack: { + // FIXME: We're guessing at LangOptions! + llvm::SmallString<32> Str; + llvm::raw_svector_ostream OS(Str); + LangOptions LangOpts; + LangOpts.CPlusPlus = true; + PrintingPolicy Policy(LangOpts); + Arg.print(Policy, OS); + return DB << OS.str(); + } } return DB; diff --git a/lib/AST/TemplateName.cpp b/lib/AST/TemplateName.cpp index ef7b315..6b378a0 100644 --- a/lib/AST/TemplateName.cpp +++ b/lib/AST/TemplateName.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/AST/TemplateName.h" +#include "clang/AST/TemplateBase.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/PrettyPrinter.h" @@ -21,15 +22,33 @@ using namespace clang; using namespace llvm; +TemplateArgument +SubstTemplateTemplateParmPackStorage::getArgumentPack() const { + return TemplateArgument(Arguments, size()); +} + +void SubstTemplateTemplateParmPackStorage::Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, Context, Parameter, TemplateArgument(Arguments, size())); +} + +void SubstTemplateTemplateParmPackStorage::Profile(llvm::FoldingSetNodeID &ID, + ASTContext &Context, + TemplateTemplateParmDecl *Parameter, + const TemplateArgument &ArgPack) { + ID.AddPointer(Parameter); + ArgPack.Profile(ID, Context); +} + TemplateName::NameKind TemplateName::getKind() const { if (Storage.is<TemplateDecl *>()) return Template; - if (Storage.is<OverloadedTemplateStorage *>()) - return OverloadedTemplate; + if (Storage.is<DependentTemplateName *>()) + return DependentTemplate; if (Storage.is<QualifiedTemplateName *>()) return QualifiedTemplate; - assert(Storage.is<DependentTemplateName *>() && "There's a case unhandled!"); - return DependentTemplate; + + return getAsOverloadedTemplate()? OverloadedTemplate + : SubstTemplateTemplateParmPack; } TemplateDecl *TemplateName::getAsTemplateDecl() const { @@ -44,8 +63,14 @@ TemplateDecl *TemplateName::getAsTemplateDecl() const { bool TemplateName::isDependent() const { if (TemplateDecl *Template = getAsTemplateDecl()) { - return isa<TemplateTemplateParmDecl>(Template) || - Template->getDeclContext()->isDependentContext(); + if (isa<TemplateTemplateParmDecl>(Template)) + return true; + // FIXME: Hack, getDeclContext() can be null if Template is still + // initializing due to PCH reading, so we check it before using it. + // Should probably modify TemplateSpecializationType to allow constructing + // it without the isDependent() checking. + return Template->getDeclContext() && + Template->getDeclContext()->isDependentContext(); } assert(!getAsOverloadedTemplate() && @@ -54,6 +79,22 @@ bool TemplateName::isDependent() const { return true; } +bool TemplateName::containsUnexpandedParameterPack() const { + if (TemplateDecl *Template = getAsTemplateDecl()) { + if (TemplateTemplateParmDecl *TTP + = dyn_cast<TemplateTemplateParmDecl>(Template)) + return TTP->isParameterPack(); + + return false; + } + + if (DependentTemplateName *DTN = getAsDependentTemplateName()) + return DTN->getQualifier() && + DTN->getQualifier()->containsUnexpandedParameterPack(); + + return getAsSubstTemplateTemplateParmPack() != 0; +} + void TemplateName::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy, bool SuppressNNS) const { @@ -74,7 +115,9 @@ TemplateName::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy, OS << DTN->getIdentifier()->getName(); else OS << "operator " << getOperatorSpelling(DTN->getOperator()); - } + } else if (SubstTemplateTemplateParmPackStorage *SubstPack + = getAsSubstTemplateTemplateParmPack()) + OS << SubstPack->getParameterPack()->getNameAsString(); } const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB, diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index ca10532..b03314e 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -19,6 +19,7 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/PrettyPrinter.h" +#include "clang/AST/TypeVisitor.h" #include "clang/Basic/Specifiers.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/raw_ostream.h" @@ -35,14 +36,13 @@ bool QualType::isConstant(QualType T, ASTContext &Ctx) { return false; } -Type::~Type() { } - unsigned ConstantArrayType::getNumAddressingBits(ASTContext &Context, QualType ElementType, const llvm::APInt &NumElements) { llvm::APSInt SizeExtended(NumElements, true); unsigned SizeTypeBits = Context.getTypeSize(Context.getSizeType()); - SizeExtended.extend(std::max(SizeTypeBits, SizeExtended.getBitWidth()) * 2); + SizeExtended = SizeExtended.extend(std::max(SizeTypeBits, + SizeExtended.getBitWidth()) * 2); uint64_t ElementSize = Context.getTypeSizeInChars(ElementType).getQuantity(); @@ -63,8 +63,20 @@ unsigned ConstantArrayType::getMaxSizeBits(ASTContext &Context) { return Bits; } +DependentSizedArrayType::DependentSizedArrayType(const ASTContext &Context, + QualType et, QualType can, + Expr *e, ArraySizeModifier sm, + unsigned tq, + SourceRange brackets) + : ArrayType(DependentSizedArray, et, can, sm, tq, + (et->containsUnexpandedParameterPack() || + (e && e->containsUnexpandedParameterPack()))), + Context(Context), SizeExpr((Stmt*) e), Brackets(brackets) +{ +} + void DependentSizedArrayType::Profile(llvm::FoldingSetNodeID &ID, - ASTContext &Context, + const ASTContext &Context, QualType ET, ArraySizeModifier SizeMod, unsigned TypeQuals, @@ -75,14 +87,51 @@ void DependentSizedArrayType::Profile(llvm::FoldingSetNodeID &ID, E->Profile(ID, Context, true); } +DependentSizedExtVectorType::DependentSizedExtVectorType(const + ASTContext &Context, + QualType ElementType, + QualType can, + Expr *SizeExpr, + SourceLocation loc) + : Type(DependentSizedExtVector, can, /*Dependent=*/true, + ElementType->isVariablyModifiedType(), + (ElementType->containsUnexpandedParameterPack() || + (SizeExpr && SizeExpr->containsUnexpandedParameterPack()))), + Context(Context), SizeExpr(SizeExpr), ElementType(ElementType), + loc(loc) +{ +} + void DependentSizedExtVectorType::Profile(llvm::FoldingSetNodeID &ID, - ASTContext &Context, + const ASTContext &Context, QualType ElementType, Expr *SizeExpr) { ID.AddPointer(ElementType.getAsOpaquePtr()); SizeExpr->Profile(ID, Context, true); } +VectorType::VectorType(QualType vecType, unsigned nElements, QualType canonType, + VectorKind vecKind) + : Type(Vector, canonType, vecType->isDependentType(), + vecType->isVariablyModifiedType(), + vecType->containsUnexpandedParameterPack()), + ElementType(vecType) +{ + VectorTypeBits.VecKind = vecKind; + VectorTypeBits.NumElements = nElements; +} + +VectorType::VectorType(TypeClass tc, QualType vecType, unsigned nElements, + QualType canonType, VectorKind vecKind) + : Type(tc, canonType, vecType->isDependentType(), + vecType->isVariablyModifiedType(), + vecType->containsUnexpandedParameterPack()), + ElementType(vecType) +{ + VectorTypeBits.VecKind = vecKind; + VectorTypeBits.NumElements = nElements; +} + /// getArrayElementTypeNoTypeQual - If this is an array type, return the /// element type of the array, potentially with type qualifiers missing. /// This method should never be used when type qualifiers are meaningful. @@ -101,51 +150,18 @@ const Type *Type::getArrayElementTypeNoTypeQual() const { ->getElementType().getTypePtr(); } -/// \brief Retrieve the unqualified variant of the given type, removing as -/// little sugar as possible. -/// -/// This routine looks through various kinds of sugar to find the -/// least-desuraged type that is unqualified. For example, given: -/// -/// \code -/// typedef int Integer; -/// typedef const Integer CInteger; -/// typedef CInteger DifferenceType; -/// \endcode -/// -/// Executing \c getUnqualifiedTypeSlow() on the type \c DifferenceType will -/// desugar until we hit the type \c Integer, which has no qualifiers on it. -QualType QualType::getUnqualifiedTypeSlow() const { - QualType Cur = *this; - while (true) { - if (!Cur.hasQualifiers()) - return Cur; - - const Type *CurTy = Cur.getTypePtr(); - switch (CurTy->getTypeClass()) { -#define ABSTRACT_TYPE(Class, Parent) -#define TYPE(Class, Parent) \ - case Type::Class: { \ - const Class##Type *Ty = cast<Class##Type>(CurTy); \ - if (!Ty->isSugared()) \ - return Cur.getLocalUnqualifiedType(); \ - Cur = Ty->desugar(); \ - break; \ - } -#include "clang/AST/TypeNodes.def" - } - } - - return Cur.getUnqualifiedType(); -} - /// getDesugaredType - Return the specified type with any "sugar" removed from /// the type. This takes off typedefs, typeof's etc. If the outer level of /// the type is already concrete, it returns it unmodified. This is similar /// to getting the canonical type, but it doesn't remove *all* typedefs. For /// example, it returns "T*" as "T*", (not as "int*"), because the pointer is /// concrete. -QualType QualType::getDesugaredType(QualType T) { +QualType QualType::getDesugaredType(QualType T, const ASTContext &Context) { + SplitQualType split = getSplitDesugaredType(T); + return Context.getQualifiedType(split.first, split.second); +} + +SplitQualType QualType::getSplitDesugaredType(QualType T) { QualifierCollector Qs; QualType Cur = T; @@ -157,7 +173,7 @@ QualType QualType::getDesugaredType(QualType T) { case Type::Class: { \ const Class##Type *Ty = cast<Class##Type>(CurTy); \ if (!Ty->isSugared()) \ - return Qs.apply(Cur); \ + return SplitQualType(Ty, Qs); \ Cur = Ty->desugar(); \ break; \ } @@ -166,6 +182,52 @@ QualType QualType::getDesugaredType(QualType T) { } } +SplitQualType QualType::getSplitUnqualifiedTypeImpl(QualType type) { + SplitQualType split = type.split(); + + // All the qualifiers we've seen so far. + Qualifiers quals = split.second; + + // The last type node we saw with any nodes inside it. + const Type *lastTypeWithQuals = split.first; + + while (true) { + QualType next; + + // Do a single-step desugar, aborting the loop if the type isn't + // sugared. + switch (split.first->getTypeClass()) { +#define ABSTRACT_TYPE(Class, Parent) +#define TYPE(Class, Parent) \ + case Type::Class: { \ + const Class##Type *ty = cast<Class##Type>(split.first); \ + if (!ty->isSugared()) goto done; \ + next = ty->desugar(); \ + break; \ + } +#include "clang/AST/TypeNodes.def" + } + + // Otherwise, split the underlying type. If that yields qualifiers, + // update the information. + split = next.split(); + if (!split.second.empty()) { + lastTypeWithQuals = split.first; + quals.addConsistentQualifiers(split.second); + } + } + + done: + return SplitQualType(lastTypeWithQuals, quals); +} + +QualType QualType::IgnoreParens(QualType T) { + // FIXME: this seems inherently un-qualifiers-safe. + while (const ParenType *PT = T->getAs<ParenType>()) + T = PT->getInnerType(); + return T; +} + /// getUnqualifiedDesugaredType - Pull any qualifiers and syntactic /// sugar off the given type. This should produce an object of the /// same dynamic type as the canonical type. @@ -268,42 +330,6 @@ QualType Type::getPointeeType() const { return QualType(); } -/// isVariablyModifiedType (C99 6.7.5p3) - Return true for variable length -/// array types and types that contain variable array types in their -/// declarator -bool Type::isVariablyModifiedType() const { - // FIXME: We should really keep a "variably modified" bit in Type, rather - // than walking the type hierarchy to recompute it. - - // A VLA is a variably modified type. - if (isVariableArrayType()) - return true; - - // An array can contain a variably modified type - if (const Type *T = getArrayElementTypeNoTypeQual()) - return T->isVariablyModifiedType(); - - // A pointer can point to a variably modified type. - // Also, C++ references and member pointers can point to a variably modified - // type, where VLAs appear as an extension to C++, and should be treated - // correctly. - if (const PointerType *PT = getAs<PointerType>()) - return PT->getPointeeType()->isVariablyModifiedType(); - if (const ReferenceType *RT = getAs<ReferenceType>()) - return RT->getPointeeType()->isVariablyModifiedType(); - if (const MemberPointerType *PT = getAs<MemberPointerType>()) - return PT->getPointeeType()->isVariablyModifiedType(); - - // A function can return a variably modified type - // This one isn't completely obvious, but it follows from the - // definition in C99 6.7.5p3. Because of this rule, it's - // illegal to declare a function returning a variably modified type. - if (const FunctionType *FT = getAs<FunctionType>()) - return FT->getResultType()->isVariablyModifiedType(); - - return false; -} - const RecordType *Type::getAsStructureType() const { // If this is directly a structure type, return it. if (const RecordType *RT = dyn_cast<RecordType>(this)) { @@ -346,10 +372,11 @@ const RecordType *Type::getAsUnionType() const { ObjCObjectType::ObjCObjectType(QualType Canonical, QualType Base, ObjCProtocolDecl * const *Protocols, unsigned NumProtocols) - : Type(ObjCObject, Canonical, false), - NumProtocols(NumProtocols), - BaseType(Base) { - assert(this->NumProtocols == NumProtocols && + : Type(ObjCObject, Canonical, false, false, false), + BaseType(Base) +{ + ObjCObjectTypeBits.NumProtocols = NumProtocols; + assert(getNumProtocols() == NumProtocols && "bitfield overflow in protocol count"); if (NumProtocols) memcpy(getProtocolStorage(), Protocols, @@ -405,15 +432,69 @@ CXXRecordDecl *Type::getAsCXXRecordDecl() const { return 0; } +namespace { + class GetContainedAutoVisitor : + public TypeVisitor<GetContainedAutoVisitor, AutoType*> { + public: + using TypeVisitor<GetContainedAutoVisitor, AutoType*>::Visit; + AutoType *Visit(QualType T) { + if (T.isNull()) + return 0; + return Visit(T.getTypePtr()); + } + + // The 'auto' type itself. + AutoType *VisitAutoType(const AutoType *AT) { + return const_cast<AutoType*>(AT); + } + + // Only these types can contain the desired 'auto' type. + AutoType *VisitPointerType(const PointerType *T) { + return Visit(T->getPointeeType()); + } + AutoType *VisitBlockPointerType(const BlockPointerType *T) { + return Visit(T->getPointeeType()); + } + AutoType *VisitReferenceType(const ReferenceType *T) { + return Visit(T->getPointeeTypeAsWritten()); + } + AutoType *VisitMemberPointerType(const MemberPointerType *T) { + return Visit(T->getPointeeType()); + } + AutoType *VisitArrayType(const ArrayType *T) { + return Visit(T->getElementType()); + } + AutoType *VisitDependentSizedExtVectorType( + const DependentSizedExtVectorType *T) { + return Visit(T->getElementType()); + } + AutoType *VisitVectorType(const VectorType *T) { + return Visit(T->getElementType()); + } + AutoType *VisitFunctionType(const FunctionType *T) { + return Visit(T->getResultType()); + } + AutoType *VisitParenType(const ParenType *T) { + return Visit(T->getInnerType()); + } + AutoType *VisitAttributedType(const AttributedType *T) { + return Visit(T->getModifiedType()); + } + }; +} + +AutoType *Type::getContainedAutoType() const { + return GetContainedAutoVisitor().Visit(this); +} + bool Type::isIntegerType() const { if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) return BT->getKind() >= BuiltinType::Bool && BT->getKind() <= BuiltinType::Int128; - if (const TagType *TT = dyn_cast<TagType>(CanonicalType)) + if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) // Incomplete enum types are not treated as integer types. // FIXME: In C++, enum types are never integer types. - if (TT->getDecl()->isEnum() && TT->getDecl()->isDefinition()) - return true; + return ET->getDecl()->isComplete(); return false; } @@ -449,9 +530,8 @@ bool Type::isIntegralType(ASTContext &Ctx) const { BT->getKind() <= BuiltinType::Int128; if (!Ctx.getLangOptions().CPlusPlus) - if (const TagType *TT = dyn_cast<TagType>(CanonicalType)) - if (TT->getDecl()->isEnum() && TT->getDecl()->isDefinition()) - return true; // Complete enum types are integral in C. + if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) + return ET->getDecl()->isComplete(); // Complete enum types are integral in C. return false; } @@ -463,19 +543,28 @@ bool Type::isIntegralOrEnumerationType() const { // Check for a complete enum type; incomplete enum types are not properly an // enumeration type in the sense required here. - if (const TagType *TT = dyn_cast<TagType>(CanonicalType)) - if (TT->getDecl()->isEnum() && TT->getDecl()->isDefinition()) - return true; + if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) + return ET->getDecl()->isComplete(); return false; } -bool Type::isEnumeralType() const { - if (const TagType *TT = dyn_cast<TagType>(CanonicalType)) - return TT->getDecl()->isEnum(); +bool Type::isIntegralOrUnscopedEnumerationType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() >= BuiltinType::Bool && + BT->getKind() <= BuiltinType::Int128; + + // Check for a complete enum type; incomplete enum types are not properly an + // enumeration type in the sense required here. + // C++0x: However, if the underlying type of the enum is fixed, it is + // considered complete. + if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) + return ET->getDecl()->isComplete() && !ET->getDecl()->isScoped(); + return false; } + bool Type::isBooleanType() const { if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) return BT->getKind() == BuiltinType::Bool; @@ -493,20 +582,28 @@ bool Type::isCharType() const { bool Type::isWideCharType() const { if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) - return BT->getKind() == BuiltinType::WChar; + return BT->getKind() == BuiltinType::WChar_S || + BT->getKind() == BuiltinType::WChar_U; return false; } /// \brief Determine whether this type is any of the built-in character /// types. bool Type::isAnyCharacterType() const { - if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) - return (BT->getKind() >= BuiltinType::Char_U && - BT->getKind() <= BuiltinType::Char32) || - (BT->getKind() >= BuiltinType::Char_S && - BT->getKind() <= BuiltinType::WChar); - - return false; + const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType); + if (BT == 0) return false; + switch (BT->getKind()) { + default: return false; + case BuiltinType::Char_U: + case BuiltinType::UChar: + case BuiltinType::WChar_U: + case BuiltinType::Char16: + case BuiltinType::Char32: + case BuiltinType::Char_S: + case BuiltinType::SChar: + case BuiltinType::WChar_S: + return true; + } } /// isSignedIntegerType - Return true if this is an integer type that is @@ -518,8 +615,12 @@ bool Type::isSignedIntegerType() const { BT->getKind() <= BuiltinType::Int128; } - if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) - return ET->getDecl()->getIntegerType()->isSignedIntegerType(); + if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) { + // Incomplete enum types are not treated as integer types. + // FIXME: In C++, enum types are never integer types. + if (ET->getDecl()->isComplete()) + return ET->getDecl()->getIntegerType()->isSignedIntegerType(); + } return false; } @@ -540,8 +641,12 @@ bool Type::isUnsignedIntegerType() const { BT->getKind() <= BuiltinType::UInt128; } - if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) - return ET->getDecl()->getIntegerType()->isUnsignedIntegerType(); + if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) { + // Incomplete enum types are not treated as integer types. + // FIXME: In C++, enum types are never integer types. + if (ET->getDecl()->isComplete()) + return ET->getDecl()->getIntegerType()->isUnsignedIntegerType(); + } return false; } @@ -579,8 +684,8 @@ bool Type::isRealType() const { if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) return BT->getKind() >= BuiltinType::Bool && BT->getKind() <= BuiltinType::LongDouble; - if (const TagType *TT = dyn_cast<TagType>(CanonicalType)) - return TT->getDecl()->isEnum() && TT->getDecl()->isDefinition(); + if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) + return ET->getDecl()->isComplete() && !ET->getDecl()->isScoped(); return false; } @@ -591,20 +696,22 @@ bool Type::isArithmeticType() const { if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) // GCC allows forward declaration of enum types (forbid by C99 6.7.2.3p2). // If a body isn't seen by the time we get here, return false. - return ET->getDecl()->isDefinition(); + // + // C++0x: Enumerations are not arithmetic types. For now, just return + // false for scoped enumerations since that will disable any + // unwanted implicit conversions. + return !ET->getDecl()->isScoped() && ET->getDecl()->isComplete(); return isa<ComplexType>(CanonicalType); } bool Type::isScalarType() const { if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) - return BT->getKind() != BuiltinType::Void; - if (const TagType *TT = dyn_cast<TagType>(CanonicalType)) { + return BT->getKind() > BuiltinType::Void && + BT->getKind() <= BuiltinType::NullPtr; + if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) // Enums are scalar types, but only if they are defined. Incomplete enums // are not treated as scalar types. - if (TT->getDecl()->isEnum() && TT->getDecl()->isDefinition()) - return true; - return false; - } + return ET->getDecl()->isComplete(); return isa<PointerType>(CanonicalType) || isa<BlockPointerType>(CanonicalType) || isa<MemberPointerType>(CanonicalType) || @@ -612,6 +719,35 @@ bool Type::isScalarType() const { isa<ObjCObjectPointerType>(CanonicalType); } +Type::ScalarTypeKind Type::getScalarTypeKind() const { + assert(isScalarType()); + + const Type *T = CanonicalType.getTypePtr(); + if (const BuiltinType *BT = dyn_cast<BuiltinType>(T)) { + if (BT->getKind() == BuiltinType::Bool) return STK_Bool; + if (BT->getKind() == BuiltinType::NullPtr) return STK_Pointer; + if (BT->isInteger()) return STK_Integral; + if (BT->isFloatingPoint()) return STK_Floating; + llvm_unreachable("unknown scalar builtin type"); + } else if (isa<PointerType>(T) || + isa<BlockPointerType>(T) || + isa<ObjCObjectPointerType>(T)) { + return STK_Pointer; + } else if (isa<MemberPointerType>(T)) { + return STK_MemberPointer; + } else if (isa<EnumType>(T)) { + assert(cast<EnumType>(T)->getDecl()->isComplete()); + return STK_Integral; + } else if (const ComplexType *CT = dyn_cast<ComplexType>(T)) { + if (CT->getElementType()->isRealFloatingType()) + return STK_FloatingComplex; + return STK_IntegralComplex; + } + + llvm_unreachable("unknown scalar type"); + return STK_Pointer; +} + /// \brief Determines whether the type is a C++ aggregate type or C /// aggregate or union type. /// @@ -652,8 +788,12 @@ bool Type::isIncompleteType() const { // Void is the only incomplete builtin type. Per C99 6.2.5p19, it can never // be completed. return isVoidType(); - case Record: case Enum: + // An enumeration with fixed underlying type is complete (C++0x 7.2p3). + if (cast<EnumType>(CanonicalType)->getDecl()->isFixed()) + return false; + // Fall through. + case Record: // A tagged type (struct/union/enum/class) is incomplete if the decl is a // forward declaration, but not a full definition (C99 6.2.5p22). return !cast<TagType>(CanonicalType)->getDecl()->isDefinition(); @@ -678,7 +818,11 @@ bool Type::isIncompleteType() const { /// isPODType - Return true if this is a plain-old-data type (C++ 3.9p10) bool Type::isPODType() const { // The compiler shouldn't query this for incomplete types, but the user might. - // We return false for that case. + // We return false for that case. Except for incomplete arrays of PODs, which + // are PODs according to the standard. + if (isIncompleteArrayType() && + cast<ArrayType>(CanonicalType)->getElementType()->isPODType()) + return true; if (isIncompleteType()) return false; @@ -687,7 +831,7 @@ bool Type::isPODType() const { default: return false; case VariableArray: case ConstantArray: - // IncompleteArray is caught by isIncompleteType() above. + // IncompleteArray is handled above. return cast<ArrayType>(CanonicalType)->getElementType()->isPODType(); case Builtin: @@ -765,7 +909,8 @@ bool Type::isPromotableIntegerType() const { // 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()) + if (this->isDependentType() || ET->getDecl()->getPromotionType().isNull() + || ET->getDecl()->isScoped()) return false; const BuiltinType *BT @@ -808,9 +953,6 @@ bool Type::isSpecifierType() const { } } -TypeWithKeyword::~TypeWithKeyword() { -} - ElaboratedTypeKeyword TypeWithKeyword::getKeywordForTypeSpec(unsigned TypeSpec) { switch (TypeSpec) { @@ -830,8 +972,10 @@ TypeWithKeyword::getTagTypeKindForTypeSpec(unsigned TypeSpec) { case TST_struct: return TTK_Struct; case TST_union: return TTK_Union; case TST_enum: return TTK_Enum; - default: llvm_unreachable("Type specifier is not a tag type kind."); } + + llvm_unreachable("Type specifier is not a tag type kind."); + return TTK_Union; } ElaboratedTypeKeyword @@ -877,7 +1021,6 @@ TypeWithKeyword::KeywordIsTagTypeKind(ElaboratedTypeKeyword Keyword) { const char* TypeWithKeyword::getKeywordName(ElaboratedTypeKeyword Keyword) { switch (Keyword) { - default: llvm_unreachable("Unknown elaborated type keyword."); case ETK_None: return ""; case ETK_Typename: return "typename"; case ETK_Class: return "class"; @@ -885,28 +1028,33 @@ TypeWithKeyword::getKeywordName(ElaboratedTypeKeyword Keyword) { case ETK_Union: return "union"; case ETK_Enum: return "enum"; } -} -ElaboratedType::~ElaboratedType() {} -DependentNameType::~DependentNameType() {} -DependentTemplateSpecializationType::~DependentTemplateSpecializationType() {} + llvm_unreachable("Unknown elaborated type keyword."); + return ""; +} DependentTemplateSpecializationType::DependentTemplateSpecializationType( ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, const IdentifierInfo *Name, unsigned NumArgs, const TemplateArgument *Args, QualType Canon) - : TypeWithKeyword(Keyword, DependentTemplateSpecialization, Canon, true), + : TypeWithKeyword(Keyword, DependentTemplateSpecialization, Canon, true, + /*VariablyModified=*/false, + NNS->containsUnexpandedParameterPack()), NNS(NNS), Name(Name), NumArgs(NumArgs) { assert(NNS && NNS->isDependent() && "DependentTemplateSpecializatonType requires dependent qualifier"); - for (unsigned I = 0; I != NumArgs; ++I) + for (unsigned I = 0; I != NumArgs; ++I) { + if (Args[I].containsUnexpandedParameterPack()) + setContainsUnexpandedParameterPack(); + new (&getArgBuffer()[I]) TemplateArgument(Args[I]); + } } void DependentTemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID, - ASTContext &Context, + const ASTContext &Context, ElaboratedTypeKeyword Keyword, NestedNameSpecifier *Qualifier, const IdentifierInfo *Name, @@ -935,17 +1083,18 @@ bool Type::isElaboratedTypeSpecifier() const { } const char *Type::getTypeClassName() const { - switch (TC) { - default: assert(0 && "Type class not in TypeNodes.def!"); + switch (TypeBits.TC) { #define ABSTRACT_TYPE(Derived, Base) #define TYPE(Derived, Base) case Derived: return #Derived; #include "clang/AST/TypeNodes.def" } + + llvm_unreachable("Invalid type class."); + return 0; } const char *BuiltinType::getName(const LangOptions &LO) const { switch (getKind()) { - default: assert(0 && "Unknown builtin type!"); case Void: return "void"; case Bool: return LO.Bool ? "bool" : "_Bool"; case Char_S: return "char"; @@ -965,21 +1114,22 @@ const char *BuiltinType::getName(const LangOptions &LO) const { case Float: return "float"; case Double: return "double"; case LongDouble: return "long double"; - case WChar: return "wchar_t"; + case WChar_S: + case WChar_U: return "wchar_t"; case Char16: return "char16_t"; case Char32: return "char32_t"; case NullPtr: return "nullptr_t"; case Overload: return "<overloaded function type>"; case Dependent: return "<dependent type>"; - case UndeducedAuto: return "auto"; case ObjCId: return "id"; case ObjCClass: return "Class"; case ObjCSel: return "SEL"; } + + llvm_unreachable("Invalid builtin type."); + return 0; } -void FunctionType::ANCHOR() {} // Key function for FunctionType. - QualType QualType::getNonLValueExprType(ASTContext &Context) const { if (const ReferenceType *RefType = getTypePtr()->getAs<ReferenceType>()) return RefType->getPointeeType(); @@ -998,8 +1148,9 @@ QualType QualType::getNonLValueExprType(ASTContext &Context) const { llvm::StringRef FunctionType::getNameForCallConv(CallingConv CC) { switch (CC) { - case CC_Default: llvm_unreachable("no name for default cc"); - default: return ""; + case CC_Default: + llvm_unreachable("no name for default cc"); + return ""; case CC_C: return "cdecl"; case CC_X86StdCall: return "stdcall"; @@ -1007,62 +1158,76 @@ llvm::StringRef FunctionType::getNameForCallConv(CallingConv CC) { case CC_X86ThisCall: return "thiscall"; case CC_X86Pascal: return "pascal"; } + + llvm_unreachable("Invalid calling convention."); + return ""; +} + +FunctionProtoType::FunctionProtoType(QualType result, const QualType *args, + unsigned numArgs, QualType canonical, + const ExtProtoInfo &epi) + : FunctionType(FunctionProto, result, epi.Variadic, epi.TypeQuals, + epi.RefQualifier, canonical, + result->isDependentType(), + result->isVariablyModifiedType(), + result->containsUnexpandedParameterPack(), + epi.ExtInfo), + NumArgs(numArgs), NumExceptions(epi.NumExceptions), + HasExceptionSpec(epi.HasExceptionSpec), + HasAnyExceptionSpec(epi.HasAnyExceptionSpec) +{ + // Fill in the trailing argument array. + QualType *argSlot = reinterpret_cast<QualType*>(this+1); + for (unsigned i = 0; i != numArgs; ++i) { + if (args[i]->isDependentType()) + setDependent(); + + if (args[i]->containsUnexpandedParameterPack()) + setContainsUnexpandedParameterPack(); + + argSlot[i] = args[i]; + } + + // Fill in the exception array. + QualType *exnSlot = argSlot + numArgs; + for (unsigned i = 0, e = epi.NumExceptions; i != e; ++i) { + if (epi.Exceptions[i]->isDependentType()) + setDependent(); + + if (epi.Exceptions[i]->containsUnexpandedParameterPack()) + setContainsUnexpandedParameterPack(); + + exnSlot[i] = epi.Exceptions[i]; + } +} + +bool FunctionProtoType::isTemplateVariadic() const { + for (unsigned ArgIdx = getNumArgs(); ArgIdx; --ArgIdx) + if (isa<PackExpansionType>(getArgType(ArgIdx - 1))) + return true; + + return false; } 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, - const FunctionType::ExtInfo &Info) { + const QualType *ArgTys, unsigned NumArgs, + const ExtProtoInfo &epi) { ID.AddPointer(Result.getAsOpaquePtr()); for (unsigned i = 0; i != NumArgs; ++i) ID.AddPointer(ArgTys[i].getAsOpaquePtr()); - ID.AddInteger(isVariadic); - ID.AddInteger(TypeQuals); - ID.AddInteger(hasExceptionSpec); - if (hasExceptionSpec) { - ID.AddInteger(anyExceptionSpec); - for (unsigned i = 0; i != NumExceptions; ++i) - ID.AddPointer(Exs[i].getAsOpaquePtr()); + ID.AddBoolean(epi.Variadic); + ID.AddInteger(epi.TypeQuals); + ID.AddInteger(epi.RefQualifier); + if (epi.HasExceptionSpec) { + ID.AddBoolean(epi.HasAnyExceptionSpec); + for (unsigned i = 0; i != epi.NumExceptions; ++i) + ID.AddPointer(epi.Exceptions[i].getAsOpaquePtr()); } - ID.AddInteger(Info.getNoReturn()); - ID.AddInteger(Info.getRegParm()); - ID.AddInteger(Info.getCC()); + epi.ExtInfo.Profile(ID); } void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getResultType(), arg_type_begin(), NumArgs, isVariadic(), - getTypeQuals(), hasExceptionSpec(), hasAnyExceptionSpec(), - getNumExceptions(), exception_begin(), - getExtInfo()); -} - -/// LookThroughTypedefs - Return the ultimate type this typedef corresponds to -/// potentially looking through *all* consequtive typedefs. This returns the -/// sum of the type qualifiers, so if you have: -/// typedef const int A; -/// typedef volatile A B; -/// looking through the typedefs for B will give you "const volatile A". -/// -QualType TypedefType::LookThroughTypedefs() const { - // Usually, there is only a single level of typedefs, be fast in that case. - QualType FirstType = getDecl()->getUnderlyingType(); - if (!isa<TypedefType>(FirstType)) - return FirstType; - - // Otherwise, do the fully general loop. - QualifierCollector Qs; - - QualType CurType; - const TypedefType *TDT = this; - do { - CurType = TDT->getDecl()->getUnderlyingType(); - TDT = dyn_cast<TypedefType>(Qs.strip(CurType)); - } while (TDT); - - return Qs.apply(CurType); + Profile(ID, getResultType(), arg_type_begin(), NumArgs, getExtProtoInfo()); } QualType TypedefType::desugar() const { @@ -1070,7 +1235,10 @@ QualType TypedefType::desugar() const { } TypeOfExprType::TypeOfExprType(Expr *E, QualType can) - : Type(TypeOfExpr, can, E->isTypeDependent()), TOExpr(E) { + : Type(TypeOfExpr, can, E->isTypeDependent(), + E->getType()->isVariablyModifiedType(), + E->containsUnexpandedParameterPack()), + TOExpr(E) { } QualType TypeOfExprType::desugar() const { @@ -1078,25 +1246,29 @@ QualType TypeOfExprType::desugar() const { } void DependentTypeOfExprType::Profile(llvm::FoldingSetNodeID &ID, - ASTContext &Context, Expr *E) { + const ASTContext &Context, Expr *E) { E->Profile(ID, Context, true); } DecltypeType::DecltypeType(Expr *E, QualType underlyingType, QualType can) - : Type(Decltype, can, E->isTypeDependent()), E(E), + : Type(Decltype, can, E->isTypeDependent(), + E->getType()->isVariablyModifiedType(), + E->containsUnexpandedParameterPack()), + E(E), UnderlyingType(underlyingType) { } -DependentDecltypeType::DependentDecltypeType(ASTContext &Context, Expr *E) +DependentDecltypeType::DependentDecltypeType(const ASTContext &Context, Expr *E) : DecltypeType(E, Context.DependentTy), Context(Context) { } void DependentDecltypeType::Profile(llvm::FoldingSetNodeID &ID, - ASTContext &Context, Expr *E) { + const ASTContext &Context, Expr *E) { E->Profile(ID, Context, true); } TagType::TagType(TypeClass TC, const TagDecl *D, QualType can) - : Type(TC, can, D->isDependentType()), + : Type(TC, can, D->isDependentType(), /*VariablyModified=*/false, + /*ContainsUnexpandedParameterPack=*/false), decl(const_cast<TagDecl*>(D)) {} static TagDecl *getInterestingTagDecl(TagDecl *decl) { @@ -1130,43 +1302,32 @@ bool EnumType::classof(const TagType *TT) { return isa<EnumDecl>(TT->getDecl()); } -static bool isDependent(const TemplateArgument &Arg) { - switch (Arg.getKind()) { - case TemplateArgument::Null: - assert(false && "Should not have a NULL template argument"); - return false; - - case TemplateArgument::Type: - return Arg.getAsType()->isDependentType(); - - case TemplateArgument::Template: - return Arg.getAsTemplate().isDependent(); - - case TemplateArgument::Declaration: - if (DeclContext *DC = dyn_cast<DeclContext>(Arg.getAsDecl())) - return DC->isDependentContext(); - return Arg.getAsDecl()->getDeclContext()->isDependentContext(); - - case TemplateArgument::Integral: - // Never dependent - return false; - - case TemplateArgument::Expression: - return (Arg.getAsExpr()->isTypeDependent() || - Arg.getAsExpr()->isValueDependent()); +SubstTemplateTypeParmPackType:: +SubstTemplateTypeParmPackType(const TemplateTypeParmType *Param, + QualType Canon, + const TemplateArgument &ArgPack) + : Type(SubstTemplateTypeParmPack, Canon, true, false, true), Replaced(Param), + Arguments(ArgPack.pack_begin()), NumArguments(ArgPack.pack_size()) +{ +} - case TemplateArgument::Pack: - for (TemplateArgument::pack_iterator P = Arg.pack_begin(), - PEnd = Arg.pack_end(); - P != PEnd; ++P) { - if (isDependent(*P)) - return true; - } +TemplateArgument SubstTemplateTypeParmPackType::getArgumentPack() const { + return TemplateArgument(Arguments, NumArguments); +} - return false; - } +void SubstTemplateTypeParmPackType::Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getReplacedParameter(), getArgumentPack()); +} - return false; +void SubstTemplateTypeParmPackType::Profile(llvm::FoldingSetNodeID &ID, + const TemplateTypeParmType *Replaced, + const TemplateArgument &ArgPack) { + ID.AddPointer(Replaced); + ID.AddInteger(ArgPack.pack_size()); + for (TemplateArgument::pack_iterator P = ArgPack.pack_begin(), + PEnd = ArgPack.pack_end(); + P != PEnd; ++P) + ID.AddPointer(P->getAsType().getAsOpaquePtr()); } bool TemplateSpecializationType:: @@ -1177,7 +1338,7 @@ anyDependentTemplateArguments(const TemplateArgumentListInfo &Args) { bool TemplateSpecializationType:: anyDependentTemplateArguments(const TemplateArgumentLoc *Args, unsigned N) { for (unsigned i = 0; i != N; ++i) - if (isDependent(Args[i].getArgument())) + if (Args[i].getArgument().isDependent()) return true; return false; } @@ -1185,7 +1346,7 @@ anyDependentTemplateArguments(const TemplateArgumentLoc *Args, unsigned N) { bool TemplateSpecializationType:: anyDependentTemplateArguments(const TemplateArgument *Args, unsigned N) { for (unsigned i = 0; i != N; ++i) - if (isDependent(Args[i])) + if (Args[i].isDependent()) return true; return false; } @@ -1196,16 +1357,28 @@ TemplateSpecializationType(TemplateName T, unsigned NumArgs, QualType Canon) : Type(TemplateSpecialization, Canon.isNull()? QualType(this, 0) : Canon, - T.isDependent() || anyDependentTemplateArguments(Args, NumArgs)), - Template(T), NumArgs(NumArgs) { + T.isDependent(), false, + T.containsUnexpandedParameterPack()), + Template(T), NumArgs(NumArgs) +{ assert((!Canon.isNull() || T.isDependent() || anyDependentTemplateArguments(Args, NumArgs)) && "No canonical type for non-dependent class template specialization"); TemplateArgument *TemplateArgs = reinterpret_cast<TemplateArgument *>(this + 1); - for (unsigned Arg = 0; Arg < NumArgs; ++Arg) + for (unsigned Arg = 0; Arg < NumArgs; ++Arg) { + // Update dependent and variably-modified bits. + if (Args[Arg].isDependent()) + setDependent(); + if (Args[Arg].getKind() == TemplateArgument::Type && + Args[Arg].getAsType()->isVariablyModifiedType()) + setVariablyModified(); + if (Args[Arg].containsUnexpandedParameterPack()) + setContainsUnexpandedParameterPack(); + new (&TemplateArgs[Arg]) TemplateArgument(Args[Arg]); + } } void @@ -1213,26 +1386,26 @@ TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID, TemplateName T, const TemplateArgument *Args, unsigned NumArgs, - ASTContext &Context) { + const ASTContext &Context) { T.Profile(ID); for (unsigned Idx = 0; Idx < NumArgs; ++Idx) Args[Idx].Profile(ID, Context); } -QualType QualifierCollector::apply(QualType QT) const { +QualType +QualifierCollector::apply(const ASTContext &Context, QualType QT) const { if (!hasNonFastQualifiers()) return QT.withFastQualifiers(getFastQualifiers()); - assert(Context && "extended qualifiers but no context!"); - return Context->getQualifiedType(QT, *this); + return Context.getQualifiedType(QT, *this); } -QualType QualifierCollector::apply(const Type *T) const { +QualType +QualifierCollector::apply(const ASTContext &Context, const Type *T) const { if (!hasNonFastQualifiers()) return QualType(T, getFastQualifiers()); - assert(Context && "extended qualifiers but no context!"); - return Context->getQualifiedType(T, *this); + return Context.getQualifiedType(T, *this); } void ObjCObjectTypeImpl::Profile(llvm::FoldingSetNodeID &ID, @@ -1248,95 +1421,223 @@ void ObjCObjectTypeImpl::Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getBaseType(), qual_begin(), getNumProtocols()); } -/// \brief Determine the linkage of this type. -Linkage Type::getLinkage() const { - if (this != CanonicalType.getTypePtr()) - return CanonicalType->getLinkage(); +namespace { + +/// \brief The cached properties of a type. +class CachedProperties { + char linkage; + char visibility; + bool local; - if (!LinkageKnown) { - CachedLinkage = getLinkageImpl(); - LinkageKnown = true; - } +public: + CachedProperties(Linkage linkage, Visibility visibility, bool local) + : linkage(linkage), visibility(visibility), local(local) {} - return static_cast<clang::Linkage>(CachedLinkage); + Linkage getLinkage() const { return (Linkage) linkage; } + Visibility getVisibility() const { return (Visibility) visibility; } + bool hasLocalOrUnnamedType() const { return local; } + + friend CachedProperties merge(CachedProperties L, CachedProperties R) { + return CachedProperties(minLinkage(L.getLinkage(), R.getLinkage()), + minVisibility(L.getVisibility(), R.getVisibility()), + L.hasLocalOrUnnamedType() | R.hasLocalOrUnnamedType()); + } +}; } -Linkage Type::getLinkageImpl() const { - // C++ [basic.link]p8: - // Names not covered by these rules have no linkage. - return NoLinkage; -} +static CachedProperties computeCachedProperties(const Type *T); -void Type::ClearLinkageCache() { - if (this != CanonicalType.getTypePtr()) - CanonicalType->ClearLinkageCache(); - else - LinkageKnown = false; -} +namespace clang { +/// The type-property cache. This is templated so as to be +/// instantiated at an internal type to prevent unnecessary symbol +/// leakage. +template <class Private> class TypePropertyCache { +public: + static CachedProperties get(QualType T) { + return get(T.getTypePtr()); + } -Linkage BuiltinType::getLinkageImpl() 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; -} + static CachedProperties get(const Type *T) { + ensure(T); + return CachedProperties(T->TypeBits.getLinkage(), + T->TypeBits.getVisibility(), + T->TypeBits.hasLocalOrUnnamedType()); + } -Linkage TagType::getLinkageImpl() 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(); -} + static void ensure(const Type *T) { + // If the cache is valid, we're okay. + if (T->TypeBits.isCacheValid()) return; + + // If this type is non-canonical, ask its canonical type for the + // relevant information. + if (!T->isCanonicalUnqualified()) { + const Type *CT = T->getCanonicalTypeInternal().getTypePtr(); + ensure(CT); + T->TypeBits.CacheValidAndVisibility = + CT->TypeBits.CacheValidAndVisibility; + T->TypeBits.CachedLinkage = CT->TypeBits.CachedLinkage; + T->TypeBits.CachedLocalOrUnnamed = CT->TypeBits.CachedLocalOrUnnamed; + return; + } -// 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::getLinkageImpl() const { - return ElementType->getLinkage(); + // Compute the cached properties and then set the cache. + CachedProperties Result = computeCachedProperties(T); + T->TypeBits.CacheValidAndVisibility = Result.getVisibility() + 1U; + assert(T->TypeBits.isCacheValid() && + T->TypeBits.getVisibility() == Result.getVisibility()); + T->TypeBits.CachedLinkage = Result.getLinkage(); + T->TypeBits.CachedLocalOrUnnamed = Result.hasLocalOrUnnamedType(); + } +}; } -Linkage PointerType::getLinkageImpl() const { - return PointeeType->getLinkage(); -} +// Instantiate the friend template at a private class. In a +// reasonable implementation, these symbols will be internal. +// It is terrible that this is the best way to accomplish this. +namespace { class Private {}; } +typedef TypePropertyCache<Private> Cache; + +static CachedProperties computeCachedProperties(const Type *T) { + switch (T->getTypeClass()) { +#define TYPE(Class,Base) +#define NON_CANONICAL_TYPE(Class,Base) case Type::Class: +#include "clang/AST/TypeNodes.def" + llvm_unreachable("didn't expect a non-canonical type here"); + +#define TYPE(Class,Base) +#define DEPENDENT_TYPE(Class,Base) case Type::Class: +#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class,Base) case Type::Class: +#include "clang/AST/TypeNodes.def" + // Treat dependent types as external. + assert(T->isDependentType()); + return CachedProperties(ExternalLinkage, DefaultVisibility, false); + + case Type::Builtin: + // 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 CachedProperties(ExternalLinkage, DefaultVisibility, false); + + case Type::Record: + case Type::Enum: { + const TagDecl *Tag = cast<TagType>(T)->getDecl(); + + // 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 + NamedDecl::LinkageInfo LV = Tag->getLinkageAndVisibility(); + bool IsLocalOrUnnamed = + Tag->getDeclContext()->isFunctionOrMethod() || + (!Tag->getIdentifier() && !Tag->getTypedefForAnonDecl()); + return CachedProperties(LV.linkage(), LV.visibility(), IsLocalOrUnnamed); + } + + // 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 + case Type::Complex: + return Cache::get(cast<ComplexType>(T)->getElementType()); + case Type::Pointer: + return Cache::get(cast<PointerType>(T)->getPointeeType()); + case Type::BlockPointer: + return Cache::get(cast<BlockPointerType>(T)->getPointeeType()); + case Type::LValueReference: + case Type::RValueReference: + return Cache::get(cast<ReferenceType>(T)->getPointeeType()); + case Type::MemberPointer: { + const MemberPointerType *MPT = cast<MemberPointerType>(T); + return merge(Cache::get(MPT->getClass()), + Cache::get(MPT->getPointeeType())); + } + case Type::ConstantArray: + case Type::IncompleteArray: + case Type::VariableArray: + return Cache::get(cast<ArrayType>(T)->getElementType()); + case Type::Vector: + case Type::ExtVector: + return Cache::get(cast<VectorType>(T)->getElementType()); + case Type::FunctionNoProto: + return Cache::get(cast<FunctionType>(T)->getResultType()); + case Type::FunctionProto: { + const FunctionProtoType *FPT = cast<FunctionProtoType>(T); + CachedProperties result = Cache::get(FPT->getResultType()); + for (FunctionProtoType::arg_type_iterator ai = FPT->arg_type_begin(), + ae = FPT->arg_type_end(); ai != ae; ++ai) + result = merge(result, Cache::get(*ai)); + return result; + } + case Type::ObjCInterface: { + NamedDecl::LinkageInfo LV = + cast<ObjCInterfaceType>(T)->getDecl()->getLinkageAndVisibility(); + return CachedProperties(LV.linkage(), LV.visibility(), false); + } + case Type::ObjCObject: + return Cache::get(cast<ObjCObjectType>(T)->getBaseType()); + case Type::ObjCObjectPointer: + return Cache::get(cast<ObjCObjectPointerType>(T)->getPointeeType()); + } + + llvm_unreachable("unhandled type class"); -Linkage BlockPointerType::getLinkageImpl() const { - return PointeeType->getLinkage(); + // C++ [basic.link]p8: + // Names not covered by these rules have no linkage. + return CachedProperties(NoLinkage, DefaultVisibility, false); } -Linkage ReferenceType::getLinkageImpl() const { - return PointeeType->getLinkage(); +/// \brief Determine the linkage of this type. +Linkage Type::getLinkage() const { + Cache::ensure(this); + return TypeBits.getLinkage(); } -Linkage MemberPointerType::getLinkageImpl() const { - return minLinkage(Class->getLinkage(), PointeeType->getLinkage()); +/// \brief Determine the linkage of this type. +Visibility Type::getVisibility() const { + Cache::ensure(this); + return TypeBits.getVisibility(); } -Linkage ArrayType::getLinkageImpl() const { - return ElementType->getLinkage(); +bool Type::hasUnnamedOrLocalType() const { + Cache::ensure(this); + return TypeBits.hasLocalOrUnnamedType(); } -Linkage VectorType::getLinkageImpl() const { - return ElementType->getLinkage(); +std::pair<Linkage,Visibility> Type::getLinkageAndVisibility() const { + Cache::ensure(this); + return std::make_pair(TypeBits.getLinkage(), TypeBits.getVisibility()); } -Linkage FunctionNoProtoType::getLinkageImpl() const { - return getResultType()->getLinkage(); +void Type::ClearLinkageCache() { + TypeBits.CacheValidAndVisibility = 0; + if (QualType(this, 0) != CanonicalType) + CanonicalType->TypeBits.CacheValidAndVisibility = 0; } -Linkage FunctionProtoType::getLinkageImpl() 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()); +bool Type::hasSizedVLAType() const { + if (!isVariablyModifiedType()) return false; - return L; -} + if (const PointerType *ptr = getAs<PointerType>()) + return ptr->getPointeeType()->hasSizedVLAType(); + if (const ReferenceType *ref = getAs<ReferenceType>()) + return ref->getPointeeType()->hasSizedVLAType(); + if (const ArrayType *arr = getAsArrayTypeUnsafe()) { + if (isa<VariableArrayType>(arr) && + cast<VariableArrayType>(arr)->getSizeExpr()) + return true; + + return arr->getElementType()->hasSizedVLAType(); + } -Linkage ObjCObjectType::getLinkageImpl() const { - return ExternalLinkage; + return false; } -Linkage ObjCObjectPointerType::getLinkageImpl() const { - return ExternalLinkage; +QualType::DestructionKind QualType::isDestructedTypeImpl(QualType type) { + /// Currently, the only destruction kind we recognize is C++ objects + /// with non-trivial destructors. + const CXXRecordDecl *record = + type->getBaseElementTypeUnsafe()->getAsCXXRecordDecl(); + if (record && !record->hasTrivialDestructor()) + return DK_cxx_destructor; + + return DK_none; } diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp index 66578fb..14db7f8 100644 --- a/lib/AST/TypeLoc.cpp +++ b/lib/AST/TypeLoc.cpp @@ -77,14 +77,15 @@ TypeLoc TypeLoc::getNextTypeLocImpl(TypeLoc TL) { /// \brief Initializes a type location, and all of its children /// recursively, as if the entire tree had been written in the /// given location. -void TypeLoc::initializeImpl(TypeLoc TL, SourceLocation Loc) { +void TypeLoc::initializeImpl(ASTContext &Context, TypeLoc TL, + SourceLocation Loc) { while (true) { switch (TL.getTypeLocClass()) { #define ABSTRACT_TYPELOC(CLASS, PARENT) #define TYPELOC(CLASS, PARENT) \ case CLASS: { \ CLASS##TypeLoc TLCasted = cast<CLASS##TypeLoc>(TL); \ - TLCasted.initializeLocal(Loc); \ + TLCasted.initializeLocal(Context, Loc); \ TL = TLCasted.getNextTypeLoc(); \ if (!TL) return; \ continue; \ @@ -187,11 +188,10 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const { return TST_char16; case BuiltinType::Char32: return TST_char32; - case BuiltinType::WChar: + case BuiltinType::WChar_S: + case BuiltinType::WChar_U: return TST_wchar; - case BuiltinType::UndeducedAuto: - return TST_auto; - + case BuiltinType::UChar: case BuiltinType::UShort: case BuiltinType::UInt: @@ -222,3 +222,44 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const { return TST_unspecified; } + +TypeLoc TypeLoc::IgnoreParensImpl(TypeLoc TL) { + while (ParenTypeLoc* PTL = dyn_cast<ParenTypeLoc>(&TL)) + TL = PTL->getInnerLoc(); + return TL; +} + +void TemplateSpecializationTypeLoc::initializeArgLocs(ASTContext &Context, + unsigned NumArgs, + const TemplateArgument *Args, + TemplateArgumentLocInfo *ArgInfos, + SourceLocation Loc) { + for (unsigned i = 0, e = NumArgs; i != e; ++i) { + switch (Args[i].getKind()) { + case TemplateArgument::Null: + case TemplateArgument::Declaration: + case TemplateArgument::Integral: + case TemplateArgument::Pack: + case TemplateArgument::Expression: + // FIXME: Can we do better for declarations and integral values? + ArgInfos[i] = TemplateArgumentLocInfo(); + break; + + case TemplateArgument::Type: + ArgInfos[i] = TemplateArgumentLocInfo( + Context.getTrivialTypeSourceInfo(Args[i].getAsType(), + Loc)); + break; + + case TemplateArgument::Template: + ArgInfos[i] = TemplateArgumentLocInfo(SourceRange(Loc), Loc, + SourceLocation()); + break; + + case TemplateArgument::TemplateExpansion: + ArgInfos[i] = TemplateArgumentLocInfo(SourceRange(Loc), Loc, Loc); + break; + } + } +} + diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index d3a6b64..1390739 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -30,12 +30,13 @@ namespace { public: explicit TypePrinter(const PrintingPolicy &Policy) : Policy(Policy) { } - void Print(QualType T, std::string &S); + void print(const Type *ty, Qualifiers qs, std::string &buffer); + void print(QualType T, std::string &S); void AppendScope(DeclContext *DC, std::string &S); - void PrintTag(TagDecl *T, std::string &S); + void printTag(TagDecl *T, std::string &S); #define ABSTRACT_TYPE(CLASS, PARENT) #define TYPE(CLASS, PARENT) \ - void Print##CLASS(const CLASS##Type *T, std::string &S); + void print##CLASS(const CLASS##Type *T, std::string &S); #include "clang/AST/TypeNodes.def" }; } @@ -55,9 +56,14 @@ static void AppendTypeQualList(std::string &S, unsigned TypeQuals) { } } -void TypePrinter::Print(QualType T, std::string &S) { - if (T.isNull()) { - S += "NULL TYPE"; +void TypePrinter::print(QualType t, std::string &buffer) { + SplitQualType split = t.split(); + print(split.first, split.second, buffer); +} + +void TypePrinter::print(const Type *T, Qualifiers Quals, std::string &buffer) { + if (!T) { + buffer += "NULL TYPE"; return; } @@ -65,28 +71,104 @@ void TypePrinter::Print(QualType T, std::string &S) { return; // Print qualifiers as appropriate. - Qualifiers Quals = T.getLocalQualifiers(); - if (!Quals.empty()) { - std::string TQS; - Quals.getAsStringInternal(TQS, Policy); + + // CanPrefixQualifiers - We prefer to print type qualifiers before the type, + // so that we get "const int" instead of "int const", but we can't do this if + // the type is complex. For example if the type is "int*", we *must* print + // "int * const", printing "const int *" is different. Only do this when the + // type expands to a simple string. + bool CanPrefixQualifiers = false; + + Type::TypeClass TC = T->getTypeClass(); + if (const AutoType *AT = dyn_cast<AutoType>(T)) + TC = AT->desugar()->getTypeClass(); + if (const SubstTemplateTypeParmType *Subst + = dyn_cast<SubstTemplateTypeParmType>(T)) + TC = Subst->getReplacementType()->getTypeClass(); + + switch (TC) { + case Type::Builtin: + case Type::Complex: + case Type::UnresolvedUsing: + case Type::Typedef: + case Type::TypeOfExpr: + case Type::TypeOf: + case Type::Decltype: + case Type::Record: + case Type::Enum: + case Type::Elaborated: + case Type::TemplateTypeParm: + case Type::SubstTemplateTypeParmPack: + case Type::TemplateSpecialization: + case Type::InjectedClassName: + case Type::DependentName: + case Type::DependentTemplateSpecialization: + case Type::ObjCObject: + case Type::ObjCInterface: + CanPrefixQualifiers = true; + break; + + case Type::ObjCObjectPointer: + CanPrefixQualifiers = T->isObjCIdType() || T->isObjCClassType() || + T->isObjCQualifiedIdType() || T->isObjCQualifiedClassType(); + break; + + case Type::Pointer: + case Type::BlockPointer: + case Type::LValueReference: + case Type::RValueReference: + case Type::MemberPointer: + case Type::ConstantArray: + case Type::IncompleteArray: + case Type::VariableArray: + case Type::DependentSizedArray: + case Type::DependentSizedExtVector: + case Type::Vector: + case Type::ExtVector: + case Type::FunctionProto: + case Type::FunctionNoProto: + case Type::Paren: + case Type::Attributed: + case Type::PackExpansion: + case Type::SubstTemplateTypeParm: + case Type::Auto: + CanPrefixQualifiers = false; + break; + } + + if (!CanPrefixQualifiers && !Quals.empty()) { + std::string qualsBuffer; + Quals.getAsStringInternal(qualsBuffer, Policy); - if (!S.empty()) { - TQS += ' '; - TQS += S; + if (!buffer.empty()) { + qualsBuffer += ' '; + qualsBuffer += buffer; } - std::swap(S, TQS); + std::swap(buffer, qualsBuffer); } switch (T->getTypeClass()) { #define ABSTRACT_TYPE(CLASS, PARENT) -#define TYPE(CLASS, PARENT) case Type::CLASS: \ - Print##CLASS(cast<CLASS##Type>(T.getTypePtr()), S); \ +#define TYPE(CLASS, PARENT) case Type::CLASS: \ + print##CLASS(cast<CLASS##Type>(T), buffer); \ break; #include "clang/AST/TypeNodes.def" } + + // If we're adding the qualifiers as a prefix, do it now. + if (CanPrefixQualifiers && !Quals.empty()) { + std::string qualsBuffer; + Quals.getAsStringInternal(qualsBuffer, Policy); + + if (!buffer.empty()) { + qualsBuffer += ' '; + qualsBuffer += buffer; + } + std::swap(buffer, qualsBuffer); + } } -void TypePrinter::PrintBuiltin(const BuiltinType *T, std::string &S) { +void TypePrinter::printBuiltin(const BuiltinType *T, std::string &S) { if (S.empty()) { S = T->getName(Policy.LangOpts); } else { @@ -96,12 +178,12 @@ void TypePrinter::PrintBuiltin(const BuiltinType *T, std::string &S) { } } -void TypePrinter::PrintComplex(const ComplexType *T, std::string &S) { - Print(T->getElementType(), S); +void TypePrinter::printComplex(const ComplexType *T, std::string &S) { + print(T->getElementType(), S); S = "_Complex " + S; } -void TypePrinter::PrintPointer(const PointerType *T, std::string &S) { +void TypePrinter::printPointer(const PointerType *T, std::string &S) { S = '*' + S; // Handle things like 'int (*A)[4];' correctly. @@ -109,15 +191,15 @@ void TypePrinter::PrintPointer(const PointerType *T, std::string &S) { if (isa<ArrayType>(T->getPointeeType())) S = '(' + S + ')'; - Print(T->getPointeeType(), S); + print(T->getPointeeType(), S); } -void TypePrinter::PrintBlockPointer(const BlockPointerType *T, std::string &S) { +void TypePrinter::printBlockPointer(const BlockPointerType *T, std::string &S) { S = '^' + S; - Print(T->getPointeeType(), S); + print(T->getPointeeType(), S); } -void TypePrinter::PrintLValueReference(const LValueReferenceType *T, +void TypePrinter::printLValueReference(const LValueReferenceType *T, std::string &S) { S = '&' + S; @@ -126,10 +208,10 @@ void TypePrinter::PrintLValueReference(const LValueReferenceType *T, if (isa<ArrayType>(T->getPointeeTypeAsWritten())) S = '(' + S + ')'; - Print(T->getPointeeTypeAsWritten(), S); + print(T->getPointeeTypeAsWritten(), S); } -void TypePrinter::PrintRValueReference(const RValueReferenceType *T, +void TypePrinter::printRValueReference(const RValueReferenceType *T, std::string &S) { S = "&&" + S; @@ -138,13 +220,13 @@ void TypePrinter::PrintRValueReference(const RValueReferenceType *T, if (isa<ArrayType>(T->getPointeeTypeAsWritten())) S = '(' + S + ')'; - Print(T->getPointeeTypeAsWritten(), S); + print(T->getPointeeTypeAsWritten(), S); } -void TypePrinter::PrintMemberPointer(const MemberPointerType *T, +void TypePrinter::printMemberPointer(const MemberPointerType *T, std::string &S) { std::string C; - Print(QualType(T->getClass(), 0), C); + print(QualType(T->getClass(), 0), C); C += "::*"; S = C + S; @@ -153,25 +235,25 @@ void TypePrinter::PrintMemberPointer(const MemberPointerType *T, if (isa<ArrayType>(T->getPointeeType())) S = '(' + S + ')'; - Print(T->getPointeeType(), S); + print(T->getPointeeType(), S); } -void TypePrinter::PrintConstantArray(const ConstantArrayType *T, +void TypePrinter::printConstantArray(const ConstantArrayType *T, std::string &S) { S += '['; S += llvm::utostr(T->getSize().getZExtValue()); S += ']'; - Print(T->getElementType(), S); + print(T->getElementType(), S); } -void TypePrinter::PrintIncompleteArray(const IncompleteArrayType *T, +void TypePrinter::printIncompleteArray(const IncompleteArrayType *T, std::string &S) { S += "[]"; - Print(T->getElementType(), S); + print(T->getElementType(), S); } -void TypePrinter::PrintVariableArray(const VariableArrayType *T, +void TypePrinter::printVariableArray(const VariableArrayType *T, std::string &S) { S += '['; @@ -193,10 +275,10 @@ void TypePrinter::PrintVariableArray(const VariableArrayType *T, } S += ']'; - Print(T->getElementType(), S); + print(T->getElementType(), S); } -void TypePrinter::PrintDependentSizedArray(const DependentSizedArrayType *T, +void TypePrinter::printDependentSizedArray(const DependentSizedArrayType *T, std::string &S) { S += '['; @@ -208,13 +290,13 @@ void TypePrinter::PrintDependentSizedArray(const DependentSizedArrayType *T, } S += ']'; - Print(T->getElementType(), S); + print(T->getElementType(), S); } -void TypePrinter::PrintDependentSizedExtVector( +void TypePrinter::printDependentSizedExtVector( const DependentSizedExtVectorType *T, std::string &S) { - Print(T->getElementType(), S); + print(T->getElementType(), S); S += " __attribute__((ext_vector_type("; if (T->getSizeExpr()) { @@ -226,36 +308,52 @@ void TypePrinter::PrintDependentSizedExtVector( S += ")))"; } -void TypePrinter::PrintVector(const VectorType *T, std::string &S) { - if (T->getAltiVecSpecific() != VectorType::NotAltiVec) { - if (T->getAltiVecSpecific() == VectorType::Pixel) - S = "__vector __pixel " + S; - else { - Print(T->getElementType(), S); - S = ((T->getAltiVecSpecific() == VectorType::Bool) - ? "__vector __bool " : "__vector ") + S; - } - } else { +void TypePrinter::printVector(const VectorType *T, std::string &S) { + switch (T->getVectorKind()) { + case VectorType::AltiVecPixel: + S = "__vector __pixel " + S; + break; + case VectorType::AltiVecBool: + print(T->getElementType(), S); + S = "__vector __bool " + S; + break; + case VectorType::AltiVecVector: + print(T->getElementType(), S); + S = "__vector " + S; + break; + case VectorType::NeonVector: + print(T->getElementType(), S); + S = ("__attribute__((neon_vector_type(" + + llvm::utostr_32(T->getNumElements()) + "))) " + S); + break; + case VectorType::NeonPolyVector: + print(T->getElementType(), S); + S = ("__attribute__((neon_polyvector_type(" + + llvm::utostr_32(T->getNumElements()) + "))) " + S); + break; + case VectorType::GenericVector: { // FIXME: We prefer to print the size directly here, but have no way // to get the size of the type. - Print(T->getElementType(), S); + 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); + print(T->getElementType(), ET); V += " * sizeof(" + ET + ")))) "; S = V + S; + break; + } } } -void TypePrinter::PrintExtVector(const ExtVectorType *T, std::string &S) { +void TypePrinter::printExtVector(const ExtVectorType *T, std::string &S) { S += " __attribute__((ext_vector_type("; S += llvm::utostr_32(T->getNumElements()); S += ")))"; - Print(T->getElementType(), S); + print(T->getElementType(), S); } -void TypePrinter::PrintFunctionProto(const FunctionProtoType *T, +void TypePrinter::printFunctionProto(const FunctionProtoType *T, std::string &S) { // If needed for precedence reasons, wrap the inner part in grouping parens. if (!S.empty()) @@ -267,7 +365,7 @@ void TypePrinter::PrintFunctionProto(const FunctionProtoType *T, ParamPolicy.SuppressSpecifiers = false; for (unsigned i = 0, e = T->getNumArgs(); i != e; ++i) { if (i) S += ", "; - Print(T->getArgType(i), Tmp); + print(T->getArgType(i), Tmp); S += Tmp; Tmp.clear(); } @@ -309,6 +407,21 @@ void TypePrinter::PrintFunctionProto(const FunctionProtoType *T, S += " __attribute__((regparm (" + llvm::utostr_32(Info.getRegParm()) + ")))"; + AppendTypeQualList(S, T->getTypeQuals()); + + switch (T->getRefQualifier()) { + case RQ_None: + break; + + case RQ_LValue: + S += " &"; + break; + + case RQ_RValue: + S += " &&"; + break; + } + if (T->hasExceptionSpec()) { S += " throw("; if (T->hasAnyExceptionSpec()) @@ -319,18 +432,16 @@ void TypePrinter::PrintFunctionProto(const FunctionProtoType *T, S += ", "; std::string ExceptionType; - Print(T->getExceptionType(I), ExceptionType); + print(T->getExceptionType(I), ExceptionType); S += ExceptionType; } S += ")"; } - AppendTypeQualList(S, T->getTypeQuals()); - - Print(T->getResultType(), S); + print(T->getResultType(), S); } -void TypePrinter::PrintFunctionNoProto(const FunctionNoProtoType *T, +void TypePrinter::printFunctionNoProto(const FunctionNoProtoType *T, std::string &S) { // If needed for precedence reasons, wrap the inner part in grouping parens. if (!S.empty()) @@ -339,10 +450,10 @@ void TypePrinter::PrintFunctionNoProto(const FunctionNoProtoType *T, S += "()"; if (T->getNoReturnAttr()) S += " __attribute__((noreturn))"; - Print(T->getResultType(), S); + print(T->getResultType(), S); } -static void PrintTypeSpec(const NamedDecl *D, std::string &S) { +static void printTypeSpec(const NamedDecl *D, std::string &S) { IdentifierInfo *II = D->getIdentifier(); if (S.empty()) S = II->getName().str(); @@ -350,16 +461,16 @@ static void PrintTypeSpec(const NamedDecl *D, std::string &S) { S = II->getName().str() + ' ' + S; } -void TypePrinter::PrintUnresolvedUsing(const UnresolvedUsingType *T, +void TypePrinter::printUnresolvedUsing(const UnresolvedUsingType *T, std::string &S) { - PrintTypeSpec(T->getDecl(), S); + printTypeSpec(T->getDecl(), S); } -void TypePrinter::PrintTypedef(const TypedefType *T, std::string &S) { - PrintTypeSpec(T->getDecl(), S); +void TypePrinter::printTypedef(const TypedefType *T, std::string &S) { + printTypeSpec(T->getDecl(), S); } -void TypePrinter::PrintTypeOfExpr(const TypeOfExprType *T, std::string &S) { +void TypePrinter::printTypeOfExpr(const TypeOfExprType *T, std::string &S) { if (!S.empty()) // Prefix the basic type, e.g. 'typeof(e) X'. S = ' ' + S; std::string Str; @@ -368,15 +479,15 @@ void TypePrinter::PrintTypeOfExpr(const TypeOfExprType *T, std::string &S) { S = "typeof " + s.str() + S; } -void TypePrinter::PrintTypeOf(const TypeOfType *T, std::string &S) { +void TypePrinter::printTypeOf(const TypeOfType *T, std::string &S) { if (!S.empty()) // Prefix the basic type, e.g. 'typeof(t) X'. S = ' ' + S; std::string Tmp; - Print(T->getUnderlyingType(), Tmp); + print(T->getUnderlyingType(), Tmp); S = "typeof(" + Tmp + ")" + S; } -void TypePrinter::PrintDecltype(const DecltypeType *T, std::string &S) { +void TypePrinter::printDecltype(const DecltypeType *T, std::string &S) { if (!S.empty()) // Prefix the basic type, e.g. 'decltype(t) X'. S = ' ' + S; std::string Str; @@ -385,6 +496,17 @@ void TypePrinter::PrintDecltype(const DecltypeType *T, std::string &S) { S = "decltype(" + s.str() + ")" + S; } +void TypePrinter::printAuto(const AutoType *T, std::string &S) { + // If the type has been deduced, do not print 'auto'. + if (T->isDeduced()) { + print(T->getDeducedType(), S); + } else { + if (!S.empty()) // Prefix the basic type, e.g. 'auto X'. + S = ' ' + S; + S = "auto" + S; + } +} + /// Appends the given scope to the end of a string. void TypePrinter::AppendScope(DeclContext *DC, std::string &Buffer) { if (DC->isTranslationUnit()) return; @@ -402,8 +524,8 @@ void TypePrinter::AppendScope(DeclContext *DC, std::string &Buffer) { const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); std::string TemplateArgsStr = TemplateSpecializationType::PrintTemplateArgumentList( - TemplateArgs.getFlatArgumentList(), - TemplateArgs.flat_size(), + TemplateArgs.data(), + TemplateArgs.size(), Policy); Buffer += Spec->getIdentifier()->getName(); Buffer += TemplateArgsStr; @@ -418,7 +540,7 @@ void TypePrinter::AppendScope(DeclContext *DC, std::string &Buffer) { Buffer += "::"; } -void TypePrinter::PrintTag(TagDecl *D, std::string &InnerString) { +void TypePrinter::printTag(TagDecl *D, std::string &InnerString) { if (Policy.SuppressTag) return; @@ -457,9 +579,9 @@ void TypePrinter::PrintTag(TagDecl *D, std::string &InnerString) { if (!HasKindDecoration) OS << " " << D->getKindName(); - if (D->getLocation().isValid()) { - PresumedLoc PLoc = D->getASTContext().getSourceManager().getPresumedLoc( + PresumedLoc PLoc = D->getASTContext().getSourceManager().getPresumedLoc( D->getLocation()); + if (PLoc.isValid()) { OS << " at " << PLoc.getFilename() << ':' << PLoc.getLine() << ':' << PLoc.getColumn(); @@ -482,8 +604,8 @@ void TypePrinter::PrintTag(TagDecl *D, std::string &InnerString) { NumArgs = TST->getNumArgs(); } else { const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); - Args = TemplateArgs.getFlatArgumentList(); - NumArgs = TemplateArgs.flat_size(); + Args = TemplateArgs.data(); + NumArgs = TemplateArgs.size(); } Buffer += TemplateSpecializationType::PrintTemplateArgumentList(Args, NumArgs, @@ -498,15 +620,15 @@ void TypePrinter::PrintTag(TagDecl *D, std::string &InnerString) { std::swap(Buffer, InnerString); } -void TypePrinter::PrintRecord(const RecordType *T, std::string &S) { - PrintTag(T->getDecl(), S); +void TypePrinter::printRecord(const RecordType *T, std::string &S) { + printTag(T->getDecl(), S); } -void TypePrinter::PrintEnum(const EnumType *T, std::string &S) { - PrintTag(T->getDecl(), S); +void TypePrinter::printEnum(const EnumType *T, std::string &S) { + printTag(T->getDecl(), S); } -void TypePrinter::PrintTemplateTypeParm(const TemplateTypeParmType *T, +void TypePrinter::printTemplateTypeParm(const TemplateTypeParmType *T, std::string &S) { if (!S.empty()) // Prefix the basic type, e.g. 'parmname X'. S = ' ' + S; @@ -518,12 +640,18 @@ void TypePrinter::PrintTemplateTypeParm(const TemplateTypeParmType *T, S = T->getName()->getName().str() + S; } -void TypePrinter::PrintSubstTemplateTypeParm(const SubstTemplateTypeParmType *T, +void TypePrinter::printSubstTemplateTypeParm(const SubstTemplateTypeParmType *T, std::string &S) { - Print(T->getReplacementType(), S); + print(T->getReplacementType(), S); } -void TypePrinter::PrintTemplateSpecialization( +void TypePrinter::printSubstTemplateTypeParmPack( + const SubstTemplateTypeParmPackType *T, + std::string &S) { + printTemplateTypeParm(T->getReplacedParameter(), S); +} + +void TypePrinter::printTemplateSpecialization( const TemplateSpecializationType *T, std::string &S) { std::string SpecString; @@ -543,12 +671,12 @@ void TypePrinter::PrintTemplateSpecialization( S = SpecString + ' ' + S; } -void TypePrinter::PrintInjectedClassName(const InjectedClassNameType *T, +void TypePrinter::printInjectedClassName(const InjectedClassNameType *T, std::string &S) { - PrintTemplateSpecialization(T->getInjectedTST(), S); + printTemplateSpecialization(T->getInjectedTST(), S); } -void TypePrinter::PrintElaborated(const ElaboratedType *T, std::string &S) { +void TypePrinter::printElaborated(const ElaboratedType *T, std::string &S) { std::string MyString; { @@ -564,7 +692,7 @@ void TypePrinter::PrintElaborated(const ElaboratedType *T, std::string &S) { std::string TypeStr; PrintingPolicy InnerPolicy(Policy); InnerPolicy.SuppressScope = true; - TypePrinter(InnerPolicy).Print(T->getNamedType(), TypeStr); + TypePrinter(InnerPolicy).print(T->getNamedType(), TypeStr); MyString += TypeStr; if (S.empty()) @@ -573,7 +701,13 @@ void TypePrinter::PrintElaborated(const ElaboratedType *T, std::string &S) { S = MyString + ' ' + S; } -void TypePrinter::PrintDependentName(const DependentNameType *T, std::string &S) { +void TypePrinter::printParen(const ParenType *T, std::string &S) { + if (!S.empty() && !isa<FunctionType>(T->getInnerType())) + S = '(' + S + ')'; + print(T->getInnerType(), S); +} + +void TypePrinter::printDependentName(const DependentNameType *T, std::string &S) { std::string MyString; { @@ -593,7 +727,7 @@ void TypePrinter::PrintDependentName(const DependentNameType *T, std::string &S) S = MyString + ' ' + S; } -void TypePrinter::PrintDependentTemplateSpecialization( +void TypePrinter::printDependentTemplateSpecialization( const DependentTemplateSpecializationType *T, std::string &S) { std::string MyString; { @@ -617,7 +751,91 @@ void TypePrinter::PrintDependentTemplateSpecialization( S = MyString + ' ' + S; } -void TypePrinter::PrintObjCInterface(const ObjCInterfaceType *T, +void TypePrinter::printPackExpansion(const PackExpansionType *T, + std::string &S) { + print(T->getPattern(), S); + S += "..."; +} + +void TypePrinter::printAttributed(const AttributedType *T, + std::string &S) { + print(T->getModifiedType(), S); + + // TODO: not all attributes are GCC-style attributes. + S += "__attribute__(("; + switch (T->getAttrKind()) { + case AttributedType::attr_address_space: + S += "address_space("; + S += T->getEquivalentType().getAddressSpace(); + S += ")"; + break; + + case AttributedType::attr_vector_size: { + S += "__vector_size__("; + if (const VectorType *vector =T->getEquivalentType()->getAs<VectorType>()) { + S += vector->getNumElements(); + S += " * sizeof("; + + std::string tmp; + print(vector->getElementType(), tmp); + S += tmp; + S += ")"; + } + S += ")"; + break; + } + + case AttributedType::attr_neon_vector_type: + case AttributedType::attr_neon_polyvector_type: { + if (T->getAttrKind() == AttributedType::attr_neon_vector_type) + S += "neon_vector_type("; + else + S += "neon_polyvector_type("; + const VectorType *vector = T->getEquivalentType()->getAs<VectorType>(); + S += llvm::utostr_32(vector->getNumElements()); + S += ")"; + break; + } + + case AttributedType::attr_regparm: { + S += "regparm("; + QualType t = T->getEquivalentType(); + while (!t->isFunctionType()) + t = t->getPointeeType(); + S += t->getAs<FunctionType>()->getRegParmType(); + S += ")"; + break; + } + + case AttributedType::attr_objc_gc: { + S += "objc_gc("; + + QualType tmp = T->getEquivalentType(); + while (tmp.getObjCGCAttr() == Qualifiers::GCNone) { + QualType next = tmp->getPointeeType(); + if (next == tmp) break; + tmp = next; + } + + if (tmp.isObjCGCWeak()) + S += "weak"; + else + S += "strong"; + S += ")"; + break; + } + + case AttributedType::attr_noreturn: S += "noreturn"; break; + case AttributedType::attr_cdecl: S += "cdecl"; break; + case AttributedType::attr_fastcall: S += "fastcall"; break; + case AttributedType::attr_stdcall: S += "stdcall"; break; + case AttributedType::attr_thiscall: S += "thiscall"; break; + case AttributedType::attr_pascal: S += "pascal"; break; + } + S += "))"; +} + +void TypePrinter::printObjCInterface(const ObjCInterfaceType *T, std::string &S) { if (!S.empty()) // Prefix the basic type, e.g. 'typedefname X'. S = ' ' + S; @@ -626,13 +844,13 @@ void TypePrinter::PrintObjCInterface(const ObjCInterfaceType *T, S = ObjCQIString + S; } -void TypePrinter::PrintObjCObject(const ObjCObjectType *T, +void TypePrinter::printObjCObject(const ObjCObjectType *T, std::string &S) { if (T->qual_empty()) - return Print(T->getBaseType(), S); + return print(T->getBaseType(), S); std::string tmp; - Print(T->getBaseType(), tmp); + print(T->getBaseType(), tmp); tmp += '<'; bool isFirst = true; for (ObjCObjectType::qual_iterator @@ -652,18 +870,23 @@ void TypePrinter::PrintObjCObject(const ObjCObjectType *T, std::swap(tmp, S); } -void TypePrinter::PrintObjCObjectPointer(const ObjCObjectPointerType *T, +void TypePrinter::printObjCObjectPointer(const ObjCObjectPointerType *T, std::string &S) { std::string ObjCQIString; + T->getPointeeType().getLocalQualifiers().getAsStringInternal(ObjCQIString, + Policy); + if (!ObjCQIString.empty()) + ObjCQIString += ' '; + if (T->isObjCIdType() || T->isObjCQualifiedIdType()) - ObjCQIString = "id"; + ObjCQIString += "id"; else if (T->isObjCClassType() || T->isObjCQualifiedClassType()) - ObjCQIString = "Class"; + ObjCQIString += "Class"; else if (T->isObjCSelType()) - ObjCQIString = "SEL"; + ObjCQIString += "SEL"; else - ObjCQIString = T->getInterfaceDecl()->getNameAsString(); + ObjCQIString += T->getInterfaceDecl()->getNameAsString(); if (!T->qual_empty()) { ObjCQIString += '<'; @@ -677,9 +900,6 @@ void TypePrinter::PrintObjCObjectPointer(const ObjCObjectPointerType *T, ObjCQIString += '>'; } - T->getPointeeType().getLocalQualifiers().getAsStringInternal(ObjCQIString, - Policy); - if (!T->isObjCIdType() && !T->isObjCQualifiedIdType()) ObjCQIString += " *"; // Don't forget the implicit pointer. else if (!S.empty()) // Prefix the basic type, e.g. 'typedefname X'. @@ -688,44 +908,6 @@ void TypePrinter::PrintObjCObjectPointer(const ObjCObjectPointerType *T, S = ObjCQIString + S; } -static void PrintTemplateArgument(std::string &Buffer, - const TemplateArgument &Arg, - const PrintingPolicy &Policy) { - switch (Arg.getKind()) { - case TemplateArgument::Null: - assert(false && "Null template argument"); - break; - - case TemplateArgument::Type: - Arg.getAsType().getAsStringInternal(Buffer, Policy); - break; - - case TemplateArgument::Declaration: - Buffer = cast<NamedDecl>(Arg.getAsDecl())->getNameAsString(); - break; - - case TemplateArgument::Template: { - llvm::raw_string_ostream s(Buffer); - Arg.getAsTemplate().print(s, Policy); - break; - } - - case TemplateArgument::Integral: - Buffer = Arg.getAsIntegral()->toString(10, true); - break; - - case TemplateArgument::Expression: { - llvm::raw_string_ostream s(Buffer); - Arg.getAsExpr()->printPretty(s, 0, Policy); - break; - } - - case TemplateArgument::Pack: - assert(0 && "FIXME: Implement!"); - break; - } -} - std::string TemplateSpecializationType:: PrintTemplateArgumentList(const TemplateArgumentListInfo &Args, const PrintingPolicy &Policy) { @@ -738,17 +920,27 @@ std::string TemplateSpecializationType::PrintTemplateArgumentList( const TemplateArgument *Args, unsigned NumArgs, - const PrintingPolicy &Policy) { + const PrintingPolicy &Policy, + bool SkipBrackets) { std::string SpecString; - SpecString += '<'; + if (!SkipBrackets) + SpecString += '<'; + for (unsigned Arg = 0; Arg < NumArgs; ++Arg) { - if (Arg) + if (SpecString.size() > !SkipBrackets) SpecString += ", "; // Print the argument into a string. std::string ArgString; - PrintTemplateArgument(ArgString, Args[Arg], Policy); - + if (Args[Arg].getKind() == TemplateArgument::Pack) { + ArgString = PrintTemplateArgumentList(Args[Arg].pack_begin(), + Args[Arg].pack_size(), + Policy, true); + } else { + llvm::raw_string_ostream ArgOut(ArgString); + Args[Arg].print(Policy, ArgOut); + } + // If this is the first argument and its string representation // begins with the global scope specifier ('::foo'), add a space // to avoid printing the diagraph '<:'. @@ -761,10 +953,11 @@ TemplateSpecializationType::PrintTemplateArgumentList( // If the last character of our string is '>', add another space to // keep the two '>''s separate tokens. We don't *have* to do this in // C++0x, but it's still good hygiene. - if (SpecString[SpecString.size() - 1] == '>') + if (!SpecString.empty() && SpecString[SpecString.size() - 1] == '>') SpecString += ' '; - SpecString += '>'; + if (!SkipBrackets) + SpecString += '>'; return SpecString; } @@ -776,12 +969,20 @@ PrintTemplateArgumentList(const TemplateArgumentLoc *Args, unsigned NumArgs, std::string SpecString; SpecString += '<'; for (unsigned Arg = 0; Arg < NumArgs; ++Arg) { - if (Arg) + if (SpecString.size() > 1) SpecString += ", "; // Print the argument into a string. std::string ArgString; - PrintTemplateArgument(ArgString, Args[Arg].getArgument(), Policy); + if (Args[Arg].getArgument().getKind() == TemplateArgument::Pack) { + ArgString = PrintTemplateArgumentList( + Args[Arg].getArgument().pack_begin(), + Args[Arg].getArgument().pack_size(), + Policy, true); + } else { + llvm::raw_string_ostream ArgOut(ArgString); + Args[Arg].getArgument().print(Policy, ArgOut); + } // If this is the first argument and its string representation // begins with the global scope specifier ('::foo'), add a space @@ -847,15 +1048,15 @@ void Qualifiers::getAsStringInternal(std::string &S, } } -std::string QualType::getAsString() const { - std::string S; - LangOptions LO; - getAsStringInternal(S, PrintingPolicy(LO)); - return S; +std::string QualType::getAsString(const Type *ty, Qualifiers qs) { + std::string buffer; + LangOptions options; + getAsStringInternal(ty, qs, buffer, PrintingPolicy(options)); + return buffer; } -void QualType::getAsStringInternal(std::string &S, - const PrintingPolicy &Policy) const { - TypePrinter Printer(Policy); - Printer.Print(*this, S); +void QualType::getAsStringInternal(const Type *ty, Qualifiers qs, + std::string &buffer, + const PrintingPolicy &policy) { + TypePrinter(policy).print(ty, qs, buffer); } |