diff options
Diffstat (limited to 'lib/AST')
50 files changed, 8689 insertions, 4760 deletions
diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp index 98e825b..541836b21b 100644 --- a/lib/AST/APValue.cpp +++ b/lib/AST/APValue.cpp @@ -212,6 +212,40 @@ void APValue::DestroyDataAndMakeUninit() { Kind = Uninitialized; } +bool APValue::needsCleanup() const { + switch (getKind()) { + case Uninitialized: + case AddrLabelDiff: + return false; + case Struct: + case Union: + case Array: + case Vector: + return true; + case Int: + return getInt().needsCleanup(); + case Float: + return getFloat().needsCleanup(); + case ComplexFloat: + assert(getComplexFloatImag().needsCleanup() == + getComplexFloatReal().needsCleanup() && + "In _Complex float types, real and imaginary values always have the " + "same size."); + return getComplexFloatReal().needsCleanup(); + case ComplexInt: + assert(getComplexIntImag().needsCleanup() == + getComplexIntReal().needsCleanup() && + "In _Complex int types, real and imaginary values must have the " + "same size."); + return getComplexIntReal().needsCleanup(); + case LValue: + return reinterpret_cast<const LV *>(Data)->hasPathPtr(); + case MemberPointer: + return reinterpret_cast<const MemberPointerData *>(Data)->hasPathPtr(); + } + llvm_unreachable("Unknown APValue kind!"); +} + void APValue::swap(APValue &RHS) { std::swap(Kind, RHS.Kind); char TmpData[MaxSize]; diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 176aec5..a03cf9e7 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -25,13 +25,16 @@ #include "clang/AST/ExprCXX.h" #include "clang/AST/ExternalASTSource.h" #include "clang/AST/Mangle.h" +#include "clang/AST/MangleNumberingContext.h" #include "clang/AST/RecordLayout.h" +#include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/Triple.h" #include "llvm/Support/Capacity.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" @@ -132,8 +135,14 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const { isa<RedeclarableTemplateDecl>(D) || isa<ClassTemplateSpecializationDecl>(D)) DeclLoc = D->getLocStart(); - else + else { DeclLoc = D->getLocation(); + // If location of the typedef name is in a macro, it is because being + // declared via a macro. Try using declaration's starting location + // as the "declaration location". + if (DeclLoc.isMacroID() && isa<TypedefDecl>(D)) + DeclLoc = D->getLocStart(); + } // If the declaration doesn't map directly to a location in a file, we // can't find the comment. @@ -175,7 +184,8 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const { // First check whether we have a trailing comment. if (Comment != RawComments.end() && (*Comment)->isDocumentation() && (*Comment)->isTrailingComment() && - (isa<FieldDecl>(D) || isa<EnumConstantDecl>(D) || isa<VarDecl>(D))) { + (isa<FieldDecl>(D) || isa<EnumConstantDecl>(D) || isa<VarDecl>(D) || + isa<ObjCMethodDecl>(D) || isa<ObjCPropertyDecl>(D))) { std::pair<FileID, unsigned> CommentBeginDecomp = SourceMgr.getDecomposedLoc((*Comment)->getSourceRange().getBegin()); // Check that Doxygen trailing comment comes after the declaration, starts @@ -220,7 +230,7 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const { // There should be no other declarations or preprocessor directives between // comment and declaration. - if (Text.find_first_of(",;{}#@") != StringRef::npos) + if (Text.find_first_of(";{}#@") != StringRef::npos) return NULL; return *Comment; @@ -406,9 +416,16 @@ comments::FullComment *ASTContext::cloneFullComment(comments::FullComment *FC, } +comments::FullComment *ASTContext::getLocalCommentForDeclUncached(const Decl *D) const { + const RawComment *RC = getRawCommentForDeclNoCache(D); + return RC ? RC->parse(*this, 0, D) : 0; +} + comments::FullComment *ASTContext::getCommentForDecl( const Decl *D, const Preprocessor *PP) const { + if (D->isInvalidDecl()) + return NULL; D = adjustDeclToTemplate(D); const Decl *Canonical = D->getCanonicalDecl(); @@ -679,6 +696,19 @@ static const LangAS::Map *getAddressSpaceMap(const TargetInfo &T, } } +static bool isAddrSpaceMapManglingEnabled(const TargetInfo &TI, + const LangOptions &LangOpts) { + switch (LangOpts.getAddressSpaceMapMangling()) { + case LangOptions::ASMM_Target: + return TI.useAddressSpaceMapMangling(); + case LangOptions::ASMM_On: + return true; + case LangOptions::ASMM_Off: + return false; + } + llvm_unreachable("getAddressSpaceMapMangling() doesn't cover anything."); +} + ASTContext::ASTContext(LangOptions& LOpts, SourceManager &SM, const TargetInfo *t, IdentifierTable &idents, SelectorTable &sels, @@ -690,7 +720,7 @@ ASTContext::ASTContext(LangOptions& LOpts, SourceManager &SM, DependentTemplateSpecializationTypes(this_()), SubstTemplateTemplateParmPacks(this_()), GlobalNestedNameSpecifier(0), - Int128Decl(0), UInt128Decl(0), + Int128Decl(0), UInt128Decl(0), Float128StubDecl(0), BuiltinVaListDecl(0), ObjCIdDecl(0), ObjCSelDecl(0), ObjCClassDecl(0), ObjCProtocolClassDecl(0), BOOLDecl(0), @@ -709,8 +739,7 @@ ASTContext::ASTContext(LangOptions& LOpts, SourceManager &SM, ExternalSource(0), Listener(0), Comments(SM), CommentsLoaded(false), CommentCommandTraits(BumpAlloc, LOpts.CommentOpts), - LastSDM(0, 0), - UniqueBlockByRefTypeID(0) + LastSDM(0, 0) { if (size_reserve > 0) Types.reserve(size_reserve); TUDecl = TranslationUnitDecl::Create(*this); @@ -726,10 +755,12 @@ ASTContext::~ASTContext() { // FIXME: Is this the ideal solution? ReleaseDeclContextMaps(); - // Call all of the deallocation functions. - for (unsigned I = 0, N = Deallocations.size(); I != N; ++I) - Deallocations[I].first(Deallocations[I].second); - + // Call all of the deallocation functions on all of their targets. + for (DeallocationMap::const_iterator I = Deallocations.begin(), + E = Deallocations.end(); I != E; ++I) + for (unsigned J = 0, N = I->second.size(); J != N; ++J) + (I->first)((I->second)[J]); + // ASTRecordLayout objects in ASTRecordLayouts must always be destroyed // because they can contain DenseMaps. for (llvm::DenseMap<const ObjCContainerDecl*, @@ -750,10 +781,16 @@ ASTContext::~ASTContext() { AEnd = DeclAttrs.end(); A != AEnd; ++A) A->second->~AttrVec(); + + for (llvm::DenseMap<const DeclContext *, MangleNumberingContext *>::iterator + I = MangleNumberingContexts.begin(), + E = MangleNumberingContexts.end(); + I != E; ++I) + delete I->second; } void ASTContext::AddDeallocation(void (*Callback)(void*), void *Data) { - Deallocations.push_back(std::make_pair(Callback, Data)); + Deallocations[Callback].push_back(Data); } void @@ -848,6 +885,20 @@ TypedefDecl *ASTContext::getUInt128Decl() const { return UInt128Decl; } +TypeDecl *ASTContext::getFloat128StubType() const { + assert(LangOpts.CPlusPlus && "should only be called for c++"); + if (!Float128StubDecl) { + Float128StubDecl = CXXRecordDecl::Create(const_cast<ASTContext &>(*this), + TTK_Struct, + getTranslationUnitDecl(), + SourceLocation(), + SourceLocation(), + &Idents.get("__float128")); + } + + return Float128StubDecl; +} + void ASTContext::InitBuiltinType(CanQualType &R, BuiltinType::Kind K) { BuiltinType *Ty = new (*this, TypeAlignment) BuiltinType(K); R = CanQualType::CreateUnsafe(QualType(Ty, 0)); @@ -863,6 +914,7 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target) { ABI.reset(createCXXABI(Target)); AddrSpaceMap = getAddressSpaceMap(Target, LangOpts); + AddrSpaceMapMangling = isAddrSpaceMapManglingEnabled(Target, LangOpts); // C99 6.2.5p19. InitBuiltinType(VoidTy, BuiltinType::Void); @@ -897,13 +949,17 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target) { InitBuiltinType(Int128Ty, BuiltinType::Int128); InitBuiltinType(UnsignedInt128Ty, BuiltinType::UInt128); - if (LangOpts.CPlusPlus && LangOpts.WChar) { // C++ 3.9.1p5 - if (TargetInfo::isTypeSigned(Target.getWCharType())) - InitBuiltinType(WCharTy, BuiltinType::WChar_S); - else // -fshort-wchar makes wchar_t be unsigned. - InitBuiltinType(WCharTy, BuiltinType::WChar_U); - } else // C99 (or C++ using -fno-wchar) - WCharTy = getFromTargetType(Target.getWCharType()); + // C++ 3.9.1p5 + if (TargetInfo::isTypeSigned(Target.getWCharType())) + InitBuiltinType(WCharTy, BuiltinType::WChar_S); + else // -fshort-wchar makes wchar_t be unsigned. + InitBuiltinType(WCharTy, BuiltinType::WChar_U); + if (LangOpts.CPlusPlus && LangOpts.WChar) + WideCharTy = WCharTy; + else { + // C99 (or C++ using -fno-wchar). + WideCharTy = getFromTargetType(Target.getWCharType()); + } WIntTy = getFromTargetType(Target.getWIntType()); @@ -1008,13 +1064,20 @@ void ASTContext::eraseDeclAttrs(const Decl *D) { } } +// FIXME: Remove ? MemberSpecializationInfo * ASTContext::getInstantiatedFromStaticDataMember(const VarDecl *Var) { assert(Var->isStaticDataMember() && "Not a static data member"); - llvm::DenseMap<const VarDecl *, MemberSpecializationInfo *>::iterator Pos - = InstantiatedFromStaticDataMember.find(Var); - if (Pos == InstantiatedFromStaticDataMember.end()) - return 0; + return getTemplateOrSpecializationInfo(Var) + .dyn_cast<MemberSpecializationInfo *>(); +} + +ASTContext::TemplateOrSpecializationInfo +ASTContext::getTemplateOrSpecializationInfo(const VarDecl *Var) { + llvm::DenseMap<const VarDecl *, TemplateOrSpecializationInfo>::iterator Pos = + TemplateOrInstantiation.find(Var); + if (Pos == TemplateOrInstantiation.end()) + return TemplateOrSpecializationInfo(); return Pos->second; } @@ -1025,10 +1088,16 @@ ASTContext::setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl, SourceLocation PointOfInstantiation) { assert(Inst->isStaticDataMember() && "Not a static data member"); assert(Tmpl->isStaticDataMember() && "Not a static data member"); - assert(!InstantiatedFromStaticDataMember[Inst] && - "Already noted what static data member was instantiated from"); - InstantiatedFromStaticDataMember[Inst] - = new (*this) MemberSpecializationInfo(Tmpl, TSK, PointOfInstantiation); + setTemplateOrSpecializationInfo(Inst, new (*this) MemberSpecializationInfo( + Tmpl, TSK, PointOfInstantiation)); +} + +void +ASTContext::setTemplateOrSpecializationInfo(VarDecl *Inst, + TemplateOrSpecializationInfo TSI) { + assert(!TemplateOrInstantiation[Inst] && + "Already noted what the variable was instantiated from"); + TemplateOrInstantiation[Inst] = TSI; } FunctionDecl *ASTContext::getClassScopeSpecializationPattern( @@ -1105,38 +1174,6 @@ void ASTContext::setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst, InstantiatedFromUnnamedFieldDecl[Inst] = Tmpl; } -bool ASTContext::ZeroBitfieldFollowsNonBitfield(const FieldDecl *FD, - const FieldDecl *LastFD) const { - return (FD->isBitField() && LastFD && !LastFD->isBitField() && - FD->getBitWidthValue(*this) == 0); -} - -bool ASTContext::ZeroBitfieldFollowsBitfield(const FieldDecl *FD, - const FieldDecl *LastFD) const { - return (FD->isBitField() && LastFD && LastFD->isBitField() && - FD->getBitWidthValue(*this) == 0 && - LastFD->getBitWidthValue(*this) != 0); -} - -bool ASTContext::BitfieldFollowsBitfield(const FieldDecl *FD, - const FieldDecl *LastFD) const { - return (FD->isBitField() && LastFD && LastFD->isBitField() && - FD->getBitWidthValue(*this) && - LastFD->getBitWidthValue(*this)); -} - -bool ASTContext::NonBitfieldFollowsBitfield(const FieldDecl *FD, - const FieldDecl *LastFD) const { - return (!FD->isBitField() && LastFD && LastFD->isBitField() && - LastFD->getBitWidthValue(*this)); -} - -bool ASTContext::BitfieldFollowsNonBitfield(const FieldDecl *FD, - const FieldDecl *LastFD) const { - return (FD->isBitField() && LastFD && !LastFD->isBitField() && - FD->getBitWidthValue(*this)); -} - ASTContext::overridden_cxx_method_iterator ASTContext::overridden_methods_begin(const CXXMethodDecl *Method) const { llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector>::const_iterator Pos @@ -1224,12 +1261,7 @@ const llvm::fltSemantics &ASTContext::getFloatTypeSemantics(QualType T) const { } } -/// getDeclAlign - Return a conservative estimate of the alignment of the -/// specified decl. Note that bitfields do not have a valid alignment, so -/// this method will assert on them. -/// If @p RefAsPointee, references are treated like their underlying type -/// (for alignof), else they're treated like pointers (for CodeGen). -CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) const { +CharUnits ASTContext::getDeclAlign(const Decl *D, bool ForAlignof) const { unsigned Align = Target->getCharWidth(); bool UseAlignAttrOnly = false; @@ -1262,7 +1294,7 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) const { } else if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) { QualType T = VD->getType(); if (const ReferenceType* RT = T->getAs<ReferenceType>()) { - if (RefAsPointee) + if (ForAlignof) T = RT->getPointeeType(); else T = getPointerType(RT->getPointeeType()); @@ -1270,14 +1302,15 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) const { if (!T->isIncompleteType() && !T->isFunctionType()) { // Adjust alignments of declarations with array type by the // large-array alignment on the target. - unsigned MinWidth = Target->getLargeArrayMinWidth(); - 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()); + if (const ArrayType *arrayType = getAsArrayType(T)) { + unsigned MinWidth = Target->getLargeArrayMinWidth(); + if (!ForAlignof && MinWidth) { + 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); @@ -1294,24 +1327,27 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) const { // 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); - } + if (const FieldDecl *Field = dyn_cast<FieldDecl>(VD)) { + const RecordDecl *Parent = Field->getParent(); + // We can only produce a sensible answer if the record is valid. + if (!Parent->isInvalidDecl()) { + const ASTRecordLayout &Layout = getASTRecordLayout(Parent); + + // 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); + Align = std::min(Align, FieldAlign); + } } } @@ -1339,8 +1375,30 @@ ASTContext::getTypeInfoDataSizeInChars(QualType T) const { return sizeAndAlign; } +/// getConstantArrayInfoInChars - Performing the computation in CharUnits +/// instead of in bits prevents overflowing the uint64_t for some large arrays. +std::pair<CharUnits, CharUnits> +static getConstantArrayInfoInChars(const ASTContext &Context, + const ConstantArrayType *CAT) { + std::pair<CharUnits, CharUnits> EltInfo = + Context.getTypeInfoInChars(CAT->getElementType()); + uint64_t Size = CAT->getSize().getZExtValue(); + assert((Size == 0 || static_cast<uint64_t>(EltInfo.first.getQuantity()) <= + (uint64_t)(-1)/Size) && + "Overflow in array type char size evaluation"); + uint64_t Width = EltInfo.first.getQuantity() * Size; + unsigned Align = EltInfo.second.getQuantity(); + if (!Context.getTargetInfo().getCXXABI().isMicrosoft() || + Context.getTargetInfo().getPointerWidth(0) == 64) + Width = llvm::RoundUpToAlignment(Width, Align); + return std::make_pair(CharUnits::fromQuantity(Width), + CharUnits::fromQuantity(Align)); +} + std::pair<CharUnits, CharUnits> ASTContext::getTypeInfoInChars(const Type *T) const { + if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(T)) + return getConstantArrayInfoInChars(*this, CAT); std::pair<uint64_t, unsigned> Info = getTypeInfo(T); return std::make_pair(toCharUnitsFromBits(Info.first), toCharUnitsFromBits(Info.second)); @@ -1376,6 +1434,10 @@ ASTContext::getTypeInfoImpl(const Type *T) const { #define ABSTRACT_TYPE(Class, Base) #define NON_CANONICAL_TYPE(Class, Base) #define DEPENDENT_TYPE(Class, Base) case Type::Class: +#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) \ + case Type::Class: \ + assert(!T->isDependentType() && "should not see dependent types here"); \ + return getTypeInfo(cast<Class##Type>(T)->desugar().getTypePtr()); #include "clang/AST/TypeNodes.def" llvm_unreachable("Should not see dependent types"); @@ -1401,7 +1463,9 @@ ASTContext::getTypeInfoImpl(const Type *T) const { "Overflow in array type bit size evaluation"); Width = EltInfo.first*Size; Align = EltInfo.second; - Width = llvm::RoundUpToAlignment(Width, Align); + if (!getTargetInfo().getCXXABI().isMicrosoft() || + getTargetInfo().getPointerWidth(0) == 64) + Width = llvm::RoundUpToAlignment(Width, Align); break; } case Type::ExtVector: @@ -1568,6 +1632,8 @@ ASTContext::getTypeInfoImpl(const Type *T) const { } case Type::ObjCObject: return getTypeInfo(cast<ObjCObjectType>(T)->getBaseType().getTypePtr()); + case Type::Decayed: + return getTypeInfo(cast<DecayedType>(T)->getDecayedType().getTypePtr()); case Type::ObjCInterface: { const ObjCInterfaceType *ObjCI = cast<ObjCInterfaceType>(T); const ASTRecordLayout &Layout = getASTObjCInterfaceLayout(ObjCI->getDecl()); @@ -1624,20 +1690,6 @@ ASTContext::getTypeInfoImpl(const Type *T) const { break; } - case Type::TypeOfExpr: - return getTypeInfo(cast<TypeOfExprType>(T)->getUnderlyingExpr()->getType() - .getTypePtr()); - - case Type::TypeOf: - return getTypeInfo(cast<TypeOfType>(T)->getUnderlyingType().getTypePtr()); - - case Type::Decltype: - return getTypeInfo(cast<DecltypeType>(T)->getUnderlyingExpr()->getType() - .getTypePtr()); - - case Type::UnaryTransform: - return getTypeInfo(cast<UnaryTransformType>(T)->getUnderlyingType()); - case Type::Elaborated: return getTypeInfo(cast<ElaboratedType>(T)->getNamedType().getTypePtr()); @@ -1645,18 +1697,6 @@ ASTContext::getTypeInfoImpl(const Type *T) const { return getTypeInfo( cast<AttributedType>(T)->getEquivalentType().getTypePtr()); - case Type::TemplateSpecialization: { - assert(getCanonicalType(T) != T && - "Cannot request the size of a dependent type"); - const TemplateSpecializationType *TST = cast<TemplateSpecializationType>(T); - // A type alias template specialization may refer to a typedef with the - // aligned attribute on it. - if (TST->isTypeAlias()) - return getTypeInfo(TST->getAliasedType().getTypePtr()); - else - return getTypeInfo(getCanonicalType(T)); - } - case Type::Atomic: { // Start with the base type information. std::pair<uint64_t, unsigned> Info @@ -1696,10 +1736,10 @@ int64_t ASTContext::toBits(CharUnits CharSize) const { /// getTypeSizeInChars - Return the size of the specified type, in characters. /// This method does not work on incomplete types. CharUnits ASTContext::getTypeSizeInChars(QualType T) const { - return toCharUnitsFromBits(getTypeSize(T)); + return getTypeInfoInChars(T).first; } CharUnits ASTContext::getTypeSizeInChars(const Type *T) const { - return toCharUnitsFromBits(getTypeSize(T)); + return getTypeInfoInChars(T).first; } /// getTypeAlignInChars - Return the ABI-specified alignment of a type, in @@ -1718,6 +1758,9 @@ CharUnits ASTContext::getTypeAlignInChars(const Type *T) const { unsigned ASTContext::getPreferredTypeAlign(const Type *T) const { unsigned ABIAlign = getTypeAlign(T); + if (Target->getTriple().getArch() == llvm::Triple::xcore) + return ABIAlign; // Never overalign on XCore. + // Double and long long should be naturally aligned if possible. if (const ComplexType* CT = T->getAs<ComplexType>()) T = CT->getElementType().getTypePtr(); @@ -2042,10 +2085,7 @@ const FunctionType *ASTContext::adjustFunctionType(const FunctionType *T, const FunctionProtoType *FPT = cast<FunctionProtoType>(T); FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); EPI.ExtInfo = Info; - Result = getFunctionType(FPT->getResultType(), - ArrayRef<QualType>(FPT->arg_type_begin(), - FPT->getNumArgs()), - EPI); + Result = getFunctionType(FPT->getResultType(), FPT->getArgTypes(), EPI); } return cast<FunctionType>(Result.getTypePtr()); @@ -2053,12 +2093,18 @@ const FunctionType *ASTContext::adjustFunctionType(const FunctionType *T, void ASTContext::adjustDeducedFunctionResultType(FunctionDecl *FD, QualType ResultType) { - // FIXME: Need to inform serialization code about this! - for (FD = FD->getMostRecentDecl(); FD; FD = FD->getPreviousDecl()) { + FD = FD->getMostRecentDecl(); + while (true) { const FunctionProtoType *FPT = FD->getType()->castAs<FunctionProtoType>(); FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); FD->setType(getFunctionType(ResultType, FPT->getArgTypes(), EPI)); + if (FunctionDecl *Next = FD->getPreviousDecl()) + FD = Next; + else + break; } + if (ASTMutationListener *L = getASTMutationListener()) + L->DeducedReturnType(FD, ResultType); } /// getComplexType - Return the uniqued reference to the type for a complex @@ -2117,6 +2163,45 @@ QualType ASTContext::getPointerType(QualType T) const { return QualType(New, 0); } +QualType ASTContext::getDecayedType(QualType T) const { + assert((T->isArrayType() || T->isFunctionType()) && "T does not decay"); + + llvm::FoldingSetNodeID ID; + DecayedType::Profile(ID, T); + void *InsertPos = 0; + if (DecayedType *DT = DecayedTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(DT, 0); + + QualType Decayed; + + // C99 6.7.5.3p7: + // A declaration of a parameter as "array of type" shall be + // adjusted to "qualified pointer to type", where the type + // qualifiers (if any) are those specified within the [ and ] of + // the array type derivation. + if (T->isArrayType()) + Decayed = getArrayDecayedType(T); + + // C99 6.7.5.3p8: + // A declaration of a parameter as "function returning type" + // shall be adjusted to "pointer to function returning type", as + // in 6.3.2.1. + if (T->isFunctionType()) + Decayed = getPointerType(T); + + QualType Canonical = getCanonicalType(Decayed); + + // Get the new insert position for the node we care about. + DecayedType *NewIP = DecayedTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP; + + DecayedType *New = + new (*this, TypeAlignment) DecayedType(T, Decayed, Canonical); + Types.push_back(New); + DecayedTypes.InsertNode(New, InsertPos); + return QualType(New, 0); +} + /// getBlockPointerType - Return the uniqued reference to the type for /// a pointer to the specified block. QualType ASTContext::getBlockPointerType(QualType T) const { @@ -2676,9 +2761,8 @@ ASTContext::getDependentSizedExtVectorType(QualType vecType, QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, const FunctionType::ExtInfo &Info) const { - const CallingConv DefaultCC = Info.getCC(); - const CallingConv CallConv = (LangOpts.MRTD && DefaultCC == CC_Default) ? - CC_X86StdCall : DefaultCC; + const CallingConv CallConv = Info.getCC(); + // Unique functions, to guarantee there is only one function of a particular // structure. llvm::FoldingSetNodeID ID; @@ -2690,11 +2774,8 @@ ASTContext::getFunctionNoProtoType(QualType ResultTy, return QualType(FT, 0); QualType Canonical; - if (!ResultTy.isCanonical() || - getCanonicalCallConv(CallConv) != CallConv) { - Canonical = - getFunctionNoProtoType(getCanonicalType(ResultTy), - Info.withCallingConv(getCanonicalCallConv(CallConv))); + if (!ResultTy.isCanonical()) { + Canonical = getFunctionNoProtoType(getCanonicalType(ResultTy), Info); // Get the new insert position for the node we care about. FunctionNoProtoType *NewIP = @@ -2743,14 +2824,10 @@ ASTContext::getFunctionType(QualType ResultTy, ArrayRef<QualType> ArgArray, if (!ArgArray[i].isCanonicalAsParam()) isCanonical = false; - const CallingConv DefaultCC = EPI.ExtInfo.getCC(); - const CallingConv CallConv = (LangOpts.MRTD && DefaultCC == CC_Default) ? - CC_X86StdCall : DefaultCC; - // If this type isn't canonical, get the canonical version of it. // The exception spec is not part of the canonical type. QualType Canonical; - if (!isCanonical || getCanonicalCallConv(CallConv) != CallConv) { + if (!isCanonical) { SmallVector<QualType, 16> CanonicalArgs; CanonicalArgs.reserve(NumArgs); for (unsigned i = 0; i != NumArgs; ++i) @@ -2760,8 +2837,6 @@ ASTContext::getFunctionType(QualType ResultTy, ArrayRef<QualType> ArgArray, CanonicalEPI.HasTrailingReturn = false; CanonicalEPI.ExceptionSpecType = EST_None; CanonicalEPI.NumExceptions = 0; - CanonicalEPI.ExtInfo - = CanonicalEPI.ExtInfo.withCallingConv(getCanonicalCallConv(CallConv)); // Result types do not have ARC lifetime qualifiers. QualType CanResultTy = getCanonicalType(ResultTy); @@ -2803,7 +2878,6 @@ ASTContext::getFunctionType(QualType ResultTy, ArrayRef<QualType> ArgArray, FunctionProtoType *FTP = (FunctionProtoType*) Allocate(Size, TypeAlignment); FunctionProtoType::ExtProtoInfo newEPI = EPI; - newEPI.ExtInfo = EPI.ExtInfo.withCallingConv(CallConv); new (FTP) FunctionProtoType(ResultTy, ArgArray, Canonical, newEPI); Types.push_back(FTP); FunctionProtoTypes.InsertNode(FTP, InsertPos); @@ -2856,13 +2930,11 @@ QualType ASTContext::getTypeDeclTypeSlow(const TypeDecl *Decl) const { "Template type parameter types are always available."); if (const RecordDecl *Record = dyn_cast<RecordDecl>(Decl)) { - assert(!Record->getPreviousDecl() && - "struct/union has previous declaration"); + assert(Record->isFirstDecl() && "struct/union has previous declaration"); assert(!NeedsInjectedClassNameType(Record)); return getRecordType(Record); } else if (const EnumDecl *Enum = dyn_cast<EnumDecl>(Decl)) { - assert(!Enum->getPreviousDecl() && - "enum has previous declaration"); + assert(Enum->isFirstDecl() && "enum has previous declaration"); return getEnumType(Enum); } else if (const UnresolvedUsingTypenameDecl *Using = dyn_cast<UnresolvedUsingTypenameDecl>(Decl)) { @@ -4104,22 +4176,9 @@ const ArrayType *ASTContext::getAsArrayType(QualType T) const { } QualType ASTContext::getAdjustedParameterType(QualType T) const { - // C99 6.7.5.3p7: - // A declaration of a parameter as "array of type" shall be - // adjusted to "qualified pointer to type", where the type - // qualifiers (if any) are those specified within the [ and ] of - // the array type derivation. - if (T->isArrayType()) - return getArrayDecayedType(T); - - // C99 6.7.5.3p8: - // A declaration of a parameter as "function returning type" - // shall be adjusted to "pointer to function returning type", as - // in 6.3.2.1. - if (T->isFunctionType()) - return getPointerType(T); - - return T; + if (T->isArrayType() || T->isFunctionType()) + return getDecayedType(T); + return T; } QualType ASTContext::getSignatureParameterType(QualType T) const { @@ -4364,12 +4423,27 @@ Qualifiers::ObjCLifetime ASTContext::getInnerObjCOwnership(QualType T) const { return Qualifiers::OCL_None; } +static const Type *getIntegerTypeForEnum(const EnumType *ET) { + // Incomplete enum types are not treated as integer types. + // FIXME: In C++, enum types are never integer types. + if (ET->getDecl()->isComplete() && !ET->getDecl()->isScoped()) + return ET->getDecl()->getIntegerType().getTypePtr(); + return NULL; +} + /// 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) const { const Type *LHSC = getCanonicalType(LHS).getTypePtr(); const Type *RHSC = getCanonicalType(RHS).getTypePtr(); + + // Unwrap enums to their underlying type. + if (const EnumType *ET = dyn_cast<EnumType>(LHSC)) + LHSC = getIntegerTypeForEnum(ET); + if (const EnumType *ET = dyn_cast<EnumType>(RHSC)) + RHSC = getIntegerTypeForEnum(ET); + if (LHSC == RHSC) return 0; bool LHSUnsigned = LHSC->isUnsignedIntegerType(); @@ -4484,7 +4558,7 @@ QualType ASTContext::getBlockDescriptorType() const { UnsignedLongTy, }; - const char *FieldNames[] = { + static const char *const FieldNames[] = { "reserved", "Size" }; @@ -4525,7 +4599,7 @@ QualType ASTContext::getBlockDescriptorExtendedType() const { getPointerType(VoidPtrTy) }; - const char *FieldNames[] = { + static const char *const FieldNames[] = { "reserved", "Size", "CopyFuncPtr", @@ -4910,6 +4984,10 @@ void ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD, if (PD->isReadOnly()) { S += ",R"; + if (PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_copy) + S += ",C"; + if (PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_retain) + S += ",&"; } else { switch (PD->getSetterKind()) { case ObjCPropertyDecl::Assign: break; @@ -5200,12 +5278,9 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, } else { S += '['; - if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT)) { - if (getTypeSize(CAT->getElementType()) == 0) - S += '0'; - else - S += llvm::utostr(CAT->getSize().getZExtValue()); - } else { + if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT)) + S += llvm::utostr(CAT->getSize().getZExtValue()); + else { //Variable length arrays are encoded as a regular array with 0 elements. assert((isa<VariableArrayType>(AT) || isa<IncompleteArrayType>(AT)) && "Unknown array type!"); @@ -5384,6 +5459,20 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, // We encode the underlying type which comes out as // {...}; S += '^'; + if (FD && OPT->getInterfaceDecl()) { + // Prevent recursive encoding of fields in some rare cases. + ObjCInterfaceDecl *OI = OPT->getInterfaceDecl(); + SmallVector<const ObjCIvarDecl*, 32> Ivars; + DeepCollectObjCIvars(OI, true, Ivars); + for (unsigned i = 0, e = Ivars.size(); i != e; ++i) { + if (cast<FieldDecl>(Ivars[i]) == FD) { + S += '{'; + S += OI->getIdentifier()->getName(); + S += '}'; + return; + } + } + } getObjCEncodingForTypeImpl(PointeeTy, S, false, ExpandPointedToStructures, NULL, @@ -5484,7 +5573,8 @@ void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl, if (base->isEmpty()) continue; uint64_t offs = toBits(layout.getVBaseClassOffset(base)); - if (FieldOrBaseOffsets.find(offs) == FieldOrBaseOffsets.end()) + if (offs >= uint64_t(toBits(layout.getNonVirtualSize())) && + FieldOrBaseOffsets.find(offs) == FieldOrBaseOffsets.end()) FieldOrBaseOffsets.insert(FieldOrBaseOffsets.end(), std::make_pair(offs, base)); } @@ -6267,6 +6357,8 @@ ASTContext::getSubstTemplateTemplateParmPack(TemplateTemplateParmDecl *Param, CanQualType ASTContext::getFromTargetType(unsigned Type) const { switch (Type) { case TargetInfo::NoInt: return CanQualType(); + case TargetInfo::SignedChar: return SignedCharTy; + case TargetInfo::UnsignedChar: return UnsignedCharTy; case TargetInfo::SignedShort: return ShortTy; case TargetInfo::UnsignedShort: return UnsignedShortTy; case TargetInfo::SignedInt: return IntTy; @@ -6369,15 +6461,6 @@ ASTContext::ProtocolCompatibleWithProtocol(ObjCProtocolDecl *lProto, return false; } -/// QualifiedIdConformsQualifiedId - compare id<pr,...> with id<pr1,...> -/// return true if lhs's protocols conform to rhs's protocol; false -/// otherwise. -bool ASTContext::QualifiedIdConformsQualifiedId(QualType lhs, QualType rhs) { - if (lhs->isObjCQualifiedIdType() && rhs->isObjCQualifiedIdType()) - return ObjCQualifiedIdTypesAreCompatible(lhs, rhs, false); - return false; -} - /// ObjCQualifiedClassTypesAreCompatible - compare Class<pr,...> and /// Class<pr1, ...>. bool ASTContext::ObjCQualifiedClassTypesAreCompatible(QualType lhs, @@ -6890,7 +6973,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, FunctionType::ExtInfo rbaseInfo = rbase->getExtInfo(); // Compatible functions must have compatible calling conventions - if (!isSameCallConv(lbaseInfo.getCC(), rbaseInfo.getCC())) + if (lbaseInfo.getCC() != rbaseInfo.getCC()) return QualType(); // Regparm is part of the calling convention. @@ -7000,10 +7083,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, FunctionProtoType::ExtProtoInfo EPI = proto->getExtProtoInfo(); EPI.ExtInfo = einfo; - return getFunctionType(retType, - ArrayRef<QualType>(proto->arg_type_begin(), - proto->getNumArgs()), - EPI); + return getFunctionType(retType, proto->getArgTypes(), EPI); } if (allLTypes) return lhs; @@ -7351,11 +7431,8 @@ QualType ASTContext::mergeObjCGCQualifiers(QualType LHS, QualType RHS) { if (const FunctionProtoType *FPT = cast<FunctionProtoType>(F)) { FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); EPI.ExtInfo = getFunctionExtInfo(LHS); - QualType ResultType - = getFunctionType(OldReturnType, - ArrayRef<QualType>(FPT->arg_type_begin(), - FPT->getNumArgs()), - EPI); + QualType ResultType = + getFunctionType(OldReturnType, FPT->getArgTypes(), EPI); return ResultType; } } @@ -7407,7 +7484,7 @@ QualType ASTContext::mergeObjCGCQualifiers(QualType LHS, QualType RHS) { //===----------------------------------------------------------------------===// unsigned ASTContext::getIntWidth(QualType T) const { - if (const EnumType *ET = dyn_cast<EnumType>(T)) + if (const EnumType *ET = T->getAs<EnumType>()) T = ET->getDecl()->getIntegerType(); if (T->isBooleanType()) return 1; @@ -7450,6 +7527,8 @@ QualType ASTContext::getCorrespondingUnsignedType(QualType T) const { ASTMutationListener::~ASTMutationListener() { } +void ASTMutationListener::DeducedReturnType(const FunctionDecl *FD, + QualType ReturnType) {} //===----------------------------------------------------------------------===// // Builtin Type Computation @@ -7507,6 +7586,11 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context, "Bad modifiers used with 'v'!"); Type = Context.VoidTy; break; + case 'h': + assert(HowLong == 0 && !Signed && !Unsigned && + "Bad modifiers used with 'f'!"); + Type = Context.HalfTy; + break; case 'f': assert(HowLong == 0 && !Signed && !Unsigned && "Bad modifiers used with 'f'!"); @@ -7734,7 +7818,7 @@ QualType ASTContext::GetBuiltinType(unsigned Id, assert((TypeStr[0] != '.' || TypeStr[1] == 0) && "'.' should only occur at end of builtin type list!"); - FunctionType::ExtInfo EI; + FunctionType::ExtInfo EI(CC_C); if (BuiltinInfo.isNoReturn(Id)) EI = EI.withNoReturn(true); bool Variadic = (TypeStr[0] == '.'); @@ -7751,36 +7835,30 @@ QualType ASTContext::GetBuiltinType(unsigned Id, } GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) { - GVALinkage External = GVA_StrongExternal; - - Linkage L = FD->getLinkage(); - switch (L) { - case NoLinkage: - case InternalLinkage: - case UniqueExternalLinkage: + if (!FD->isExternallyVisible()) return GVA_Internal; - - case ExternalLinkage: - switch (FD->getTemplateSpecializationKind()) { - case TSK_Undeclared: - case TSK_ExplicitSpecialization: - External = GVA_StrongExternal; - break; - case TSK_ExplicitInstantiationDefinition: - return GVA_ExplicitTemplateInstantiation; + GVALinkage External = GVA_StrongExternal; + switch (FD->getTemplateSpecializationKind()) { + case TSK_Undeclared: + case TSK_ExplicitSpecialization: + External = GVA_StrongExternal; + break; - case TSK_ExplicitInstantiationDeclaration: - case TSK_ImplicitInstantiation: - External = GVA_TemplateInstantiation; - break; - } + case TSK_ExplicitInstantiationDefinition: + return GVA_ExplicitTemplateInstantiation; + + case TSK_ExplicitInstantiationDeclaration: + case TSK_ImplicitInstantiation: + External = GVA_TemplateInstantiation; + break; } if (!FD->isInlined()) return External; - - if (!getLangOpts().CPlusPlus || FD->hasAttr<GNUInlineAttr>()) { + + if ((!getLangOpts().CPlusPlus && !getLangOpts().MicrosoftMode) || + FD->hasAttr<GNUInlineAttr>()) { // GNU or C99 inline semantics. Determine whether this symbol should be // externally visible. if (FD->isInlineDefinitionExternallyVisible()) @@ -7804,37 +7882,23 @@ GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) { } GVALinkage ASTContext::GetGVALinkageForVariable(const VarDecl *VD) { - // If this is a static data member, compute the kind of template - // specialization. Otherwise, this variable is not part of a - // template. - TemplateSpecializationKind TSK = TSK_Undeclared; - if (VD->isStaticDataMember()) - TSK = VD->getTemplateSpecializationKind(); - - Linkage L = VD->getLinkage(); - - switch (L) { - case NoLinkage: - case InternalLinkage: - case UniqueExternalLinkage: + if (!VD->isExternallyVisible()) return GVA_Internal; - case ExternalLinkage: - switch (TSK) { - case TSK_Undeclared: - case TSK_ExplicitSpecialization: - return GVA_StrongExternal; + switch (VD->getTemplateSpecializationKind()) { + case TSK_Undeclared: + case TSK_ExplicitSpecialization: + return GVA_StrongExternal; - case TSK_ExplicitInstantiationDeclaration: - llvm_unreachable("Variable should not be instantiated"); - // Fall through to treat this like any other instantiation. - - case TSK_ExplicitInstantiationDefinition: - return GVA_ExplicitTemplateInstantiation; + case TSK_ExplicitInstantiationDeclaration: + llvm_unreachable("Variable should not be instantiated"); + // Fall through to treat this like any other instantiation. - case TSK_ImplicitInstantiation: - return GVA_TemplateInstantiation; - } + case TSK_ExplicitInstantiationDefinition: + return GVA_ExplicitTemplateInstantiation; + + case TSK_ImplicitInstantiation: + return GVA_TemplateInstantiation; } llvm_unreachable("Invalid Linkage!"); @@ -7918,16 +7982,13 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) { return false; } -CallingConv ASTContext::getDefaultCXXMethodCallConv(bool isVariadic) { +CallingConv ASTContext::getDefaultCallingConvention(bool IsVariadic, + bool IsCXXMethod) const { // Pass through to the C++ ABI object - return ABI->getDefaultMethodCallConv(isVariadic); -} + if (IsCXXMethod) + return ABI->getDefaultMethodCallConv(IsVariadic); -CallingConv ASTContext::getCanonicalCallConv(CallingConv CC) const { - if (CC == CC_C && !LangOpts.MRTD && - getTargetInfo().getCXXABI().isMemberFunctionCCDefault()) - return CC_Default; - return CC; + return (LangOpts.MRTD && !IsVariadic) ? CC_X86StdCall : CC_C; } bool ASTContext::isNearlyEmpty(const CXXRecordDecl *RD) const { @@ -7941,9 +8002,9 @@ MangleContext *ASTContext::createMangleContext() { case TargetCXXABI::GenericItanium: case TargetCXXABI::GenericARM: case TargetCXXABI::iOS: - return createItaniumMangleContext(*this, getDiagnostics()); + return ItaniumMangleContext::create(*this, getDiagnostics()); case TargetCXXABI::Microsoft: - return createMicrosoftMangleContext(*this, getDiagnostics()); + return MicrosoftMangleContext::create(*this, getDiagnostics()); } llvm_unreachable("Unsupported ABI"); } @@ -7951,45 +8012,77 @@ MangleContext *ASTContext::createMangleContext() { CXXABI::~CXXABI() {} size_t ASTContext::getSideTableAllocatedMemory() const { - return ASTRecordLayouts.getMemorySize() - + llvm::capacity_in_bytes(ObjCLayouts) - + llvm::capacity_in_bytes(KeyFunctions) - + llvm::capacity_in_bytes(ObjCImpls) - + llvm::capacity_in_bytes(BlockVarCopyInits) - + llvm::capacity_in_bytes(DeclAttrs) - + llvm::capacity_in_bytes(InstantiatedFromStaticDataMember) - + llvm::capacity_in_bytes(InstantiatedFromUsingDecl) - + llvm::capacity_in_bytes(InstantiatedFromUsingShadowDecl) - + llvm::capacity_in_bytes(InstantiatedFromUnnamedFieldDecl) - + llvm::capacity_in_bytes(OverriddenMethods) - + llvm::capacity_in_bytes(Types) - + llvm::capacity_in_bytes(VariableArrayTypes) - + llvm::capacity_in_bytes(ClassScopeSpecializationPattern); -} - -void ASTContext::addUnnamedTag(const TagDecl *Tag) { - // FIXME: This mangling should be applied to function local classes too - if (!Tag->getName().empty() || Tag->getTypedefNameForAnonDecl() || - !isa<CXXRecordDecl>(Tag->getParent()) || Tag->getLinkage() != ExternalLinkage) - return; + return ASTRecordLayouts.getMemorySize() + + llvm::capacity_in_bytes(ObjCLayouts) + + llvm::capacity_in_bytes(KeyFunctions) + + llvm::capacity_in_bytes(ObjCImpls) + + llvm::capacity_in_bytes(BlockVarCopyInits) + + llvm::capacity_in_bytes(DeclAttrs) + + llvm::capacity_in_bytes(TemplateOrInstantiation) + + llvm::capacity_in_bytes(InstantiatedFromUsingDecl) + + llvm::capacity_in_bytes(InstantiatedFromUsingShadowDecl) + + llvm::capacity_in_bytes(InstantiatedFromUnnamedFieldDecl) + + llvm::capacity_in_bytes(OverriddenMethods) + + llvm::capacity_in_bytes(Types) + + llvm::capacity_in_bytes(VariableArrayTypes) + + llvm::capacity_in_bytes(ClassScopeSpecializationPattern); +} + +/// getIntTypeForBitwidth - +/// sets integer QualTy according to specified details: +/// bitwidth, signed/unsigned. +/// Returns empty type if there is no appropriate target types. +QualType ASTContext::getIntTypeForBitwidth(unsigned DestWidth, + unsigned Signed) const { + TargetInfo::IntType Ty = getTargetInfo().getIntTypeByWidth(DestWidth, Signed); + CanQualType QualTy = getFromTargetType(Ty); + if (!QualTy && DestWidth == 128) + return Signed ? Int128Ty : UnsignedInt128Ty; + return QualTy; +} + +/// getRealTypeForBitwidth - +/// sets floating point QualTy according to specified bitwidth. +/// Returns empty type if there is no appropriate target types. +QualType ASTContext::getRealTypeForBitwidth(unsigned DestWidth) const { + TargetInfo::RealType Ty = getTargetInfo().getRealTypeByWidth(DestWidth); + switch (Ty) { + case TargetInfo::Float: + return FloatTy; + case TargetInfo::Double: + return DoubleTy; + case TargetInfo::LongDouble: + return LongDoubleTy; + case TargetInfo::NoFloat: + return QualType(); + } - std::pair<llvm::DenseMap<const DeclContext *, unsigned>::iterator, bool> P = - UnnamedMangleContexts.insert(std::make_pair(Tag->getParent(), 0)); - UnnamedMangleNumbers.insert(std::make_pair(Tag, P.first->second++)); + llvm_unreachable("Unhandled TargetInfo::RealType value"); } -int ASTContext::getUnnamedTagManglingNumber(const TagDecl *Tag) const { - llvm::DenseMap<const TagDecl *, unsigned>::const_iterator I = - UnnamedMangleNumbers.find(Tag); - return I != UnnamedMangleNumbers.end() ? I->second : -1; +void ASTContext::setManglingNumber(const NamedDecl *ND, unsigned Number) { + if (Number > 1) + MangleNumbers[ND] = Number; } -unsigned ASTContext::getLambdaManglingNumber(CXXMethodDecl *CallOperator) { - CXXRecordDecl *Lambda = CallOperator->getParent(); - return LambdaMangleContexts[Lambda->getDeclContext()] - .getManglingNumber(CallOperator); +unsigned ASTContext::getManglingNumber(const NamedDecl *ND) const { + llvm::DenseMap<const NamedDecl *, unsigned>::const_iterator I = + MangleNumbers.find(ND); + return I != MangleNumbers.end() ? I->second : 1; } +MangleNumberingContext & +ASTContext::getManglingNumberContext(const DeclContext *DC) { + assert(LangOpts.CPlusPlus); // We don't need mangling numbers for plain C. + MangleNumberingContext *&MCtx = MangleNumberingContexts[DC]; + if (!MCtx) + MCtx = createMangleNumberingContext(); + return *MCtx; +} + +MangleNumberingContext *ASTContext::createMangleNumberingContext() const { + return ABI->createMangleNumberingContext(); +} void ASTContext::setParameterIndex(const ParmVarDecl *D, unsigned int index) { ParamIndices[D] = index; @@ -8001,3 +8094,160 @@ unsigned ASTContext::getParameterIndex(const ParmVarDecl *D) const { "ParmIndices lacks entry set by ParmVarDecl"); return I->second; } + +APValue * +ASTContext::getMaterializedTemporaryValue(const MaterializeTemporaryExpr *E, + bool MayCreate) { + assert(E && E->getStorageDuration() == SD_Static && + "don't need to cache the computed value for this temporary"); + if (MayCreate) + return &MaterializedTemporaryValues[E]; + + llvm::DenseMap<const MaterializeTemporaryExpr *, APValue>::iterator I = + MaterializedTemporaryValues.find(E); + return I == MaterializedTemporaryValues.end() ? 0 : &I->second; +} + +bool ASTContext::AtomicUsesUnsupportedLibcall(const AtomicExpr *E) const { + const llvm::Triple &T = getTargetInfo().getTriple(); + if (!T.isOSDarwin()) + return false; + + if (!(T.isiOS() && T.isOSVersionLT(7)) && + !(T.isMacOSX() && T.isOSVersionLT(10, 9))) + return false; + + QualType AtomicTy = E->getPtr()->getType()->getPointeeType(); + CharUnits sizeChars = getTypeSizeInChars(AtomicTy); + uint64_t Size = sizeChars.getQuantity(); + CharUnits alignChars = getTypeAlignInChars(AtomicTy); + unsigned Align = alignChars.getQuantity(); + unsigned MaxInlineWidthInBits = getTargetInfo().getMaxAtomicInlineWidth(); + return (Size != Align || toBits(sizeChars) > MaxInlineWidthInBits); +} + +namespace { + + /// \brief A \c RecursiveASTVisitor that builds a map from nodes to their + /// parents as defined by the \c RecursiveASTVisitor. + /// + /// Note that the relationship described here is purely in terms of AST + /// traversal - there are other relationships (for example declaration context) + /// in the AST that are better modeled by special matchers. + /// + /// FIXME: Currently only builds up the map using \c Stmt and \c Decl nodes. + class ParentMapASTVisitor : public RecursiveASTVisitor<ParentMapASTVisitor> { + + public: + /// \brief Builds and returns the translation unit's parent map. + /// + /// The caller takes ownership of the returned \c ParentMap. + static ASTContext::ParentMap *buildMap(TranslationUnitDecl &TU) { + ParentMapASTVisitor Visitor(new ASTContext::ParentMap); + Visitor.TraverseDecl(&TU); + return Visitor.Parents; + } + + private: + typedef RecursiveASTVisitor<ParentMapASTVisitor> VisitorBase; + + ParentMapASTVisitor(ASTContext::ParentMap *Parents) : Parents(Parents) { + } + + bool shouldVisitTemplateInstantiations() const { + return true; + } + bool shouldVisitImplicitCode() const { + return true; + } + // Disables data recursion. We intercept Traverse* methods in the RAV, which + // are not triggered during data recursion. + bool shouldUseDataRecursionFor(clang::Stmt *S) const { + return false; + } + + template <typename T> + bool TraverseNode(T *Node, bool(VisitorBase:: *traverse) (T *)) { + if (Node == NULL) + return true; + if (ParentStack.size() > 0) + // FIXME: Currently we add the same parent multiple times, for example + // when we visit all subexpressions of template instantiations; this is + // suboptimal, bug benign: the only way to visit those is with + // hasAncestor / hasParent, and those do not create new matches. + // The plan is to enable DynTypedNode to be storable in a map or hash + // map. The main problem there is to implement hash functions / + // comparison operators for all types that DynTypedNode supports that + // do not have pointer identity. + (*Parents)[Node].push_back(ParentStack.back()); + ParentStack.push_back(ast_type_traits::DynTypedNode::create(*Node)); + bool Result = (this ->* traverse) (Node); + ParentStack.pop_back(); + return Result; + } + + bool TraverseDecl(Decl *DeclNode) { + return TraverseNode(DeclNode, &VisitorBase::TraverseDecl); + } + + bool TraverseStmt(Stmt *StmtNode) { + return TraverseNode(StmtNode, &VisitorBase::TraverseStmt); + } + + ASTContext::ParentMap *Parents; + llvm::SmallVector<ast_type_traits::DynTypedNode, 16> ParentStack; + + friend class RecursiveASTVisitor<ParentMapASTVisitor>; + }; + +} // end namespace + +ASTContext::ParentVector +ASTContext::getParents(const ast_type_traits::DynTypedNode &Node) { + assert(Node.getMemoizationData() && + "Invariant broken: only nodes that support memoization may be " + "used in the parent map."); + if (!AllParents) { + // We always need to run over the whole translation unit, as + // hasAncestor can escape any subtree. + AllParents.reset( + ParentMapASTVisitor::buildMap(*getTranslationUnitDecl())); + } + ParentMap::const_iterator I = AllParents->find(Node.getMemoizationData()); + if (I == AllParents->end()) { + return ParentVector(); + } + return I->second; +} + +bool +ASTContext::ObjCMethodsAreEqual(const ObjCMethodDecl *MethodDecl, + const ObjCMethodDecl *MethodImpl) { + // No point trying to match an unavailable/deprecated mothod. + if (MethodDecl->hasAttr<UnavailableAttr>() + || MethodDecl->hasAttr<DeprecatedAttr>()) + return false; + if (MethodDecl->getObjCDeclQualifier() != + MethodImpl->getObjCDeclQualifier()) + return false; + if (!hasSameType(MethodDecl->getResultType(), + MethodImpl->getResultType())) + return false; + + if (MethodDecl->param_size() != MethodImpl->param_size()) + return false; + + for (ObjCMethodDecl::param_const_iterator IM = MethodImpl->param_begin(), + IF = MethodDecl->param_begin(), EM = MethodImpl->param_end(), + EF = MethodDecl->param_end(); + IM != EM && IF != EF; ++IM, ++IF) { + const ParmVarDecl *DeclVar = (*IF); + const ParmVarDecl *ImplVar = (*IM); + if (ImplVar->getObjCDeclQualifier() != DeclVar->getObjCDeclQualifier()) + return false; + if (!hasSameType(DeclVar->getType(), ImplVar->getType())) + return false; + } + return (MethodDecl->isVariadic() == MethodImpl->isVariadic()); + +} diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp index 1ed65e4..fce8f64 100644 --- a/lib/AST/ASTDiagnostic.cpp +++ b/lib/AST/ASTDiagnostic.cpp @@ -300,8 +300,7 @@ void clang::FormatASTNodeDiagnosticArgument( assert(ModLen == 0 && ArgLen == 0 && "Invalid modifier for DeclarationName argument"); - DeclarationName N = DeclarationName::getFromOpaqueInteger(Val); - N.printName(OS); + OS << DeclarationName::getFromOpaqueInteger(Val); break; } case DiagnosticsEngine::ak_nameddecl: { @@ -459,6 +458,10 @@ class TemplateDiff { /// FromValueDecl, ToValueDecl - Whether the argument is a decl. ValueDecl *FromValueDecl, *ToValueDecl; + /// FromAddressOf, ToAddressOf - Whether the ValueDecl needs an address of + /// operator before it. + bool FromAddressOf, ToAddressOf; + /// FromDefault, ToDefault - Whether the argument is a default argument. bool FromDefault, ToDefault; @@ -469,7 +472,8 @@ class TemplateDiff { : Kind(Invalid), NextNode(0), ChildNode(0), ParentNode(ParentNode), FromType(), ToType(), FromExpr(0), ToExpr(0), FromTD(0), ToTD(0), IsValidFromInt(false), IsValidToInt(false), FromValueDecl(0), - ToValueDecl(0), FromDefault(false), ToDefault(false), Same(false) { } + ToValueDecl(0), FromAddressOf(false), ToAddressOf(false), + FromDefault(false), ToDefault(false), Same(false) { } }; /// FlatTree - A flattened tree used to store the DiffNodes. @@ -526,9 +530,12 @@ class TemplateDiff { } /// SetNode - Set FromValueDecl and ToValueDecl of the current node. - void SetNode(ValueDecl *FromValueDecl, ValueDecl *ToValueDecl) { + void SetNode(ValueDecl *FromValueDecl, ValueDecl *ToValueDecl, + bool FromAddressOf, bool ToAddressOf) { FlatTree[CurrentNode].FromValueDecl = FromValueDecl; FlatTree[CurrentNode].ToValueDecl = ToValueDecl; + FlatTree[CurrentNode].FromAddressOf = FromAddressOf; + FlatTree[CurrentNode].ToAddressOf = ToAddressOf; } /// SetSame - Sets the same flag of the current node. @@ -620,9 +627,12 @@ class TemplateDiff { } /// GetNode - Gets the FromValueDecl and ToValueDecl. - void GetNode(ValueDecl *&FromValueDecl, ValueDecl *&ToValueDecl) { + void GetNode(ValueDecl *&FromValueDecl, ValueDecl *&ToValueDecl, + bool &FromAddressOf, bool &ToAddressOf) { FromValueDecl = FlatTree[ReadNode].FromValueDecl; ToValueDecl = FlatTree[ReadNode].ToValueDecl; + FromAddressOf = FlatTree[ReadNode].FromAddressOf; + ToAddressOf = FlatTree[ReadNode].ToAddressOf; } /// NodeIsSame - Returns true the arguments are the same. @@ -821,8 +831,10 @@ class TemplateDiff { void DiffTemplate(const TemplateSpecializationType *FromTST, const TemplateSpecializationType *ToTST) { // Begin descent into diffing template tree. - TemplateParameterList *Params = + TemplateParameterList *ParamsFrom = FromTST->getTemplateName().getAsTemplateDecl()->getTemplateParameters(); + TemplateParameterList *ParamsTo = + ToTST->getTemplateName().getAsTemplateDecl()->getTemplateParameters(); unsigned TotalArgs = 0; for (TSTiterator FromIter(Context, FromTST), ToIter(Context, ToTST); !FromIter.isEnd() || !ToIter.isEnd(); ++TotalArgs) { @@ -831,15 +843,18 @@ class TemplateDiff { // Get the parameter at index TotalArgs. If index is larger // than the total number of parameters, then there is an // argument pack, so re-use the last parameter. - NamedDecl *ParamND = Params->getParam( - (TotalArgs < Params->size()) ? TotalArgs - : Params->size() - 1); + unsigned ParamIndex = std::min(TotalArgs, ParamsFrom->size() - 1); + NamedDecl *ParamND = ParamsFrom->getParam(ParamIndex); + // Handle Types if (TemplateTypeParmDecl *DefaultTTPD = dyn_cast<TemplateTypeParmDecl>(ParamND)) { QualType FromType, ToType; FromType = GetType(FromIter, DefaultTTPD); - ToType = GetType(ToIter, DefaultTTPD); + // A forward declaration can have no default arg but the actual class + // can, don't mix up iterators and get the original parameter. + ToType = GetType( + ToIter, cast<TemplateTypeParmDecl>(ParamsTo->getParam(ParamIndex))); Tree.SetNode(FromType, ToType); Tree.SetDefault(FromIter.isEnd() && !FromType.isNull(), ToIter.isEnd() && !ToType.isNull()); @@ -942,7 +957,14 @@ class TemplateDiff { FromValueDecl = GetValueDecl(FromIter, FromExpr); if (!HasToValueDecl && ToExpr) ToValueDecl = GetValueDecl(ToIter, ToExpr); - Tree.SetNode(FromValueDecl, ToValueDecl); + QualType ArgumentType = DefaultNTTPD->getType(); + bool FromAddressOf = FromValueDecl && + !ArgumentType->isReferenceType() && + !FromValueDecl->getType()->isArrayType(); + bool ToAddressOf = ToValueDecl && + !ArgumentType->isReferenceType() && + !ToValueDecl->getType()->isArrayType(); + Tree.SetNode(FromValueDecl, ToValueDecl, FromAddressOf, ToAddressOf); Tree.SetSame(FromValueDecl && ToValueDecl && FromValueDecl->getCanonicalDecl() == ToValueDecl->getCanonicalDecl()); @@ -973,7 +995,7 @@ class TemplateDiff { /// makeTemplateList - Dump every template alias into the vector. static void makeTemplateList( - SmallVector<const TemplateSpecializationType*, 1> &TemplateList, + SmallVectorImpl<const TemplateSpecializationType *> &TemplateList, const TemplateSpecializationType *TST) { while (TST) { TemplateList.push_back(TST); @@ -1008,7 +1030,7 @@ class TemplateDiff { makeTemplateList(FromTemplateList, FromTST); makeTemplateList(ToTemplateList, ToTST); - SmallVector<const TemplateSpecializationType*, 1>::reverse_iterator + SmallVectorImpl<const TemplateSpecializationType *>::reverse_iterator FromIter = FromTemplateList.rbegin(), FromEnd = FromTemplateList.rend(), ToIter = ToTemplateList.rbegin(), ToEnd = ToTemplateList.rend(); @@ -1037,10 +1059,14 @@ class TemplateDiff { if (!Iter.isEnd()) return Iter->getAsType(); - if (!isVariadic) - return DefaultTTPD->getDefaultArgument(); + if (isVariadic) + return QualType(); + + QualType ArgType = DefaultTTPD->getDefaultArgument(); + if (ArgType->isDependentType()) + return Iter.getDesugar().getAsType(); - return QualType(); + return ArgType; } /// GetExpr - Retrieves the template expression argument, including default @@ -1080,7 +1106,7 @@ class TemplateDiff { return ArgExpr->EvaluateKnownConstInt(Context); } - /// GetValueDecl - Retrieves the template integer argument, including + /// GetValueDecl - Retrieves the template Decl argument, including /// default expression argument. ValueDecl *GetValueDecl(const TSTiterator &Iter, Expr *ArgExpr) { // Default, value-depenedent expressions require fetching @@ -1095,7 +1121,12 @@ class TemplateDiff { default: assert(0 && "Unexpected template argument kind"); } - return cast<DeclRefExpr>(ArgExpr)->getDecl(); + DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ArgExpr); + if (!DRE) { + DRE = cast<DeclRefExpr>(cast<UnaryOperator>(ArgExpr)->getSubExpr()); + } + + return DRE->getDecl(); } /// GetTemplateDecl - Retrieves the template template arguments, including @@ -1228,9 +1259,10 @@ class TemplateDiff { } case DiffTree::Declaration: { ValueDecl *FromValueDecl, *ToValueDecl; - Tree.GetNode(FromValueDecl, ToValueDecl); - PrintValueDecl(FromValueDecl, ToValueDecl, Tree.FromDefault(), - Tree.ToDefault(), Tree.NodeIsSame()); + bool FromAddressOf, ToAddressOf; + Tree.GetNode(FromValueDecl, ToValueDecl, FromAddressOf, ToAddressOf); + PrintValueDecl(FromValueDecl, ToValueDecl, FromAddressOf, ToAddressOf, + Tree.FromDefault(), Tree.ToDefault(), Tree.NodeIsSame()); return; } case DiffTree::Template: { @@ -1478,7 +1510,8 @@ class TemplateDiff { /// PrintDecl - Handles printing of Decl arguments, highlighting /// argument differences. void PrintValueDecl(ValueDecl *FromValueDecl, ValueDecl *ToValueDecl, - bool FromDefault, bool ToDefault, bool Same) { + bool FromAddressOf, bool ToAddressOf, bool FromDefault, + bool ToDefault, bool Same) { assert((FromValueDecl || ToValueDecl) && "Only one Decl argument may be NULL"); @@ -1487,15 +1520,21 @@ class TemplateDiff { } else if (!PrintTree) { OS << (FromDefault ? "(default) " : ""); Bold(); + if (FromAddressOf) + OS << "&"; OS << (FromValueDecl ? FromValueDecl->getName() : "(no argument)"); Unbold(); } else { OS << (FromDefault ? "[(default) " : "["); Bold(); + if (FromAddressOf) + OS << "&"; OS << (FromValueDecl ? FromValueDecl->getName() : "(no argument)"); Unbold(); OS << " != " << (ToDefault ? "(default) " : ""); Bold(); + if (ToAddressOf) + OS << "&"; OS << (ToValueDecl ? ToValueDecl->getName() : "(no argument)"); Unbold(); OS << ']'; diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 340cc41..2f40255 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -16,6 +16,7 @@ #include "clang/AST/Attr.h" #include "clang/AST/CommentVisitor.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclLookups.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclVisitor.h" #include "clang/AST/StmtVisitor.h" @@ -62,6 +63,9 @@ namespace { // Null statements static const TerminalColor NullColor = { raw_ostream::BLUE, false }; + // Undeserialized entities + static const TerminalColor UndeserializedColor = { raw_ostream::GREEN, true }; + // CastKind from CastExpr's static const TerminalColor CastColor = { raw_ostream::RED, false }; @@ -173,6 +177,7 @@ namespace { void dumpName(const NamedDecl *D); bool hasNodes(const DeclContext *DC); void dumpDeclContext(const DeclContext *DC); + void dumpLookups(const DeclContext *DC); void dumpAttr(const Attr *A); // C++ Utilities @@ -214,6 +219,11 @@ namespace { const ClassTemplatePartialSpecializationDecl *D); void VisitClassScopeFunctionSpecializationDecl( const ClassScopeFunctionSpecializationDecl *D); + void VisitVarTemplateDecl(const VarTemplateDecl *D); + void VisitVarTemplateSpecializationDecl( + const VarTemplateSpecializationDecl *D); + void VisitVarTemplatePartialSpecializationDecl( + const VarTemplatePartialSpecializationDecl *D); void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D); void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D); void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D); @@ -244,6 +254,7 @@ namespace { void VisitAttributedStmt(const AttributedStmt *Node); void VisitLabelStmt(const LabelStmt *Node); void VisitGotoStmt(const GotoStmt *Node); + void VisitCXXCatchStmt(const CXXCatchStmt *Node); // Exprs void VisitExpr(const Expr *Node); @@ -271,9 +282,14 @@ namespace { void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *Node); void VisitCXXConstructExpr(const CXXConstructExpr *Node); void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Node); + void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Node); void VisitExprWithCleanups(const ExprWithCleanups *Node); void VisitUnresolvedLookupExpr(const UnresolvedLookupExpr *Node); void dumpCXXTemporary(const CXXTemporary *Temporary); + void VisitLambdaExpr(const LambdaExpr *Node) { + VisitExpr(Node); + dumpDecl(Node->getLambdaClass()); + } // ObjC void VisitObjCAtCatchStmt(const ObjCAtCatchStmt *Node); @@ -329,8 +345,8 @@ void ASTDumper::indent() { OS << "\n"; ColorScope Color(*this, IndentColor); - for (llvm::SmallVector<IndentType, 32>::const_iterator I = Indents.begin(), - E = Indents.end(); + for (SmallVectorImpl<IndentType>::const_iterator I = Indents.begin(), + E = Indents.end(); I != E; ++I) { switch (*I) { case IT_Child: @@ -449,9 +465,7 @@ void ASTDumper::dumpBareDeclRef(const Decl *D) { if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) { ColorScope Color(*this, DeclNameColor); - OS << " '"; - ND->getDeclName().printName(OS); - OS << "'"; + OS << " '" << ND->getDeclName() << '\''; } if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) @@ -479,20 +493,76 @@ bool ASTDumper::hasNodes(const DeclContext *DC) { if (!DC) return false; - return DC->decls_begin() != DC->decls_end(); + return DC->hasExternalLexicalStorage() || + DC->noload_decls_begin() != DC->noload_decls_end(); } void ASTDumper::dumpDeclContext(const DeclContext *DC) { if (!DC) return; - for (DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end(); + bool HasUndeserializedDecls = DC->hasExternalLexicalStorage(); + for (DeclContext::decl_iterator I = DC->noload_decls_begin(), + E = DC->noload_decls_end(); I != E; ++I) { DeclContext::decl_iterator Next = I; ++Next; - if (Next == E) + if (Next == E && !HasUndeserializedDecls) lastChild(); dumpDecl(*I); } + if (HasUndeserializedDecls) { + lastChild(); + IndentScope Indent(*this); + ColorScope Color(*this, UndeserializedColor); + OS << "<undeserialized declarations>"; + } +} + +void ASTDumper::dumpLookups(const DeclContext *DC) { + IndentScope Indent(*this); + + OS << "StoredDeclsMap "; + dumpBareDeclRef(cast<Decl>(DC)); + + const DeclContext *Primary = DC->getPrimaryContext(); + if (Primary != DC) { + OS << " primary"; + dumpPointer(cast<Decl>(Primary)); + } + + bool HasUndeserializedLookups = Primary->hasExternalVisibleStorage(); + + DeclContext::all_lookups_iterator I = Primary->noload_lookups_begin(), + E = Primary->noload_lookups_end(); + while (I != E) { + DeclarationName Name = I.getLookupName(); + DeclContextLookupResult R = *I++; + if (I == E && !HasUndeserializedLookups) + lastChild(); + + IndentScope Indent(*this); + OS << "DeclarationName "; + { + ColorScope Color(*this, DeclNameColor); + OS << '\'' << Name << '\''; + } + + for (DeclContextLookupResult::iterator RI = R.begin(), RE = R.end(); + RI != RE; ++RI) { + if (RI + 1 == RE) + lastChild(); + dumpDeclRef(*RI); + if ((*RI)->isHidden()) + OS << " hidden"; + } + } + + if (HasUndeserializedLookups) { + lastChild(); + IndentScope Indent(*this); + ColorScope Color(*this, UndeserializedColor); + OS << "<undeserialized lookups>"; + } } void ASTDumper::dumpAttr(const Attr *A) { @@ -511,21 +581,29 @@ void ASTDumper::dumpAttr(const Attr *A) { #include "clang/AST/AttrDump.inc" } -static Decl *getPreviousDeclImpl(...) { - return 0; +static void dumpPreviousDeclImpl(raw_ostream &OS, ...) {} + +template<typename T> +static void dumpPreviousDeclImpl(raw_ostream &OS, const Mergeable<T> *D) { + const T *First = D->getFirstDecl(); + if (First != D) + OS << " first " << First; } template<typename T> -static const Decl *getPreviousDeclImpl(const Redeclarable<T> *D) { - return D->getPreviousDecl(); +static void dumpPreviousDeclImpl(raw_ostream &OS, const Redeclarable<T> *D) { + const T *Prev = D->getPreviousDecl(); + if (Prev) + OS << " prev " << Prev; } -/// Get the previous declaration in the redeclaration chain for a declaration. -static const Decl *getPreviousDecl(const Decl *D) { +/// Dump the previous declaration in the redeclaration chain for a declaration, +/// if any. +static void dumpPreviousDecl(raw_ostream &OS, const Decl *D) { switch (D->getKind()) { #define DECL(DERIVED, BASE) \ case Decl::DERIVED: \ - return getPreviousDeclImpl(cast<DERIVED##Decl>(D)); + return dumpPreviousDeclImpl(OS, cast<DERIVED##Decl>(D)); #define ABSTRACT_DECL(DECL) #include "clang/AST/DeclNodes.inc" } @@ -662,20 +740,25 @@ void ASTDumper::dumpDecl(const Decl *D) { dumpPointer(D); if (D->getLexicalDeclContext() != D->getDeclContext()) OS << " parent " << cast<Decl>(D->getDeclContext()); - if (const Decl *Prev = getPreviousDecl(D)) - OS << " prev " << Prev; + dumpPreviousDecl(OS, D); dumpSourceRange(D->getSourceRange()); + if (Module *M = D->getOwningModule()) + OS << " in " << M->getFullModuleName(); + if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) + if (ND->isHidden()) + OS << " hidden"; bool HasAttrs = D->attr_begin() != D->attr_end(); - bool HasComment = D->getASTContext().getCommentForDecl(D, 0); + const FullComment *Comment = + D->getASTContext().getLocalCommentForDeclUncached(D); // Decls within functions are visited by the body bool HasDeclContext = !isa<FunctionDecl>(*D) && !isa<ObjCMethodDecl>(*D) && hasNodes(dyn_cast<DeclContext>(D)); - setMoreChildren(HasAttrs || HasComment || HasDeclContext); + setMoreChildren(HasAttrs || Comment || HasDeclContext); ConstDeclVisitor<ASTDumper>::Visit(D); - setMoreChildren(HasComment || HasDeclContext); + setMoreChildren(Comment || HasDeclContext); for (Decl::attr_iterator I = D->attr_begin(), E = D->attr_end(); I != E; ++I) { if (I + 1 == E) @@ -685,7 +768,10 @@ void ASTDumper::dumpDecl(const Decl *D) { setMoreChildren(HasDeclContext); lastChild(); - dumpFullComment(D->getASTContext().getCommentForDecl(D, 0)); + dumpFullComment(Comment); + + if (D->isInvalidDecl()) + OS << " invalid"; setMoreChildren(false); if (HasDeclContext) @@ -722,6 +808,8 @@ void ASTDumper::VisitRecordDecl(const RecordDecl *D) { dumpName(D); if (D->isModulePrivate()) OS << " __module_private__"; + if (D->isCompleteDefinition()) + OS << " definition"; } void ASTDumper::VisitEnumConstantDecl(const EnumConstantDecl *D) { @@ -764,6 +852,19 @@ void ASTDumper::VisitFunctionDecl(const FunctionDecl *D) { else if (D->isDeletedAsWritten()) OS << " delete"; + if (const FunctionProtoType *FPT = D->getType()->getAs<FunctionProtoType>()) { + FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); + switch (EPI.ExceptionSpecType) { + default: break; + case EST_Unevaluated: + OS << " noexcept-unevaluated " << EPI.ExceptionSpecDecl; + break; + case EST_Uninstantiated: + OS << " noexcept-uninstantiated " << EPI.ExceptionSpecTemplate; + break; + } + } + bool OldMoreChildren = hasMoreChildren(); const FunctionTemplateSpecializationInfo *FTSI = D->getTemplateSpecializationInfo(); @@ -1012,6 +1113,49 @@ void ASTDumper::VisitClassScopeFunctionSpecializationDecl( dumpTemplateArgumentListInfo(D->templateArgs()); } +void ASTDumper::VisitVarTemplateDecl(const VarTemplateDecl *D) { + dumpName(D); + dumpTemplateParameters(D->getTemplateParameters()); + + VarTemplateDecl::spec_iterator I = D->spec_begin(); + VarTemplateDecl::spec_iterator E = D->spec_end(); + if (I == E) + lastChild(); + dumpDecl(D->getTemplatedDecl()); + for (; I != E; ++I) { + VarTemplateDecl::spec_iterator Next = I; + ++Next; + if (Next == E) + lastChild(); + switch (I->getTemplateSpecializationKind()) { + case TSK_Undeclared: + case TSK_ImplicitInstantiation: + if (D == D->getCanonicalDecl()) + dumpDecl(*I); + else + dumpDeclRef(*I); + break; + case TSK_ExplicitSpecialization: + case TSK_ExplicitInstantiationDeclaration: + case TSK_ExplicitInstantiationDefinition: + dumpDeclRef(*I); + break; + } + } +} + +void ASTDumper::VisitVarTemplateSpecializationDecl( + const VarTemplateSpecializationDecl *D) { + dumpTemplateArgumentList(D->getTemplateArgs()); + VisitVarDecl(D); +} + +void ASTDumper::VisitVarTemplatePartialSpecializationDecl( + const VarTemplatePartialSpecializationDecl *D) { + dumpTemplateParameters(D->getTemplateParameters()); + VisitVarTemplateSpecializationDecl(D); +} + void ASTDumper::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) { if (D->wasDeclaredWithTypename()) OS << " typename"; @@ -1097,6 +1241,8 @@ void ASTDumper::VisitObjCIvarDecl(const ObjCIvarDecl *D) { dumpType(D->getType()); if (D->getSynthesize()) OS << " synthesize"; + if (D->getBackingIvarReferencedInAccessor()) + OS << " BackingIvarReferencedInAccessor"; switch (D->getAccessControl()) { case ObjCIvarDecl::None: @@ -1331,7 +1477,7 @@ void ASTDumper::dumpStmt(const Stmt *S) { return; } - setMoreChildren(S->children()); + setMoreChildren(!S->children().empty()); ConstStmtVisitor<ASTDumper>::Visit(S); setMoreChildren(false); for (Stmt::const_child_range CI = S->children(); CI; ++CI) { @@ -1385,6 +1531,11 @@ void ASTDumper::VisitGotoStmt(const GotoStmt *Node) { dumpPointer(Node->getLabel()); } +void ASTDumper::VisitCXXCatchStmt(const CXXCatchStmt *Node) { + VisitStmt(Node); + dumpDecl(Node->getExceptionDecl()); +} + //===----------------------------------------------------------------------===// // Expr dumping methods. //===----------------------------------------------------------------------===// @@ -1510,6 +1661,7 @@ void ASTDumper::VisitPredefinedExpr(const PredefinedExpr *Node) { default: llvm_unreachable("unknown case"); case PredefinedExpr::Func: OS << " __func__"; break; case PredefinedExpr::Function: OS << " __FUNCTION__"; break; + case PredefinedExpr::FuncDName: OS << " __FUNCDNAME__"; break; case PredefinedExpr::LFunction: OS << " L__FUNCTION__"; break; case PredefinedExpr::PrettyFunction: OS << " __PRETTY_FUNCTION__";break; } @@ -1659,6 +1811,15 @@ void ASTDumper::VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Node) { dumpCXXTemporary(Node->getTemporary()); } +void +ASTDumper::VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Node) { + VisitExpr(Node); + if (const ValueDecl *VD = Node->getExtendingDecl()) { + OS << " extended by "; + dumpBareDeclRef(VD); + } +} + void ASTDumper::VisitExprWithCleanups(const ExprWithCleanups *Node) { VisitExpr(Node); for (unsigned i = 0, e = Node->getNumObjects(); i != e; ++i) @@ -1949,6 +2110,20 @@ void Decl::dumpColor() const { &getASTContext().getSourceManager(), /*ShowColors*/true); P.dumpDecl(this); } + +void DeclContext::dumpLookups() const { + dumpLookups(llvm::errs()); +} + +void DeclContext::dumpLookups(raw_ostream &OS) const { + const DeclContext *DC = this; + while (!DC->isTranslationUnit()) + DC = DC->getParent(); + ASTContext &Ctx = cast<TranslationUnitDecl>(DC)->getASTContext(); + ASTDumper P(OS, &Ctx.getCommentCommandTraits(), &Ctx.getSourceManager()); + P.dumpLookups(this); +} + //===----------------------------------------------------------------------===// // Stmt method implementations //===----------------------------------------------------------------------===// diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index 915eb6f..e16015b 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -106,6 +106,8 @@ namespace clang { bool ImportDefinition(RecordDecl *From, RecordDecl *To, ImportDefinitionKind Kind = IDK_Default); + bool ImportDefinition(VarDecl *From, VarDecl *To, + ImportDefinitionKind Kind = IDK_Default); bool ImportDefinition(EnumDecl *From, EnumDecl *To, ImportDefinitionKind Kind = IDK_Default); bool ImportDefinition(ObjCInterfaceDecl *From, ObjCInterfaceDecl *To, @@ -120,9 +122,12 @@ namespace clang { SmallVectorImpl<TemplateArgument> &ToArgs); bool IsStructuralMatch(RecordDecl *FromRecord, RecordDecl *ToRecord, bool Complain = true); + bool IsStructuralMatch(VarDecl *FromVar, VarDecl *ToVar, + bool Complain = true); bool IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToRecord); bool IsStructuralMatch(EnumConstantDecl *FromEC, EnumConstantDecl *ToEC); bool IsStructuralMatch(ClassTemplateDecl *From, ClassTemplateDecl *To); + bool IsStructuralMatch(VarTemplateDecl *From, VarTemplateDecl *To); Decl *VisitDecl(Decl *D); Decl *VisitTranslationUnitDecl(TranslationUnitDecl *D); Decl *VisitNamespaceDecl(NamespaceDecl *D); @@ -157,7 +162,9 @@ namespace clang { Decl *VisitClassTemplateDecl(ClassTemplateDecl *D); Decl *VisitClassTemplateSpecializationDecl( ClassTemplateSpecializationDecl *D); - + Decl *VisitVarTemplateDecl(VarTemplateDecl *D); + Decl *VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *D); + // Importing statements Stmt *VisitStmt(Stmt *S); @@ -400,6 +407,13 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, return false; break; + case Type::Decayed: + if (!IsStructurallyEquivalent(Context, + cast<DecayedType>(T1)->getPointeeType(), + cast<DecayedType>(T2)->getPointeeType())) + return false; + break; + case Type::Pointer: if (!IsStructurallyEquivalent(Context, cast<PointerType>(T1)->getPointeeType(), @@ -1695,7 +1709,8 @@ QualType ASTNodeImporter::VisitAutoType(const AutoType *T) { return QualType(); } - return Importer.getToContext().getAutoType(ToDeduced, T->isDecltypeAuto()); + return Importer.getToContext().getAutoType(ToDeduced, T->isDecltypeAuto(), + /*IsDependent*/false); } QualType ASTNodeImporter::VisitRecordType(const RecordType *T) { @@ -1968,9 +1983,6 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To, = FromData.HasDeclaredCopyConstructorWithConstParam; ToData.HasDeclaredCopyAssignmentWithConstParam = FromData.HasDeclaredCopyAssignmentWithConstParam; - ToData.FailedImplicitMoveConstructor - = FromData.FailedImplicitMoveConstructor; - ToData.FailedImplicitMoveAssignment = FromData.FailedImplicitMoveAssignment; ToData.IsLambda = FromData.IsLambda; SmallVector<CXXBaseSpecifier *, 4> Bases; @@ -2010,6 +2022,21 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To, return false; } +bool ASTNodeImporter::ImportDefinition(VarDecl *From, VarDecl *To, + ImportDefinitionKind Kind) { + if (To->getDefinition()) + return false; + + // FIXME: Can we really import any initializer? Alternatively, we could force + // ourselves to import every declaration of a variable and then only use + // getInit() here. + To->setInit(Importer.Import(const_cast<Expr *>(From->getAnyInitializer()))); + + // FIXME: Other bits to merge? + + return false; +} + bool ASTNodeImporter::ImportDefinition(EnumDecl *From, EnumDecl *To, ImportDefinitionKind Kind) { if (To->getDefinition() || To->isBeingDefined()) { @@ -2148,13 +2175,30 @@ bool ASTNodeImporter::ImportTemplateArguments(const TemplateArgument *FromArgs, bool ASTNodeImporter::IsStructuralMatch(RecordDecl *FromRecord, RecordDecl *ToRecord, bool Complain) { + // Eliminate a potential failure point where we attempt to re-import + // something we're trying to import while completing ToRecord. + Decl *ToOrigin = Importer.GetOriginalDecl(ToRecord); + if (ToOrigin) { + RecordDecl *ToOriginRecord = dyn_cast<RecordDecl>(ToOrigin); + if (ToOriginRecord) + ToRecord = ToOriginRecord; + } + StructuralEquivalenceContext Ctx(Importer.getFromContext(), - Importer.getToContext(), + ToRecord->getASTContext(), Importer.getNonEquivalentDecls(), false, Complain); return Ctx.IsStructurallyEquivalent(FromRecord, ToRecord); } +bool ASTNodeImporter::IsStructuralMatch(VarDecl *FromVar, VarDecl *ToVar, + bool Complain) { + StructuralEquivalenceContext Ctx( + Importer.getFromContext(), Importer.getToContext(), + Importer.getNonEquivalentDecls(), false, Complain); + return Ctx.IsStructurallyEquivalent(FromVar, ToVar); +} + bool ASTNodeImporter::IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToEnum) { StructuralEquivalenceContext Ctx(Importer.getFromContext(), Importer.getToContext(), @@ -2181,6 +2225,14 @@ bool ASTNodeImporter::IsStructuralMatch(ClassTemplateDecl *From, return Ctx.IsStructurallyEquivalent(From, To); } +bool ASTNodeImporter::IsStructuralMatch(VarTemplateDecl *From, + VarTemplateDecl *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(); @@ -2610,8 +2662,8 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { continue; if (FunctionDecl *FoundFunction = dyn_cast<FunctionDecl>(FoundDecls[I])) { - if (isExternalLinkage(FoundFunction->getLinkage()) && - isExternalLinkage(D->getLinkage())) { + if (FoundFunction->hasExternalFormalLinkage() && + D->hasExternalFormalLinkage()) { if (Importer.IsStructurallyEquivalent(D->getType(), FoundFunction->getType())) { // FIXME: Actually try to merge the body and other attributes. @@ -2664,10 +2716,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { FromEPI.NoexceptExpr) { FunctionProtoType::ExtProtoInfo DefaultEPI; FromTy = Importer.getFromContext().getFunctionType( - FromFPT->getResultType(), - ArrayRef<QualType>(FromFPT->arg_type_begin(), - FromFPT->getNumArgs()), - DefaultEPI); + FromFPT->getResultType(), FromFPT->getArgTypes(), DefaultEPI); usedDifferentExceptionSpec = true; } } @@ -2878,7 +2927,7 @@ Decl *ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *D) { if (Importer.IsStructurallyEquivalent(D->getType(), FoundField->getType(), - Name)) { + !Name.isEmpty())) { Importer.Imported(D, FoundField); return FoundField; } @@ -2965,7 +3014,8 @@ Decl *ASTNodeImporter::VisitObjCIvarDecl(ObjCIvarDecl *D) { Importer.Import(D->getInnerLocStart()), Loc, Name.getAsIdentifierInfo(), T, TInfo, D->getAccessControl(), - BitWidth, D->getSynthesize()); + BitWidth, D->getSynthesize(), + D->getBackingIvarReferencedInAccessor()); ToIvar->setLexicalDeclContext(LexicalDC); Importer.Imported(D, ToIvar); LexicalDC->addDeclInternal(ToIvar); @@ -2995,8 +3045,8 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) { if (VarDecl *FoundVar = dyn_cast<VarDecl>(FoundDecls[I])) { // We have found a variable that we may need to merge with. Check it. - if (isExternalLinkage(FoundVar->getLinkage()) && - isExternalLinkage(D->getLinkage())) { + if (FoundVar->hasExternalFormalLinkage() && + D->hasExternalFormalLinkage()) { if (Importer.IsStructurallyEquivalent(D->getType(), FoundVar->getType())) { MergeWithVar = FoundVar; @@ -3088,13 +3138,9 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) { LexicalDC->addDeclInternal(ToVar); // Merge the initializer. - // FIXME: Can we really import any initializer? Alternatively, we could force - // ourselves to import every declaration of a variable and then only use - // getInit() here. - ToVar->setInit(Importer.Import(const_cast<Expr *>(D->getAnyInitializer()))); + if (ImportDefinition(D, ToVar)) + return 0; - // FIXME: Other bits to merge? - return ToVar; } @@ -4108,6 +4154,205 @@ Decl *ASTNodeImporter::VisitClassTemplateSpecializationDecl( return D2; } +Decl *ASTNodeImporter::VisitVarTemplateDecl(VarTemplateDecl *D) { + // If this variable 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. + VarDecl *Definition = + cast_or_null<VarDecl>(D->getTemplatedDecl()->getDefinition()); + if (Definition && Definition != D->getTemplatedDecl()) { + Decl *ImportedDef = Importer.Import(Definition->getDescribedVarTemplate()); + if (!ImportedDef) + return 0; + + return Importer.Imported(D, ImportedDef); + } + + // Import the major distinguishing characteristics of this variable 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. + assert(!DC->isFunctionOrMethod() && + "Variable templates cannot be declared at function scope"); + SmallVector<NamedDecl *, 4> ConflictingDecls; + SmallVector<NamedDecl *, 2> FoundDecls; + DC->localUncachedLookup(Name, FoundDecls); + for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { + if (!FoundDecls[I]->isInIdentifierNamespace(Decl::IDNS_Ordinary)) + continue; + + Decl *Found = FoundDecls[I]; + if (VarTemplateDecl *FoundTemplate = dyn_cast<VarTemplateDecl>(Found)) { + if (IsStructuralMatch(D, FoundTemplate)) { + // The variable templates structurally match; call it the same template. + Importer.Imported(D->getTemplatedDecl(), + FoundTemplate->getTemplatedDecl()); + return Importer.Imported(D, FoundTemplate); + } + } + + ConflictingDecls.push_back(FoundDecls[I]); + } + + if (!ConflictingDecls.empty()) { + Name = Importer.HandleNameConflict(Name, DC, Decl::IDNS_Ordinary, + ConflictingDecls.data(), + ConflictingDecls.size()); + } + + if (!Name) + return 0; + + VarDecl *DTemplated = D->getTemplatedDecl(); + + // Import the type. + QualType T = Importer.Import(DTemplated->getType()); + if (T.isNull()) + return 0; + + // Create the declaration that is being templated. + SourceLocation StartLoc = Importer.Import(DTemplated->getLocStart()); + SourceLocation IdLoc = Importer.Import(DTemplated->getLocation()); + TypeSourceInfo *TInfo = Importer.Import(DTemplated->getTypeSourceInfo()); + VarDecl *D2Templated = VarDecl::Create(Importer.getToContext(), DC, StartLoc, + IdLoc, Name.getAsIdentifierInfo(), T, + TInfo, DTemplated->getStorageClass()); + D2Templated->setAccess(DTemplated->getAccess()); + D2Templated->setQualifierInfo(Importer.Import(DTemplated->getQualifierLoc())); + D2Templated->setLexicalDeclContext(LexicalDC); + + // Importer.Imported(DTemplated, D2Templated); + // LexicalDC->addDeclInternal(D2Templated); + + // Merge the initializer. + if (ImportDefinition(DTemplated, D2Templated)) + return 0; + + // Create the variable template declaration itself. + TemplateParameterList *TemplateParams = + ImportTemplateParameterList(D->getTemplateParameters()); + if (!TemplateParams) + return 0; + + VarTemplateDecl *D2 = VarTemplateDecl::Create( + Importer.getToContext(), DC, Loc, Name, TemplateParams, D2Templated, + /*PrevDecl=*/0); + D2Templated->setDescribedVarTemplate(D2); + + D2->setAccess(D->getAccess()); + D2->setLexicalDeclContext(LexicalDC); + LexicalDC->addDeclInternal(D2); + + // Note the relationship between the variable templates. + Importer.Imported(D, D2); + Importer.Imported(DTemplated, D2Templated); + + if (DTemplated->isThisDeclarationADefinition() && + !D2Templated->isThisDeclarationADefinition()) { + // FIXME: Import definition! + } + + return D2; +} + +Decl *ASTNodeImporter::VisitVarTemplateSpecializationDecl( + VarTemplateSpecializationDecl *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. + VarDecl *Definition = D->getDefinition(); + if (Definition && Definition != D) { + Decl *ImportedDef = Importer.Import(Definition); + if (!ImportedDef) + return 0; + + return Importer.Imported(D, ImportedDef); + } + + VarTemplateDecl *VarTemplate = cast_or_null<VarTemplateDecl>( + Importer.Import(D->getSpecializedTemplate())); + if (!VarTemplate) + return 0; + + // Import the context of this declaration. + DeclContext *DC = VarTemplate->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 StartLoc = Importer.Import(D->getLocStart()); + SourceLocation IdLoc = Importer.Import(D->getLocation()); + + // Import template arguments. + 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; + VarTemplateSpecializationDecl *D2 = VarTemplate->findSpecialization( + TemplateArgs.data(), TemplateArgs.size(), InsertPos); + if (D2) { + // We already have a variable template specialization with these template + // arguments. + + // FIXME: Check for specialization vs. instantiation errors. + + if (VarDecl *FoundDef = D2->getDefinition()) { + if (!D->isThisDeclarationADefinition() || + IsStructuralMatch(D, FoundDef)) { + // The record types structurally match, or the "from" translation + // unit only had a forward declaration anyway; call it the same + // variable. + return Importer.Imported(D, FoundDef); + } + } + } else { + + // Import the type. + QualType T = Importer.Import(D->getType()); + if (T.isNull()) + return 0; + TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo()); + + // Create a new specialization. + D2 = VarTemplateSpecializationDecl::Create( + Importer.getToContext(), DC, StartLoc, IdLoc, VarTemplate, T, TInfo, + D->getStorageClass(), TemplateArgs.data(), TemplateArgs.size()); + D2->setSpecializationKind(D->getSpecializationKind()); + D2->setTemplateArgsInfo(D->getTemplateArgsInfo()); + + // Add this specialization to the class template. + VarTemplate->AddSpecialization(D2, InsertPos); + + // Import the qualifier, if any. + D2->setQualifierInfo(Importer.Import(D->getQualifierLoc())); + + // Add the specialization to this context. + D2->setLexicalDeclContext(LexicalDC); + LexicalDC->addDeclInternal(D2); + } + Importer.Imported(D, D2); + + if (D->isThisDeclarationADefinition() && ImportDefinition(D, D2)) + return 0; + + return D2; +} + //---------------------------------------------------------------------------- // Import Statements //---------------------------------------------------------------------------- @@ -4406,7 +4651,7 @@ Decl *ASTImporter::Import(Decl *FromD) { } else if (TypedefNameDecl *FromTypedef = dyn_cast<TypedefNameDecl>(FromD)) { // When we've finished transforming a typedef, see whether it was the // typedef for an anonymous tag. - for (SmallVector<TagDecl *, 4>::iterator + for (SmallVectorImpl<TagDecl *>::iterator FromTag = AnonTagsWithPendingTypedefs.begin(), FromTagEnd = AnonTagsWithPendingTypedefs.end(); FromTag != FromTagEnd; ++FromTag) { diff --git a/lib/AST/ASTTypeTraits.cpp b/lib/AST/ASTTypeTraits.cpp new file mode 100644 index 0000000..ae47ea9 --- /dev/null +++ b/lib/AST/ASTTypeTraits.cpp @@ -0,0 +1,105 @@ +//===--- ASTTypeTraits.cpp --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Provides a dynamic type identifier and a dynamically typed node container +// that can be used to store an AST base node at runtime in the same storage in +// a type safe way. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ASTTypeTraits.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclCXX.h" + +namespace clang { +namespace ast_type_traits { + +const ASTNodeKind::KindInfo ASTNodeKind::AllKindInfo[] = { + { NKI_None, "<None>" }, + { NKI_None, "CXXCtorInitializer" }, + { NKI_None, "TemplateArgument" }, + { NKI_None, "NestedNameSpecifier" }, + { NKI_None, "NestedNameSpecifierLoc" }, + { NKI_None, "QualType" }, + { NKI_None, "TypeLoc" }, + { NKI_None, "Decl" }, +#define DECL(DERIVED, BASE) { NKI_##BASE, #DERIVED "Decl" }, +#include "clang/AST/DeclNodes.inc" + { NKI_None, "Stmt" }, +#define STMT(DERIVED, BASE) { NKI_##BASE, #DERIVED }, +#include "clang/AST/StmtNodes.inc" + { NKI_None, "Type" }, +#define TYPE(DERIVED, BASE) { NKI_##BASE, #DERIVED "Type" }, +#include "clang/AST/TypeNodes.def" +}; + +bool ASTNodeKind::isBaseOf(ASTNodeKind Other) const { + return isBaseOf(KindId, Other.KindId); +} + +bool ASTNodeKind::isSame(ASTNodeKind Other) const { + return KindId != NKI_None && KindId == Other.KindId; +} + +bool ASTNodeKind::isBaseOf(NodeKindId Base, NodeKindId Derived) { + if (Base == NKI_None || Derived == NKI_None) return false; + while (Derived != Base && Derived != NKI_None) + Derived = AllKindInfo[Derived].ParentId; + return Derived == Base; +} + +StringRef ASTNodeKind::asStringRef() const { return AllKindInfo[KindId].Name; } + +void DynTypedNode::print(llvm::raw_ostream &OS, + const PrintingPolicy &PP) const { + if (const TemplateArgument *TA = get<TemplateArgument>()) + TA->print(PP, OS); + else if (const NestedNameSpecifier *NNS = get<NestedNameSpecifier>()) + NNS->print(OS, PP); + else if (const NestedNameSpecifierLoc *NNSL = get<NestedNameSpecifierLoc>()) + NNSL->getNestedNameSpecifier()->print(OS, PP); + else if (const QualType *QT = get<QualType>()) + QT->print(OS, PP); + else if (const TypeLoc *TL = get<TypeLoc>()) + TL->getType().print(OS, PP); + else if (const Decl *D = get<Decl>()) + D->print(OS, PP); + else if (const Stmt *S = get<Stmt>()) + S->printPretty(OS, 0, PP); + else if (const Type *T = get<Type>()) + QualType(T, 0).print(OS, PP); + else + OS << "Unable to print values of type " << NodeKind.asStringRef() << "\n"; +} + +void DynTypedNode::dump(llvm::raw_ostream &OS, SourceManager &SM) const { + if (const Decl *D = get<Decl>()) + D->dump(OS); + else if (const Stmt *S = get<Stmt>()) + S->dump(OS, SM); + else + OS << "Unable to dump values of type " << NodeKind.asStringRef() << "\n"; +} + +SourceRange DynTypedNode::getSourceRange() const { + if (const CXXCtorInitializer *CCI = get<CXXCtorInitializer>()) + return CCI->getSourceRange(); + if (const NestedNameSpecifierLoc *NNSL = get<NestedNameSpecifierLoc>()) + return NNSL->getSourceRange(); + if (const TypeLoc *TL = get<TypeLoc>()) + return TL->getSourceRange(); + if (const Decl *D = get<Decl>()) + return D->getSourceRange(); + if (const Stmt *S = get<Stmt>()) + return S->getSourceRange(); + return SourceRange(); +} + +} // end namespace ast_type_traits +} // end namespace clang diff --git a/lib/AST/AttrImpl.cpp b/lib/AST/AttrImpl.cpp index daf65e5..7af3c8b 100644 --- a/lib/AST/AttrImpl.cpp +++ b/lib/AST/AttrImpl.cpp @@ -15,6 +15,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Expr.h" #include "clang/AST/Type.h" +#include "llvm/ADT/StringSwitch.h" using namespace clang; Attr::~Attr() { } diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt index e804fe7..461e8b3 100644 --- a/lib/AST/CMakeLists.txt +++ b/lib/AST/CMakeLists.txt @@ -7,6 +7,7 @@ add_clang_library(clangAST ASTDiagnostic.cpp ASTDumper.cpp ASTImporter.cpp + ASTTypeTraits.cpp AttrImpl.cpp CXXInheritance.cpp Comment.cpp @@ -25,7 +26,6 @@ add_clang_library(clangAST DeclOpenMP.cpp DeclPrinter.cpp DeclTemplate.cpp - DumpXML.cpp Expr.cpp ExprClassification.cpp ExprConstant.cpp @@ -34,8 +34,8 @@ add_clang_library(clangAST InheritViz.cpp ItaniumCXXABI.cpp ItaniumMangle.cpp - LambdaMangleContext.cpp Mangle.cpp + MangleNumberingContext.cpp MicrosoftCXXABI.cpp MicrosoftMangle.cpp NestedNameSpecifier.cpp diff --git a/lib/AST/CXXABI.h b/lib/AST/CXXABI.h index 6d67d9a..89203f1 100644 --- a/lib/AST/CXXABI.h +++ b/lib/AST/CXXABI.h @@ -21,6 +21,7 @@ namespace clang { class ASTContext; class MemberPointerType; +class MangleNumberingContext; /// Implements C++ ABI-specific semantic analysis functions. class CXXABI { @@ -34,9 +35,12 @@ public: /// Returns the default calling convention for C++ methods. virtual CallingConv getDefaultMethodCallConv(bool isVariadic) const = 0; - // Returns whether the given class is nearly empty, with just virtual pointers - // and no data except possibly virtual bases. + /// 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; + + /// Returns a new mangling number context for this C++ ABI. + virtual MangleNumberingContext *createMangleNumberingContext() const = 0; }; /// Creates an instance of a C++ ABI class. diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp index 0e0b35d..b51014b 100644 --- a/lib/AST/CXXInheritance.cpp +++ b/lib/AST/CXXInheritance.cpp @@ -168,9 +168,9 @@ bool CXXRecordDecl::forallBases(ForallBasesCallback *BaseMatches, } } - if (Queue.empty()) break; - Record = Queue.back(); // not actually a queue. - Queue.pop_back(); + if (Queue.empty()) + break; + Record = Queue.pop_back_val(); // not actually a queue. } return AllMatches; @@ -447,7 +447,7 @@ FindNestedNameSpecifierMember(const CXXBaseSpecifier *Specifier, void OverridingMethods::add(unsigned OverriddenSubobject, UniqueVirtualMethod Overriding) { - SmallVector<UniqueVirtualMethod, 4> &SubobjectOverrides + SmallVectorImpl<UniqueVirtualMethod> &SubobjectOverrides = Overrides[OverriddenSubobject]; if (std::find(SubobjectOverrides.begin(), SubobjectOverrides.end(), Overriding) == SubobjectOverrides.end()) @@ -650,11 +650,11 @@ CXXRecordDecl::getFinalOverriders(CXXFinalOverriderMap &FinalOverriders) const { SOEnd = OM->second.end(); SO != SOEnd; ++SO) { - SmallVector<UniqueVirtualMethod, 4> &Overriding = SO->second; + SmallVectorImpl<UniqueVirtualMethod> &Overriding = SO->second; if (Overriding.size() < 2) continue; - for (SmallVector<UniqueVirtualMethod, 4>::iterator + for (SmallVectorImpl<UniqueVirtualMethod>::iterator Pos = Overriding.begin(), PosEnd = Overriding.end(); Pos != PosEnd; /* increment in loop */) { @@ -669,7 +669,7 @@ CXXRecordDecl::getFinalOverriders(CXXFinalOverriderMap &FinalOverriders) const { // in a base class subobject that hides the virtual base class // subobject. bool Hidden = false; - for (SmallVector<UniqueVirtualMethod, 4>::iterator + for (SmallVectorImpl<UniqueVirtualMethod>::iterator OP = Overriding.begin(), OPEnd = Overriding.end(); OP != OPEnd && !Hidden; ++OP) { diff --git a/lib/AST/Comment.cpp b/lib/AST/Comment.cpp index 68c73fd..f24a23d 100644 --- a/lib/AST/Comment.cpp +++ b/lib/AST/Comment.cpp @@ -12,6 +12,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" +#include "clang/Basic/CharInfo.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" @@ -41,14 +42,16 @@ good implements_child_begin_end(Comment::child_iterator (T::*)() const) { return good(); } +LLVM_ATTRIBUTE_UNUSED static inline bad implements_child_begin_end( Comment::child_iterator (Comment::*)() const) { return bad(); } #define ASSERT_IMPLEMENTS_child_begin(function) \ - (void) sizeof(good(implements_child_begin_end(function))) + (void) good(implements_child_begin_end(function)) +LLVM_ATTRIBUTE_UNUSED static inline void CheckCommentASTNodes() { #define ABSTRACT_COMMENT(COMMENT) #define COMMENT(CLASS, PARENT) \ @@ -94,9 +97,7 @@ Comment::child_iterator Comment::child_end() const { bool TextComment::isWhitespaceNoCache() const { for (StringRef::const_iterator I = Text.begin(), E = Text.end(); I != E; ++I) { - const char C = *I; - if (C != ' ' && C != '\n' && C != '\r' && - C != '\t' && C != '\f' && C != '\v') + if (!clang::isWhitespace(*I)) return false; } return true; @@ -293,12 +294,14 @@ void DeclInfo::fill() { StringRef ParamCommandComment::getParamName(const FullComment *FC) const { assert(isParamIndexValid()); - return FC->getThisDeclInfo()->ParamVars[getParamIndex()]->getName(); + if (isVarArgParam()) + return "..."; + return FC->getDeclInfo()->ParamVars[getParamIndex()]->getName(); } StringRef TParamCommandComment::getParamName(const FullComment *FC) const { assert(isPositionValid()); - const TemplateParameterList *TPL = FC->getThisDeclInfo()->TemplateParameters; + const TemplateParameterList *TPL = FC->getDeclInfo()->TemplateParameters; for (unsigned i = 0, e = getDepth(); i != e; ++i) { if (i == e-1) return TPL->getParam(getIndex(i))->getName(); diff --git a/lib/AST/CommentCommandTraits.cpp b/lib/AST/CommentCommandTraits.cpp index e24d542..01bd12e 100644 --- a/lib/AST/CommentCommandTraits.cpp +++ b/lib/AST/CommentCommandTraits.cpp @@ -43,6 +43,49 @@ const CommandInfo *CommandTraits::getCommandInfo(unsigned CommandID) const { return getRegisteredCommandInfo(CommandID); } +static void +HelperTypoCorrectCommandInfo(SmallVectorImpl<const CommandInfo *> &BestCommand, + StringRef Typo, const CommandInfo *Command) { + const unsigned MaxEditDistance = 1; + unsigned BestEditDistance = MaxEditDistance + 1; + StringRef Name = Command->Name; + + unsigned MinPossibleEditDistance = abs((int)Name.size() - (int)Typo.size()); + if (MinPossibleEditDistance > 0 && + Typo.size() / MinPossibleEditDistance < 1) + return; + unsigned EditDistance = Typo.edit_distance(Name, true, MaxEditDistance); + if (EditDistance > MaxEditDistance) + return; + if (EditDistance == BestEditDistance) + BestCommand.push_back(Command); + else if (EditDistance < BestEditDistance) { + BestCommand.clear(); + BestCommand.push_back(Command); + BestEditDistance = EditDistance; + } +} + +const CommandInfo * +CommandTraits::getTypoCorrectCommandInfo(StringRef Typo) const { + // single character command impostures, such as \t or \n must not go + // through the fixit logic. + if (Typo.size() <= 1) + return NULL; + + SmallVector<const CommandInfo *, 2> BestCommand; + + const int NumOfCommands = llvm::array_lengthof(Commands); + for (int i = 0; i < NumOfCommands; i++) + HelperTypoCorrectCommandInfo(BestCommand, Typo, &Commands[i]); + + for (unsigned i = 0, e = RegisteredCommands.size(); i != e; ++i) + if (!RegisteredCommands[i]->IsUnknownCommand) + HelperTypoCorrectCommandInfo(BestCommand, Typo, RegisteredCommands[i]); + + return (BestCommand.size() != 1) ? NULL : BestCommand[0]; +} + CommandInfo *CommandTraits::createCommandInfoWithName(StringRef CommandName) { char *Name = Allocator.Allocate<char>(CommandName.size() + 1); memcpy(Name, CommandName.data(), CommandName.size()); diff --git a/lib/AST/CommentLexer.cpp b/lib/AST/CommentLexer.cpp index 70410d6..01ed3ce 100644 --- a/lib/AST/CommentLexer.cpp +++ b/lib/AST/CommentLexer.cpp @@ -157,7 +157,7 @@ const char *skipDecimalCharacterReference(const char *BufferPtr, } const char *skipHexCharacterReference(const char *BufferPtr, - const char *BufferEnd) { + const char *BufferEnd) { for ( ; BufferPtr != BufferEnd; ++BufferPtr) { if (!isHTMLHexCharacterReferenceCharacter(*BufferPtr)) return BufferPtr; @@ -265,6 +265,7 @@ const char *findCCommentEnd(const char *BufferPtr, const char *BufferEnd) { } llvm_unreachable("buffer end hit before '*/' was seen"); } + } // unnamed namespace void Lexer::lexCommentText(Token &T) { @@ -352,10 +353,20 @@ void Lexer::lexCommentText(Token &T) { const CommandInfo *Info = Traits.getCommandInfoOrNULL(CommandName); if (!Info) { - formTokenWithChars(T, TokenPtr, tok::unknown_command); - T.setUnknownCommandName(CommandName); - Diag(T.getLocation(), diag::warn_unknown_comment_command_name); - return; + if ((Info = Traits.getTypoCorrectCommandInfo(CommandName))) { + StringRef CorrectedName = Info->Name; + SourceLocation Loc = getSourceLocation(BufferPtr); + SourceRange CommandRange(Loc.getLocWithOffset(1), + getSourceLocation(TokenPtr)); + Diag(Loc, diag::warn_correct_comment_command_name) + << CommandName << CorrectedName + << FixItHint::CreateReplacement(CommandRange, CorrectedName); + } else { + formTokenWithChars(T, TokenPtr, tok::unknown_command); + T.setUnknownCommandName(CommandName); + Diag(T.getLocation(), diag::warn_unknown_comment_command_name); + return; + } } if (Info->IsVerbatimBlockCommand) { setupAndLexVerbatimBlock(T, TokenPtr, *BufferPtr, Info); diff --git a/lib/AST/CommentParser.cpp b/lib/AST/CommentParser.cpp index d89c79b..03e0101 100644 --- a/lib/AST/CommentParser.cpp +++ b/lib/AST/CommentParser.cpp @@ -16,6 +16,15 @@ #include "llvm/Support/ErrorHandling.h" namespace clang { + +static inline bool isWhitespace(llvm::StringRef S) { + for (StringRef::const_iterator I = S.begin(), E = S.end(); I != E; ++I) { + if (!isWhitespace(*I)) + return false; + } + return true; +} + namespace comments { /// Re-lexes a sequence of tok::text tokens. @@ -594,6 +603,18 @@ BlockContentComment *Parser::parseParagraphOrBlockCommand() { consumeToken(); break; // Two newlines -- end of paragraph. } + // Also allow [tok::newline, tok::text, tok::newline] if the middle + // tok::text is just whitespace. + if (Tok.is(tok::text) && isWhitespace(Tok.getText())) { + Token WhitespaceTok = Tok; + consumeToken(); + if (Tok.is(tok::newline) || Tok.is(tok::eof)) { + consumeToken(); + break; + } + // We have [tok::newline, tok::text, non-newline]. Put back tok::text. + putBack(WhitespaceTok); + } if (Content.size() > 0) Content.back()->addTrailingNewline(); continue; diff --git a/lib/AST/CommentSema.cpp b/lib/AST/CommentSema.cpp index e0138d5..1c6222f 100644 --- a/lib/AST/CommentSema.cpp +++ b/lib/AST/CommentSema.cpp @@ -29,8 +29,7 @@ Sema::Sema(llvm::BumpPtrAllocator &Allocator, const SourceManager &SourceMgr, DiagnosticsEngine &Diags, CommandTraits &Traits, const Preprocessor *PP) : Allocator(Allocator), SourceMgr(SourceMgr), Diags(Diags), Traits(Traits), - PP(PP), ThisDeclInfo(NULL), BriefCommand(NULL), ReturnsCommand(NULL), - HeaderfileCommand(NULL) { + PP(PP), ThisDeclInfo(NULL), BriefCommand(NULL), HeaderfileCommand(NULL) { } void Sema::setDecl(const Decl *D) { @@ -99,10 +98,10 @@ void Sema::checkFunctionDeclVerbatimLine(const BlockCommandComment *Comment) { unsigned DiagSelect; switch (Comment->getCommandID()) { case CommandTraits::KCI_function: - DiagSelect = !isAnyFunctionDecl() ? 1 : 0; + DiagSelect = (!isAnyFunctionDecl() && !isFunctionTemplateDecl())? 1 : 0; break; case CommandTraits::KCI_functiongroup: - DiagSelect = !isAnyFunctionDecl() ? 2 : 0; + DiagSelect = (!isAnyFunctionDecl() && !isFunctionTemplateDecl())? 2 : 0; break; case CommandTraits::KCI_method: DiagSelect = !isObjCMethodDecl() ? 3 : 0; @@ -131,7 +130,12 @@ void Sema::checkContainerDeclVerbatimLine(const BlockCommandComment *Comment) { unsigned DiagSelect; switch (Comment->getCommandID()) { case CommandTraits::KCI_class: - DiagSelect = !isClassOrStructDecl() ? 1 : 0; + DiagSelect = (!isClassOrStructDecl() && !isClassTemplateDecl()) ? 1 : 0; + // Allow @class command on @interface declarations. + // FIXME. Currently, \class and @class are indistinguishable. So, + // \class is also allowed on an @interface declaration + if (DiagSelect && Comment->getCommandMarker() && isObjCInterfaceDecl()) + DiagSelect = 0; break; case CommandTraits::KCI_interface: DiagSelect = !isObjCInterfaceDecl() ? 2 : 0; @@ -206,59 +210,43 @@ void Sema::checkContainerDecl(const BlockCommandComment *Comment) { << Comment->getSourceRange(); } +/// \brief Turn a string into the corresponding PassDirection or -1 if it's not +/// valid. +static int getParamPassDirection(StringRef Arg) { + return llvm::StringSwitch<int>(Arg) + .Case("[in]", ParamCommandComment::In) + .Case("[out]", ParamCommandComment::Out) + .Cases("[in,out]", "[out,in]", ParamCommandComment::InOut) + .Default(-1); +} + void Sema::actOnParamCommandDirectionArg(ParamCommandComment *Command, SourceLocation ArgLocBegin, SourceLocation ArgLocEnd, StringRef Arg) { - ParamCommandComment::PassDirection Direction; std::string ArgLower = Arg.lower(); - // TODO: optimize: lower Name first (need an API in SmallString for that), - // after that StringSwitch. - if (ArgLower == "[in]") - Direction = ParamCommandComment::In; - else if (ArgLower == "[out]") - Direction = ParamCommandComment::Out; - else if (ArgLower == "[in,out]" || ArgLower == "[out,in]") - Direction = ParamCommandComment::InOut; - else { - // Remove spaces. - std::string::iterator O = ArgLower.begin(); - for (std::string::iterator I = ArgLower.begin(), E = ArgLower.end(); - I != E; ++I) { - const char C = *I; - if (C != ' ' && C != '\n' && C != '\r' && - C != '\t' && C != '\v' && C != '\f') - *O++ = C; - } - ArgLower.resize(O - ArgLower.begin()); - - bool RemovingWhitespaceHelped = false; - if (ArgLower == "[in]") { - Direction = ParamCommandComment::In; - RemovingWhitespaceHelped = true; - } else if (ArgLower == "[out]") { - Direction = ParamCommandComment::Out; - RemovingWhitespaceHelped = true; - } else if (ArgLower == "[in,out]" || ArgLower == "[out,in]") { - Direction = ParamCommandComment::InOut; - RemovingWhitespaceHelped = true; - } else { - Direction = ParamCommandComment::In; - RemovingWhitespaceHelped = false; - } + int Direction = getParamPassDirection(ArgLower); + + if (Direction == -1) { + // Try again with whitespace removed. + ArgLower.erase( + std::remove_if(ArgLower.begin(), ArgLower.end(), clang::isWhitespace), + ArgLower.end()); + Direction = getParamPassDirection(ArgLower); SourceRange ArgRange(ArgLocBegin, ArgLocEnd); - if (RemovingWhitespaceHelped) + if (Direction != -1) { + const char *FixedName = ParamCommandComment::getDirectionAsString( + (ParamCommandComment::PassDirection)Direction); Diag(ArgLocBegin, diag::warn_doc_param_spaces_in_direction) - << ArgRange - << FixItHint::CreateReplacement( - ArgRange, - ParamCommandComment::getDirectionAsString(Direction)); - else - Diag(ArgLocBegin, diag::warn_doc_param_invalid_direction) - << ArgRange; + << ArgRange << FixItHint::CreateReplacement(ArgRange, FixedName); + } else { + Diag(ArgLocBegin, diag::warn_doc_param_invalid_direction) << ArgRange; + Direction = ParamCommandComment::In; // Sane fall back. + } } - Command->setDirection(Direction, /* Explicit = */ true); + Command->setDirection((ParamCommandComment::PassDirection)Direction, + /*Explicit=*/true); } void Sema::actOnParamCommandParamNameArg(ParamCommandComment *Command, @@ -326,17 +314,15 @@ void Sema::actOnTParamCommandParamNameArg(TParamCommandComment *Command, SmallVector<unsigned, 2> Position; if (resolveTParamReference(Arg, TemplateParameters, &Position)) { Command->setPosition(copyArray(llvm::makeArrayRef(Position))); - llvm::StringMap<TParamCommandComment *>::iterator PrevCommandIt = - TemplateParameterDocs.find(Arg); - if (PrevCommandIt != TemplateParameterDocs.end()) { + TParamCommandComment *&PrevCommand = TemplateParameterDocs[Arg]; + if (PrevCommand) { SourceRange ArgRange(ArgLocBegin, ArgLocEnd); Diag(ArgLocBegin, diag::warn_doc_tparam_duplicate) << Arg << ArgRange; - TParamCommandComment *PrevCommand = PrevCommandIt->second; Diag(PrevCommand->getLocation(), diag::note_doc_tparam_previous) << PrevCommand->getParamNameRange(); } - TemplateParameterDocs[Arg] = Command; + PrevCommand = Command; return; } @@ -511,8 +497,7 @@ HTMLEndTagComment *Sema::actOnHTMLEndTag(SourceLocation LocBegin, } while (!HTMLOpenTags.empty()) { - const HTMLStartTagComment *HST = HTMLOpenTags.back(); - HTMLOpenTags.pop_back(); + const HTMLStartTagComment *HST = HTMLOpenTags.pop_back_val(); StringRef LastNotClosedTagName = HST->getTagName(); if (LastNotClosedTagName == TagName) break; @@ -618,12 +603,6 @@ void Sema::checkBlockCommandDuplicate(const BlockCommandComment *Command) { return; } PrevCommand = BriefCommand; - } else if (Info->IsReturnsCommand) { - if (!ReturnsCommand) { - ReturnsCommand = Command; - return; - } - PrevCommand = ReturnsCommand; } else if (Info->IsHeaderfileCommand) { if (!HeaderfileCommand) { HeaderfileCommand = Command; @@ -728,6 +707,10 @@ void Sema::resolveParamCommandIndexes(const FullComment *FC) { // Check that referenced parameter name is in the function decl. const unsigned ResolvedParamIndex = resolveParmVarReference(ParamName, ParamVars); + if (ResolvedParamIndex == ParamCommandComment::VarArgParamIndex) { + PCC->setIsVarArgParam(); + continue; + } if (ResolvedParamIndex == ParamCommandComment::InvalidParamIndex) { UnresolvedParamCommands.push_back(PCC); continue; @@ -798,14 +781,24 @@ bool Sema::isAnyFunctionDecl() { return isFunctionDecl() && ThisDeclInfo->CurrentDecl && isa<FunctionDecl>(ThisDeclInfo->CurrentDecl); } - + +bool Sema::isFunctionOrMethodVariadic() { + if (!isAnyFunctionDecl() && !isObjCMethodDecl()) + return false; + if (const FunctionDecl *FD = + dyn_cast<FunctionDecl>(ThisDeclInfo->CurrentDecl)) + return FD->isVariadic(); + if (const ObjCMethodDecl *MD = + dyn_cast<ObjCMethodDecl>(ThisDeclInfo->CurrentDecl)) + return MD->isVariadic(); + return false; +} + bool Sema::isObjCMethodDecl() { return isFunctionDecl() && ThisDeclInfo->CurrentDecl && isa<ObjCMethodDecl>(ThisDeclInfo->CurrentDecl); } - -/// isFunctionPointerVarDecl - returns 'true' if declaration is a pointer to -/// function decl. + bool Sema::isFunctionPointerVarDecl() { if (!ThisDeclInfo) return false; @@ -865,6 +858,24 @@ bool Sema::isClassOrStructDecl() { isa<RecordDecl>(ThisDeclInfo->CurrentDecl) && !isUnionDecl(); } + +bool Sema::isClassTemplateDecl() { + if (!ThisDeclInfo) + return false; + if (!ThisDeclInfo->IsFilled) + inspectThisDecl(); + return ThisDeclInfo->CurrentDecl && + (isa<ClassTemplateDecl>(ThisDeclInfo->CurrentDecl)); +} + +bool Sema::isFunctionTemplateDecl() { + if (!ThisDeclInfo) + return false; + if (!ThisDeclInfo->IsFilled) + inspectThisDecl(); + return ThisDeclInfo->CurrentDecl && + (isa<FunctionTemplateDecl>(ThisDeclInfo->CurrentDecl)); +} bool Sema::isObjCInterfaceDecl() { if (!ThisDeclInfo) @@ -901,6 +912,8 @@ unsigned Sema::resolveParmVarReference(StringRef Name, if (II && II->getName() == Name) return i; } + if (Name == "..." && isFunctionOrMethodVariadic()) + return ParamCommandComment::VarArgParamIndex; return ParamCommandComment::InvalidParamIndex; } diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index ab9d73b..6bd9858 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -34,6 +34,10 @@ using namespace clang; +Decl *clang::getPrimaryMergedDecl(Decl *D) { + return D->getASTContext().getPrimaryMergedDecl(D); +} + //===----------------------------------------------------------------------===// // NamedDecl Implementation //===----------------------------------------------------------------------===// @@ -85,6 +89,7 @@ using namespace clang; // and settings from the immediate context. const unsigned IgnoreExplicitVisibilityBit = 2; +const unsigned IgnoreAllVisibilityBit = 4; /// Kinds of LV computation. The linkage side of the computation is /// always the same, but different things can change how visibility is @@ -108,7 +113,11 @@ enum LVComputationKind { /// Do an LV computation for, ultimately, a non-type declaration /// that already has some sort of explicit visibility. Visibility /// may only be restricted by the visibility of template arguments. - LVForExplicitValue = (LVForValue | IgnoreExplicitVisibilityBit) + LVForExplicitValue = (LVForValue | IgnoreExplicitVisibilityBit), + + /// Do an LV computation when we only care about the linkage. + LVForLinkageOnly = + LVForValue | IgnoreExplicitVisibilityBit | IgnoreAllVisibilityBit }; /// Does this computation kind permit us to consider additional @@ -211,11 +220,19 @@ static Optional<Visibility> getVisibilityOf(const NamedDecl *D, return None; } +static LinkageInfo +getLVForType(const Type &T, LVComputationKind computation) { + if (computation == LVForLinkageOnly) + return LinkageInfo(T.getLinkage(), DefaultVisibility, true); + return T.getLinkageAndVisibility(); +} + /// \brief Get the most restrictive linkage for the types in the given /// template parameter list. For visibility purposes, template /// parameters are part of the signature of a template. static LinkageInfo -getLVForTemplateParameterList(const TemplateParameterList *params) { +getLVForTemplateParameterList(const TemplateParameterList *params, + LVComputationKind computation) { LinkageInfo LV; for (TemplateParameterList::const_iterator P = params->begin(), PEnd = params->end(); @@ -234,7 +251,7 @@ getLVForTemplateParameterList(const TemplateParameterList *params) { // Handle the non-pack case first. if (!NTTP->isExpandedParameterPack()) { if (!NTTP->getType()->isDependentType()) { - LV.merge(NTTP->getType()->getLinkageAndVisibility()); + LV.merge(getLVForType(*NTTP->getType(), computation)); } continue; } @@ -254,7 +271,8 @@ getLVForTemplateParameterList(const TemplateParameterList *params) { // Handle the non-pack case first. if (!TTP->isExpandedParameterPack()) { - LV.merge(getLVForTemplateParameterList(TTP->getTemplateParameters())); + LV.merge(getLVForTemplateParameterList(TTP->getTemplateParameters(), + computation)); continue; } @@ -262,7 +280,7 @@ getLVForTemplateParameterList(const TemplateParameterList *params) { for (unsigned i = 0, n = TTP->getNumExpansionTemplateParameters(); i != n; ++i) { LV.merge(getLVForTemplateParameterList( - TTP->getExpansionTemplateParameters(i))); + TTP->getExpansionTemplateParameters(i), computation)); } } @@ -273,13 +291,25 @@ getLVForTemplateParameterList(const TemplateParameterList *params) { static LinkageInfo getLVForDecl(const NamedDecl *D, LVComputationKind computation); +static const Decl *getOutermostFuncOrBlockContext(const Decl *D) { + const Decl *Ret = NULL; + const DeclContext *DC = D->getDeclContext(); + while (DC->getDeclKind() != Decl::TranslationUnit) { + if (isa<FunctionDecl>(DC) || isa<BlockDecl>(DC)) + Ret = cast<Decl>(DC); + DC = DC->getParent(); + } + return Ret; +} + /// \brief Get the most restrictive linkage for the types and /// declarations in the given template argument list. /// /// Note that we don't take an LVComputationKind because we always /// want to honor the visibility of template arguments in the same way. static LinkageInfo -getLVForTemplateArgumentList(ArrayRef<TemplateArgument> args) { +getLVForTemplateArgumentList(ArrayRef<TemplateArgument> args, + LVComputationKind computation) { LinkageInfo LV; for (unsigned i = 0, e = args.size(); i != e; ++i) { @@ -291,13 +321,13 @@ getLVForTemplateArgumentList(ArrayRef<TemplateArgument> args) { continue; case TemplateArgument::Type: - LV.merge(arg.getAsType()->getLinkageAndVisibility()); + LV.merge(getLVForType(*arg.getAsType(), computation)); continue; case TemplateArgument::Declaration: if (NamedDecl *ND = dyn_cast<NamedDecl>(arg.getAsDecl())) { assert(!usesTypeVisibility(ND)); - LV.merge(getLVForDecl(ND, LVForValue)); + LV.merge(getLVForDecl(ND, computation)); } continue; @@ -309,11 +339,11 @@ getLVForTemplateArgumentList(ArrayRef<TemplateArgument> args) { case TemplateArgument::TemplateExpansion: if (TemplateDecl *Template = arg.getAsTemplateOrTemplatePattern().getAsTemplateDecl()) - LV.merge(getLVForDecl(Template, LVForValue)); + LV.merge(getLVForDecl(Template, computation)); continue; case TemplateArgument::Pack: - LV.merge(getLVForTemplateArgumentList(arg.getPackAsArray())); + LV.merge(getLVForTemplateArgumentList(arg.getPackAsArray(), computation)); continue; } llvm_unreachable("bad template argument kind"); @@ -323,8 +353,9 @@ getLVForTemplateArgumentList(ArrayRef<TemplateArgument> args) { } static LinkageInfo -getLVForTemplateArgumentList(const TemplateArgumentList &TArgs) { - return getLVForTemplateArgumentList(TArgs.asArray()); +getLVForTemplateArgumentList(const TemplateArgumentList &TArgs, + LVComputationKind computation) { + return getLVForTemplateArgumentList(TArgs.asArray(), computation); } static bool shouldConsiderTemplateVisibility(const FunctionDecl *fn, @@ -348,19 +379,20 @@ static bool shouldConsiderTemplateVisibility(const FunctionDecl *fn, /// \param[out] LV the computation to use for the parent static void mergeTemplateLV(LinkageInfo &LV, const FunctionDecl *fn, - const FunctionTemplateSpecializationInfo *specInfo) { + const FunctionTemplateSpecializationInfo *specInfo, + LVComputationKind computation) { bool considerVisibility = shouldConsiderTemplateVisibility(fn, specInfo); // Merge information from the template parameters. FunctionTemplateDecl *temp = specInfo->getTemplate(); LinkageInfo tempLV = - getLVForTemplateParameterList(temp->getTemplateParameters()); + getLVForTemplateParameterList(temp->getTemplateParameters(), computation); LV.mergeMaybeWithVisibility(tempLV, considerVisibility); // Merge information from the template arguments. const TemplateArgumentList &templateArgs = *specInfo->TemplateArguments; - LinkageInfo argsLV = getLVForTemplateArgumentList(templateArgs); + LinkageInfo argsLV = getLVForTemplateArgumentList(templateArgs, computation); LV.mergeMaybeWithVisibility(argsLV, considerVisibility); } @@ -379,6 +411,8 @@ static bool hasDirectVisibilityAttribute(const NamedDecl *D, if (D->hasAttr<VisibilityAttr>()) return true; return false; + case LVForLinkageOnly: + return false; } llvm_unreachable("bad visibility computation kind"); } @@ -431,7 +465,7 @@ static void mergeTemplateLV(LinkageInfo &LV, ClassTemplateDecl *temp = spec->getSpecializedTemplate(); LinkageInfo tempLV = - getLVForTemplateParameterList(temp->getTemplateParameters()); + getLVForTemplateParameterList(temp->getTemplateParameters(), computation); LV.mergeMaybeWithVisibility(tempLV, considerVisibility && !hasExplicitVisibilityAlready(computation)); @@ -439,8 +473,10 @@ static void mergeTemplateLV(LinkageInfo &LV, // template-argument visibility if we've got an explicit // instantiation with a visibility attribute. const TemplateArgumentList &templateArgs = spec->getTemplateArgs(); - LinkageInfo argsLV = getLVForTemplateArgumentList(templateArgs); - LV.mergeMaybeWithVisibility(argsLV, considerVisibility); + LinkageInfo argsLV = getLVForTemplateArgumentList(templateArgs, computation); + if (considerVisibility) + LV.mergeVisibility(argsLV); + LV.mergeExternalVisibility(argsLV); } static bool useInlineVisibilityHidden(const NamedDecl *D) { @@ -472,7 +508,7 @@ static bool useInlineVisibilityHidden(const NamedDecl *D) { } template <typename T> static bool isFirstInExternCContext(T *D) { - const T *First = D->getFirstDeclaration(); + const T *First = D->getFirstDecl(); return First->isInExternCContext(); } @@ -508,7 +544,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, !Var->getType().isVolatileQualified()) { const VarDecl *PrevVar = Var->getPreviousDecl(); if (PrevVar) - return PrevVar->getLinkageAndVisibility(); + return getLVForDecl(PrevVar, computation); if (Var->getStorageClass() != SC_Extern && Var->getStorageClass() != SC_PrivateExtern && @@ -539,11 +575,10 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, // Explicitly declared static. if (Function->getCanonicalDecl()->getStorageClass() == SC_Static) 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 LinkageInfo::internal(); } + // - a data member of an anonymous union. + assert(!isa<IndirectFieldDecl>(D) && "Didn't expect an IndirectFieldDecl!"); + assert(!isa<FieldDecl>(D) && "Didn't expect a FieldDecl!"); if (D->isInAnonymousNamespace()) { const VarDecl *Var = dyn_cast<VarDecl>(D); @@ -627,7 +662,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, // Note that we don't want to make the variable non-external // because of this, but unique-external linkage suits us. if (Context.getLangOpts().CPlusPlus && !isFirstInExternCContext(Var)) { - LinkageInfo TypeLV = Var->getType()->getLinkageAndVisibility(); + LinkageInfo TypeLV = getLVForType(*Var->getType(), computation); if (TypeLV.getLinkage() != ExternalLinkage) return LinkageInfo::uniqueExternal(); if (!LV.isVisibilityExplicit()) @@ -660,16 +695,27 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, // this translation unit. However, we should use the C linkage // rules instead for extern "C" declarations. if (Context.getLangOpts().CPlusPlus && - !Function->isInExternCContext() && - Function->getType()->getLinkage() == UniqueExternalLinkage) - return LinkageInfo::uniqueExternal(); + !Function->isInExternCContext()) { + // Only look at the type-as-written. If this function has an auto-deduced + // return type, we can't compute the linkage of that type because it could + // require looking at the linkage of this function, and we don't need this + // for correctness because the type is not part of the function's + // signature. + // FIXME: This is a hack. We should be able to solve this circularity and + // the one in getLVForClassMember for Functions some other way. + QualType TypeAsWritten = Function->getType(); + if (TypeSourceInfo *TSI = Function->getTypeSourceInfo()) + TypeAsWritten = TSI->getType(); + if (TypeAsWritten->getLinkage() == UniqueExternalLinkage) + return LinkageInfo::uniqueExternal(); + } // Consider LV from the template and the template arguments. // We're at file scope, so we do not need to worry about nested // specializations. if (FunctionTemplateSpecializationInfo *specInfo = Function->getTemplateSpecializationInfo()) { - mergeTemplateLV(LV, Function, specInfo); + mergeTemplateLV(LV, Function, specInfo, computation); } // - a named class (Clause 9), or an unnamed class defined in a @@ -695,7 +741,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, } else if (isa<EnumConstantDecl>(D)) { LinkageInfo EnumLV = getLVForDecl(cast<NamedDecl>(D->getDeclContext()), computation); - if (!isExternalLinkage(EnumLV.getLinkage())) + if (!isExternalFormalLinkage(EnumLV.getLinkage())) return LinkageInfo::none(); LV.merge(EnumLV); @@ -704,7 +750,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, } else if (const TemplateDecl *temp = dyn_cast<TemplateDecl>(D)) { bool considerVisibility = !hasExplicitVisibilityAlready(computation); LinkageInfo tempLV = - getLVForTemplateParameterList(temp->getTemplateParameters()); + getLVForTemplateParameterList(temp->getTemplateParameters(), computation); LV.mergeMaybeWithVisibility(tempLV, considerVisibility); // - a namespace (7.3), unless it is declared within an unnamed @@ -739,6 +785,7 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, if (!(isa<CXXMethodDecl>(D) || isa<VarDecl>(D) || isa<FieldDecl>(D) || + isa<IndirectFieldDecl>(D) || isa<TagDecl>(D))) return LinkageInfo::none(); @@ -766,13 +813,14 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, LinkageInfo classLV = getLVForDecl(cast<RecordDecl>(D->getDeclContext()), classComputation); - if (!isExternalLinkage(classLV.getLinkage())) - return LinkageInfo::none(); - // If the class already has unique-external linkage, we can't improve. if (classLV.getLinkage() == UniqueExternalLinkage) return LinkageInfo::uniqueExternal(); + if (!isExternallyVisible(classLV.getLinkage())) + return LinkageInfo::none(); + + // Otherwise, don't merge in classLV yet, because in certain cases // we need to completely ignore the visibility from it. @@ -782,14 +830,25 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) { // 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(); - + // But only look at the type-as-written. If this function has an auto-deduced + // return type, we can't compute the linkage of that type because it could + // require looking at the linkage of this function, and we don't need this + // for correctness because the type is not part of the function's + // signature. + // FIXME: This is a hack. We should be able to solve this circularity and the + // one in getLVForNamespaceScopeDecl for Functions some other way. + { + QualType TypeAsWritten = MD->getType(); + if (TypeSourceInfo *TSI = MD->getTypeSourceInfo()) + TypeAsWritten = TSI->getType(); + if (TypeAsWritten->getLinkage() == UniqueExternalLinkage) + return LinkageInfo::uniqueExternal(); + } // If this is a method template specialization, use the linkage for // the template parameters and arguments. if (FunctionTemplateSpecializationInfo *spec = MD->getTemplateSpecializationInfo()) { - mergeTemplateLV(LV, MD, spec); + mergeTemplateLV(LV, MD, spec, computation); if (spec->isExplicitSpecialization()) { explicitSpecSuppressor = MD; } else if (isExplicitMemberSpecialization(spec->getTemplate())) { @@ -819,9 +878,10 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, } 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. - LinkageInfo typeLV = VD->getType()->getLinkageAndVisibility(); - LV.mergeMaybeWithVisibility(typeLV, - !LV.isVisibilityExplicit() && !classLV.isVisibilityExplicit()); + LinkageInfo typeLV = getLVForType(*VD->getType(), computation); + if (!LV.isVisibilityExplicit() && !classLV.isVisibilityExplicit()) + LV.mergeVisibility(typeLV); + LV.mergeExternalVisibility(typeLV); if (isExplicitMemberSpecialization(VD)) { explicitSpecSuppressor = VD; @@ -834,7 +894,7 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, !classLV.isVisibilityExplicit() && !hasExplicitVisibilityAlready(computation)); LinkageInfo tempLV = - getLVForTemplateParameterList(temp->getTemplateParameters()); + getLVForTemplateParameterList(temp->getTemplateParameters(), computation); LV.mergeMaybeWithVisibility(tempLV, considerVisibility); if (const RedeclarableTemplateDecl *redeclTemp = @@ -866,81 +926,42 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, void NamedDecl::anchor() { } +static LinkageInfo computeLVForDecl(const NamedDecl *D, + LVComputationKind computation); + bool NamedDecl::isLinkageValid() const { - if (!HasCachedLinkage) + if (!hasCachedLinkage()) return true; - return getLVForDecl(this, LVForExplicitValue).getLinkage() == - Linkage(CachedLinkage); + return computeLVForDecl(this, LVForLinkageOnly).getLinkage() == + getCachedLinkage(); } -Linkage NamedDecl::getLinkage() const { - if (HasCachedLinkage) - return Linkage(CachedLinkage); - +Linkage NamedDecl::getLinkageInternal() const { // We don't care about visibility here, so ask for the cheapest // possible visibility analysis. - CachedLinkage = getLVForDecl(this, LVForExplicitValue).getLinkage(); - HasCachedLinkage = 1; - -#ifndef NDEBUG - verifyLinkage(); -#endif - - return Linkage(CachedLinkage); + return getLVForDecl(this, LVForLinkageOnly).getLinkage(); } LinkageInfo NamedDecl::getLinkageAndVisibility() const { LVComputationKind computation = (usesTypeVisibility(this) ? LVForType : LVForValue); - LinkageInfo LI = getLVForDecl(this, computation); - if (HasCachedLinkage) { - assert(Linkage(CachedLinkage) == LI.getLinkage()); - return LI; - } - HasCachedLinkage = 1; - CachedLinkage = LI.getLinkage(); - -#ifndef NDEBUG - verifyLinkage(); -#endif - - return LI; + return getLVForDecl(this, computation); } -void NamedDecl::verifyLinkage() const { - // In C (because of gnu inline) and in c++ with microsoft extensions an - // static can follow an extern, so we can have two decls with different - // linkages. - const LangOptions &Opts = getASTContext().getLangOpts(); - if (!Opts.CPlusPlus || Opts.MicrosoftExt) - return; - - // We have just computed the linkage for this decl. By induction we know - // that all other computed linkages match, check that the one we just computed - // also does. - NamedDecl *D = NULL; - for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) { - NamedDecl *T = cast<NamedDecl>(*I); - if (T == this) - continue; - if (T->HasCachedLinkage != 0) { - D = T; - break; - } - } - assert(!D || D->CachedLinkage == CachedLinkage); -} +static Optional<Visibility> +getExplicitVisibilityAux(const NamedDecl *ND, + NamedDecl::ExplicitVisibilityKind kind, + bool IsMostRecent) { + assert(!IsMostRecent || ND == ND->getMostRecentDecl()); -Optional<Visibility> -NamedDecl::getExplicitVisibility(ExplicitVisibilityKind kind) const { // Check the declaration itself first. - if (Optional<Visibility> V = getVisibilityOf(this, kind)) + if (Optional<Visibility> V = getVisibilityOf(ND, kind)) return V; // If this is a member class of a specialization of a class template // and the corresponding decl has explicit visibility, use that. - if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(this)) { + if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(ND)) { CXXRecordDecl *InstantiatedFrom = RD->getInstantiatedFromMemberClass(); if (InstantiatedFrom) return getVisibilityOf(InstantiatedFrom, kind); @@ -950,16 +971,18 @@ NamedDecl::getExplicitVisibility(ExplicitVisibilityKind kind) const { // specialization of a class template, check for visibility // on the pattern. if (const ClassTemplateSpecializationDecl *spec - = dyn_cast<ClassTemplateSpecializationDecl>(this)) + = dyn_cast<ClassTemplateSpecializationDecl>(ND)) return getVisibilityOf(spec->getSpecializedTemplate()->getTemplatedDecl(), kind); // Use the most recent declaration. - const NamedDecl *MostRecent = cast<NamedDecl>(this->getMostRecentDecl()); - if (MostRecent != this) - return MostRecent->getExplicitVisibility(kind); + if (!IsMostRecent && !isa<NamespaceDecl>(ND)) { + const NamedDecl *MostRecent = ND->getMostRecentDecl(); + if (MostRecent != ND) + return getExplicitVisibilityAux(MostRecent, kind, true); + } - if (const VarDecl *Var = dyn_cast<VarDecl>(this)) { + if (const VarDecl *Var = dyn_cast<VarDecl>(ND)) { if (Var->isStaticDataMember()) { VarDecl *InstantiatedFrom = Var->getInstantiatedFromStaticDataMember(); if (InstantiatedFrom) @@ -969,7 +992,7 @@ NamedDecl::getExplicitVisibility(ExplicitVisibilityKind kind) const { return None; } // Also handle function template specializations. - if (const FunctionDecl *fn = dyn_cast<FunctionDecl>(this)) { + if (const FunctionDecl *fn = dyn_cast<FunctionDecl>(ND)) { // If the function is a specialization of a template with an // explicit visibility attribute, use that. if (FunctionTemplateSpecializationInfo *templateInfo @@ -987,12 +1010,33 @@ NamedDecl::getExplicitVisibility(ExplicitVisibilityKind kind) const { } // The visibility of a template is stored in the templated decl. - if (const TemplateDecl *TD = dyn_cast<TemplateDecl>(this)) + if (const TemplateDecl *TD = dyn_cast<TemplateDecl>(ND)) return getVisibilityOf(TD->getTemplatedDecl(), kind); return None; } +Optional<Visibility> +NamedDecl::getExplicitVisibility(ExplicitVisibilityKind kind) const { + return getExplicitVisibilityAux(this, kind, false); +} + +static LinkageInfo getLVForClosure(const DeclContext *DC, Decl *ContextDecl, + LVComputationKind computation) { + // This lambda has its linkage/visibility determined by its owner. + if (ContextDecl) { + if (isa<ParmVarDecl>(ContextDecl)) + DC = ContextDecl->getDeclContext()->getRedeclContext(); + else + return getLVForDecl(cast<NamedDecl>(ContextDecl), computation); + } + + if (const NamedDecl *ND = dyn_cast<NamedDecl>(DC)) + return getLVForDecl(ND, computation); + + return LinkageInfo::external(); +} + static LinkageInfo getLVForLocalDecl(const NamedDecl *D, LVComputationKind computation) { if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) { @@ -1040,13 +1084,55 @@ static LinkageInfo getLVForLocalDecl(const NamedDecl *D, return LV; } + + if (!Var->isStaticLocal()) + return LinkageInfo::none(); } - return LinkageInfo::none(); + ASTContext &Context = D->getASTContext(); + if (!Context.getLangOpts().CPlusPlus) + return LinkageInfo::none(); + + const Decl *OuterD = getOutermostFuncOrBlockContext(D); + if (!OuterD) + return LinkageInfo::none(); + + LinkageInfo LV; + if (const BlockDecl *BD = dyn_cast<BlockDecl>(OuterD)) { + if (!BD->getBlockManglingNumber()) + return LinkageInfo::none(); + + LV = getLVForClosure(BD->getDeclContext()->getRedeclContext(), + BD->getBlockManglingContextDecl(), computation); + } else { + const FunctionDecl *FD = cast<FunctionDecl>(OuterD); + if (!FD->isInlined() && + FD->getTemplateSpecializationKind() == TSK_Undeclared) + return LinkageInfo::none(); + + LV = getLVForDecl(FD, computation); + } + if (!isExternallyVisible(LV.getLinkage())) + return LinkageInfo::none(); + return LinkageInfo(VisibleNoLinkage, LV.getVisibility(), + LV.isVisibilityExplicit()); } -static LinkageInfo getLVForDecl(const NamedDecl *D, - LVComputationKind computation) { +static inline const CXXRecordDecl* +getOutermostEnclosingLambda(const CXXRecordDecl *Record) { + const CXXRecordDecl *Ret = Record; + while (Record && Record->isLambda()) { + Ret = Record; + if (!Record->getParent()) break; + // Get the Containing Class of this Lambda Class + Record = dyn_cast_or_null<CXXRecordDecl>( + Record->getParent()->getParent()); + } + return Ret; +} + +static LinkageInfo computeLVForDecl(const NamedDecl *D, + LVComputationKind computation) { // Objective-C: treat all Objective-C declarations as having external // linkage. switch (D->getKind()) { @@ -1074,20 +1160,25 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, // This lambda has no mangling number, so it's internal. return LinkageInfo::internal(); } - - // This lambda has its linkage/visibility determined by its owner. - const DeclContext *DC = D->getDeclContext()->getRedeclContext(); - if (Decl *ContextDecl = Record->getLambdaContextDecl()) { - if (isa<ParmVarDecl>(ContextDecl)) - DC = ContextDecl->getDeclContext()->getRedeclContext(); - else - return getLVForDecl(cast<NamedDecl>(ContextDecl), computation); - } - if (const NamedDecl *ND = dyn_cast<NamedDecl>(DC)) - return getLVForDecl(ND, computation); + // This lambda has its linkage/visibility determined: + // - either by the outermost lambda if that lambda has no mangling + // number. + // - or by the parent of the outer most lambda + // This prevents infinite recursion in settings such as nested lambdas + // used in NSDMI's, for e.g. + // struct L { + // int t{}; + // int t2 = ([](int a) { return [](int b) { return b; };})(t)(t); + // }; + const CXXRecordDecl *OuterMostLambda = + getOutermostEnclosingLambda(Record); + if (!OuterMostLambda->getLambdaManglingNumber()) + return LinkageInfo::internal(); - return LinkageInfo::external(); + return getLVForClosure( + OuterMostLambda->getDeclContext()->getRedeclContext(), + OuterMostLambda->getLambdaContextDecl(), computation); } break; @@ -1127,6 +1218,57 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, return LinkageInfo::none(); } +namespace clang { +class LinkageComputer { +public: + static LinkageInfo getLVForDecl(const NamedDecl *D, + LVComputationKind computation) { + if (computation == LVForLinkageOnly && D->hasCachedLinkage()) + return LinkageInfo(D->getCachedLinkage(), DefaultVisibility, false); + + LinkageInfo LV = computeLVForDecl(D, computation); + if (D->hasCachedLinkage()) + assert(D->getCachedLinkage() == LV.getLinkage()); + + D->setCachedLinkage(LV.getLinkage()); + +#ifndef NDEBUG + // In C (because of gnu inline) and in c++ with microsoft extensions an + // static can follow an extern, so we can have two decls with different + // linkages. + const LangOptions &Opts = D->getASTContext().getLangOpts(); + if (!Opts.CPlusPlus || Opts.MicrosoftExt) + return LV; + + // We have just computed the linkage for this decl. By induction we know + // that all other computed linkages match, check that the one we just + // computed + // also does. + NamedDecl *Old = NULL; + for (NamedDecl::redecl_iterator I = D->redecls_begin(), + E = D->redecls_end(); + I != E; ++I) { + NamedDecl *T = cast<NamedDecl>(*I); + if (T == D) + continue; + if (T->hasCachedLinkage()) { + Old = T; + break; + } + } + assert(!Old || Old->getCachedLinkage() == D->getCachedLinkage()); +#endif + + return LV; + } +}; +} + +static LinkageInfo getLVForDecl(const NamedDecl *D, + LVComputationKind computation) { + return clang::LinkageComputer::getLVForDecl(D, computation); +} + std::string NamedDecl::getQualifiedNameAsString() const { return getQualifiedNameAsString(getASTContext().getPrintingPolicy()); } @@ -1265,6 +1407,15 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD) const { cast<UsingDecl>(OldD)->getQualifier()); } + if (isa<UnresolvedUsingValueDecl>(this) && + isa<UnresolvedUsingValueDecl>(OldD)) { + ASTContext &Context = getASTContext(); + return Context.getCanonicalNestedNameSpecifier( + cast<UnresolvedUsingValueDecl>(this)->getQualifier()) == + Context.getCanonicalNestedNameSpecifier( + cast<UnresolvedUsingValueDecl>(OldD)->getQualifier()); + } + // A typedef of an Objective-C class type can replace an Objective-C class // declaration or definition, and vice versa. if ((isa<TypedefNameDecl>(this) && isa<ObjCInterfaceDecl>(OldD)) || @@ -1278,7 +1429,7 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD) const { } bool NamedDecl::hasLinkage() const { - return getLinkage() != NoLinkage; + return getFormalLinkage() != NoLinkage; } NamedDecl *NamedDecl::getUnderlyingDeclImpl() { @@ -1469,6 +1620,17 @@ const char *VarDecl::getStorageClassSpecifierString(StorageClass SC) { llvm_unreachable("Invalid storage class"); } +VarDecl::VarDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id, QualType T, + TypeSourceInfo *TInfo, StorageClass SC) + : DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc), Init() { + assert(sizeof(VarDeclBitfields) <= sizeof(unsigned)); + assert(sizeof(ParmVarDeclBitfields) <= sizeof(unsigned)); + AllBits = 0; + VarDeclBits.SClass = SC; + // Everything else is implicitly initialized to false. +} + VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation StartL, SourceLocation IdL, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, @@ -1502,7 +1664,7 @@ template<typename T> static LanguageLinkage getLanguageLinkageTemplate(const T &D) { // C++ [dcl.link]p1: All function types, function names with external linkage, // and variable names with external linkage have a language linkage. - if (!isExternalLinkage(D.getLinkage())) + if (!D.hasExternalFormalLinkage()) return NoLanguageLinkage; // Language linkage is a C++ concept, but saying that everything else in C has @@ -1547,32 +1709,15 @@ bool VarDecl::isExternC() const { return isExternCTemplate(*this); } -static bool isLinkageSpecContext(const DeclContext *DC, - LinkageSpecDecl::LanguageIDs ID) { - while (DC->getDeclKind() != Decl::TranslationUnit) { - if (DC->getDeclKind() == Decl::LinkageSpec) - return cast<LinkageSpecDecl>(DC)->getLanguage() == ID; - DC = DC->getParent(); - } - return false; -} - -template <typename T> -static bool isInLanguageSpecContext(T *D, LinkageSpecDecl::LanguageIDs ID) { - return isLinkageSpecContext(D->getLexicalDeclContext(), ID); -} - bool VarDecl::isInExternCContext() const { - return isInLanguageSpecContext(this, LinkageSpecDecl::lang_c); + return getLexicalDeclContext()->isExternCContext(); } bool VarDecl::isInExternCXXContext() const { - return isInLanguageSpecContext(this, LinkageSpecDecl::lang_cxx); + return getLexicalDeclContext()->isExternCXXContext(); } -VarDecl *VarDecl::getCanonicalDecl() { - return getFirstDeclaration(); -} +VarDecl *VarDecl::getCanonicalDecl() { return getFirstDecl(); } VarDecl::DefinitionKind VarDecl::isThisDeclarationADefinition( ASTContext &C) const @@ -1581,13 +1726,24 @@ VarDecl::DefinitionKind VarDecl::isThisDeclarationADefinition( // A declaration is a definition unless [...] it contains the 'extern' // specifier or a linkage-specification and neither an initializer [...], // it declares a static data member in a class declaration [...]. - // C++ [temp.expl.spec]p15: - // An explicit specialization of a static data member of a template is a - // definition if the declaration includes an initializer; otherwise, it is - // a declaration. + // C++1y [temp.expl.spec]p15: + // An explicit specialization of a static data member or an explicit + // specialization of a static data member template is a definition if the + // declaration includes an initializer; otherwise, it is a declaration. + // + // FIXME: How do you declare (but not define) a partial specialization of + // a static data member template outside the containing class? if (isStaticDataMember()) { - if (isOutOfLine() && (hasInit() || - getTemplateSpecializationKind() != TSK_ExplicitSpecialization)) + if (isOutOfLine() && + (hasInit() || + // If the first declaration is out-of-line, this may be an + // instantiation of an out-of-line partial specialization of a variable + // template for which we have not yet instantiated the initializer. + (getFirstDecl()->isOutOfLine() + ? getTemplateSpecializationKind() == TSK_Undeclared + : getTemplateSpecializationKind() != + TSK_ExplicitSpecialization) || + isa<VarTemplatePartialSpecializationDecl>(this))) return Definition; else return DeclarationOnly; @@ -1602,6 +1758,16 @@ VarDecl::DefinitionKind VarDecl::isThisDeclarationADefinition( if (hasInit()) return Definition; + if (hasAttr<AliasAttr>()) + return Definition; + + // A variable template specialization (other than a static data member + // template or an explicit specialization) is a declaration until we + // instantiate its initializer. + if (isa<VarTemplateSpecializationDecl>(this) && + getTemplateSpecializationKind() != TSK_ExplicitSpecialization) + return DeclarationOnly; + if (hasExternalStorage()) return DeclarationOnly; @@ -1631,7 +1797,7 @@ VarDecl *VarDecl::getActingDefinition() { return 0; VarDecl *LastTentative = 0; - VarDecl *First = getFirstDeclaration(); + VarDecl *First = getFirstDecl(); for (redecl_iterator I = First->redecls_begin(), E = First->redecls_end(); I != E; ++I) { Kind = (*I)->isThisDeclarationADefinition(); @@ -1643,20 +1809,8 @@ VarDecl *VarDecl::getActingDefinition() { return LastTentative; } -bool VarDecl::isTentativeDefinitionNow() const { - DefinitionKind Kind = isThisDeclarationADefinition(); - if (Kind != TentativeDefinition) - return false; - - for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) { - if ((*I)->isThisDeclarationADefinition() == Definition) - return false; - } - return true; -} - VarDecl *VarDecl::getDefinition(ASTContext &C) { - VarDecl *First = getFirstDeclaration(); + VarDecl *First = getFirstDecl(); for (redecl_iterator I = First->redecls_begin(), E = First->redecls_end(); I != E; ++I) { if ((*I)->isThisDeclarationADefinition(C) == Definition) @@ -1668,7 +1822,7 @@ VarDecl *VarDecl::getDefinition(ASTContext &C) { VarDecl::DefinitionKind VarDecl::hasDefinition(ASTContext &C) const { DefinitionKind Kind = DeclarationOnly; - const VarDecl *First = getFirstDeclaration(); + const VarDecl *First = getFirstDecl(); for (redecl_iterator I = First->redecls_begin(), E = First->redecls_end(); I != E; ++I) { Kind = std::max(Kind, (*I)->isThisDeclarationADefinition(C)); @@ -1763,6 +1917,10 @@ EvaluatedStmt *VarDecl::ensureEvaluatedStmt() const { EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>(); if (!Eval) { Stmt *S = Init.get<Stmt *>(); + // Note: EvaluatedStmt contains an APValue, which usually holds + // resources not allocated from the ASTContext. We need to do some + // work to avoid leaking those, but we do so in VarDecl::evaluateValue + // where we can detect whether there's anything to clean up or not. Eval = new (getASTContext()) EvaluatedStmt; Eval->Value = S; Init = Eval; @@ -1775,6 +1933,13 @@ APValue *VarDecl::evaluateValue() const { return evaluateValue(Notes); } +namespace { +// Destroy an APValue that was allocated in an ASTContext. +void DestroyAPValue(void* UntypedValue) { + static_cast<APValue*>(UntypedValue)->~APValue(); +} +} // namespace + APValue *VarDecl::evaluateValue( SmallVectorImpl<PartialDiagnosticAt> &Notes) const { EvaluatedStmt *Eval = ensureEvaluatedStmt(); @@ -1800,9 +1965,13 @@ APValue *VarDecl::evaluateValue( bool Result = Init->EvaluateAsInitializer(Eval->Evaluated, getASTContext(), this, Notes); - // Ensure the result is an uninitialized APValue if evaluation fails. + // Ensure the computed APValue is cleaned up later if evaluation succeeded, + // or that it's empty (so that there's nothing to clean up) if evaluation + // failed. if (!Result) Eval->Evaluated = APValue(); + else if (Eval->Evaluated.needsCleanup()) + getASTContext().AddDeallocation(DestroyAPValue, &Eval->Evaluated); Eval->IsEvaluating = false; Eval->WasEvaluated = true; @@ -1853,19 +2022,6 @@ bool VarDecl::checkInitIsICE() const { return Eval->IsICE; } -bool VarDecl::extendsLifetimeOfTemporary() const { - assert(getType()->isReferenceType() &&"Non-references never extend lifetime"); - - const Expr *E = getInit(); - if (!E) - return false; - - if (const ExprWithCleanups *Cleanups = dyn_cast<ExprWithCleanups>(E)) - E = Cleanups->getSubExpr(); - - return isa<MaterializeTemporaryExpr>(E); -} - VarDecl *VarDecl::getInstantiatedFromStaticDataMember() const { if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) return cast<VarDecl>(MSI->getInstantiatedFrom()); @@ -1874,25 +2030,73 @@ VarDecl *VarDecl::getInstantiatedFromStaticDataMember() const { } TemplateSpecializationKind VarDecl::getTemplateSpecializationKind() const { + if (const VarTemplateSpecializationDecl *Spec = + dyn_cast<VarTemplateSpecializationDecl>(this)) + return Spec->getSpecializationKind(); + if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) return MSI->getTemplateSpecializationKind(); - + return TSK_Undeclared; } +SourceLocation VarDecl::getPointOfInstantiation() const { + if (const VarTemplateSpecializationDecl *Spec = + dyn_cast<VarTemplateSpecializationDecl>(this)) + return Spec->getPointOfInstantiation(); + + if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) + return MSI->getPointOfInstantiation(); + + return SourceLocation(); +} + +VarTemplateDecl *VarDecl::getDescribedVarTemplate() const { + return getASTContext().getTemplateOrSpecializationInfo(this) + .dyn_cast<VarTemplateDecl *>(); +} + +void VarDecl::setDescribedVarTemplate(VarTemplateDecl *Template) { + getASTContext().setTemplateOrSpecializationInfo(this, Template); +} + MemberSpecializationInfo *VarDecl::getMemberSpecializationInfo() const { - return getASTContext().getInstantiatedFromStaticDataMember(this); + if (isStaticDataMember()) + // FIXME: Remove ? + // return getASTContext().getInstantiatedFromStaticDataMember(this); + return getASTContext().getTemplateOrSpecializationInfo(this) + .dyn_cast<MemberSpecializationInfo *>(); + return 0; } void VarDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK, SourceLocation PointOfInstantiation) { - MemberSpecializationInfo *MSI = getMemberSpecializationInfo(); - assert(MSI && "Not an instantiated static data member?"); - MSI->setTemplateSpecializationKind(TSK); - if (TSK != TSK_ExplicitSpecialization && - PointOfInstantiation.isValid() && - MSI->getPointOfInstantiation().isInvalid()) - MSI->setPointOfInstantiation(PointOfInstantiation); + assert((isa<VarTemplateSpecializationDecl>(this) || + getMemberSpecializationInfo()) && + "not a variable or static data member template specialization"); + + if (VarTemplateSpecializationDecl *Spec = + dyn_cast<VarTemplateSpecializationDecl>(this)) { + Spec->setSpecializationKind(TSK); + if (TSK != TSK_ExplicitSpecialization && PointOfInstantiation.isValid() && + Spec->getPointOfInstantiation().isInvalid()) + Spec->setPointOfInstantiation(PointOfInstantiation); + } + + if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) { + MSI->setTemplateSpecializationKind(TSK); + if (TSK != TSK_ExplicitSpecialization && PointOfInstantiation.isValid() && + MSI->getPointOfInstantiation().isInvalid()) + MSI->setPointOfInstantiation(PointOfInstantiation); + } +} + +void +VarDecl::setInstantiationOfStaticDataMember(VarDecl *VD, + TemplateSpecializationKind TSK) { + assert(getASTContext().getTemplateOrSpecializationInfo(this).isNull() && + "Previous template or instantiation?"); + getASTContext().setInstantiatedFromStaticDataMember(this, VD, TSK); } //===----------------------------------------------------------------------===// @@ -1908,6 +2112,14 @@ ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC, S, DefArg); } +QualType ParmVarDecl::getOriginalType() const { + TypeSourceInfo *TSI = getTypeSourceInfo(); + QualType T = TSI ? TSI->getType() : getType(); + if (const DecayedType *DT = dyn_cast<DecayedType>(T)) + return DT->getOriginalType(); + return T; +} + ParmVarDecl *ParmVarDecl::CreateDeserialized(ASTContext &C, unsigned ID) { void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ParmVarDecl)); return new (Mem) ParmVarDecl(ParmVar, 0, SourceLocation(), SourceLocation(), @@ -2010,7 +2222,8 @@ bool FunctionDecl::hasTrivialBody() const bool FunctionDecl::isDefined(const FunctionDecl *&Definition) const { for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) { - if (I->IsDeleted || I->IsDefaulted || I->Body || I->IsLateTemplateParsed) { + if (I->IsDeleted || I->IsDefaulted || I->Body || I->IsLateTemplateParsed || + I->hasAttr<AliasAttr>()) { Definition = I->IsDeleted ? I->getCanonicalDecl() : *I; return true; } @@ -2020,15 +2233,11 @@ bool FunctionDecl::isDefined(const FunctionDecl *&Definition) const { } Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const { - for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) { - if (I->Body) { - Definition = *I; - return I->Body.get(getASTContext().getExternalSource()); - } else if (I->IsLateTemplateParsed) { - Definition = *I; - return 0; - } - } + if (!hasBody(Definition)) + return 0; + + if (Definition->Body) + return Definition->Body.get(getASTContext().getExternalSource()); return 0; } @@ -2046,13 +2255,45 @@ void FunctionDecl::setPure(bool P) { Parent->markedVirtualFunctionPure(); } +template<std::size_t Len> +static bool isNamed(const NamedDecl *ND, const char (&Str)[Len]) { + IdentifierInfo *II = ND->getIdentifier(); + return II && II->isStr(Str); +} + bool FunctionDecl::isMain() const { const TranslationUnitDecl *tunit = dyn_cast<TranslationUnitDecl>(getDeclContext()->getRedeclContext()); return tunit && !tunit->getASTContext().getLangOpts().Freestanding && - getIdentifier() && - getIdentifier()->isStr("main"); + isNamed(this, "main"); +} + +bool FunctionDecl::isMSVCRTEntryPoint() const { + const TranslationUnitDecl *TUnit = + dyn_cast<TranslationUnitDecl>(getDeclContext()->getRedeclContext()); + if (!TUnit) + return false; + + // Even though we aren't really targeting MSVCRT if we are freestanding, + // semantic analysis for these functions remains the same. + + // MSVCRT entry points only exist on MSVCRT targets. + if (!TUnit->getASTContext().getTargetInfo().getTriple().isOSMSVCRT()) + return false; + + // Nameless functions like constructors cannot be entry points. + if (!getIdentifier()) + return false; + + return llvm::StringSwitch<bool>(getName()) + .Cases("main", // an ANSI console app + "wmain", // a Unicode console App + "WinMain", // an ANSI GUI app + "wWinMain", // a Unicode GUI app + "DllMain", // a DLL + true) + .Default(false); } bool FunctionDecl::isReservedGlobalPlacementOperator() const { @@ -2077,13 +2318,83 @@ bool FunctionDecl::isReservedGlobalPlacementOperator() const { return (proto->getArgType(1).getCanonicalType() == Context.VoidPtrTy); } -LanguageLinkage FunctionDecl::getLanguageLinkage() const { - // Users expect to be able to write - // extern "C" void *__builtin_alloca (size_t); - // so consider builtins as having C language linkage. - if (getBuiltinID()) - return CLanguageLinkage; +static bool isNamespaceStd(const DeclContext *DC) { + const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC->getRedeclContext()); + return ND && isNamed(ND, "std") && + ND->getParent()->getRedeclContext()->isTranslationUnit(); +} +bool FunctionDecl::isReplaceableGlobalAllocationFunction() const { + if (getDeclName().getNameKind() != DeclarationName::CXXOperatorName) + return false; + if (getDeclName().getCXXOverloadedOperator() != OO_New && + getDeclName().getCXXOverloadedOperator() != OO_Delete && + getDeclName().getCXXOverloadedOperator() != OO_Array_New && + getDeclName().getCXXOverloadedOperator() != OO_Array_Delete) + return false; + + if (isa<CXXRecordDecl>(getDeclContext())) + return false; + assert(getDeclContext()->getRedeclContext()->isTranslationUnit()); + + const FunctionProtoType *FPT = getType()->castAs<FunctionProtoType>(); + if (FPT->getNumArgs() > 2 || FPT->isVariadic()) + return false; + + // If this is a single-parameter function, it must be a replaceable global + // allocation or deallocation function. + if (FPT->getNumArgs() == 1) + return true; + + // Otherwise, we're looking for a second parameter whose type is + // 'const std::nothrow_t &', or, in C++1y, 'std::size_t'. + QualType Ty = FPT->getArgType(1); + ASTContext &Ctx = getASTContext(); + if (Ctx.getLangOpts().SizedDeallocation && + Ctx.hasSameType(Ty, Ctx.getSizeType())) + return true; + if (!Ty->isReferenceType()) + return false; + Ty = Ty->getPointeeType(); + if (Ty.getCVRQualifiers() != Qualifiers::Const) + return false; + // FIXME: Recognise nothrow_t in an inline namespace inside std? + const CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); + return RD && isNamed(RD, "nothrow_t") && isNamespaceStd(RD->getDeclContext()); +} + +FunctionDecl * +FunctionDecl::getCorrespondingUnsizedGlobalDeallocationFunction() const { + ASTContext &Ctx = getASTContext(); + if (!Ctx.getLangOpts().SizedDeallocation) + return 0; + + if (getDeclName().getNameKind() != DeclarationName::CXXOperatorName) + return 0; + if (getDeclName().getCXXOverloadedOperator() != OO_Delete && + getDeclName().getCXXOverloadedOperator() != OO_Array_Delete) + return 0; + if (isa<CXXRecordDecl>(getDeclContext())) + return 0; + assert(getDeclContext()->getRedeclContext()->isTranslationUnit()); + + if (getNumParams() != 2 || isVariadic() || + !Ctx.hasSameType(getType()->castAs<FunctionProtoType>()->getArgType(1), + Ctx.getSizeType())) + return 0; + + // This is a sized deallocation function. Find the corresponding unsized + // deallocation function. + lookup_const_result R = getDeclContext()->lookup(getDeclName()); + for (lookup_const_result::iterator RI = R.begin(), RE = R.end(); RI != RE; + ++RI) + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*RI)) + if (FD->getNumParams() == 1 && !FD->isVariadic()) + return FD; + return 0; +} + +LanguageLinkage FunctionDecl::getLanguageLinkage() const { return getLanguageLinkageTemplate(*this); } @@ -2092,11 +2403,11 @@ bool FunctionDecl::isExternC() const { } bool FunctionDecl::isInExternCContext() const { - return isInLanguageSpecContext(this, LinkageSpecDecl::lang_c); + return getLexicalDeclContext()->isExternCContext(); } bool FunctionDecl::isInExternCXXContext() const { - return isInLanguageSpecContext(this, LinkageSpecDecl::lang_cxx); + return getLexicalDeclContext()->isExternCXXContext(); } bool FunctionDecl::isGlobal() const { @@ -2127,13 +2438,13 @@ bool FunctionDecl::isNoReturn() const { void FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) { - redeclarable_base::setPreviousDeclaration(PrevDecl); + redeclarable_base::setPreviousDecl(PrevDecl); if (FunctionTemplateDecl *FunTmpl = getDescribedFunctionTemplate()) { FunctionTemplateDecl *PrevFunTmpl = PrevDecl? PrevDecl->getDescribedFunctionTemplate() : 0; assert((!PrevDecl || PrevFunTmpl) && "Function/function template mismatch"); - FunTmpl->setPreviousDeclaration(PrevFunTmpl); + FunTmpl->setPreviousDecl(PrevFunTmpl); } if (PrevDecl && PrevDecl->IsInline) @@ -2141,12 +2452,10 @@ FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) { } const FunctionDecl *FunctionDecl::getCanonicalDecl() const { - return getFirstDeclaration(); + return getFirstDecl(); } -FunctionDecl *FunctionDecl::getCanonicalDecl() { - return getFirstDeclaration(); -} +FunctionDecl *FunctionDecl::getCanonicalDecl() { return getFirstDecl(); } /// \brief Returns a value indicating whether this function /// corresponds to a builtin function. @@ -2166,6 +2475,22 @@ unsigned FunctionDecl::getBuiltinID() const { return 0; ASTContext &Context = getASTContext(); + if (Context.getLangOpts().CPlusPlus) { + const LinkageSpecDecl *LinkageDecl = dyn_cast<LinkageSpecDecl>( + getFirstDecl()->getDeclContext()); + // In C++, the first declaration of a builtin is always inside an implicit + // extern "C". + // FIXME: A recognised library function may not be directly in an extern "C" + // declaration, for instance "extern "C" { namespace std { decl } }". + if (!LinkageDecl || LinkageDecl->getLanguage() != LinkageSpecDecl::lang_c) + return 0; + } + + // If the function is marked "overloadable", it has a different mangled name + // and is not the C library function. + if (getAttr<OverloadableAttr>()) + return 0; + if (!Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) return BuiltinID; @@ -2177,22 +2502,7 @@ unsigned FunctionDecl::getBuiltinID() const { if (getStorageClass() == SC_Static) return 0; - // If this function is at translation-unit scope and we're not in - // C++, it refers to the C library function. - if (!Context.getLangOpts().CPlusPlus && - getDeclContext()->isTranslationUnit()) - return BuiltinID; - - // If the function is in an extern "C" linkage specification and is - // not marked "overloadable", it's the real function. - if (isa<LinkageSpecDecl>(getDeclContext()) && - cast<LinkageSpecDecl>(getDeclContext())->getLanguage() - == LinkageSpecDecl::lang_c && - !getAttr<OverloadableAttr>()) - return BuiltinID; - - // Not a builtin - return 0; + return BuiltinID; } @@ -2304,7 +2614,7 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const { const FunctionDecl *Prev = this; bool FoundBody = false; while ((Prev = Prev->getPreviousDecl())) { - FoundBody |= Prev->Body; + FoundBody |= Prev->Body.isValid(); if (Prev->Body) { // If it's not the case that both 'inline' and 'extern' are @@ -2332,7 +2642,7 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const { const FunctionDecl *Prev = this; bool FoundBody = false; while ((Prev = Prev->getPreviousDecl())) { - FoundBody |= Prev->Body; + FoundBody |= Prev->Body.isValid(); if (RedeclForcesDefC99(Prev)) return false; } @@ -2818,26 +3128,18 @@ unsigned FieldDecl::getBitWidthValue(const ASTContext &Ctx) const { } unsigned FieldDecl::getFieldIndex() const { + const FieldDecl *Canonical = getCanonicalDecl(); + if (Canonical != this) + return Canonical->getFieldIndex(); + if (CachedFieldIndex) return CachedFieldIndex - 1; unsigned Index = 0; const RecordDecl *RD = getParent(); - const FieldDecl *LastFD = 0; - bool IsMsStruct = RD->isMsStruct(getASTContext()); for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); - I != E; ++I, ++Index) { - I->CachedFieldIndex = Index + 1; - - if (IsMsStruct) { - // Zero-length bitfields following non-bitfield members are ignored. - if (getASTContext().ZeroBitfieldFollowsNonBitfield(*I, LastFD)) { - --Index; - continue; - } - LastFD = *I; - } - } + I != E; ++I, ++Index) + I->getCanonicalDecl()->CachedFieldIndex = Index + 1; assert(CachedFieldIndex && "failed to find field in parent"); return CachedFieldIndex - 1; @@ -2874,12 +3176,10 @@ SourceRange TagDecl::getSourceRange() const { return SourceRange(getOuterLocStart(), E); } -TagDecl* TagDecl::getCanonicalDecl() { - return getFirstDeclaration(); -} +TagDecl *TagDecl::getCanonicalDecl() { return getFirstDecl(); } void TagDecl::setTypedefNameForAnonDecl(TypedefNameDecl *TDD) { - TypedefNameDeclOrQualifier = TDD; + NamedDeclOrQualifier = TDD; if (TypeForDecl) assert(TypeForDecl->isLinkageValid()); assert(isLinkageValid()); @@ -2936,7 +3236,7 @@ void TagDecl::setQualifierInfo(NestedNameSpecifierLoc QualifierLoc) { if (QualifierLoc) { // Make sure the extended qualifier info is allocated. if (!hasExtInfo()) - TypedefNameDeclOrQualifier = new (getASTContext()) ExtInfo; + NamedDeclOrQualifier = new (getASTContext()) ExtInfo; // Set qualifier info. getExtInfo()->QualifierLoc = QualifierLoc; } else { @@ -2944,7 +3244,7 @@ void TagDecl::setQualifierInfo(NestedNameSpecifierLoc QualifierLoc) { if (hasExtInfo()) { if (getExtInfo()->NumTemplParamLists == 0) { getASTContext().Deallocate(getExtInfo()); - TypedefNameDeclOrQualifier = (TypedefNameDecl*) 0; + NamedDeclOrQualifier = (TypedefNameDecl*) 0; } else getExtInfo()->QualifierLoc = QualifierLoc; @@ -2959,7 +3259,7 @@ void TagDecl::setTemplateParameterListsInfo(ASTContext &Context, // Make sure the extended decl info is allocated. if (!hasExtInfo()) // Allocate external info struct. - TypedefNameDeclOrQualifier = new (getASTContext()) ExtInfo; + NamedDeclOrQualifier = new (getASTContext()) ExtInfo; // Set the template parameter lists info. getExtInfo()->setTemplateParameterListsInfo(Context, NumTPLists, TPLists); } diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index 084a432..121c5a6 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -291,6 +291,16 @@ bool Decl::isUsed(bool CheckUsedAttr) const { return false; } +void Decl::markUsed(ASTContext &C) { + if (Used) + return; + + if (C.getASTMutationListener()) + C.getASTMutationListener()->DeclarationMarkedUsed(this); + + Used = true; +} + bool Decl::isReferenced() const { if (Referenced) return true; @@ -538,6 +548,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { return IDNS_Namespace; case FunctionTemplate: + case VarTemplate: return IDNS_Ordinary; case ClassTemplate: @@ -560,6 +571,8 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case ClassTemplateSpecialization: case ClassTemplatePartialSpecialization: case ClassScopeFunctionSpecialization: + case VarTemplateSpecialization: + case VarTemplatePartialSpecialization: case ObjCImplementation: case ObjCCategory: case ObjCCategoryImpl: @@ -595,32 +608,6 @@ const AttrVec &Decl::getAttrs() const { return getASTContext().getDeclAttrs(this); } -void Decl::swapAttrs(Decl *RHS) { - bool HasLHSAttr = this->HasAttrs; - bool HasRHSAttr = RHS->HasAttrs; - - // Usually, neither decl has attrs, nothing to do. - if (!HasLHSAttr && !HasRHSAttr) return; - - // If 'this' has no attrs, swap the other way. - if (!HasLHSAttr) - return RHS->swapAttrs(this); - - ASTContext &Context = getASTContext(); - - // Handle the case when both decls have attrs. - if (HasRHSAttr) { - std::swap(Context.getDeclAttrs(this), Context.getDeclAttrs(RHS)); - return; - } - - // Otherwise, LHS has an attr and RHS doesn't. - Context.getDeclAttrs(RHS) = Context.getDeclAttrs(this); - Context.eraseDeclAttrs(this); - this->HasAttrs = false; - RHS->HasAttrs = true; -} - Decl *Decl::castFromDeclContext (const DeclContext *D) { Decl::Kind DK = D->getDeclKind(); switch(DK) { @@ -819,6 +806,24 @@ bool DeclContext::isTransparentContext() const { return false; } +static bool isLinkageSpecContext(const DeclContext *DC, + LinkageSpecDecl::LanguageIDs ID) { + while (DC->getDeclKind() != Decl::TranslationUnit) { + if (DC->getDeclKind() == Decl::LinkageSpec) + return cast<LinkageSpecDecl>(DC)->getLanguage() == ID; + DC = DC->getParent(); + } + return false; +} + +bool DeclContext::isExternCContext() const { + return isLinkageSpecContext(this, clang::LinkageSpecDecl::lang_c); +} + +bool DeclContext::isExternCXXContext() const { + return isLinkageSpecContext(this, clang::LinkageSpecDecl::lang_cxx); +} + bool DeclContext::Encloses(const DeclContext *DC) const { if (getPrimaryContext() != this) return getPrimaryContext()->Encloses(DC); @@ -939,11 +944,8 @@ void DeclContext::reconcileExternalVisibleStorage() { NeedToReconcileExternalVisibleStorage = false; StoredDeclsMap &Map = *LookupPtr.getPointer(); - ExternalASTSource *Source = getParentASTContext().getExternalSource(); - for (StoredDeclsMap::iterator I = Map.begin(); I != Map.end(); ++I) { - I->second.removeExternalDecls(); - Source->FindExternalVisibleDeclsByName(this, I->first); - } + for (StoredDeclsMap::iterator I = Map.begin(); I != Map.end(); ++I) + I->second.setHasExternalDecls(); } /// \brief Load the declarations within this lexical storage from an @@ -996,8 +998,7 @@ ExternalASTSource::SetNoExternalVisibleDeclsForName(const DeclContext *DC, if (!(Map = DC->LookupPtr.getPointer())) Map = DC->CreateStoredDeclsMap(Context); - // Add an entry to the map for this name, if it's not already present. - (*Map)[Name]; + (*Map)[Name].removeExternalDecls(); return DeclContext::lookup_result(); } @@ -1012,13 +1013,38 @@ ExternalASTSource::SetExternalVisibleDeclsForName(const DeclContext *DC, Map = DC->CreateStoredDeclsMap(Context); StoredDeclsList &List = (*Map)[Name]; - for (ArrayRef<NamedDecl*>::iterator - I = Decls.begin(), E = Decls.end(); I != E; ++I) { - if (List.isNull()) - List.setOnlyValue(*I); - else - // FIXME: Need declarationReplaces handling for redeclarations in modules. - List.AddSubsequentDecl(*I); + + // Clear out any old external visible declarations, to avoid quadratic + // performance in the redeclaration checks below. + List.removeExternalDecls(); + + if (!List.isNull()) { + // We have both existing declarations and new declarations for this name. + // Some of the declarations may simply replace existing ones. Handle those + // first. + llvm::SmallVector<unsigned, 8> Skip; + for (unsigned I = 0, N = Decls.size(); I != N; ++I) + if (List.HandleRedeclaration(Decls[I])) + Skip.push_back(I); + Skip.push_back(Decls.size()); + + // Add in any new declarations. + unsigned SkipPos = 0; + for (unsigned I = 0, N = Decls.size(); I != N; ++I) { + if (I == Skip[SkipPos]) + ++SkipPos; + else + List.AddSubsequentDecl(Decls[I]); + } + } else { + // Convert the array to a StoredDeclsList. + for (ArrayRef<NamedDecl*>::iterator + I = Decls.begin(), E = Decls.end(); I != E; ++I) { + if (List.isNull()) + List.setOnlyValue(*I); + else + List.AddSubsequentDecl(*I); + } } return List.getLookupResult(); @@ -1171,7 +1197,8 @@ StoredDeclsMap *DeclContext::buildLookup() { SmallVector<DeclContext *, 2> Contexts; collectAllContexts(Contexts); for (unsigned I = 0, N = Contexts.size(); I != N; ++I) - buildLookupImpl(Contexts[I]); + buildLookupImpl<&DeclContext::decls_begin, + &DeclContext::decls_end>(Contexts[I]); // We no longer have any lazy decls. LookupPtr.setInt(false); @@ -1183,16 +1210,26 @@ StoredDeclsMap *DeclContext::buildLookup() { /// declarations contained within DCtx, which will either be this /// DeclContext, a DeclContext linked to it, or a transparent context /// nested within it. +template<DeclContext::decl_iterator (DeclContext::*Begin)() const, + DeclContext::decl_iterator (DeclContext::*End)() const> void DeclContext::buildLookupImpl(DeclContext *DCtx) { - for (decl_iterator I = DCtx->decls_begin(), E = DCtx->decls_end(); + for (decl_iterator I = (DCtx->*Begin)(), E = (DCtx->*End)(); I != E; ++I) { Decl *D = *I; // Insert this declaration into the lookup structure, but only if // it's semantically within its decl context. Any other decls which // should be found in this context are added eagerly. + // + // If it's from an AST file, don't add it now. It'll get handled by + // FindExternalVisibleDeclsByName if needed. Exception: if we're not + // in C++, we do not track external visible decls for the TU, so in + // that case we need to collect them all here. if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) - if (ND->getDeclContext() == DCtx && !shouldBeHidden(ND)) + if (ND->getDeclContext() == DCtx && !shouldBeHidden(ND) && + (!ND->isFromASTFile() || + (isTranslationUnit() && + !getParentASTContext().getLangOpts().CPlusPlus))) makeDeclVisibleInContextImpl(ND, false); // If this declaration is itself a transparent declaration context @@ -1200,7 +1237,7 @@ void DeclContext::buildLookupImpl(DeclContext *DCtx) { // context (recursively). if (DeclContext *InnerCtx = dyn_cast<DeclContext>(D)) if (InnerCtx->isTransparentContext() || InnerCtx->isInlineNamespace()) - buildLookupImpl(InnerCtx); + buildLookupImpl<Begin, End>(InnerCtx); } } @@ -1223,16 +1260,14 @@ DeclContext::lookup(DeclarationName Name) { if (!Map) Map = CreateStoredDeclsMap(getParentASTContext()); - // If a PCH/module has a result for this name, and we have a local - // declaration, we will have imported the PCH/module result when adding the - // local declaration or when reconciling the module. + // If we have a lookup result with no external decls, we are done. std::pair<StoredDeclsMap::iterator, bool> R = Map->insert(std::make_pair(Name, StoredDeclsList())); - if (!R.second) + if (!R.second && !R.first->second.hasExternalDecls()) return R.first->second.getLookupResult(); ExternalASTSource *Source = getParentASTContext().getExternalSource(); - if (Source->FindExternalVisibleDeclsByName(this, Name)) { + if (Source->FindExternalVisibleDeclsByName(this, Name) || R.second) { if (StoredDeclsMap *Map = LookupPtr.getPointer()) { StoredDeclsMap::iterator I = Map->find(Name); if (I != Map->end()) @@ -1257,6 +1292,46 @@ DeclContext::lookup(DeclarationName Name) { return I->second.getLookupResult(); } +DeclContext::lookup_result +DeclContext::noload_lookup(DeclarationName Name) { + assert(DeclKind != Decl::LinkageSpec && + "Should not perform lookups into linkage specs!"); + if (!hasExternalVisibleStorage()) + return lookup(Name); + + DeclContext *PrimaryContext = getPrimaryContext(); + if (PrimaryContext != this) + return PrimaryContext->noload_lookup(Name); + + StoredDeclsMap *Map = LookupPtr.getPointer(); + if (LookupPtr.getInt()) { + // Carefully build the lookup map, without deserializing anything. + SmallVector<DeclContext *, 2> Contexts; + collectAllContexts(Contexts); + for (unsigned I = 0, N = Contexts.size(); I != N; ++I) + buildLookupImpl<&DeclContext::noload_decls_begin, + &DeclContext::noload_decls_end>(Contexts[I]); + + // We no longer have any lazy decls. + LookupPtr.setInt(false); + + // There may now be names for which we have local decls but are + // missing the external decls. FIXME: Just set the hasExternalDecls + // flag on those names that have external decls. + NeedToReconcileExternalVisibleStorage = true; + + Map = LookupPtr.getPointer(); + } + + if (!Map) + return lookup_result(lookup_iterator(0), lookup_iterator(0)); + + StoredDeclsMap::iterator I = Map->find(Name); + return I != Map->end() + ? I->second.getLookupResult() + : lookup_result(lookup_iterator(0), lookup_iterator(0)); +} + void DeclContext::localUncachedLookup(DeclarationName Name, SmallVectorImpl<NamedDecl *> &Results) { Results.clear(); @@ -1338,14 +1413,7 @@ void DeclContext::makeDeclVisibleInContextWithFlags(NamedDecl *D, bool Internal, assert(this == getPrimaryContext() && "expected a primary DC"); // Skip declarations within functions. - // FIXME: We shouldn't need to build lookup tables for function declarations - // ever, and we can't do so correctly because we can't model the nesting of - // scopes which occurs within functions. We use "qualified" lookup into - // function declarations when handling friend declarations inside nested - // classes, and consequently accept the following invalid code: - // - // void f() { void g(); { int g; struct S { friend void g(); }; } } - if (isFunctionOrMethod() && !isa<FunctionDecl>(D)) + if (isFunctionOrMethod()) return; // Skip declarations which should be invisible to name lookup. @@ -1406,7 +1474,18 @@ void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D, bool Internal) { // Insert this declaration into the map. StoredDeclsList &DeclNameEntries = (*Map)[D->getDeclName()]; - if (DeclNameEntries.isNull()) { + + if (Internal) { + // If this is being added as part of loading an external declaration, + // this may not be the only external declaration with this name. + // In this case, we never try to replace an existing declaration; we'll + // handle that when we finalize the list of declarations for this name. + DeclNameEntries.setHasExternalDecls(); + DeclNameEntries.AddSubsequentDecl(D); + return; + } + + else if (DeclNameEntries.isNull()) { DeclNameEntries.setOnlyValue(D); return; } diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 0646499..a17abdd 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -10,9 +10,9 @@ // This file implements the C++ related Decl classes. // //===----------------------------------------------------------------------===// - #include "clang/AST/DeclCXX.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/ASTLambda.h" #include "clang/AST/ASTMutationListener.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclTemplate.h" @@ -35,6 +35,17 @@ AccessSpecDecl *AccessSpecDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (Mem) AccessSpecDecl(EmptyShell()); } +void LazyASTUnresolvedSet::getFromExternalSource(ASTContext &C) const { + ExternalASTSource *Source = C.getExternalSource(); + assert(Impl.Decls.isLazy() && "getFromExternalSource for non-lazy set"); + assert(Source && "getFromExternalSource with no external source"); + + for (ASTUnresolvedSet::iterator I = Impl.begin(); I != Impl.end(); ++I) + I.setDecl(cast<NamedDecl>(Source->GetExternalDecl( + reinterpret_cast<uintptr_t>(I.getDecl()) >> 2))); + Impl.Decls.setLazy(false); +} + CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D) : UserDeclaredConstructor(false), UserDeclaredSpecialMembers(0), Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false), @@ -60,9 +71,8 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D) ImplicitCopyAssignmentHasConstParam(true), HasDeclaredCopyConstructorWithConstParam(false), HasDeclaredCopyAssignmentWithConstParam(false), - FailedImplicitMoveConstructor(false), FailedImplicitMoveAssignment(false), IsLambda(false), NumBases(0), NumVBases(0), Bases(), VBases(), - Definition(D), FirstFriend(0) { + Definition(D), FirstFriend() { } CXXBaseSpecifier *CXXRecordDecl::DefinitionData::getBasesSlowCase() const { @@ -97,12 +107,17 @@ CXXRecordDecl *CXXRecordDecl::Create(const ASTContext &C, TagKind TK, CXXRecordDecl *CXXRecordDecl::CreateLambda(const ASTContext &C, DeclContext *DC, TypeSourceInfo *Info, SourceLocation Loc, - bool Dependent) { + bool Dependent, bool IsGeneric, + LambdaCaptureDefault CaptureDefault) { CXXRecordDecl* R = new (C) CXXRecordDecl(CXXRecord, TTK_Class, DC, Loc, Loc, 0, 0); R->IsBeingDefined = true; - R->DefinitionData = new (C) struct LambdaDefinitionData(R, Info, Dependent); + R->DefinitionData = new (C) struct LambdaDefinitionData(R, Info, + Dependent, + IsGeneric, + CaptureDefault); R->MayHaveOutOfDateDef = false; + R->setImplicit(true); C.getTypeDeclType(R, /*PrevDecl=*/0); return R; } @@ -552,18 +567,16 @@ void CXXRecordDecl::addedMember(Decl *D) { if (Conversion->getPrimaryTemplate()) { // We don't record specializations. - } else if (FunTmpl) { - if (FunTmpl->getPreviousDecl()) - data().Conversions.replace(FunTmpl->getPreviousDecl(), - FunTmpl, AS); - else - data().Conversions.addDecl(getASTContext(), FunTmpl, AS); } else { - if (Conversion->getPreviousDecl()) - data().Conversions.replace(Conversion->getPreviousDecl(), - Conversion, AS); + ASTContext &Ctx = getASTContext(); + ASTUnresolvedSet &Conversions = data().Conversions.get(Ctx); + NamedDecl *Primary = + FunTmpl ? cast<NamedDecl>(FunTmpl) : cast<NamedDecl>(Conversion); + if (Primary->getPreviousDecl()) + Conversions.replace(cast<NamedDecl>(Primary->getPreviousDecl()), + Primary, AS); else - data().Conversions.addDecl(getASTContext(), Conversion, AS); + Conversions.addDecl(Ctx, Primary, AS); } } @@ -662,7 +675,7 @@ void CXXRecordDecl::addedMember(Decl *D) { if (!Context.getLangOpts().ObjCAutoRefCount || T.getObjCLifetime() != Qualifiers::OCL_ExplicitNone) setHasObjectMember(true); - } else if (!T.isPODType(Context)) + } else if (!T.isCXX98PODType(Context)) data().PlainOldData = false; if (T->isReferenceType()) { @@ -712,6 +725,13 @@ void CXXRecordDecl::addedMember(Decl *D) { if (FieldRec->getDefinition()) { addedClassSubobject(FieldRec); + // We may need to perform overload resolution to determine whether a + // field can be moved if it's const or volatile qualified. + if (T.getCVRQualifiers() & (Qualifiers::Const | Qualifiers::Volatile)) { + data().NeedOverloadResolutionForMoveConstructor = true; + data().NeedOverloadResolutionForMoveAssignment = true; + } + // C++11 [class.ctor]p5, C++11 [class.copy]p11: // A defaulted [special member] for a class X is defined as // deleted if: @@ -880,10 +900,13 @@ void CXXRecordDecl::addedMember(Decl *D) { } // Handle using declarations of conversion functions. - if (UsingShadowDecl *Shadow = dyn_cast<UsingShadowDecl>(D)) + if (UsingShadowDecl *Shadow = dyn_cast<UsingShadowDecl>(D)) { if (Shadow->getDeclName().getNameKind() - == DeclarationName::CXXConversionFunctionName) - data().Conversions.addDecl(getASTContext(), Shadow, Shadow->getAccess()); + == DeclarationName::CXXConversionFunctionName) { + ASTContext &Ctx = getASTContext(); + data().Conversions.get(Ctx).addDecl(Ctx, Shadow, Shadow->getAccess()); + } + } } void CXXRecordDecl::finishedDefaultedOrDeletedMember(CXXMethodDecl *D) { @@ -929,6 +952,43 @@ bool CXXRecordDecl::isCLike() const { return isPOD() && data().HasOnlyCMembers; } + +bool CXXRecordDecl::isGenericLambda() const { + if (!isLambda()) return false; + return getLambdaData().IsGenericLambda; +} + +CXXMethodDecl* CXXRecordDecl::getLambdaCallOperator() const { + if (!isLambda()) return 0; + DeclarationName Name = + getASTContext().DeclarationNames.getCXXOperatorName(OO_Call); + DeclContext::lookup_const_result Calls = lookup(Name); + + assert(!Calls.empty() && "Missing lambda call operator!"); + assert(Calls.size() == 1 && "More than one lambda call operator!"); + + NamedDecl *CallOp = Calls.front(); + if (FunctionTemplateDecl *CallOpTmpl = + dyn_cast<FunctionTemplateDecl>(CallOp)) + return cast<CXXMethodDecl>(CallOpTmpl->getTemplatedDecl()); + + return cast<CXXMethodDecl>(CallOp); +} + +CXXMethodDecl* CXXRecordDecl::getLambdaStaticInvoker() const { + if (!isLambda()) return 0; + DeclarationName Name = + &getASTContext().Idents.get(getLambdaStaticInvokerName()); + DeclContext::lookup_const_result Invoker = lookup(Name); + if (Invoker.empty()) return 0; + assert(Invoker.size() == 1 && "More than one static invoker operator!"); + NamedDecl *InvokerFun = Invoker.front(); + if (FunctionTemplateDecl *InvokerTemplate = + dyn_cast<FunctionTemplateDecl>(InvokerFun)) + return cast<CXXMethodDecl>(InvokerTemplate->getTemplatedDecl()); + + return cast<CXXMethodDecl>(InvokerFun); +} void CXXRecordDecl::getCaptureFields( llvm::DenseMap<const VarDecl *, FieldDecl *> &Captures, @@ -940,15 +1000,22 @@ void CXXRecordDecl::getCaptureFields( RecordDecl::field_iterator Field = field_begin(); for (LambdaExpr::Capture *C = Lambda.Captures, *CEnd = C + Lambda.NumCaptures; C != CEnd; ++C, ++Field) { - if (C->capturesThis()) { + if (C->capturesThis()) ThisCapture = *Field; - continue; - } - - Captures[C->getCapturedVar()] = *Field; + else if (C->capturesVariable()) + Captures[C->getCapturedVar()] = *Field; } + assert(Field == field_end()); } +TemplateParameterList * +CXXRecordDecl::getGenericLambdaTemplateParameterList() const { + if (!isLambda()) return 0; + CXXMethodDecl *CallOp = getLambdaCallOperator(); + if (FunctionTemplateDecl *Tmpl = CallOp->getDescribedFunctionTemplate()) + return Tmpl->getTemplateParameters(); + return 0; +} static CanQualType GetConversionType(ASTContext &Context, NamedDecl *Conv) { QualType T; @@ -1085,16 +1152,21 @@ static void CollectVisibleConversions(ASTContext &Context, /// in current class; including conversion function templates. std::pair<CXXRecordDecl::conversion_iterator,CXXRecordDecl::conversion_iterator> CXXRecordDecl::getVisibleConversionFunctions() { - // If root class, all conversions are visible. - if (bases_begin() == bases_end()) - return std::make_pair(data().Conversions.begin(), data().Conversions.end()); - // If visible conversion list is already evaluated, return it. - if (!data().ComputedVisibleConversions) { - CollectVisibleConversions(getASTContext(), this, data().VisibleConversions); - data().ComputedVisibleConversions = true; + ASTContext &Ctx = getASTContext(); + + ASTUnresolvedSet *Set; + if (bases_begin() == bases_end()) { + // If root class, all conversions are visible. + Set = &data().Conversions.get(Ctx); + } else { + Set = &data().VisibleConversions.get(Ctx); + // If visible conversion list is not evaluated, evaluate it. + if (!data().ComputedVisibleConversions) { + CollectVisibleConversions(Ctx, this, *Set); + data().ComputedVisibleConversions = true; + } } - return std::make_pair(data().VisibleConversions.begin(), - data().VisibleConversions.end()); + return std::make_pair(Set->begin(), Set->end()); } void CXXRecordDecl::removeConversion(const NamedDecl *ConvDecl) { @@ -1109,7 +1181,7 @@ void CXXRecordDecl::removeConversion(const NamedDecl *ConvDecl) { // with sufficiently large numbers of directly-declared conversions // that asymptotic behavior matters. - ASTUnresolvedSet &Convs = data().Conversions; + ASTUnresolvedSet &Convs = data().Conversions.get(getASTContext()); for (unsigned I = 0, E = Convs.size(); I != E; ++I) { if (Convs[I].getDecl() == ConvDecl) { Convs.erase(I); @@ -1134,7 +1206,7 @@ CXXRecordDecl::setInstantiationOfMemberClass(CXXRecordDecl *RD, TemplateSpecializationKind TSK) { assert(TemplateOrInstantiation.isNull() && "Previous template or instantiation?"); - assert(!isa<ClassTemplateSpecializationDecl>(this)); + assert(!isa<ClassTemplatePartialSpecializationDecl>(this)); TemplateOrInstantiation = new (getASTContext()) MemberSpecializationInfo(RD, TSK); } @@ -1235,8 +1307,7 @@ void CXXRecordDecl::completeDefinition(CXXFinalOverriderMap *FinalOverriders) { } // Set access bits correctly on the directly-declared conversions. - for (UnresolvedSetIterator I = data().Conversions.begin(), - E = data().Conversions.end(); + for (conversion_iterator I = conversion_begin(), E = conversion_end(); I != E; ++I) I.setAccess((*I)->getAccess()); } @@ -1266,21 +1337,8 @@ bool CXXMethodDecl::isStatic() const { if (MD->getStorageClass() == SC_Static) return true; - DeclarationName Name = getDeclName(); - // [class.free]p1: - // Any allocation function for a class T is a static member - // (even if not explicitly declared static). - if (Name.getCXXOverloadedOperator() == OO_New || - Name.getCXXOverloadedOperator() == OO_Array_New) - return true; - - // [class.free]p6 Any deallocation function for a class X is a static member - // (even if not explicitly declared static). - if (Name.getCXXOverloadedOperator() == OO_Delete || - Name.getCXXOverloadedOperator() == OO_Array_Delete) - return true; - - return false; + OverloadedOperatorKind OOK = getDeclName().getCXXOverloadedOperator(); + return isStaticOverloadedOperator(OOK); } static bool recursivelyOverrides(const CXXMethodDecl *DerivedMD, @@ -1408,7 +1466,8 @@ bool CXXMethodDecl::isCopyAssignmentOperator() const { // type X, X&, const X&, volatile X& or const volatile X&. if (/*operator=*/getOverloadedOperator() != OO_Equal || /*non-static*/ isStatic() || - /*non-template*/getPrimaryTemplate() || getDescribedFunctionTemplate()) + /*non-template*/getPrimaryTemplate() || getDescribedFunctionTemplate() || + getNumParams() != 1) return false; QualType ParamType = getParamDecl(0)->getType(); @@ -1427,7 +1486,8 @@ bool CXXMethodDecl::isMoveAssignmentOperator() const { // non-template member function of class X with exactly one parameter of type // X&&, const X&&, volatile X&&, or const volatile X&&. if (getOverloadedOperator() != OO_Equal || isStatic() || - getPrimaryTemplate() || getDescribedFunctionTemplate()) + getPrimaryTemplate() || getDescribedFunctionTemplate() || + getNumParams() != 1) return false; QualType ParamType = getParamDecl(0)->getType(); @@ -1492,11 +1552,17 @@ bool CXXMethodDecl::hasInlineBody() const { } bool CXXMethodDecl::isLambdaStaticInvoker() const { - return getParent()->isLambda() && - getIdentifier() && getIdentifier()->getName() == "__invoke"; + const CXXRecordDecl *P = getParent(); + if (P->isLambda()) { + if (const CXXMethodDecl *StaticInvoker = P->getLambdaStaticInvoker()) { + if (StaticInvoker == this) return true; + if (P->isGenericLambda() && this->isFunctionTemplateSpecialization()) + return StaticInvoker == this->getPrimaryTemplate()->getTemplatedDecl(); + } + } + return false; } - CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context, TypeSourceInfo *TInfo, bool IsVirtual, SourceLocation L, Expr *Init, @@ -1865,7 +1931,7 @@ NamespaceDecl::NamespaceDecl(DeclContext *DC, bool Inline, : NamedDecl(Namespace, DC, IdLoc, Id), DeclContext(Namespace), LocStart(StartLoc), RBraceLoc(), AnonOrFirstNamespaceAndInline(0, Inline) { - setPreviousDeclaration(PrevDecl); + setPreviousDecl(PrevDecl); if (PrevDecl) AnonOrFirstNamespaceAndInline.setPointer(PrevDecl->getOriginalNamespace()); @@ -1959,8 +2025,8 @@ void UsingDecl::removeShadowDecl(UsingShadowDecl *S) { UsingDecl *UsingDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation UL, NestedNameSpecifierLoc QualifierLoc, const DeclarationNameInfo &NameInfo, - bool IsTypeNameArg) { - return new (C) UsingDecl(DC, UL, QualifierLoc, NameInfo, IsTypeNameArg); + bool HasTypename) { + return new (C) UsingDecl(DC, UL, QualifierLoc, NameInfo, HasTypename); } UsingDecl *UsingDecl::CreateDeserialized(ASTContext &C, unsigned ID) { @@ -1969,6 +2035,12 @@ UsingDecl *UsingDecl::CreateDeserialized(ASTContext &C, unsigned ID) { DeclarationNameInfo(), false); } +SourceRange UsingDecl::getSourceRange() const { + SourceLocation Begin = isAccessDeclaration() + ? getQualifierLoc().getBeginLoc() : UsingLocation; + return SourceRange(Begin, getNameInfo().getEndLoc()); +} + void UnresolvedUsingValueDecl::anchor() { } UnresolvedUsingValueDecl * @@ -1988,6 +2060,12 @@ UnresolvedUsingValueDecl::CreateDeserialized(ASTContext &C, unsigned ID) { DeclarationNameInfo()); } +SourceRange UnresolvedUsingValueDecl::getSourceRange() const { + SourceLocation Begin = isAccessDeclaration() + ? getQualifierLoc().getBeginLoc() : UsingLocation; + return SourceRange(Begin, getNameInfo().getEndLoc()); +} + void UnresolvedUsingTypenameDecl::anchor() { } UnresolvedUsingTypenameDecl * diff --git a/lib/AST/DeclFriend.cpp b/lib/AST/DeclFriend.cpp index 37a812e..1c639d6 100644 --- a/lib/AST/DeclFriend.cpp +++ b/lib/AST/DeclFriend.cpp @@ -63,3 +63,8 @@ FriendDecl *FriendDecl::CreateDeserialized(ASTContext &C, unsigned ID, return new (Mem) FriendDecl(EmptyShell(), FriendTypeNumTPLists); } +FriendDecl *CXXRecordDecl::getFirstFriend() const { + ExternalASTSource *Source = getParentASTContext().getExternalSource(); + Decl *First = data().FirstFriend.get(Source); + return First ? cast<FriendDecl>(First) : 0; +} diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index 4ddbb22..b2b5b70 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -441,6 +441,17 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::lookupInheritedClass( return NULL; } +ObjCProtocolDecl * +ObjCInterfaceDecl::lookupNestedProtocol(IdentifierInfo *Name) { + for (ObjCInterfaceDecl::all_protocol_iterator P = + all_referenced_protocol_begin(), PE = all_referenced_protocol_end(); + P != PE; ++P) + if ((*P)->lookupProtocolNamed(Name)) + return (*P); + ObjCInterfaceDecl *SuperClass = getSuperClass(); + return SuperClass ? SuperClass->lookupNestedProtocol(Name) : NULL; +} + /// lookupMethod - This method returns an instance/class method by looking in /// the class, its categories, and its super classes (using a linear search). /// When argument category "C" is specified, any implicit method found @@ -627,23 +638,29 @@ ObjCMethodDecl *ObjCMethodDecl::getNextRedeclaration() { Decl *CtxD = cast<Decl>(getDeclContext()); - if (ObjCInterfaceDecl *IFD = dyn_cast<ObjCInterfaceDecl>(CtxD)) { - if (ObjCImplementationDecl *ImplD = Ctx.getObjCImplementation(IFD)) - Redecl = ImplD->getMethod(getSelector(), isInstanceMethod()); - - } else if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(CtxD)) { - if (ObjCCategoryImplDecl *ImplD = Ctx.getObjCImplementation(CD)) - Redecl = ImplD->getMethod(getSelector(), isInstanceMethod()); - - } else if (ObjCImplementationDecl *ImplD = - dyn_cast<ObjCImplementationDecl>(CtxD)) { - if (ObjCInterfaceDecl *IFD = ImplD->getClassInterface()) - Redecl = IFD->getMethod(getSelector(), isInstanceMethod()); - - } else if (ObjCCategoryImplDecl *CImplD = - dyn_cast<ObjCCategoryImplDecl>(CtxD)) { - if (ObjCCategoryDecl *CatD = CImplD->getCategoryDecl()) - Redecl = CatD->getMethod(getSelector(), isInstanceMethod()); + if (!CtxD->isInvalidDecl()) { + if (ObjCInterfaceDecl *IFD = dyn_cast<ObjCInterfaceDecl>(CtxD)) { + if (ObjCImplementationDecl *ImplD = Ctx.getObjCImplementation(IFD)) + if (!ImplD->isInvalidDecl()) + Redecl = ImplD->getMethod(getSelector(), isInstanceMethod()); + + } else if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(CtxD)) { + if (ObjCCategoryImplDecl *ImplD = Ctx.getObjCImplementation(CD)) + if (!ImplD->isInvalidDecl()) + Redecl = ImplD->getMethod(getSelector(), isInstanceMethod()); + + } else if (ObjCImplementationDecl *ImplD = + dyn_cast<ObjCImplementationDecl>(CtxD)) { + if (ObjCInterfaceDecl *IFD = ImplD->getClassInterface()) + if (!IFD->isInvalidDecl()) + Redecl = IFD->getMethod(getSelector(), isInstanceMethod()); + + } else if (ObjCCategoryImplDecl *CImplD = + dyn_cast<ObjCCategoryImplDecl>(CtxD)) { + if (ObjCCategoryDecl *CatD = CImplD->getCategoryDecl()) + if (!CatD->isInvalidDecl()) + Redecl = CatD->getMethod(getSelector(), isInstanceMethod()); + } } if (!Redecl && isRedeclaration()) { @@ -1062,7 +1079,7 @@ ObjCInterfaceDecl(DeclContext *DC, SourceLocation atLoc, IdentifierInfo *Id, : ObjCContainerDecl(ObjCInterface, DC, Id, CLoc, atLoc), TypeForDecl(0), Data() { - setPreviousDeclaration(PrevDecl); + setPreviousDecl(PrevDecl); // Copy the 'data' pointer over. if (PrevDecl) @@ -1308,7 +1325,8 @@ ObjCIvarDecl *ObjCIvarDecl::Create(ASTContext &C, ObjCContainerDecl *DC, SourceLocation IdLoc, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, AccessControl ac, Expr *BW, - bool synthesized) { + bool synthesized, + bool backingIvarReferencedInAccessor) { if (DC) { // Ivar's can only appear in interfaces, implementations (via synthesized // properties), and class extensions (via direct declaration, or synthesized @@ -1336,13 +1354,13 @@ ObjCIvarDecl *ObjCIvarDecl::Create(ASTContext &C, ObjCContainerDecl *DC, } return new (C) ObjCIvarDecl(DC, StartLoc, IdLoc, Id, T, TInfo, - ac, BW, synthesized); + ac, BW, synthesized, backingIvarReferencedInAccessor); } ObjCIvarDecl *ObjCIvarDecl::CreateDeserialized(ASTContext &C, unsigned ID) { void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ObjCIvarDecl)); return new (Mem) ObjCIvarDecl(0, SourceLocation(), SourceLocation(), 0, - QualType(), 0, ObjCIvarDecl::None, 0, false); + QualType(), 0, ObjCIvarDecl::None, 0, false, false); } const ObjCInterfaceDecl *ObjCIvarDecl::getContainingInterface() const { @@ -1401,7 +1419,7 @@ ObjCProtocolDecl::ObjCProtocolDecl(DeclContext *DC, IdentifierInfo *Id, ObjCProtocolDecl *PrevDecl) : ObjCContainerDecl(ObjCProtocol, DC, Id, nameLoc, atStartLoc), Data() { - setPreviousDeclaration(PrevDecl); + setPreviousDecl(PrevDecl); if (PrevDecl) Data = PrevDecl->Data; } @@ -1493,6 +1511,30 @@ void ObjCProtocolDecl::collectPropertiesToImplement(PropertyMap &PM, } } + +void ObjCProtocolDecl::collectInheritedProtocolProperties( + const ObjCPropertyDecl *Property, + ProtocolPropertyMap &PM) const { + if (const ObjCProtocolDecl *PDecl = getDefinition()) { + bool MatchFound = false; + for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(), + E = PDecl->prop_end(); P != E; ++P) { + ObjCPropertyDecl *Prop = *P; + if (Prop == Property) + continue; + if (Prop->getIdentifier() == Property->getIdentifier()) { + PM[PDecl] = Prop; + MatchFound = true; + break; + } + } + // Scan through protocol's protocols which did not have a matching property. + if (!MatchFound) + for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(), + E = PDecl->protocol_end(); PI != E; ++PI) + (*PI)->collectInheritedProtocolProperties(Property, PM); + } +} //===----------------------------------------------------------------------===// // ObjCCategoryDecl diff --git a/lib/AST/DeclOpenMP.cpp b/lib/AST/DeclOpenMP.cpp index c0d10a0..0d195f7 100644 --- a/lib/AST/DeclOpenMP.cpp +++ b/lib/AST/DeclOpenMP.cpp @@ -28,9 +28,9 @@ void OMPThreadPrivateDecl::anchor() { } OMPThreadPrivateDecl *OMPThreadPrivateDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, - ArrayRef<DeclRefExpr *> VL) { + ArrayRef<Expr *> VL) { unsigned Size = sizeof(OMPThreadPrivateDecl) + - (VL.size() * sizeof(DeclRefExpr *)); + (VL.size() * sizeof(Expr *)); void *Mem = C.Allocate(Size, llvm::alignOf<OMPThreadPrivateDecl>()); OMPThreadPrivateDecl *D = new (Mem) OMPThreadPrivateDecl(OMPThreadPrivate, @@ -43,7 +43,7 @@ OMPThreadPrivateDecl *OMPThreadPrivateDecl::Create(ASTContext &C, OMPThreadPrivateDecl *OMPThreadPrivateDecl::CreateDeserialized(ASTContext &C, unsigned ID, unsigned N) { - unsigned Size = sizeof(OMPThreadPrivateDecl) + (N * sizeof(DeclRefExpr *)); + unsigned Size = sizeof(OMPThreadPrivateDecl) + (N * sizeof(Expr *)); void *Mem = AllocateDeserializedDecl(C, ID, Size); OMPThreadPrivateDecl *D = new (Mem) OMPThreadPrivateDecl(OMPThreadPrivate, @@ -52,9 +52,10 @@ OMPThreadPrivateDecl *OMPThreadPrivateDecl::CreateDeserialized(ASTContext &C, return D; } -void OMPThreadPrivateDecl::setVars(ArrayRef<DeclRefExpr *> VL) { +void OMPThreadPrivateDecl::setVars(ArrayRef<Expr *> VL) { assert(VL.size() == NumVars && "Number of variables is not the same as the preallocated buffer"); - DeclRefExpr **Vars = reinterpret_cast<DeclRefExpr **>(this + 1); + Expr **Vars = reinterpret_cast<Expr **>(this + 1); std::copy(VL.begin(), VL.end(), Vars); } + diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index d47972b..767f662 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -260,6 +260,8 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) { QualType CurDeclType = getDeclType(*D); if (!Decls.empty() && !CurDeclType.isNull()) { QualType BaseType = GetBaseType(CurDeclType); + if (!BaseType.isNull() && isa<ElaboratedType>(BaseType)) + BaseType = cast<ElaboratedType>(BaseType)->getNamedType(); if (!BaseType.isNull() && isa<TagType>(BaseType) && cast<TagType>(BaseType)->getDecl() == Decls[0]) { Decls.push_back(*D); @@ -337,12 +339,14 @@ void DeclPrinter::VisitTypedefDecl(TypedefDecl *D) { if (D->isModulePrivate()) Out << "__module_private__ "; } - D->getUnderlyingType().print(Out, Policy, D->getName()); + D->getTypeSourceInfo()->getType().print(Out, Policy, D->getName()); prettyPrintAttributes(D); } void DeclPrinter::VisitTypeAliasDecl(TypeAliasDecl *D) { - Out << "using " << *D << " = " << D->getUnderlyingType().getAsString(Policy); + Out << "using " << *D; + prettyPrintAttributes(D); + Out << " = " << D->getTypeSourceInfo()->getType().getAsString(Policy); } void DeclPrinter::VisitEnumDecl(EnumDecl *D) { @@ -665,9 +669,9 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) { Out << "__module_private__ "; } - QualType T = D->getASTContext().getUnqualifiedObjCPointerType(D->getType()); - if (ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(D)) - T = Parm->getOriginalType(); + QualType T = D->getTypeSourceInfo() + ? D->getTypeSourceInfo()->getType() + : D->getASTContext().getUnqualifiedObjCPointerType(D->getType()); T.print(Out, Policy, D->getName()); Expr *Init = D->getInit(); if (!Policy.SuppressInitializers && Init) { @@ -1153,7 +1157,10 @@ void DeclPrinter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PID) { } void DeclPrinter::VisitUsingDecl(UsingDecl *D) { - Out << "using "; + if (!D->isAccessDeclaration()) + Out << "using "; + if (D->hasTypename()) + Out << "typename "; D->getQualifier()->print(Out, Policy); Out << *D; } @@ -1166,7 +1173,8 @@ DeclPrinter::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) { } void DeclPrinter::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) { - Out << "using "; + if (!D->isAccessDeclaration()) + Out << "using "; D->getQualifier()->print(Out, Policy); Out << D->getName(); } @@ -1180,9 +1188,10 @@ void DeclPrinter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) { if (!D->varlist_empty()) { for (OMPThreadPrivateDecl::varlist_iterator I = D->varlist_begin(), E = D->varlist_end(); - I != E; ++I) { - Out << (I == D->varlist_begin() ? '(' : ',') - << *cast<NamedDecl>((*I)->getDecl()); + I != E; ++I) { + Out << (I == D->varlist_begin() ? '(' : ','); + NamedDecl *ND = cast<NamedDecl>(cast<DeclRefExpr>(*I)->getDecl()); + ND->printQualifiedName(Out); } Out << ")"; } diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index 0b94f7d..7172fb7 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -129,33 +129,34 @@ static void AdoptTemplateParameterList(TemplateParameterList *Params, //===----------------------------------------------------------------------===// RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() const { - if (!Common) { - // Walk the previous-declaration chain until we either find a declaration - // with a common pointer or we run out of previous declarations. - SmallVector<const RedeclarableTemplateDecl *, 2> PrevDecls; - for (const RedeclarableTemplateDecl *Prev = getPreviousDecl(); Prev; - Prev = Prev->getPreviousDecl()) { - if (Prev->Common) { - Common = Prev->Common; - break; - } - - PrevDecls.push_back(Prev); + if (Common) + return Common; + + // Walk the previous-declaration chain until we either find a declaration + // with a common pointer or we run out of previous declarations. + SmallVector<const RedeclarableTemplateDecl *, 2> PrevDecls; + for (const RedeclarableTemplateDecl *Prev = getPreviousDecl(); Prev; + Prev = Prev->getPreviousDecl()) { + if (Prev->Common) { + Common = Prev->Common; + break; } - // If we never found a common pointer, allocate one now. - if (!Common) { - // FIXME: If any of the declarations is from an AST file, we probably - // need an update record to add the common data. - - Common = newCommon(getASTContext()); - } - - // Update any previous declarations we saw with the common pointer. - for (unsigned I = 0, N = PrevDecls.size(); I != N; ++I) - PrevDecls[I]->Common = Common; + PrevDecls.push_back(Prev); + } + + // If we never found a common pointer, allocate one now. + if (!Common) { + // FIXME: If any of the declarations is from an AST file, we probably + // need an update record to add the common data. + + Common = newCommon(getASTContext()); } + // Update any previous declarations we saw with the common pointer. + for (unsigned I = 0, N = PrevDecls.size(); I != N; ++I) + PrevDecls[I]->Common = Common; + return Common; } @@ -245,6 +246,23 @@ FunctionTemplateDecl::newCommon(ASTContext &C) const { return CommonPtr; } +void FunctionTemplateDecl::LoadLazySpecializations() const { + 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::FoldingSetVector<FunctionTemplateSpecializationInfo> & +FunctionTemplateDecl::getSpecializations() const { + LoadLazySpecializations(); + return getCommonPtr()->Specializations; +} + FunctionDecl * FunctionTemplateDecl::findSpecialization(const TemplateArgument *Args, unsigned NumArgs, void *&InsertPos) { @@ -261,18 +279,17 @@ void FunctionTemplateDecl::addSpecialization( L->AddedCXXTemplateSpecialization(this, Info->Function); } -std::pair<const TemplateArgument *, unsigned> -FunctionTemplateDecl::getInjectedTemplateArgs() { +ArrayRef<TemplateArgument> FunctionTemplateDecl::getInjectedTemplateArgs() { TemplateParameterList *Params = getTemplateParameters(); Common *CommonPtr = getCommonPtr(); if (!CommonPtr->InjectedArgs) { CommonPtr->InjectedArgs - = new (getASTContext()) TemplateArgument [Params->size()]; - GenerateInjectedTemplateArgs(getASTContext(), Params, + = new (getASTContext()) TemplateArgument[Params->size()]; + GenerateInjectedTemplateArgs(getASTContext(), Params, CommonPtr->InjectedArgs); } - - return std::make_pair(CommonPtr->InjectedArgs, Params->size()); + + return llvm::makeArrayRef(CommonPtr->InjectedArgs, Params->size()); } //===----------------------------------------------------------------------===// @@ -292,7 +309,7 @@ ClassTemplateDecl *ClassTemplateDecl::Create(ASTContext &C, ClassTemplateDecl *PrevDecl) { AdoptTemplateParameterList(Params, cast<DeclContext>(Decl)); ClassTemplateDecl *New = new (C) ClassTemplateDecl(DC, L, Name, Params, Decl); - New->setPreviousDeclaration(PrevDecl); + New->setPreviousDecl(PrevDecl); return New; } @@ -381,13 +398,11 @@ void ClassTemplateDecl::getPartialSpecializations( llvm::FoldingSetVector<ClassTemplatePartialSpecializationDecl> &PartialSpecs = getPartialSpecializations(); PS.clear(); - PS.resize(PartialSpecs.size()); + PS.reserve(PartialSpecs.size()); for (llvm::FoldingSetVector<ClassTemplatePartialSpecializationDecl>::iterator P = PartialSpecs.begin(), PEnd = PartialSpecs.end(); - P != PEnd; ++P) { - assert(!PS[P->getSequenceNumber()]); - PS[P->getSequenceNumber()] = P->getMostRecentDecl(); - } + P != PEnd; ++P) + PS.push_back(P->getMostRecentDecl()); } ClassTemplatePartialSpecializationDecl * @@ -813,19 +828,16 @@ ClassTemplatePartialSpecializationDecl(ASTContext &Context, TagKind TK, ClassTemplateDecl *SpecializedTemplate, const TemplateArgument *Args, unsigned NumArgs, - TemplateArgumentLoc *ArgInfos, - unsigned NumArgInfos, - ClassTemplatePartialSpecializationDecl *PrevDecl, - unsigned SequenceNumber) + const ASTTemplateArgumentListInfo *ArgInfos, + ClassTemplatePartialSpecializationDecl *PrevDecl) : ClassTemplateSpecializationDecl(Context, ClassTemplatePartialSpecialization, TK, DC, StartLoc, IdLoc, SpecializedTemplate, Args, NumArgs, PrevDecl), TemplateParams(Params), ArgsAsWritten(ArgInfos), - NumArgsAsWritten(NumArgInfos), SequenceNumber(SequenceNumber), InstantiatedFromMember(0, false) -{ +{ AdoptTemplateParameterList(Params, this); } @@ -839,12 +851,9 @@ Create(ASTContext &Context, TagKind TK,DeclContext *DC, unsigned NumArgs, const TemplateArgumentListInfo &ArgInfos, QualType CanonInjectedType, - ClassTemplatePartialSpecializationDecl *PrevDecl, - unsigned SequenceNumber) { - unsigned N = ArgInfos.size(); - TemplateArgumentLoc *ClonedArgs = new (Context) TemplateArgumentLoc[N]; - for (unsigned I = 0; I != N; ++I) - ClonedArgs[I] = ArgInfos[I]; + ClassTemplatePartialSpecializationDecl *PrevDecl) { + const ASTTemplateArgumentListInfo *ASTArgInfos = + ASTTemplateArgumentListInfo::Create(Context, ArgInfos); ClassTemplatePartialSpecializationDecl *Result = new (Context)ClassTemplatePartialSpecializationDecl(Context, TK, DC, @@ -852,9 +861,8 @@ Create(ASTContext &Context, TagKind TK,DeclContext *DC, Params, SpecializedTemplate, Args, NumArgs, - ClonedArgs, N, - PrevDecl, - SequenceNumber); + ASTArgInfos, + PrevDecl); Result->setSpecializationKind(TSK_ExplicitSpecialization); Result->MayHaveOutOfDateDef = false; @@ -942,3 +950,252 @@ ClassScopeFunctionSpecializationDecl::CreateDeserialized(ASTContext &C, return new (Mem) ClassScopeFunctionSpecializationDecl(0, SourceLocation(), 0, false, TemplateArgumentListInfo()); } + +//===----------------------------------------------------------------------===// +// VarTemplateDecl Implementation +//===----------------------------------------------------------------------===// + +void VarTemplateDecl::DeallocateCommon(void *Ptr) { + static_cast<Common *>(Ptr)->~Common(); +} + +VarTemplateDecl *VarTemplateDecl::getDefinition() { + VarTemplateDecl *CurD = this; + while (CurD) { + if (CurD->isThisDeclarationADefinition()) + return CurD; + CurD = CurD->getPreviousDecl(); + } + return 0; +} + +VarTemplateDecl *VarTemplateDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, DeclarationName Name, + TemplateParameterList *Params, + NamedDecl *Decl, + VarTemplateDecl *PrevDecl) { + VarTemplateDecl *New = new (C) VarTemplateDecl(DC, L, Name, Params, Decl); + New->setPreviousDecl(PrevDecl); + return New; +} + +VarTemplateDecl *VarTemplateDecl::CreateDeserialized(ASTContext &C, + unsigned ID) { + void *Mem = AllocateDeserializedDecl(C, ID, sizeof(VarTemplateDecl)); + return new (Mem) VarTemplateDecl(EmptyShell()); +} + +// TODO: Unify accross class, function and variable templates? +// May require moving this and Common to RedeclarableTemplateDecl. +void VarTemplateDecl::LoadLazySpecializations() const { + 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::FoldingSetVector<VarTemplateSpecializationDecl> & +VarTemplateDecl::getSpecializations() const { + LoadLazySpecializations(); + return getCommonPtr()->Specializations; +} + +llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl> & +VarTemplateDecl::getPartialSpecializations() { + LoadLazySpecializations(); + return getCommonPtr()->PartialSpecializations; +} + +RedeclarableTemplateDecl::CommonBase * +VarTemplateDecl::newCommon(ASTContext &C) const { + Common *CommonPtr = new (C) Common; + C.AddDeallocation(DeallocateCommon, CommonPtr); + return CommonPtr; +} + +VarTemplateSpecializationDecl * +VarTemplateDecl::findSpecialization(const TemplateArgument *Args, + unsigned NumArgs, void *&InsertPos) { + return findSpecializationImpl(getSpecializations(), Args, NumArgs, InsertPos); +} + +void VarTemplateDecl::AddSpecialization(VarTemplateSpecializationDecl *D, + void *InsertPos) { + if (InsertPos) + getSpecializations().InsertNode(D, InsertPos); + else { + VarTemplateSpecializationDecl *Existing = + getSpecializations().GetOrInsertNode(D); + (void)Existing; + assert(Existing->isCanonicalDecl() && "Non-canonical specialization?"); + } + if (ASTMutationListener *L = getASTMutationListener()) + L->AddedCXXTemplateSpecialization(this, D); +} + +VarTemplatePartialSpecializationDecl * +VarTemplateDecl::findPartialSpecialization(const TemplateArgument *Args, + unsigned NumArgs, void *&InsertPos) { + return findSpecializationImpl(getPartialSpecializations(), Args, NumArgs, + InsertPos); +} + +void VarTemplateDecl::AddPartialSpecialization( + VarTemplatePartialSpecializationDecl *D, void *InsertPos) { + if (InsertPos) + getPartialSpecializations().InsertNode(D, InsertPos); + else { + VarTemplatePartialSpecializationDecl *Existing = + getPartialSpecializations().GetOrInsertNode(D); + (void)Existing; + assert(Existing->isCanonicalDecl() && "Non-canonical specialization?"); + } + + if (ASTMutationListener *L = getASTMutationListener()) + L->AddedCXXTemplateSpecialization(this, D); +} + +void VarTemplateDecl::getPartialSpecializations( + SmallVectorImpl<VarTemplatePartialSpecializationDecl *> &PS) { + llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl> &PartialSpecs = + getPartialSpecializations(); + PS.clear(); + PS.reserve(PartialSpecs.size()); + for (llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl>::iterator + P = PartialSpecs.begin(), + PEnd = PartialSpecs.end(); + P != PEnd; ++P) + PS.push_back(P->getMostRecentDecl()); +} + +VarTemplatePartialSpecializationDecl * +VarTemplateDecl::findPartialSpecInstantiatedFromMember( + VarTemplatePartialSpecializationDecl *D) { + Decl *DCanon = D->getCanonicalDecl(); + for (llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl>::iterator + P = getPartialSpecializations().begin(), + PEnd = getPartialSpecializations().end(); + P != PEnd; ++P) { + if (P->getInstantiatedFromMember()->getCanonicalDecl() == DCanon) + return P->getMostRecentDecl(); + } + + return 0; +} + +//===----------------------------------------------------------------------===// +// VarTemplateSpecializationDecl Implementation +//===----------------------------------------------------------------------===// +VarTemplateSpecializationDecl::VarTemplateSpecializationDecl( + ASTContext &Context, Kind DK, DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, VarTemplateDecl *SpecializedTemplate, QualType T, + TypeSourceInfo *TInfo, StorageClass S, const TemplateArgument *Args, + unsigned NumArgs) + : VarDecl(DK, DC, StartLoc, IdLoc, SpecializedTemplate->getIdentifier(), T, + TInfo, S), + SpecializedTemplate(SpecializedTemplate), ExplicitInfo(0), + TemplateArgs(TemplateArgumentList::CreateCopy(Context, Args, NumArgs)), + SpecializationKind(TSK_Undeclared) {} + +VarTemplateSpecializationDecl::VarTemplateSpecializationDecl(Kind DK) + : VarDecl(DK, 0, SourceLocation(), SourceLocation(), 0, QualType(), 0, + SC_None), + ExplicitInfo(0), SpecializationKind(TSK_Undeclared) {} + +VarTemplateSpecializationDecl *VarTemplateSpecializationDecl::Create( + ASTContext &Context, DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, VarTemplateDecl *SpecializedTemplate, QualType T, + TypeSourceInfo *TInfo, StorageClass S, const TemplateArgument *Args, + unsigned NumArgs) { + VarTemplateSpecializationDecl *Result = new (Context) + VarTemplateSpecializationDecl(Context, VarTemplateSpecialization, DC, + StartLoc, IdLoc, SpecializedTemplate, T, + TInfo, S, Args, NumArgs); + return Result; +} + +VarTemplateSpecializationDecl * +VarTemplateSpecializationDecl::CreateDeserialized(ASTContext &C, unsigned ID) { + void *Mem = + AllocateDeserializedDecl(C, ID, sizeof(VarTemplateSpecializationDecl)); + VarTemplateSpecializationDecl *Result = + new (Mem) VarTemplateSpecializationDecl(VarTemplateSpecialization); + return Result; +} + +void VarTemplateSpecializationDecl::getNameForDiagnostic( + raw_ostream &OS, const PrintingPolicy &Policy, bool Qualified) const { + NamedDecl::getNameForDiagnostic(OS, Policy, Qualified); + + const TemplateArgumentList &TemplateArgs = getTemplateArgs(); + TemplateSpecializationType::PrintTemplateArgumentList( + OS, TemplateArgs.data(), TemplateArgs.size(), Policy); +} + +VarTemplateDecl *VarTemplateSpecializationDecl::getSpecializedTemplate() const { + if (SpecializedPartialSpecialization *PartialSpec = + SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization *>()) + return PartialSpec->PartialSpecialization->getSpecializedTemplate(); + return SpecializedTemplate.get<VarTemplateDecl *>(); +} + +void VarTemplateSpecializationDecl::setTemplateArgsInfo( + const TemplateArgumentListInfo &ArgsInfo) { + unsigned N = ArgsInfo.size(); + TemplateArgsInfo.setLAngleLoc(ArgsInfo.getLAngleLoc()); + TemplateArgsInfo.setRAngleLoc(ArgsInfo.getRAngleLoc()); + for (unsigned I = 0; I != N; ++I) + TemplateArgsInfo.addArgument(ArgsInfo[I]); +} + +//===----------------------------------------------------------------------===// +// VarTemplatePartialSpecializationDecl Implementation +//===----------------------------------------------------------------------===// +void VarTemplatePartialSpecializationDecl::anchor() {} + +VarTemplatePartialSpecializationDecl::VarTemplatePartialSpecializationDecl( + ASTContext &Context, DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, TemplateParameterList *Params, + VarTemplateDecl *SpecializedTemplate, QualType T, TypeSourceInfo *TInfo, + StorageClass S, const TemplateArgument *Args, unsigned NumArgs, + const ASTTemplateArgumentListInfo *ArgInfos) + : VarTemplateSpecializationDecl(Context, VarTemplatePartialSpecialization, + DC, StartLoc, IdLoc, SpecializedTemplate, T, + TInfo, S, Args, NumArgs), + TemplateParams(Params), ArgsAsWritten(ArgInfos), + InstantiatedFromMember(0, false) { + // TODO: The template parameters should be in DC by now. Verify. + // AdoptTemplateParameterList(Params, DC); +} + +VarTemplatePartialSpecializationDecl * +VarTemplatePartialSpecializationDecl::Create( + ASTContext &Context, DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, TemplateParameterList *Params, + VarTemplateDecl *SpecializedTemplate, QualType T, TypeSourceInfo *TInfo, + StorageClass S, const TemplateArgument *Args, unsigned NumArgs, + const TemplateArgumentListInfo &ArgInfos) { + const ASTTemplateArgumentListInfo *ASTArgInfos + = ASTTemplateArgumentListInfo::Create(Context, ArgInfos); + + VarTemplatePartialSpecializationDecl *Result = + new (Context) VarTemplatePartialSpecializationDecl( + Context, DC, StartLoc, IdLoc, Params, SpecializedTemplate, T, TInfo, + S, Args, NumArgs, ASTArgInfos); + Result->setSpecializationKind(TSK_ExplicitSpecialization); + return Result; +} + +VarTemplatePartialSpecializationDecl * +VarTemplatePartialSpecializationDecl::CreateDeserialized(ASTContext &C, + unsigned ID) { + void *Mem = AllocateDeserializedDecl( + C, ID, sizeof(VarTemplatePartialSpecializationDecl)); + VarTemplatePartialSpecializationDecl *Result = + new (Mem) VarTemplatePartialSpecializationDecl(); + return Result; +} diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp index e4a41b6..e064e23 100644 --- a/lib/AST/DeclarationName.cpp +++ b/lib/AST/DeclarationName.cpp @@ -133,6 +133,66 @@ int DeclarationName::compare(DeclarationName LHS, DeclarationName RHS) { llvm_unreachable("Invalid DeclarationName Kind!"); } +raw_ostream &operator<<(raw_ostream &OS, DeclarationName N) { + switch (N.getNameKind()) { + case DeclarationName::Identifier: + if (const IdentifierInfo *II = N.getAsIdentifierInfo()) + OS << II->getName(); + return OS; + + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + return OS << N.getObjCSelector().getAsString(); + + case DeclarationName::CXXConstructorName: { + QualType ClassType = N.getCXXNameType(); + if (const RecordType *ClassRec = ClassType->getAs<RecordType>()) + return OS << *ClassRec->getDecl(); + return OS << ClassType.getAsString(); + } + + case DeclarationName::CXXDestructorName: { + OS << '~'; + QualType Type = N.getCXXNameType(); + if (const RecordType *Rec = Type->getAs<RecordType>()) + return OS << *Rec->getDecl(); + return OS << Type.getAsString(); + } + + case DeclarationName::CXXOperatorName: { + static const char* const OperatorNames[NUM_OVERLOADED_OPERATORS] = { + 0, +#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ + Spelling, +#include "clang/Basic/OperatorKinds.def" + }; + const char *OpName = OperatorNames[N.getCXXOverloadedOperator()]; + assert(OpName && "not an overloaded operator"); + + OS << "operator"; + if (OpName[0] >= 'a' && OpName[0] <= 'z') + OS << ' '; + return OS << OpName; + } + + case DeclarationName::CXXLiteralOperatorName: + return OS << "operator \"\" " << N.getCXXLiteralIdentifier()->getName(); + + case DeclarationName::CXXConversionFunctionName: { + OS << "operator "; + QualType Type = N.getCXXNameType(); + if (const RecordType *Rec = Type->getAs<RecordType>()) + return OS << *Rec->getDecl(); + return OS << Type.getAsString(); + } + case DeclarationName::CXXUsingDirective: + return OS << "<using-directive>"; + } + + llvm_unreachable("Unexpected declaration name kind"); +} + } // end namespace clang DeclarationName::NameKind DeclarationName::getNameKind() const { @@ -180,80 +240,10 @@ bool DeclarationName::isDependentName() const { std::string DeclarationName::getAsString() const { std::string Result; llvm::raw_string_ostream OS(Result); - printName(OS); + OS << *this; return OS.str(); } -void DeclarationName::printName(raw_ostream &OS) const { - switch (getNameKind()) { - case Identifier: - if (const IdentifierInfo *II = getAsIdentifierInfo()) - OS << II->getName(); - return; - - case ObjCZeroArgSelector: - case ObjCOneArgSelector: - case ObjCMultiArgSelector: - OS << getObjCSelector().getAsString(); - return; - - case CXXConstructorName: { - QualType ClassType = getCXXNameType(); - if (const RecordType *ClassRec = ClassType->getAs<RecordType>()) - OS << *ClassRec->getDecl(); - else - OS << ClassType.getAsString(); - return; - } - - case CXXDestructorName: { - OS << '~'; - QualType Type = getCXXNameType(); - if (const RecordType *Rec = Type->getAs<RecordType>()) - OS << *Rec->getDecl(); - else - OS << Type.getAsString(); - return; - } - - case CXXOperatorName: { - static const char* const OperatorNames[NUM_OVERLOADED_OPERATORS] = { - 0, -#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ - Spelling, -#include "clang/Basic/OperatorKinds.def" - }; - const char *OpName = OperatorNames[getCXXOverloadedOperator()]; - assert(OpName && "not an overloaded operator"); - - OS << "operator"; - if (OpName[0] >= 'a' && OpName[0] <= 'z') - OS << ' '; - OS << OpName; - return; - } - - case CXXLiteralOperatorName: - OS << "operator \"\" " << getCXXLiteralIdentifier()->getName(); - return; - - case CXXConversionFunctionName: { - OS << "operator "; - QualType Type = getCXXNameType(); - if (const RecordType *Rec = Type->getAs<RecordType>()) - OS << *Rec->getDecl(); - else - OS << Type.getAsString(); - return; - } - case CXXUsingDirective: - OS << "<using-directive>"; - return; - } - - llvm_unreachable("Unexpected declaration name kind"); -} - QualType DeclarationName::getCXXNameType() const { if (CXXSpecialName *CXXName = getAsCXXSpecialName()) return CXXName->Type; @@ -336,8 +326,7 @@ DeclarationName DeclarationName::getUsingDirectiveName() { } void DeclarationName::dump() const { - printName(llvm::errs()); - llvm::errs() << '\n'; + llvm::errs() << *this << '\n'; } DeclarationNameTable::DeclarationNameTable(const ASTContext &C) : Ctx(C) { @@ -537,7 +526,7 @@ void DeclarationNameInfo::printName(raw_ostream &OS) const { case DeclarationName::CXXOperatorName: case DeclarationName::CXXLiteralOperatorName: case DeclarationName::CXXUsingDirective: - Name.printName(OS); + OS << Name; return; case DeclarationName::CXXConstructorName: @@ -549,9 +538,8 @@ void DeclarationNameInfo::printName(raw_ostream &OS) const { else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName) OS << "operator "; OS << TInfo->getType().getAsString(); - } - else - Name.printName(OS); + } else + OS << Name; return; } llvm_unreachable("Unexpected declaration name kind"); diff --git a/lib/AST/DumpXML.cpp b/lib/AST/DumpXML.cpp deleted file mode 100644 index be22ae4..0000000 --- a/lib/AST/DumpXML.cpp +++ /dev/null @@ -1,1053 +0,0 @@ -//===--- DumpXML.cpp - Detailed XML dumping -------------------------------===// -// -// 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/Attr.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 "llvm/ADT/SmallString.h" - -using namespace clang; - -#ifndef NDEBUG - -namespace { - -enum NodeState { - NS_Attrs, NS_LazyChildren, NS_Children -}; - -struct Node { - StringRef Name; - NodeState State; - Node(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) { - if (D->isUsed()) - static_cast<Impl*>(this)->set("used", "1"); - switch (D->getKind()) { -#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()) { -#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 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!"); -} - -struct XMLDumper : public XMLDeclVisitor<XMLDumper>, - public XMLTypeVisitor<XMLDumper> { - raw_ostream &out; - ASTContext &Context; - SmallVector<Node, 16> Stack; - unsigned Indent; - explicit XMLDumper(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(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(StringRef attr, 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(StringRef prop, const void *p) { - 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(StringRef prop, const llvm::APSInt &v) { - set(prop, v.toString(10)); - } - - void setInteger(StringRef prop, unsigned n) { - SmallString<10> buffer; - llvm::raw_svector_ostream os(buffer); - os << n; - os.flush(); - set(prop, buffer); - } - - void setFlag(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, 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(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: - case TemplateArgument::NullPtr: - // 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->getPreviousDecl()) - setPointer("previous", Prev); - } - - - // TranslationUnitDecl - void visitTranslationUnitDeclAsContext(TranslationUnitDecl *D) { - visitDeclContext(D); - } - - // LinkageSpecDecl - void visitLinkageSpecDeclAttrs(LinkageSpecDecl *D) { - 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())); - StringRef initStyle = ""; - switch (D->getInitStyle()) { - case VarDecl::CInit: initStyle = "c"; break; - case VarDecl::CallInit: initStyle = "call"; break; - case VarDecl::ListInit: initStyle = "list"; break; - } - set("initstyle", initStyle); - 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->isDeletedAsWritten()); - if (D->getStorageClass() != SC_None) - set("storage", - VarDecl::getStorageClassSpecifierString(D->getStorageClass())); - setFlag("inline", D->isInlineSpecified()); - if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>()) - set("asmlabel", ALA->getLabel()); - // TODO: instantiation, etc. - } - void visitFunctionDeclChildren(FunctionDecl *D) { - for (FunctionDecl::param_iterator - I = D->param_begin(), E = D->param_end(); I != E; ++I) - dispatch(*I); - for (ArrayRef<NamedDecl *>::iterator I = D->getDeclsInPrototypeScope().begin(), - E = D->getDeclsInPrototypeScope().end(); - I != E; ++I) - dispatch(*I); - if (D->doesThisDeclarationHaveABody()) - 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<TypedefNameDecl>(D); - } - void visitTypedefDeclChildren(TypedefDecl *D) { - dispatch(D->getTypeSourceInfo()->getTypeLoc()); - } - - // TypeAliasDecl - void visitTypeAliasDeclAttrs(TypeAliasDecl *D) { - visitRedeclarableAttrs<TypedefNameDecl>(D); - } - void visitTypeAliasDeclChildren(TypeAliasDecl *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()); - if (D->getTemplatedDecl()) - 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); - } - - void visitObjCInterfaceDeclAttrs(ObjCInterfaceDecl *D) { - setPointer("typeptr", D->getTypeForDecl()); - setFlag("forward_decl", !D->isThisDeclarationADefinition()); - 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); - } - - if (!D->visible_categories_empty()) { - TemporaryContainer C(*this, "categories"); - - for (ObjCInterfaceDecl::visible_categories_iterator - Cat = D->visible_categories_begin(), - CatEnd = D->visible_categories_end(); - Cat != CatEnd; ++Cat) { - visitDeclRef(*Cat); - } - } - } - void visitObjCInterfaceDeclAsContext(ObjCInterfaceDecl *D) { - visitDeclContext(D); - } - - // ObjCCategoryDecl - void visitObjCCategoryDeclAttrs(ObjCCategoryDecl *D) { - setFlag("extension", D->IsClassExtension()); - } - 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) { - 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); - } - } - - // ObjCProtocolDecl - void visitObjCProtocolDeclChildren(ObjCProtocolDecl *D) { - if (!D->isThisDeclarationADefinition()) - return; - - 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) { - if (!D->isThisDeclarationADefinition()) - return; - - visitDeclContext(D); - } - - // ObjCMethodDecl - void visitObjCMethodDeclAttrs(ObjCMethodDecl *D) { - // decl qualifier? - // implementation control? - - setFlag("instance", D->isInstanceMethod()); - setFlag("variadic", D->isVariadic()); - setFlag("property_accessor", D->isPropertyAccessor()); - setFlag("defined", D->isDefined()); - setFlag("related_result_type", D->hasRelatedResultType()); - } - 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(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"); - case CC_AAPCS: return set("cc", "aapcs"); - case CC_AAPCS_VFP: return set("cc", "aapcs_vfp"); - case CC_PnaclCall: return set("cc", "pnaclcall"); - case CC_IntelOclBicc: return set("cc", "intel_ocl_bicc"); - } - } - - 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->getHasRegParm()) setInteger("regparm", T->getRegParmType()); - } - void visitFunctionTypeChildren(FunctionType *T) { - dispatch(T->getResultType()); - } - - void visitFunctionProtoTypeAttrs(FunctionProtoType *T) { - setFlag("const", T->isConst()); - setFlag("volatile", T->isVolatile()); - setFlag("restrict", T->isRestrict()); - switch (T->getExceptionSpecType()) { - case EST_None: break; - case EST_DynamicNone: set("exception_spec", "throw()"); break; - case EST_Dynamic: set("exception_spec", "throw(T)"); break; - case EST_MSAny: set("exception_spec", "throw(...)"); break; - case EST_BasicNoexcept: set("exception_spec", "noexcept"); break; - case EST_ComputedNoexcept: set("exception_spec", "noexcept(expr)"); break; - case EST_Unevaluated: set("exception_spec", "unevaluated"); break; - case EST_Uninstantiated: set("exception_spec", "uninstantiated"); break; - } - } - 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->hasDynamicExceptionSpec()) { - push("exception_specifiers"); - setFlag("any", T->getExceptionSpecType() == EST_MSAny); - completeAttrs(); - for (FunctionProtoType::exception_iterator - I = T->exception_begin(), E = T->exception_end(); I != E; ++I) - dispatch(*I); - pop(); - } - // FIXME: noexcept specifier - } - - 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(raw_ostream &out) const { - XMLDumper(out, getASTContext()).dispatch(const_cast<Decl*>(this)); -} - -#else /* ifndef NDEBUG */ - -void Decl::dumpXML() const {} -void Decl::dumpXML(raw_ostream &out) const {} - -#endif diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 9538ddf..9055ddac 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -20,6 +20,7 @@ #include "clang/AST/EvaluatedExprVisitor.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/Mangle.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/StmtVisitor.h" #include "clang/Basic/Builtins.h" @@ -50,9 +51,9 @@ const CXXRecordDecl *Expr::getBestDynamicClassType() const { return cast<CXXRecordDecl>(D); } -const Expr * -Expr::skipRValueSubobjectAdjustments( - SmallVectorImpl<SubobjectAdjustment> &Adjustments) const { +const Expr *Expr::skipRValueSubobjectAdjustments( + SmallVectorImpl<const Expr *> &CommaLHSs, + SmallVectorImpl<SubobjectAdjustment> &Adjustments) const { const Expr *E = this; while (true) { E = E->IgnoreParens(); @@ -73,12 +74,14 @@ Expr::skipRValueSubobjectAdjustments( continue; } } else if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) { - if (!ME->isArrow() && ME->getBase()->isRValue()) { + if (!ME->isArrow()) { assert(ME->getBase()->getType()->isRecordType()); if (FieldDecl *Field = dyn_cast<FieldDecl>(ME->getMemberDecl())) { - E = ME->getBase(); - Adjustments.push_back(SubobjectAdjustment(Field)); - continue; + if (!Field->isBitField() && !Field->getType()->isReferenceType()) { + E = ME->getBase(); + Adjustments.push_back(SubobjectAdjustment(Field)); + continue; + } } } } else if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) { @@ -88,6 +91,11 @@ Expr::skipRValueSubobjectAdjustments( const MemberPointerType *MPT = BO->getRHS()->getType()->getAs<MemberPointerType>(); Adjustments.push_back(SubobjectAdjustment(MPT, BO->getRHS())); + continue; + } else if (BO->getOpcode() == BO_Comma) { + CommaLHSs.push_back(BO->getLHS()); + E = BO->getRHS(); + continue; } } @@ -231,8 +239,8 @@ SourceLocation Expr::getExprLoc() const { /// \brief Compute the type-, value-, and instantiation-dependence of a /// declaration reference /// based on the declaration being referenced. -static void computeDeclRefDependence(ASTContext &Ctx, NamedDecl *D, QualType T, - bool &TypeDependent, +static void computeDeclRefDependence(const ASTContext &Ctx, NamedDecl *D, + QualType T, bool &TypeDependent, bool &ValueDependent, bool &InstantiationDependent) { TypeDependent = false; @@ -307,6 +315,9 @@ static void computeDeclRefDependence(ASTContext &Ctx, NamedDecl *D, QualType T, Var->getDeclContext()->isDependentContext()) { ValueDependent = true; InstantiationDependent = true; + TypeSourceInfo *TInfo = Var->getFirstDecl()->getTypeSourceInfo(); + if (TInfo->getType()->isIncompleteArrayType()) + TypeDependent = true; } return; @@ -321,7 +332,7 @@ static void computeDeclRefDependence(ASTContext &Ctx, NamedDecl *D, QualType T, } } -void DeclRefExpr::computeDependence(ASTContext &Ctx) { +void DeclRefExpr::computeDependence(const ASTContext &Ctx) { bool TypeDependent = false; bool ValueDependent = false; bool InstantiationDependent = false; @@ -355,7 +366,7 @@ void DeclRefExpr::computeDependence(ASTContext &Ctx) { ExprBits.ContainsUnexpandedParameterPack = true; } -DeclRefExpr::DeclRefExpr(ASTContext &Ctx, +DeclRefExpr::DeclRefExpr(const ASTContext &Ctx, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, ValueDecl *D, bool RefersToEnclosingLocal, @@ -392,7 +403,7 @@ DeclRefExpr::DeclRefExpr(ASTContext &Ctx, computeDependence(Ctx); } -DeclRefExpr *DeclRefExpr::Create(ASTContext &Context, +DeclRefExpr *DeclRefExpr::Create(const ASTContext &Context, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, ValueDecl *D, @@ -408,7 +419,7 @@ DeclRefExpr *DeclRefExpr::Create(ASTContext &Context, T, VK, FoundD, TemplateArgs); } -DeclRefExpr *DeclRefExpr::Create(ASTContext &Context, +DeclRefExpr *DeclRefExpr::Create(const ASTContext &Context, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, ValueDecl *D, @@ -423,7 +434,7 @@ DeclRefExpr *DeclRefExpr::Create(ASTContext &Context, FoundD = 0; std::size_t Size = sizeof(DeclRefExpr); - if (QualifierLoc != 0) + if (QualifierLoc) Size += sizeof(NestedNameSpecifierLoc); if (FoundD) Size += sizeof(NamedDecl *); @@ -438,7 +449,7 @@ DeclRefExpr *DeclRefExpr::Create(ASTContext &Context, NameInfo, FoundD, TemplateArgs, T, VK); } -DeclRefExpr *DeclRefExpr::CreateEmpty(ASTContext &Context, +DeclRefExpr *DeclRefExpr::CreateEmpty(const ASTContext &Context, bool HasQualifier, bool HasFoundDecl, bool HasTemplateKWAndArgsInfo, @@ -471,6 +482,30 @@ SourceLocation DeclRefExpr::getLocEnd() const { std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) { ASTContext &Context = CurrentDecl->getASTContext(); + if (IT == PredefinedExpr::FuncDName) { + if (const NamedDecl *ND = dyn_cast<NamedDecl>(CurrentDecl)) { + OwningPtr<MangleContext> MC; + MC.reset(Context.createMangleContext()); + + if (MC->shouldMangleDeclName(ND)) { + SmallString<256> Buffer; + llvm::raw_svector_ostream Out(Buffer); + if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(ND)) + MC->mangleCXXCtor(CD, Ctor_Base, Out); + else if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(ND)) + MC->mangleCXXDtor(DD, Dtor_Base, Out); + else + MC->mangleName(ND, Out); + + Out.flush(); + if (!Buffer.empty() && Buffer.front() == '\01') + return Buffer.substr(1); + return Buffer.str(); + } else + return ND->getIdentifier()->getName(); + } + return ""; + } if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CurrentDecl)) { if (IT != PrettyFunction && IT != PrettyFunctionNoVirtual) return FD->getNameAsString(); @@ -578,7 +613,18 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) { POut.flush(); - if (!isa<CXXConstructorDecl>(FD) && !isa<CXXDestructorDecl>(FD)) + // Print "auto" for all deduced return types. This includes C++1y return + // type deduction and lambdas. For trailing return types resolve the + // decltype expression. Otherwise print the real type when this is + // not a constructor or destructor. + if ((isa<CXXMethodDecl>(FD) && + cast<CXXMethodDecl>(FD)->getParent()->isLambda()) || + (FT && FT->getResultType()->getAs<AutoType>())) + Proto = "auto " + Proto; + else if (FT && FT->getResultType()->getAs<DecltypeType>()) + FT->getResultType()->getAs<DecltypeType>()->getUnderlyingType() + .getAsStringInternal(Proto, Policy); + else if (!isa<CXXConstructorDecl>(FD) && !isa<CXXDestructorDecl>(FD)) AFT->getResultType().getAsStringInternal(Proto, Policy); Out << Proto; @@ -586,6 +632,16 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) { Out.flush(); return Name.str().str(); } + if (const CapturedDecl *CD = dyn_cast<CapturedDecl>(CurrentDecl)) { + for (const DeclContext *DC = CD->getParent(); DC; DC = DC->getParent()) + // Skip to its enclosing function or method, but not its enclosing + // CapturedDecl. + if (DC->isFunctionOrMethod() && (DC->getDeclKind() != Decl::Captured)) { + const Decl *D = Decl::castFromDeclContext(DC); + return ComputeName(IT, D); + } + llvm_unreachable("CapturedDecl not inside a function or method"); + } if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(CurrentDecl)) { SmallString<256> Name; llvm::raw_svector_ostream Out(Name); @@ -615,7 +671,8 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) { return ""; } -void APNumericStorage::setIntValue(ASTContext &C, const llvm::APInt &Val) { +void APNumericStorage::setIntValue(const ASTContext &C, + const llvm::APInt &Val) { if (hasAllocation()) C.Deallocate(pVal); @@ -631,7 +688,7 @@ void APNumericStorage::setIntValue(ASTContext &C, const llvm::APInt &Val) { VAL = 0; } -IntegerLiteral::IntegerLiteral(ASTContext &C, const llvm::APInt &V, +IntegerLiteral::IntegerLiteral(const ASTContext &C, const llvm::APInt &V, QualType type, SourceLocation l) : Expr(IntegerLiteralClass, type, VK_RValue, OK_Ordinary, false, false, false, false), @@ -643,17 +700,17 @@ IntegerLiteral::IntegerLiteral(ASTContext &C, const llvm::APInt &V, } IntegerLiteral * -IntegerLiteral::Create(ASTContext &C, const llvm::APInt &V, +IntegerLiteral::Create(const ASTContext &C, const llvm::APInt &V, QualType type, SourceLocation l) { return new (C) IntegerLiteral(C, V, type, l); } IntegerLiteral * -IntegerLiteral::Create(ASTContext &C, EmptyShell Empty) { +IntegerLiteral::Create(const ASTContext &C, EmptyShell Empty) { return new (C) IntegerLiteral(Empty); } -FloatingLiteral::FloatingLiteral(ASTContext &C, const llvm::APFloat &V, +FloatingLiteral::FloatingLiteral(const ASTContext &C, const llvm::APFloat &V, bool isexact, QualType Type, SourceLocation L) : Expr(FloatingLiteralClass, Type, VK_RValue, OK_Ordinary, false, false, false, false), Loc(L) { @@ -662,20 +719,20 @@ FloatingLiteral::FloatingLiteral(ASTContext &C, const llvm::APFloat &V, setValue(C, V); } -FloatingLiteral::FloatingLiteral(ASTContext &C, EmptyShell Empty) +FloatingLiteral::FloatingLiteral(const ASTContext &C, EmptyShell Empty) : Expr(FloatingLiteralClass, Empty) { setRawSemantics(IEEEhalf); FloatingLiteralBits.IsExact = false; } FloatingLiteral * -FloatingLiteral::Create(ASTContext &C, const llvm::APFloat &V, +FloatingLiteral::Create(const ASTContext &C, const llvm::APFloat &V, bool isexact, QualType Type, SourceLocation L) { return new (C) FloatingLiteral(C, V, isexact, Type, L); } FloatingLiteral * -FloatingLiteral::Create(ASTContext &C, EmptyShell Empty) { +FloatingLiteral::Create(const ASTContext &C, EmptyShell Empty) { return new (C) FloatingLiteral(C, Empty); } @@ -749,7 +806,7 @@ int StringLiteral::mapCharByteWidth(TargetInfo const &target,StringKind k) { return CharByteWidth; } -StringLiteral *StringLiteral::Create(ASTContext &C, StringRef Str, +StringLiteral *StringLiteral::Create(const ASTContext &C, StringRef Str, StringKind Kind, bool Pascal, QualType Ty, const SourceLocation *Loc, unsigned NumStrs) { @@ -771,7 +828,8 @@ StringLiteral *StringLiteral::Create(ASTContext &C, StringRef Str, return SL; } -StringLiteral *StringLiteral::CreateEmpty(ASTContext &C, unsigned NumStrs) { +StringLiteral *StringLiteral::CreateEmpty(const ASTContext &C, + unsigned NumStrs) { void *Mem = C.Allocate(sizeof(StringLiteral)+ sizeof(SourceLocation)*(NumStrs-1), llvm::alignOf<StringLiteral>()); @@ -875,7 +933,7 @@ void StringLiteral::outputString(raw_ostream &OS) const { OS << '"'; } -void StringLiteral::setString(ASTContext &C, StringRef Str, +void StringLiteral::setString(const ASTContext &C, StringRef Str, StringKind Kind, bool IsPascal) { //FIXME: we assume that the string data comes from a target that uses the same // code unit size and endianess for the type of string. @@ -1028,9 +1086,9 @@ OverloadedOperatorKind UnaryOperator::getOverloadedOperator(Opcode Opc) { // Postfix Operators. //===----------------------------------------------------------------------===// -CallExpr::CallExpr(ASTContext& C, StmtClass SC, Expr *fn, unsigned NumPreArgs, - ArrayRef<Expr*> args, QualType t, ExprValueKind VK, - SourceLocation rparenloc) +CallExpr::CallExpr(const ASTContext& C, StmtClass SC, Expr *fn, + unsigned NumPreArgs, ArrayRef<Expr*> args, QualType t, + ExprValueKind VK, SourceLocation rparenloc) : Expr(SC, t, VK, OK_Ordinary, fn->isTypeDependent(), fn->isValueDependent(), @@ -1057,7 +1115,7 @@ CallExpr::CallExpr(ASTContext& C, StmtClass SC, Expr *fn, unsigned NumPreArgs, RParenLoc = rparenloc; } -CallExpr::CallExpr(ASTContext& C, Expr *fn, ArrayRef<Expr*> args, +CallExpr::CallExpr(const ASTContext& C, Expr *fn, ArrayRef<Expr*> args, QualType t, ExprValueKind VK, SourceLocation rparenloc) : Expr(CallExprClass, t, VK, OK_Ordinary, fn->isTypeDependent(), @@ -1085,14 +1143,14 @@ CallExpr::CallExpr(ASTContext& C, Expr *fn, ArrayRef<Expr*> args, RParenLoc = rparenloc; } -CallExpr::CallExpr(ASTContext &C, StmtClass SC, EmptyShell Empty) +CallExpr::CallExpr(const ASTContext &C, StmtClass SC, EmptyShell Empty) : Expr(SC, Empty), SubExprs(0), NumArgs(0) { // FIXME: Why do we allocate this? SubExprs = new (C) Stmt*[PREARGS_START]; CallExprBits.NumPreArgs = 0; } -CallExpr::CallExpr(ASTContext &C, StmtClass SC, unsigned NumPreArgs, +CallExpr::CallExpr(const ASTContext &C, StmtClass SC, unsigned NumPreArgs, EmptyShell Empty) : Expr(SC, Empty), SubExprs(0), NumArgs(0) { // FIXME: Why do we allocate this? @@ -1131,7 +1189,7 @@ FunctionDecl *CallExpr::getDirectCallee() { /// setNumArgs - This changes the number of arguments present in this call. /// Any orphaned expressions are deleted by this, and any new operands are set /// to null. -void CallExpr::setNumArgs(ASTContext& C, unsigned NumArgs) { +void CallExpr::setNumArgs(const ASTContext& C, unsigned NumArgs) { // No change, just return. if (NumArgs == getNumArgs()) return; @@ -1220,7 +1278,7 @@ SourceLocation CallExpr::getLocEnd() const { return end; } -OffsetOfExpr *OffsetOfExpr::Create(ASTContext &C, QualType type, +OffsetOfExpr *OffsetOfExpr::Create(const ASTContext &C, QualType type, SourceLocation OperatorLoc, TypeSourceInfo *tsi, ArrayRef<OffsetOfNode> comps, @@ -1234,7 +1292,7 @@ OffsetOfExpr *OffsetOfExpr::Create(ASTContext &C, QualType type, RParenLoc); } -OffsetOfExpr *OffsetOfExpr::CreateEmpty(ASTContext &C, +OffsetOfExpr *OffsetOfExpr::CreateEmpty(const ASTContext &C, unsigned numComps, unsigned numExprs) { void *Mem = C.Allocate(sizeof(OffsetOfExpr) + sizeof(OffsetOfNode) * numComps + @@ -1242,7 +1300,7 @@ OffsetOfExpr *OffsetOfExpr::CreateEmpty(ASTContext &C, return new (Mem) OffsetOfExpr(numComps, numExprs); } -OffsetOfExpr::OffsetOfExpr(ASTContext &C, QualType type, +OffsetOfExpr::OffsetOfExpr(const ASTContext &C, QualType type, SourceLocation OperatorLoc, TypeSourceInfo *tsi, ArrayRef<OffsetOfNode> comps, ArrayRef<Expr*> exprs, SourceLocation RParenLoc) @@ -1276,7 +1334,7 @@ IdentifierInfo *OffsetOfExpr::OffsetOfNode::getFieldName() const { return reinterpret_cast<IdentifierInfo *> (Data & ~(uintptr_t)Mask); } -MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow, +MemberExpr *MemberExpr::Create(const ASTContext &C, Expr *base, bool isarrow, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, ValueDecl *memberdecl, @@ -1630,7 +1688,7 @@ void CastExpr::setCastPath(const CXXCastPath &Path) { memcpy(path_buffer(), Path.data(), Path.size() * sizeof(CXXBaseSpecifier*)); } -ImplicitCastExpr *ImplicitCastExpr::Create(ASTContext &C, QualType T, +ImplicitCastExpr *ImplicitCastExpr::Create(const ASTContext &C, QualType T, CastKind Kind, Expr *Operand, const CXXCastPath *BasePath, ExprValueKind VK) { @@ -1643,7 +1701,7 @@ ImplicitCastExpr *ImplicitCastExpr::Create(ASTContext &C, QualType T, return E; } -ImplicitCastExpr *ImplicitCastExpr::CreateEmpty(ASTContext &C, +ImplicitCastExpr *ImplicitCastExpr::CreateEmpty(const ASTContext &C, unsigned PathSize) { void *Buffer = C.Allocate(sizeof(ImplicitCastExpr) + PathSize * sizeof(CXXBaseSpecifier*)); @@ -1651,7 +1709,7 @@ ImplicitCastExpr *ImplicitCastExpr::CreateEmpty(ASTContext &C, } -CStyleCastExpr *CStyleCastExpr::Create(ASTContext &C, QualType T, +CStyleCastExpr *CStyleCastExpr::Create(const ASTContext &C, QualType T, ExprValueKind VK, CastKind K, Expr *Op, const CXXCastPath *BasePath, TypeSourceInfo *WrittenTy, @@ -1665,7 +1723,8 @@ CStyleCastExpr *CStyleCastExpr::Create(ASTContext &C, QualType T, return E; } -CStyleCastExpr *CStyleCastExpr::CreateEmpty(ASTContext &C, unsigned PathSize) { +CStyleCastExpr *CStyleCastExpr::CreateEmpty(const ASTContext &C, + unsigned PathSize) { void *Buffer = C.Allocate(sizeof(CStyleCastExpr) + PathSize * sizeof(CXXBaseSpecifier*)); return new (Buffer) CStyleCastExpr(EmptyShell(), PathSize); @@ -1774,7 +1833,7 @@ OverloadedOperatorKind BinaryOperator::getOverloadedOperator(Opcode Opc) { return OverOps[Opc]; } -InitListExpr::InitListExpr(ASTContext &C, SourceLocation lbraceloc, +InitListExpr::InitListExpr(const ASTContext &C, SourceLocation lbraceloc, ArrayRef<Expr*> initExprs, SourceLocation rbraceloc) : Expr(InitListExprClass, QualType(), VK_RValue, OK_Ordinary, false, false, false, false), @@ -1782,7 +1841,6 @@ InitListExpr::InitListExpr(ASTContext &C, SourceLocation lbraceloc, LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), AltForm(0, true) { sawArrayRangeDesignator(false); - setInitializesStdInitializerList(false); for (unsigned I = 0; I != initExprs.size(); ++I) { if (initExprs[I]->isTypeDependent()) ExprBits.TypeDependent = true; @@ -1797,16 +1855,16 @@ InitListExpr::InitListExpr(ASTContext &C, SourceLocation lbraceloc, InitExprs.insert(C, InitExprs.end(), initExprs.begin(), initExprs.end()); } -void InitListExpr::reserveInits(ASTContext &C, unsigned NumInits) { +void InitListExpr::reserveInits(const ASTContext &C, unsigned NumInits) { if (NumInits > InitExprs.size()) InitExprs.reserve(C, NumInits); } -void InitListExpr::resizeInits(ASTContext &C, unsigned NumInits) { +void InitListExpr::resizeInits(const ASTContext &C, unsigned NumInits) { InitExprs.resize(C, NumInits, 0); } -Expr *InitListExpr::updateInit(ASTContext &C, unsigned Init, Expr *expr) { +Expr *InitListExpr::updateInit(const ASTContext &C, unsigned Init, Expr *expr) { if (Init >= InitExprs.size()) { InitExprs.insert(C, InitExprs.end(), Init - InitExprs.size() + 1, 0); InitExprs.back() = expr; @@ -1923,6 +1981,9 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc, case GenericSelectionExprClass: return cast<GenericSelectionExpr>(this)->getResultExpr()-> isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx); + case ChooseExprClass: + return cast<ChooseExpr>(this)->getChosenSubExpr()-> + isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx); case UnaryOperatorClass: { const UnaryOperator *UO = cast<UnaryOperator>(this); @@ -2066,17 +2127,24 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc, return false; case CXXTemporaryObjectExprClass: - case CXXConstructExprClass: + case CXXConstructExprClass: { + if (const CXXRecordDecl *Type = getType()->getAsCXXRecordDecl()) { + if (Type->hasAttr<WarnUnusedAttr>()) { + WarnE = this; + Loc = getLocStart(); + R1 = getSourceRange(); + return true; + } + } return false; + } case ObjCMessageExprClass: { const ObjCMessageExpr *ME = cast<ObjCMessageExpr>(this); if (Ctx.getLangOpts().ObjCAutoRefCount && ME->isInstanceMessage() && !ME->getType()->isVoidType() && - ME->getSelector().getIdentifierInfoForSlot(0) && - ME->getSelector().getIdentifierInfoForSlot(0) - ->getName().startswith("init")) { + ME->getMethodFamily() == OMF_init) { WarnE = this; Loc = getExprLoc(); R1 = ME->getSourceRange(); @@ -2161,7 +2229,7 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc, WarnE = this; if (const CXXFunctionalCastExpr *CXXCE = dyn_cast<CXXFunctionalCastExpr>(this)) { - Loc = CXXCE->getTypeBeginLoc(); + Loc = CXXCE->getLocStart(); R1 = CXXCE->getSubExpr()->getSourceRange(); } else { const CStyleCastExpr *CStyleCE = cast<CStyleCastExpr>(this); @@ -2291,6 +2359,12 @@ Expr* Expr::IgnoreParens() { continue; } } + if (ChooseExpr* P = dyn_cast<ChooseExpr>(E)) { + if (!P->isConditionDependent()) { + E = P->getChosenSubExpr(); + continue; + } + } return E; } } @@ -2300,26 +2374,11 @@ Expr* Expr::IgnoreParens() { Expr *Expr::IgnoreParenCasts() { Expr *E = this; while (true) { - if (ParenExpr* P = dyn_cast<ParenExpr>(E)) { - E = P->getSubExpr(); - continue; - } + E = E->IgnoreParens(); if (CastExpr *P = dyn_cast<CastExpr>(E)) { E = P->getSubExpr(); continue; } - if (UnaryOperator* P = dyn_cast<UnaryOperator>(E)) { - if (P->getOpcode() == UO_Extension) { - E = P->getSubExpr(); - continue; - } - } - if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) { - if (!P->isResultDependent()) { - E = P->getResultExpr(); - continue; - } - } if (MaterializeTemporaryExpr *Materialize = dyn_cast<MaterializeTemporaryExpr>(E)) { E = Materialize->GetTemporaryExpr(); @@ -2341,24 +2400,12 @@ Expr *Expr::IgnoreParenCasts() { 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)) { + E = E->IgnoreParens(); + 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; - } - } else if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) { - if (!P->isResultDependent()) { - E = P->getResultExpr(); - continue; - } } else if (MaterializeTemporaryExpr *Materialize = dyn_cast<MaterializeTemporaryExpr>(E)) { E = Materialize->GetTemporaryExpr(); @@ -2376,10 +2423,7 @@ Expr *Expr::IgnoreParenLValueCasts() { Expr *Expr::ignoreParenBaseCasts() { Expr *E = this; while (true) { - if (ParenExpr *P = dyn_cast<ParenExpr>(E)) { - E = P->getSubExpr(); - continue; - } + E = E->IgnoreParens(); if (CastExpr *CE = dyn_cast<CastExpr>(E)) { if (CE->getCastKind() == CK_DerivedToBase || CE->getCastKind() == CK_UncheckedDerivedToBase || @@ -2396,26 +2440,11 @@ Expr *Expr::ignoreParenBaseCasts() { Expr *Expr::IgnoreParenImpCasts() { Expr *E = this; while (true) { - if (ParenExpr *P = dyn_cast<ParenExpr>(E)) { - E = P->getSubExpr(); - continue; - } + E = E->IgnoreParens(); if (ImplicitCastExpr *P = dyn_cast<ImplicitCastExpr>(E)) { E = P->getSubExpr(); continue; } - if (UnaryOperator* P = dyn_cast<UnaryOperator>(E)) { - if (P->getOpcode() == UO_Extension) { - E = P->getSubExpr(); - continue; - } - } - if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) { - if (!P->isResultDependent()) { - E = P->getResultExpr(); - continue; - } - } if (MaterializeTemporaryExpr *Materialize = dyn_cast<MaterializeTemporaryExpr>(E)) { E = Materialize->GetTemporaryExpr(); @@ -2444,10 +2473,7 @@ Expr *Expr::IgnoreConversionOperator() { Expr *Expr::IgnoreParenNoopCasts(ASTContext &Ctx) { Expr *E = this; while (true) { - if (ParenExpr *P = dyn_cast<ParenExpr>(E)) { - E = P->getSubExpr(); - continue; - } + E = E->IgnoreParens(); if (CastExpr *P = dyn_cast<CastExpr>(E)) { // We ignore integer <-> casts that are of the same width, ptr<->ptr and @@ -2469,20 +2495,6 @@ Expr *Expr::IgnoreParenNoopCasts(ASTContext &Ctx) { } } - if (UnaryOperator* P = dyn_cast<UnaryOperator>(E)) { - if (P->getOpcode() == UO_Extension) { - E = P->getSubExpr(); - continue; - } - } - - if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) { - if (!P->isResultDependent()) { - E = P->getResultExpr(); - continue; - } - } - if (SubstNonTypeTemplateParmExpr *NTTP = dyn_cast<SubstNonTypeTemplateParmExpr>(E)) { E = NTTP->getReplacement(); @@ -2628,11 +2640,11 @@ bool Expr::hasAnyTypeDependentArguments(ArrayRef<Expr *> Exprs) { bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const { // This function is attempting whether an expression is an initializer - // which can be evaluated at compile-time. isEvaluatable handles most - // of the cases, but it can't deal with some initializer-specific - // expressions, and it can't deal with aggregates; we deal with those here, - // and fall back to isEvaluatable for the other cases. - + // which can be evaluated at compile-time. It very closely parallels + // ConstExprEmitter in CGExprConstant.cpp; if they don't match, it + // will lead to unexpected results. Like ConstExprEmitter, it falls back + // to isEvaluatable most of the time. + // // If we ever capture reference-binding directly in the AST, we can // kill the second parameter. @@ -2643,30 +2655,23 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const { switch (getStmtClass()) { default: break; - case IntegerLiteralClass: - case FloatingLiteralClass: case StringLiteralClass: - case ObjCStringLiteralClass: case ObjCEncodeExprClass: return true; case CXXTemporaryObjectExprClass: case CXXConstructExprClass: { const CXXConstructExpr *CE = cast<CXXConstructExpr>(this); - // Only if it's - if (CE->getConstructor()->isTrivial()) { - // 1) an application of the trivial default constructor or + if (CE->getConstructor()->isTrivial() && + CE->getConstructor()->getParent()->hasTrivialDestructor()) { + // Trivial default constructor if (!CE->getNumArgs()) return true; - // 2) an elidable trivial copy construction of an operand which is - // itself a constant initializer. Note that we consider the - // operand on its own, *not* as a reference binding. - if (CE->isElidable() && - CE->getArg(0)->isConstantInitializer(Ctx, false)) - return true; + // Trivial copy constructor + assert(CE->getNumArgs() == 1 && "trivial ctor with > 1 argument"); + return CE->getArg(0)->isConstantInitializer(Ctx, false); } - // 3) a foldable constexpr constructor. break; } case CompoundLiteralExprClass: { @@ -2677,16 +2682,47 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const { return Exp->isConstantInitializer(Ctx, false); } case InitListExprClass: { - // FIXME: This doesn't deal with fields with reference types correctly. - // FIXME: This incorrectly allows pointers cast to integers to be assigned - // to bitfields. - const InitListExpr *Exp = cast<InitListExpr>(this); - unsigned numInits = Exp->getNumInits(); - for (unsigned i = 0; i < numInits; i++) { - if (!Exp->getInit(i)->isConstantInitializer(Ctx, false)) - return false; + const InitListExpr *ILE = cast<InitListExpr>(this); + if (ILE->getType()->isArrayType()) { + unsigned numInits = ILE->getNumInits(); + for (unsigned i = 0; i < numInits; i++) { + if (!ILE->getInit(i)->isConstantInitializer(Ctx, false)) + return false; + } + return true; } - return true; + + if (ILE->getType()->isRecordType()) { + unsigned ElementNo = 0; + RecordDecl *RD = ILE->getType()->getAs<RecordType>()->getDecl(); + for (RecordDecl::field_iterator Field = RD->field_begin(), + FieldEnd = RD->field_end(); Field != FieldEnd; ++Field) { + // If this is a union, skip all the fields that aren't being initialized. + if (RD->isUnion() && ILE->getInitializedFieldInUnion() != *Field) + continue; + + // Don't emit anonymous bitfields, they just affect layout. + if (Field->isUnnamedBitfield()) + continue; + + if (ElementNo < ILE->getNumInits()) { + const Expr *Elt = ILE->getInit(ElementNo++); + if (Field->isBitField()) { + // Bitfields have to evaluate to an integer. + llvm::APSInt ResultTmp; + if (!Elt->EvaluateAsInt(ResultTmp, Ctx)) + return false; + } else { + bool RefType = Field->getType()->isReferenceType(); + if (!Elt->isConstantInitializer(Ctx, RefType)) + return false; + } + } + } + return true; + } + + break; } case ImplicitValueInitExprClass: return true; @@ -2694,12 +2730,12 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const { return cast<ParenExpr>(this)->getSubExpr() ->isConstantInitializer(Ctx, IsForRef); case GenericSelectionExprClass: - if (cast<GenericSelectionExpr>(this)->isResultDependent()) - return false; return cast<GenericSelectionExpr>(this)->getResultExpr() ->isConstantInitializer(Ctx, IsForRef); case ChooseExprClass: - return cast<ChooseExpr>(this)->getChosenSubExpr(Ctx) + if (cast<ChooseExpr>(this)->isConditionDependent()) + return false; + return cast<ChooseExpr>(this)->getChosenSubExpr() ->isConstantInitializer(Ctx, IsForRef); case UnaryOperatorClass: { const UnaryOperator* Exp = cast<UnaryOperator>(this); @@ -2710,31 +2746,20 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const { case CXXFunctionalCastExprClass: case CXXStaticCastExprClass: case ImplicitCastExprClass: - case CStyleCastExprClass: { + case CStyleCastExprClass: + case ObjCBridgedCastExprClass: + case CXXDynamicCastExprClass: + case CXXReinterpretCastExprClass: + case CXXConstCastExprClass: { const CastExpr *CE = cast<CastExpr>(this); - // If we're promoting an integer to an _Atomic type then this is constant - // if the integer is constant. We also need to check the converse in case - // someone does something like: - // - // int a = (_Atomic(int))42; - // - // I doubt anyone would write code like this directly, but it's quite - // possible as the result of macro expansions. - if (CE->getCastKind() == CK_NonAtomicToAtomic || - CE->getCastKind() == CK_AtomicToNonAtomic) - return CE->getSubExpr()->isConstantInitializer(Ctx, false); - - // Handle bitcasts of vector constants. - if (getType()->isVectorType() && CE->getCastKind() == CK_BitCast) - return CE->getSubExpr()->isConstantInitializer(Ctx, false); - // Handle misc casts we want to ignore. - // FIXME: Is it really safe to ignore all these? if (CE->getCastKind() == CK_NoOp || CE->getCastKind() == CK_LValueToRValue || CE->getCastKind() == CK_ToUnion || - CE->getCastKind() == CK_ConstructorConversion) + CE->getCastKind() == CK_ConstructorConversion || + CE->getCastKind() == CK_NonAtomicToAtomic || + CE->getCastKind() == CK_AtomicToNonAtomic) return CE->getSubExpr()->isConstantInitializer(Ctx, false); break; @@ -2742,6 +2767,16 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const { case MaterializeTemporaryExprClass: return cast<MaterializeTemporaryExpr>(this)->GetTemporaryExpr() ->isConstantInitializer(Ctx, false); + + case SubstNonTypeTemplateParmExprClass: + return cast<SubstNonTypeTemplateParmExpr>(this)->getReplacement() + ->isConstantInitializer(Ctx, false); + case CXXDefaultArgExprClass: + return cast<CXXDefaultArgExpr>(this)->getExpr() + ->isConstantInitializer(Ctx, false); + case CXXDefaultInitExprClass: + return cast<CXXDefaultInitExpr>(this)->getExpr() + ->isConstantInitializer(Ctx, false); } return isEvaluatable(Ctx); } @@ -2829,9 +2864,11 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const { case DesignatedInitExprClass: case ParenListExprClass: case CXXPseudoDestructorExprClass: + case CXXStdInitializerListExprClass: case SubstNonTypeTemplateParmExprClass: case MaterializeTemporaryExprClass: case ShuffleVectorExprClass: + case ConvertVectorExprClass: case AsTypeExprClass: // These have a side-effect if any subexpression does. break; @@ -2858,7 +2895,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const { HasSideEffects(Ctx); case ChooseExprClass: - return cast<ChooseExpr>(this)->getChosenSubExpr(Ctx)->HasSideEffects(Ctx); + return cast<ChooseExpr>(this)->getChosenSubExpr()->HasSideEffects(Ctx); case CXXDefaultArgExprClass: return cast<CXXDefaultArgExpr>(this)->getExpr()->HasSideEffects(Ctx); @@ -3017,7 +3054,8 @@ bool Expr::hasNonTrivialCall(ASTContext &Ctx) { Expr::NullPointerConstantKind Expr::isNullPointerConstant(ASTContext &Ctx, NullPointerConstantValueDependence NPC) const { - if (isValueDependent()) { + if (isValueDependent() && + (!Ctx.getLangOpts().CPlusPlus11 || Ctx.getLangOpts().MicrosoftMode)) { switch (NPC) { case NPC_NeverValueDependent: llvm_unreachable("Unexpected value dependent expression!"); @@ -3053,7 +3091,13 @@ Expr::isNullPointerConstant(ASTContext &Ctx, return PE->getSubExpr()->isNullPointerConstant(Ctx, NPC); } else if (const GenericSelectionExpr *GE = dyn_cast<GenericSelectionExpr>(this)) { + if (GE->isResultDependent()) + return NPCK_NotNull; return GE->getResultExpr()->isNullPointerConstant(Ctx, NPC); + } else if (const ChooseExpr *CE = dyn_cast<ChooseExpr>(this)) { + if (CE->isConditionDependent()) + return NPCK_NotNull; + return CE->getChosenSubExpr()->isNullPointerConstant(Ctx, NPC); } else if (const CXXDefaultArgExpr *DefaultArg = dyn_cast<CXXDefaultArgExpr>(this)) { // See through default argument expressions. @@ -3078,7 +3122,8 @@ Expr::isNullPointerConstant(ASTContext &Ctx, return NPCK_CXX11_nullptr; if (const RecordType *UT = getType()->getAsUnionType()) - if (UT && UT->getDecl()->hasAttr<TransparentUnionAttr>()) + if (!Ctx.getLangOpts().CPlusPlus11 && + 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)) @@ -3089,14 +3134,19 @@ Expr::isNullPointerConstant(ASTContext &Ctx, (Ctx.getLangOpts().CPlusPlus && getType()->isEnumeralType())) return NPCK_NotNull; - // If we have an integer constant expression, we need to *evaluate* it and - // test for the value 0. Don't use the C++11 constant expression semantics - // for this, for now; once the dust settles on core issue 903, we might only - // allow a literal 0 here in C++11 mode. if (Ctx.getLangOpts().CPlusPlus11) { - if (!isCXX98IntegralConstantExpr(Ctx)) + // C++11 [conv.ptr]p1: A null pointer constant is an integer literal with + // value zero or a prvalue of type std::nullptr_t. + // Microsoft mode permits C++98 rules reflecting MSVC behavior. + const IntegerLiteral *Lit = dyn_cast<IntegerLiteral>(this); + if (Lit && !Lit->getValue()) + return NPCK_ZeroLiteral; + else if (!Ctx.getLangOpts().MicrosoftMode || + !isCXX98IntegralConstantExpr(Ctx)) return NPCK_NotNull; } else { + // If we have an integer constant expression, we need to *evaluate* it and + // test for the value 0. if (!isIntegerConstantExpr(Ctx)) return NPCK_NotNull; } @@ -3370,7 +3420,7 @@ void ObjCMessageExpr::initArgsAndSelLocs(ArrayRef<Expr *> Args, } } -ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T, +ObjCMessageExpr *ObjCMessageExpr::Create(const ASTContext &Context, QualType T, ExprValueKind VK, SourceLocation LBracLoc, SourceLocation SuperLoc, @@ -3395,7 +3445,7 @@ ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T, Method, Args, RBracLoc, isImplicit); } -ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T, +ObjCMessageExpr *ObjCMessageExpr::Create(const ASTContext &Context, QualType T, ExprValueKind VK, SourceLocation LBracLoc, TypeSourceInfo *Receiver, @@ -3418,7 +3468,7 @@ ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T, isImplicit); } -ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T, +ObjCMessageExpr *ObjCMessageExpr::Create(const ASTContext &Context, QualType T, ExprValueKind VK, SourceLocation LBracLoc, Expr *Receiver, @@ -3441,14 +3491,14 @@ ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T, isImplicit); } -ObjCMessageExpr *ObjCMessageExpr::CreateEmpty(ASTContext &Context, +ObjCMessageExpr *ObjCMessageExpr::CreateEmpty(const ASTContext &Context, unsigned NumArgs, unsigned NumStoredSelLocs) { ObjCMessageExpr *Mem = alloc(Context, NumArgs, NumStoredSelLocs); return new (Mem) ObjCMessageExpr(EmptyShell(), NumArgs); } -ObjCMessageExpr *ObjCMessageExpr::alloc(ASTContext &C, +ObjCMessageExpr *ObjCMessageExpr::alloc(const ASTContext &C, ArrayRef<Expr *> Args, SourceLocation RBraceLoc, ArrayRef<SourceLocation> SelLocs, @@ -3460,7 +3510,7 @@ ObjCMessageExpr *ObjCMessageExpr::alloc(ASTContext &C, return alloc(C, Args.size(), NumStoredSelLocs); } -ObjCMessageExpr *ObjCMessageExpr::alloc(ASTContext &C, +ObjCMessageExpr *ObjCMessageExpr::alloc(const ASTContext &C, unsigned NumArgs, unsigned NumStoredSelLocs) { unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) + @@ -3537,11 +3587,7 @@ StringRef ObjCBridgedCastExpr::getBridgeKindName() const { llvm_unreachable("Invalid BridgeKind!"); } -bool ChooseExpr::isConditionTrue(const ASTContext &C) const { - return getCond()->EvaluateKnownConstInt(C) != 0; -} - -ShuffleVectorExpr::ShuffleVectorExpr(ASTContext &C, ArrayRef<Expr*> args, +ShuffleVectorExpr::ShuffleVectorExpr(const ASTContext &C, ArrayRef<Expr*> args, QualType Type, SourceLocation BLoc, SourceLocation RP) : Expr(ShuffleVectorExprClass, Type, VK_RValue, OK_Ordinary, @@ -3565,16 +3611,15 @@ ShuffleVectorExpr::ShuffleVectorExpr(ASTContext &C, ArrayRef<Expr*> args, } } -void ShuffleVectorExpr::setExprs(ASTContext &C, Expr ** Exprs, - unsigned NumExprs) { +void ShuffleVectorExpr::setExprs(const ASTContext &C, ArrayRef<Expr *> Exprs) { if (SubExprs) C.Deallocate(SubExprs); - SubExprs = new (C) Stmt* [NumExprs]; - this->NumExprs = NumExprs; - memcpy(SubExprs, Exprs, sizeof(Expr *) * NumExprs); + this->NumExprs = Exprs.size(); + SubExprs = new (C) Stmt*[NumExprs]; + memcpy(SubExprs, Exprs.data(), sizeof(Expr *) * Exprs.size()); } -GenericSelectionExpr::GenericSelectionExpr(ASTContext &Context, +GenericSelectionExpr::GenericSelectionExpr(const ASTContext &Context, SourceLocation GenericLoc, Expr *ControllingExpr, ArrayRef<TypeSourceInfo*> AssocTypes, ArrayRef<Expr*> AssocExprs, @@ -3600,7 +3645,7 @@ GenericSelectionExpr::GenericSelectionExpr(ASTContext &Context, std::copy(AssocExprs.begin(), AssocExprs.end(), SubExprs+END_EXPR); } -GenericSelectionExpr::GenericSelectionExpr(ASTContext &Context, +GenericSelectionExpr::GenericSelectionExpr(const ASTContext &Context, SourceLocation GenericLoc, Expr *ControllingExpr, ArrayRef<TypeSourceInfo*> AssocTypes, ArrayRef<Expr*> AssocExprs, @@ -3637,7 +3682,7 @@ IdentifierInfo *DesignatedInitExpr::Designator::getFieldName() const { return getField()->getIdentifier(); } -DesignatedInitExpr::DesignatedInitExpr(ASTContext &C, QualType Ty, +DesignatedInitExpr::DesignatedInitExpr(const ASTContext &C, QualType Ty, unsigned NumDesignators, const Designator *Designators, SourceLocation EqualOrColonLoc, @@ -3704,7 +3749,7 @@ DesignatedInitExpr::DesignatedInitExpr(ASTContext &C, QualType Ty, } DesignatedInitExpr * -DesignatedInitExpr::Create(ASTContext &C, Designator *Designators, +DesignatedInitExpr::Create(const ASTContext &C, Designator *Designators, unsigned NumDesignators, ArrayRef<Expr*> IndexExprs, SourceLocation ColonOrEqualLoc, @@ -3716,14 +3761,14 @@ DesignatedInitExpr::Create(ASTContext &C, Designator *Designators, IndexExprs, Init); } -DesignatedInitExpr *DesignatedInitExpr::CreateEmpty(ASTContext &C, +DesignatedInitExpr *DesignatedInitExpr::CreateEmpty(const ASTContext &C, unsigned NumIndexExprs) { void *Mem = C.Allocate(sizeof(DesignatedInitExpr) + sizeof(Stmt *) * (NumIndexExprs + 1), 8); return new (Mem) DesignatedInitExpr(NumIndexExprs + 1); } -void DesignatedInitExpr::setDesignators(ASTContext &C, +void DesignatedInitExpr::setDesignators(const ASTContext &C, const Designator *Desigs, unsigned NumDesigs) { Designators = new (C) Designator[NumDesigs]; @@ -3790,7 +3835,7 @@ Expr *DesignatedInitExpr::getArrayRangeEnd(const Designator &D) const { /// \brief Replaces the designator at index @p Idx with the series /// of designators in [First, Last). -void DesignatedInitExpr::ExpandDesignator(ASTContext &C, unsigned Idx, +void DesignatedInitExpr::ExpandDesignator(const ASTContext &C, unsigned Idx, const Designator *First, const Designator *Last) { unsigned NumNewDesignators = Last - First; @@ -3815,7 +3860,7 @@ void DesignatedInitExpr::ExpandDesignator(ASTContext &C, unsigned Idx, NumDesignators = NumDesignators - 1 + NumNewDesignators; } -ParenListExpr::ParenListExpr(ASTContext& C, SourceLocation lparenloc, +ParenListExpr::ParenListExpr(const ASTContext& C, SourceLocation lparenloc, ArrayRef<Expr*> exprs, SourceLocation rparenloc) : Expr(ParenListExprClass, QualType(), VK_RValue, OK_Ordinary, @@ -3847,7 +3892,8 @@ const OpaqueValueExpr *OpaqueValueExpr::findInCopyConstruct(const Expr *e) { return cast<OpaqueValueExpr>(e); } -PseudoObjectExpr *PseudoObjectExpr::Create(ASTContext &Context, EmptyShell sh, +PseudoObjectExpr *PseudoObjectExpr::Create(const ASTContext &Context, + EmptyShell sh, unsigned numSemanticExprs) { void *buffer = Context.Allocate(sizeof(PseudoObjectExpr) + (1 + numSemanticExprs) * sizeof(Expr*), @@ -3860,7 +3906,7 @@ PseudoObjectExpr::PseudoObjectExpr(EmptyShell shell, unsigned numSemanticExprs) PseudoObjectExprBits.NumSubExprs = numSemanticExprs + 1; } -PseudoObjectExpr *PseudoObjectExpr::Create(ASTContext &C, Expr *syntax, +PseudoObjectExpr *PseudoObjectExpr::Create(const ASTContext &C, Expr *syntax, ArrayRef<Expr*> semantics, unsigned resultIndex) { assert(syntax && "no syntactic expression!"); @@ -3975,7 +4021,7 @@ ObjCArrayLiteral::ObjCArrayLiteral(ArrayRef<Expr *> Elements, } } -ObjCArrayLiteral *ObjCArrayLiteral::Create(ASTContext &C, +ObjCArrayLiteral *ObjCArrayLiteral::Create(const ASTContext &C, ArrayRef<Expr *> Elements, QualType T, ObjCMethodDecl * Method, SourceRange SR) { @@ -3984,7 +4030,7 @@ ObjCArrayLiteral *ObjCArrayLiteral::Create(ASTContext &C, return new (Mem) ObjCArrayLiteral(Elements, T, Method, SR); } -ObjCArrayLiteral *ObjCArrayLiteral::CreateEmpty(ASTContext &C, +ObjCArrayLiteral *ObjCArrayLiteral::CreateEmpty(const ASTContext &C, unsigned NumElements) { void *Mem = C.Allocate(sizeof(ObjCArrayLiteral) @@ -4029,7 +4075,7 @@ ObjCDictionaryLiteral::ObjCDictionaryLiteral( } ObjCDictionaryLiteral * -ObjCDictionaryLiteral::Create(ASTContext &C, +ObjCDictionaryLiteral::Create(const ASTContext &C, ArrayRef<ObjCDictionaryElement> VK, bool HasPackExpansions, QualType T, ObjCMethodDecl *method, @@ -4044,7 +4090,7 @@ ObjCDictionaryLiteral::Create(ASTContext &C, } ObjCDictionaryLiteral * -ObjCDictionaryLiteral::CreateEmpty(ASTContext &C, unsigned NumElements, +ObjCDictionaryLiteral::CreateEmpty(const ASTContext &C, unsigned NumElements, bool HasPackExpansions) { unsigned ExpansionsSize = 0; if (HasPackExpansions) @@ -4055,7 +4101,7 @@ ObjCDictionaryLiteral::CreateEmpty(ASTContext &C, unsigned NumElements, HasPackExpansions); } -ObjCSubscriptRefExpr *ObjCSubscriptRefExpr::Create(ASTContext &C, +ObjCSubscriptRefExpr *ObjCSubscriptRefExpr::Create(const ASTContext &C, Expr *base, Expr *key, QualType T, ObjCMethodDecl *getMethod, diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 402d7b5..3738c0e 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -40,46 +40,106 @@ bool CXXTypeidExpr::isPotentiallyEvaluated() const { return false; } -QualType CXXTypeidExpr::getTypeOperand() const { +QualType CXXTypeidExpr::getTypeOperand(ASTContext &Context) const { assert(isTypeOperand() && "Cannot call getTypeOperand for typeid(expr)"); - return Operand.get<TypeSourceInfo *>()->getType().getNonReferenceType() - .getUnqualifiedType(); + Qualifiers Quals; + return Context.getUnqualifiedArrayType( + Operand.get<TypeSourceInfo *>()->getType().getNonReferenceType(), Quals); } -QualType CXXUuidofExpr::getTypeOperand() const { +QualType CXXUuidofExpr::getTypeOperand(ASTContext &Context) const { assert(isTypeOperand() && "Cannot call getTypeOperand for __uuidof(expr)"); - return Operand.get<TypeSourceInfo *>()->getType().getNonReferenceType() - .getUnqualifiedType(); + Qualifiers Quals; + return Context.getUnqualifiedArrayType( + Operand.get<TypeSourceInfo *>()->getType().getNonReferenceType(), Quals); } // static -UuidAttr *CXXUuidofExpr::GetUuidAttrOfType(QualType QT) { +UuidAttr *CXXUuidofExpr::GetUuidAttrOfType(QualType QT, + bool *RDHasMultipleGUIDsPtr) { // Optionally remove one level of pointer, reference or array indirection. const Type *Ty = QT.getTypePtr(); if (QT->isPointerType() || QT->isReferenceType()) Ty = QT->getPointeeType().getTypePtr(); else if (QT->isArrayType()) - Ty = cast<ArrayType>(QT)->getElementType().getTypePtr(); + Ty = Ty->getBaseElementTypeUnsafe(); // Loop all record redeclaration looking for an uuid attribute. CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); + if (!RD) + return 0; + + // __uuidof can grab UUIDs from template arguments. + if (ClassTemplateSpecializationDecl *CTSD = + dyn_cast<ClassTemplateSpecializationDecl>(RD)) { + const TemplateArgumentList &TAL = CTSD->getTemplateArgs(); + UuidAttr *UuidForRD = 0; + + for (unsigned I = 0, N = TAL.size(); I != N; ++I) { + const TemplateArgument &TA = TAL[I]; + bool SeenMultipleGUIDs = false; + + UuidAttr *UuidForTA = 0; + if (TA.getKind() == TemplateArgument::Type) + UuidForTA = GetUuidAttrOfType(TA.getAsType(), &SeenMultipleGUIDs); + else if (TA.getKind() == TemplateArgument::Declaration) + UuidForTA = + GetUuidAttrOfType(TA.getAsDecl()->getType(), &SeenMultipleGUIDs); + + // If the template argument has a UUID, there are three cases: + // - This is the first UUID seen for this RecordDecl. + // - This is a different UUID than previously seen for this RecordDecl. + // - This is the same UUID than previously seen for this RecordDecl. + if (UuidForTA) { + if (!UuidForRD) + UuidForRD = UuidForTA; + else if (UuidForRD != UuidForTA) + SeenMultipleGUIDs = true; + } + + // Seeing multiple UUIDs means that we couldn't find a UUID + if (SeenMultipleGUIDs) { + if (RDHasMultipleGUIDsPtr) + *RDHasMultipleGUIDsPtr = true; + return 0; + } + } + + return UuidForRD; + } + for (CXXRecordDecl::redecl_iterator I = RD->redecls_begin(), - E = RD->redecls_end(); I != E; ++I) { + E = RD->redecls_end(); + I != E; ++I) if (UuidAttr *Uuid = I->getAttr<UuidAttr>()) return Uuid; - } return 0; } +StringRef CXXUuidofExpr::getUuidAsStringRef(ASTContext &Context) const { + StringRef Uuid; + if (isTypeOperand()) + Uuid = CXXUuidofExpr::GetUuidAttrOfType(getTypeOperand(Context))->getGuid(); + else { + // Special case: __uuidof(0) means an all-zero GUID. + Expr *Op = getExprOperand(); + if (!Op->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) + Uuid = CXXUuidofExpr::GetUuidAttrOfType(Op->getType())->getGuid(); + else + Uuid = "00000000-0000-0000-0000-000000000000"; + } + return Uuid; +} + // CXXScalarValueInitExpr SourceLocation CXXScalarValueInitExpr::getLocStart() const { return TypeInfo ? TypeInfo->getTypeLoc().getBeginLoc() : RParenLoc; } // CXXNewExpr -CXXNewExpr::CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew, - FunctionDecl *operatorDelete, +CXXNewExpr::CXXNewExpr(const ASTContext &C, bool globalNew, + FunctionDecl *operatorNew, FunctionDecl *operatorDelete, bool usualArrayDeleteWantsSize, ArrayRef<Expr*> placementArgs, SourceRange typeIdParens, Expr *arraySize, @@ -134,11 +194,14 @@ CXXNewExpr::CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew, this->Range.setEnd(DirectInitRange.getEnd()); break; case ListInit: this->Range.setEnd(getInitializer()->getSourceRange().getEnd()); break; - default: break; + default: + if (TypeIdParens.isValid()) + this->Range.setEnd(TypeIdParens.getEnd()); + break; } } -void CXXNewExpr::AllocateArgsArray(ASTContext &C, bool isArray, +void CXXNewExpr::AllocateArgsArray(const ASTContext &C, bool isArray, unsigned numPlaceArgs, bool hasInitializer){ assert(SubExprs == 0 && "SubExprs already allocated"); Array = isArray; @@ -148,7 +211,7 @@ void CXXNewExpr::AllocateArgsArray(ASTContext &C, bool isArray, SubExprs = new (C) Stmt*[TotalSize]; } -bool CXXNewExpr::shouldNullCheckAllocation(ASTContext &Ctx) const { +bool CXXNewExpr::shouldNullCheckAllocation(const ASTContext &Ctx) const { return getOperatorNew()->getType()-> castAs<FunctionProtoType>()->isNothrow(Ctx); } @@ -172,14 +235,16 @@ PseudoDestructorTypeStorage::PseudoDestructorTypeStorage(TypeSourceInfo *Info) Location = Info->getTypeLoc().getLocalSourceRange().getBegin(); } -CXXPseudoDestructorExpr::CXXPseudoDestructorExpr(ASTContext &Context, +CXXPseudoDestructorExpr::CXXPseudoDestructorExpr(const ASTContext &Context, Expr *Base, bool isArrow, SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc, TypeSourceInfo *ScopeType, SourceLocation ColonColonLoc, SourceLocation TildeLoc, PseudoDestructorTypeStorage DestroyedType) : Expr(CXXPseudoDestructorExprClass, - Context.getPointerType(Context.getFunctionType(Context.VoidTy, None, - FunctionProtoType::ExtProtoInfo())), + Context.getPointerType(Context.getFunctionType( + Context.VoidTy, None, + FunctionProtoType::ExtProtoInfo( + Context.getDefaultCallingConvention(false, true)))), VK_RValue, OK_Ordinary, /*isTypeDependent=*/(Base->isTypeDependent() || (DestroyedType.getTypeSourceInfo() && @@ -224,7 +289,7 @@ SourceLocation CXXPseudoDestructorExpr::getLocEnd() const { // UnresolvedLookupExpr UnresolvedLookupExpr * -UnresolvedLookupExpr::Create(ASTContext &C, +UnresolvedLookupExpr::Create(const ASTContext &C, CXXRecordDecl *NamingClass, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, @@ -245,7 +310,7 @@ UnresolvedLookupExpr::Create(ASTContext &C, } UnresolvedLookupExpr * -UnresolvedLookupExpr::CreateEmpty(ASTContext &C, +UnresolvedLookupExpr::CreateEmpty(const ASTContext &C, bool HasTemplateKWAndArgsInfo, unsigned NumTemplateArgs) { std::size_t size = sizeof(UnresolvedLookupExpr); @@ -258,7 +323,7 @@ UnresolvedLookupExpr::CreateEmpty(ASTContext &C, return E; } -OverloadExpr::OverloadExpr(StmtClass K, ASTContext &C, +OverloadExpr::OverloadExpr(StmtClass K, const ASTContext &C, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, const DeclarationNameInfo &NameInfo, @@ -330,7 +395,7 @@ OverloadExpr::OverloadExpr(StmtClass K, ASTContext &C, setType(C.DependentTy); } -void OverloadExpr::initializeResults(ASTContext &C, +void OverloadExpr::initializeResults(const ASTContext &C, UnresolvedSetIterator Begin, UnresolvedSetIterator End) { assert(Results == 0 && "Results already initialized!"); @@ -386,11 +451,12 @@ DependentScopeDeclRefExpr::DependentScopeDeclRefExpr(QualType T, } DependentScopeDeclRefExpr * -DependentScopeDeclRefExpr::Create(ASTContext &C, +DependentScopeDeclRefExpr::Create(const ASTContext &C, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *Args) { + assert(QualifierLoc && "should be created for dependent qualifiers"); std::size_t size = sizeof(DependentScopeDeclRefExpr); if (Args) size += ASTTemplateKWAndArgsInfo::sizeFor(Args->size()); @@ -402,7 +468,7 @@ DependentScopeDeclRefExpr::Create(ASTContext &C, } DependentScopeDeclRefExpr * -DependentScopeDeclRefExpr::CreateEmpty(ASTContext &C, +DependentScopeDeclRefExpr::CreateEmpty(const ASTContext &C, bool HasTemplateKWAndArgsInfo, unsigned NumTemplateArgs) { std::size_t size = sizeof(DependentScopeDeclRefExpr); @@ -427,8 +493,8 @@ SourceLocation CXXConstructExpr::getLocEnd() const { if (isa<CXXTemporaryObjectExpr>(this)) return cast<CXXTemporaryObjectExpr>(this)->getLocEnd(); - if (ParenRange.isValid()) - return ParenRange.getEnd(); + if (ParenOrBraceRange.isValid()) + return ParenOrBraceRange.getEnd(); SourceLocation End = Loc; for (unsigned I = getNumArgs(); I > 0; --I) { @@ -520,7 +586,7 @@ const char *CXXNamedCastExpr::getCastName() const { } } -CXXStaticCastExpr *CXXStaticCastExpr::Create(ASTContext &C, QualType T, +CXXStaticCastExpr *CXXStaticCastExpr::Create(const ASTContext &C, QualType T, ExprValueKind VK, CastKind K, Expr *Op, const CXXCastPath *BasePath, @@ -538,14 +604,14 @@ CXXStaticCastExpr *CXXStaticCastExpr::Create(ASTContext &C, QualType T, return E; } -CXXStaticCastExpr *CXXStaticCastExpr::CreateEmpty(ASTContext &C, +CXXStaticCastExpr *CXXStaticCastExpr::CreateEmpty(const ASTContext &C, unsigned PathSize) { void *Buffer = C.Allocate(sizeof(CXXStaticCastExpr) + PathSize * sizeof(CXXBaseSpecifier*)); return new (Buffer) CXXStaticCastExpr(EmptyShell(), PathSize); } -CXXDynamicCastExpr *CXXDynamicCastExpr::Create(ASTContext &C, QualType T, +CXXDynamicCastExpr *CXXDynamicCastExpr::Create(const ASTContext &C, QualType T, ExprValueKind VK, CastKind K, Expr *Op, const CXXCastPath *BasePath, @@ -563,7 +629,7 @@ CXXDynamicCastExpr *CXXDynamicCastExpr::Create(ASTContext &C, QualType T, return E; } -CXXDynamicCastExpr *CXXDynamicCastExpr::CreateEmpty(ASTContext &C, +CXXDynamicCastExpr *CXXDynamicCastExpr::CreateEmpty(const ASTContext &C, unsigned PathSize) { void *Buffer = C.Allocate(sizeof(CXXDynamicCastExpr) + PathSize * sizeof(CXXBaseSpecifier*)); @@ -604,8 +670,8 @@ bool CXXDynamicCastExpr::isAlwaysNull() const } CXXReinterpretCastExpr * -CXXReinterpretCastExpr::Create(ASTContext &C, QualType T, ExprValueKind VK, - CastKind K, Expr *Op, +CXXReinterpretCastExpr::Create(const ASTContext &C, QualType T, + ExprValueKind VK, CastKind K, Expr *Op, const CXXCastPath *BasePath, TypeSourceInfo *WrittenTy, SourceLocation L, SourceLocation RParenLoc, @@ -621,13 +687,13 @@ CXXReinterpretCastExpr::Create(ASTContext &C, QualType T, ExprValueKind VK, } CXXReinterpretCastExpr * -CXXReinterpretCastExpr::CreateEmpty(ASTContext &C, unsigned PathSize) { +CXXReinterpretCastExpr::CreateEmpty(const ASTContext &C, unsigned PathSize) { void *Buffer = C.Allocate(sizeof(CXXReinterpretCastExpr) + PathSize * sizeof(CXXBaseSpecifier*)); return new (Buffer) CXXReinterpretCastExpr(EmptyShell(), PathSize); } -CXXConstCastExpr *CXXConstCastExpr::Create(ASTContext &C, QualType T, +CXXConstCastExpr *CXXConstCastExpr::Create(const ASTContext &C, QualType T, ExprValueKind VK, Expr *Op, TypeSourceInfo *WrittenTy, SourceLocation L, @@ -636,31 +702,39 @@ CXXConstCastExpr *CXXConstCastExpr::Create(ASTContext &C, QualType T, return new (C) CXXConstCastExpr(T, VK, Op, WrittenTy, L, RParenLoc, AngleBrackets); } -CXXConstCastExpr *CXXConstCastExpr::CreateEmpty(ASTContext &C) { +CXXConstCastExpr *CXXConstCastExpr::CreateEmpty(const ASTContext &C) { return new (C) CXXConstCastExpr(EmptyShell()); } CXXFunctionalCastExpr * -CXXFunctionalCastExpr::Create(ASTContext &C, QualType T, ExprValueKind VK, - TypeSourceInfo *Written, SourceLocation L, - CastKind K, Expr *Op, const CXXCastPath *BasePath, - SourceLocation R) { +CXXFunctionalCastExpr::Create(const ASTContext &C, QualType T, ExprValueKind VK, + TypeSourceInfo *Written, CastKind K, Expr *Op, + const CXXCastPath *BasePath, + SourceLocation L, SourceLocation R) { unsigned PathSize = (BasePath ? BasePath->size() : 0); void *Buffer = C.Allocate(sizeof(CXXFunctionalCastExpr) + PathSize * sizeof(CXXBaseSpecifier*)); CXXFunctionalCastExpr *E = - new (Buffer) CXXFunctionalCastExpr(T, VK, Written, L, K, Op, PathSize, R); + new (Buffer) CXXFunctionalCastExpr(T, VK, Written, K, Op, PathSize, L, R); if (PathSize) E->setCastPath(*BasePath); return E; } CXXFunctionalCastExpr * -CXXFunctionalCastExpr::CreateEmpty(ASTContext &C, unsigned PathSize) { +CXXFunctionalCastExpr::CreateEmpty(const ASTContext &C, unsigned PathSize) { void *Buffer = C.Allocate(sizeof(CXXFunctionalCastExpr) + PathSize * sizeof(CXXBaseSpecifier*)); return new (Buffer) CXXFunctionalCastExpr(EmptyShell(), PathSize); } +SourceLocation CXXFunctionalCastExpr::getLocStart() const { + return getTypeInfoAsWritten()->getTypeLoc().getLocStart(); +} + +SourceLocation CXXFunctionalCastExpr::getLocEnd() const { + return RParenLoc.isValid() ? RParenLoc : getSubExpr()->getLocEnd(); +} + UserDefinedLiteral::LiteralOperatorKind UserDefinedLiteral::getLiteralOperatorKind() const { if (getNumArgs() == 0) @@ -696,14 +770,14 @@ const IdentifierInfo *UserDefinedLiteral::getUDSuffix() const { } CXXDefaultArgExpr * -CXXDefaultArgExpr::Create(ASTContext &C, SourceLocation Loc, +CXXDefaultArgExpr::Create(const ASTContext &C, SourceLocation Loc, ParmVarDecl *Param, Expr *SubExpr) { void *Mem = C.Allocate(sizeof(CXXDefaultArgExpr) + sizeof(Stmt *)); return new (Mem) CXXDefaultArgExpr(CXXDefaultArgExprClass, Loc, Param, SubExpr); } -CXXDefaultInitExpr::CXXDefaultInitExpr(ASTContext &C, SourceLocation Loc, +CXXDefaultInitExpr::CXXDefaultInitExpr(const ASTContext &C, SourceLocation Loc, FieldDecl *Field, QualType T) : Expr(CXXDefaultInitExprClass, T.getNonLValueExprType(C), T->isLValueReferenceType() ? VK_LValue : T->isRValueReferenceType() @@ -714,12 +788,12 @@ CXXDefaultInitExpr::CXXDefaultInitExpr(ASTContext &C, SourceLocation Loc, assert(Field->hasInClassInitializer()); } -CXXTemporary *CXXTemporary::Create(ASTContext &C, +CXXTemporary *CXXTemporary::Create(const ASTContext &C, const CXXDestructorDecl *Destructor) { return new (C) CXXTemporary(Destructor); } -CXXBindTemporaryExpr *CXXBindTemporaryExpr::Create(ASTContext &C, +CXXBindTemporaryExpr *CXXBindTemporaryExpr::Create(const ASTContext &C, CXXTemporary *Temp, Expr* SubExpr) { assert((SubExpr->getType()->isRecordType() || @@ -729,11 +803,11 @@ CXXBindTemporaryExpr *CXXBindTemporaryExpr::Create(ASTContext &C, return new (C) CXXBindTemporaryExpr(Temp, SubExpr); } -CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(ASTContext &C, +CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(const ASTContext &C, CXXConstructorDecl *Cons, TypeSourceInfo *Type, ArrayRef<Expr*> Args, - SourceRange parenRange, + SourceRange ParenOrBraceRange, bool HadMultipleCandidates, bool ListInitialization, bool ZeroInitialization) @@ -743,7 +817,7 @@ CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(ASTContext &C, Cons, false, Args, HadMultipleCandidates, ListInitialization, ZeroInitialization, - CXXConstructExpr::CK_Complete, parenRange), + CXXConstructExpr::CK_Complete, ParenOrBraceRange), Type(Type) { } @@ -752,10 +826,13 @@ SourceLocation CXXTemporaryObjectExpr::getLocStart() const { } SourceLocation CXXTemporaryObjectExpr::getLocEnd() const { - return getParenRange().getEnd(); + SourceLocation Loc = getParenOrBraceRange().getEnd(); + if (Loc.isInvalid() && getNumArgs()) + Loc = getArg(getNumArgs()-1)->getLocEnd(); + return Loc; } -CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T, +CXXConstructExpr *CXXConstructExpr::Create(const ASTContext &C, QualType T, SourceLocation Loc, CXXConstructorDecl *D, bool Elidable, ArrayRef<Expr*> Args, @@ -763,28 +840,29 @@ CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T, bool ListInitialization, bool ZeroInitialization, ConstructionKind ConstructKind, - SourceRange ParenRange) { + SourceRange ParenOrBraceRange) { return new (C) CXXConstructExpr(C, CXXConstructExprClass, T, Loc, D, Elidable, Args, HadMultipleCandidates, ListInitialization, ZeroInitialization, ConstructKind, - ParenRange); + ParenOrBraceRange); } -CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T, - SourceLocation Loc, +CXXConstructExpr::CXXConstructExpr(const ASTContext &C, StmtClass SC, + QualType T, SourceLocation Loc, CXXConstructorDecl *D, bool elidable, ArrayRef<Expr*> args, bool HadMultipleCandidates, bool ListInitialization, bool ZeroInitialization, ConstructionKind ConstructKind, - SourceRange ParenRange) + SourceRange ParenOrBraceRange) : Expr(SC, T, VK_RValue, OK_Ordinary, T->isDependentType(), T->isDependentType(), T->isInstantiationDependentType(), T->containsUnexpandedParameterPack()), - Constructor(D), Loc(Loc), ParenRange(ParenRange), NumArgs(args.size()), + Constructor(D), Loc(Loc), ParenOrBraceRange(ParenOrBraceRange), + NumArgs(args.size()), Elidable(elidable), HadMultipleCandidates(HadMultipleCandidates), ListInitialization(ListInitialization), ZeroInitialization(ZeroInitialization), @@ -811,7 +889,7 @@ CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T, LambdaExpr::Capture::Capture(SourceLocation Loc, bool Implicit, LambdaCaptureKind Kind, VarDecl *Var, SourceLocation EllipsisLoc) - : VarAndBits(Var, 0), Loc(Loc), EllipsisLoc(EllipsisLoc) + : DeclAndBits(Var, 0), Loc(Loc), EllipsisLoc(EllipsisLoc) { unsigned Bits = 0; if (Implicit) @@ -829,20 +907,22 @@ LambdaExpr::Capture::Capture(SourceLocation Loc, bool Implicit, assert(Var && "capture must have a variable!"); break; } - VarAndBits.setInt(Bits); + DeclAndBits.setInt(Bits); } LambdaCaptureKind LambdaExpr::Capture::getCaptureKind() const { - if (capturesThis()) + Decl *D = DeclAndBits.getPointer(); + if (!D) return LCK_This; - return (VarAndBits.getInt() & Capture_ByCopy)? LCK_ByCopy : LCK_ByRef; + return (DeclAndBits.getInt() & Capture_ByCopy) ? LCK_ByCopy : LCK_ByRef; } -LambdaExpr::LambdaExpr(QualType T, +LambdaExpr::LambdaExpr(QualType T, SourceRange IntroducerRange, LambdaCaptureDefault CaptureDefault, - ArrayRef<Capture> Captures, + SourceLocation CaptureDefaultLoc, + ArrayRef<Capture> Captures, bool ExplicitParams, bool ExplicitResultType, ArrayRef<Expr *> CaptureInits, @@ -854,6 +934,7 @@ LambdaExpr::LambdaExpr(QualType T, T->isDependentType(), T->isDependentType(), T->isDependentType(), ContainsUnexpandedParameterPack), IntroducerRange(IntroducerRange), + CaptureDefaultLoc(CaptureDefaultLoc), NumCaptures(Captures.size()), CaptureDefault(CaptureDefault), ExplicitParams(ExplicitParams), @@ -867,7 +948,7 @@ LambdaExpr::LambdaExpr(QualType T, // FIXME: Propagate "has unexpanded parameter pack" bit. // Copy captures. - ASTContext &Context = Class->getASTContext(); + const ASTContext &Context = Class->getASTContext(); Data.NumCaptures = NumCaptures; Data.NumExplicitCaptures = 0; Data.Captures = (Capture *)Context.Allocate(sizeof(Capture) * NumCaptures); @@ -899,11 +980,12 @@ LambdaExpr::LambdaExpr(QualType T, } } -LambdaExpr *LambdaExpr::Create(ASTContext &Context, +LambdaExpr *LambdaExpr::Create(const ASTContext &Context, CXXRecordDecl *Class, SourceRange IntroducerRange, LambdaCaptureDefault CaptureDefault, - ArrayRef<Capture> Captures, + SourceLocation CaptureDefaultLoc, + ArrayRef<Capture> Captures, bool ExplicitParams, bool ExplicitResultType, ArrayRef<Expr *> CaptureInits, @@ -923,13 +1005,15 @@ LambdaExpr *LambdaExpr::Create(ASTContext &Context, Size += sizeof(VarDecl *) * ArrayIndexVars.size(); } void *Mem = Context.Allocate(Size); - return new (Mem) LambdaExpr(T, IntroducerRange, CaptureDefault, - Captures, ExplicitParams, ExplicitResultType, + return new (Mem) LambdaExpr(T, IntroducerRange, + CaptureDefault, CaptureDefaultLoc, Captures, + ExplicitParams, ExplicitResultType, CaptureInits, ArrayIndexVars, ArrayIndexStarts, ClosingBrace, ContainsUnexpandedParameterPack); } -LambdaExpr *LambdaExpr::CreateDeserialized(ASTContext &C, unsigned NumCaptures, +LambdaExpr *LambdaExpr::CreateDeserialized(const ASTContext &C, + unsigned NumCaptures, unsigned NumArrayIndexVars) { unsigned Size = sizeof(LambdaExpr) + sizeof(Stmt *) * (NumCaptures + 1); if (NumArrayIndexVars) @@ -984,13 +1068,13 @@ CXXRecordDecl *LambdaExpr::getLambdaClass() const { CXXMethodDecl *LambdaExpr::getCallOperator() const { CXXRecordDecl *Record = getLambdaClass(); - DeclarationName Name - = Record->getASTContext().DeclarationNames.getCXXOperatorName(OO_Call); - DeclContext::lookup_result Calls = Record->lookup(Name); - assert(!Calls.empty() && "Missing lambda call operator!"); - assert(Calls.size() == 1 && "More than one lambda call operator!"); - CXXMethodDecl *Result = cast<CXXMethodDecl>(Calls.front()); - return Result; + return Record->getLambdaCallOperator(); +} + +TemplateParameterList *LambdaExpr::getTemplateParameterList() const { + CXXRecordDecl *Record = getLambdaClass(); + return Record->getGenericLambdaTemplateParameterList(); + } CompoundStmt *LambdaExpr::getBody() const { @@ -1017,7 +1101,7 @@ ExprWithCleanups::ExprWithCleanups(Expr *subexpr, getObjectsBuffer()[i] = objects[i]; } -ExprWithCleanups *ExprWithCleanups::Create(ASTContext &C, Expr *subexpr, +ExprWithCleanups *ExprWithCleanups::Create(const ASTContext &C, Expr *subexpr, ArrayRef<CleanupObject> objects) { size_t size = sizeof(ExprWithCleanups) + objects.size() * sizeof(CleanupObject); @@ -1030,7 +1114,8 @@ ExprWithCleanups::ExprWithCleanups(EmptyShell empty, unsigned numObjects) ExprWithCleanupsBits.NumObjects = numObjects; } -ExprWithCleanups *ExprWithCleanups::Create(ASTContext &C, EmptyShell empty, +ExprWithCleanups *ExprWithCleanups::Create(const ASTContext &C, + EmptyShell empty, unsigned numObjects) { size_t size = sizeof(ExprWithCleanups) + numObjects * sizeof(CleanupObject); void *buffer = C.Allocate(size, llvm::alignOf<ExprWithCleanups>()); @@ -1063,7 +1148,7 @@ CXXUnresolvedConstructExpr::CXXUnresolvedConstructExpr(TypeSourceInfo *Type, } CXXUnresolvedConstructExpr * -CXXUnresolvedConstructExpr::Create(ASTContext &C, +CXXUnresolvedConstructExpr::Create(const ASTContext &C, TypeSourceInfo *Type, SourceLocation LParenLoc, ArrayRef<Expr*> Args, @@ -1074,7 +1159,7 @@ CXXUnresolvedConstructExpr::Create(ASTContext &C, } CXXUnresolvedConstructExpr * -CXXUnresolvedConstructExpr::CreateEmpty(ASTContext &C, unsigned NumArgs) { +CXXUnresolvedConstructExpr::CreateEmpty(const ASTContext &C, unsigned NumArgs) { Stmt::EmptyShell Empty; void *Mem = C.Allocate(sizeof(CXXUnresolvedConstructExpr) + sizeof(Expr *) * NumArgs); @@ -1085,7 +1170,7 @@ SourceLocation CXXUnresolvedConstructExpr::getLocStart() const { return Type->getTypeLoc().getBeginLoc(); } -CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C, +CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(const ASTContext &C, Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, @@ -1121,7 +1206,7 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C, } } -CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C, +CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(const ASTContext &C, Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, @@ -1142,7 +1227,7 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C, MemberNameInfo(MemberNameInfo) { } CXXDependentScopeMemberExpr * -CXXDependentScopeMemberExpr::Create(ASTContext &C, +CXXDependentScopeMemberExpr::Create(const ASTContext &C, Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc, @@ -1171,7 +1256,7 @@ CXXDependentScopeMemberExpr::Create(ASTContext &C, } CXXDependentScopeMemberExpr * -CXXDependentScopeMemberExpr::CreateEmpty(ASTContext &C, +CXXDependentScopeMemberExpr::CreateEmpty(const ASTContext &C, bool HasTemplateKWAndArgsInfo, unsigned NumTemplateArgs) { if (!HasTemplateKWAndArgsInfo) @@ -1222,7 +1307,7 @@ static bool hasOnlyNonStaticMemberFunctions(UnresolvedSetIterator begin, return true; } -UnresolvedMemberExpr::UnresolvedMemberExpr(ASTContext &C, +UnresolvedMemberExpr::UnresolvedMemberExpr(const ASTContext &C, bool HasUnresolvedUsing, Expr *Base, QualType BaseType, bool IsArrow, @@ -1260,8 +1345,7 @@ bool UnresolvedMemberExpr::isImplicitAccess() const { } UnresolvedMemberExpr * -UnresolvedMemberExpr::Create(ASTContext &C, - bool HasUnresolvedUsing, +UnresolvedMemberExpr::Create(const ASTContext &C, bool HasUnresolvedUsing, Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc, @@ -1284,7 +1368,8 @@ UnresolvedMemberExpr::Create(ASTContext &C, } UnresolvedMemberExpr * -UnresolvedMemberExpr::CreateEmpty(ASTContext &C, bool HasTemplateKWAndArgsInfo, +UnresolvedMemberExpr::CreateEmpty(const ASTContext &C, + bool HasTemplateKWAndArgsInfo, unsigned NumTemplateArgs) { std::size_t size = sizeof(UnresolvedMemberExpr); if (HasTemplateKWAndArgsInfo) @@ -1352,7 +1437,7 @@ FunctionParmPackExpr::FunctionParmPackExpr(QualType T, ParmVarDecl *ParamPack, } FunctionParmPackExpr * -FunctionParmPackExpr::Create(ASTContext &Context, QualType T, +FunctionParmPackExpr::Create(const ASTContext &Context, QualType T, ParmVarDecl *ParamPack, SourceLocation NameLoc, ArrayRef<Decl *> Params) { return new (Context.Allocate(sizeof(FunctionParmPackExpr) + @@ -1361,7 +1446,8 @@ FunctionParmPackExpr::Create(ASTContext &Context, QualType T, } FunctionParmPackExpr * -FunctionParmPackExpr::CreateEmpty(ASTContext &Context, unsigned NumParams) { +FunctionParmPackExpr::CreateEmpty(const ASTContext &Context, + unsigned NumParams) { return new (Context.Allocate(sizeof(FunctionParmPackExpr) + sizeof(ParmVarDecl*) * NumParams)) FunctionParmPackExpr(QualType(), 0, SourceLocation(), 0, 0); @@ -1396,7 +1482,7 @@ TypeTraitExpr::TypeTraitExpr(QualType T, SourceLocation Loc, TypeTrait Kind, } } -TypeTraitExpr *TypeTraitExpr::Create(ASTContext &C, QualType T, +TypeTraitExpr *TypeTraitExpr::Create(const ASTContext &C, QualType T, SourceLocation Loc, TypeTrait Kind, ArrayRef<TypeSourceInfo *> Args, @@ -1407,7 +1493,7 @@ TypeTraitExpr *TypeTraitExpr::Create(ASTContext &C, QualType T, return new (Mem) TypeTraitExpr(T, Loc, Kind, Args, RParenLoc, Value); } -TypeTraitExpr *TypeTraitExpr::CreateDeserialized(ASTContext &C, +TypeTraitExpr *TypeTraitExpr::CreateDeserialized(const ASTContext &C, unsigned NumArgs) { unsigned Size = sizeof(TypeTraitExpr) + sizeof(TypeSourceInfo*) * NumArgs; void *Mem = C.Allocate(Size); diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp index bcb6d4e..54f77ef 100644 --- a/lib/AST/ExprClassification.cpp +++ b/lib/AST/ExprClassification.cpp @@ -155,6 +155,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::OffsetOfExprClass: case Expr::CXXThrowExprClass: case Expr::ShuffleVectorExprClass: + case Expr::ConvertVectorExprClass: case Expr::IntegerLiteralClass: case Expr::CharacterLiteralClass: case Expr::AddrLabelExprClass: @@ -286,13 +287,16 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { // __builtin_choose_expr is equivalent to the chosen expression. case Expr::ChooseExprClass: - return ClassifyInternal(Ctx, cast<ChooseExpr>(E)->getChosenSubExpr(Ctx)); + return ClassifyInternal(Ctx, cast<ChooseExpr>(E)->getChosenSubExpr()); // Extended vector element access is an lvalue unless there are duplicates // in the shuffle expression. case Expr::ExtVectorElementExprClass: - return cast<ExtVectorElementExpr>(E)->containsDuplicateElements() ? - Cl::CL_DuplicateVectorComponents : Cl::CL_LValue; + if (cast<ExtVectorElementExpr>(E)->containsDuplicateElements()) + return Cl::CL_DuplicateVectorComponents; + if (cast<ExtVectorElementExpr>(E)->isArrow()) + return Cl::CL_LValue; + return ClassifyInternal(Ctx, cast<ExtVectorElementExpr>(E)->getBase()); // Simply look at the actual default argument. case Expr::CXXDefaultArgExprClass: @@ -353,6 +357,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::CXXConstructExprClass: case Expr::CXXTemporaryObjectExprClass: case Expr::LambdaExprClass: + case Expr::CXXStdInitializerListExprClass: return Cl::CL_ClassTemporary; case Expr::VAArgExprClass: @@ -587,6 +592,8 @@ static Cl::ModifiableType IsModifiable(ASTContext &Ctx, const Expr *E, // Const stuff is obviously not modifiable. if (CT.isConstQualified()) return Cl::CM_ConstQualified; + if (CT.getQualifiers().getAddressSpace() == LangAS::opencl_constant) + return Cl::CM_ConstQualified; // Arrays are not modifiable, only their elements are. if (CT->isArrayType()) diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 8c65029..390cfe9 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -23,8 +23,8 @@ // where it is possible to determine the evaluated result regardless. // // * A set of notes indicating why the evaluation was not a constant expression -// (under the C++11 rules only, at the moment), or, if folding failed too, -// why the expression could not be folded. +// (under the C++11 / C++1y rules only, at the moment), or, if folding failed +// too, why the expression could not be folded. // // If we are checking for a potential constant expression, failure to constant // fold a potential constant sub-expression will be indicated by a 'false' @@ -63,7 +63,25 @@ namespace { if (!B) return QualType(); if (const ValueDecl *D = B.dyn_cast<const ValueDecl*>()) return D->getType(); - return B.get<const Expr*>()->getType(); + + const Expr *Base = B.get<const Expr*>(); + + // For a materialized temporary, the type of the temporary we materialized + // may not be the type of the expression. + if (const MaterializeTemporaryExpr *MTE = + dyn_cast<MaterializeTemporaryExpr>(Base)) { + SmallVector<const Expr *, 2> CommaLHSs; + SmallVector<SubobjectAdjustment, 2> Adjustments; + const Expr *Temp = MTE->GetTemporaryExpr(); + const Expr *Inner = Temp->skipRValueSubobjectAdjustments(CommaLHSs, + Adjustments); + // Keep any cv-qualifiers from the reference if we generated a temporary + // for it. + if (Inner != Temp) + return Inner->getType(); + } + + return Base->getType(); } /// Get an LValue path entry, which is known to not be an array index, as a @@ -284,7 +302,7 @@ namespace { /// This - The binding for the this pointer in this call, if any. const LValue *This; - /// ParmBindings - Parameter bindings for this function call, indexed by + /// Arguments - Parameter bindings for this function call, indexed by /// parameters' function scope indices. APValue *Arguments; @@ -299,6 +317,12 @@ namespace { const FunctionDecl *Callee, const LValue *This, APValue *Arguments); ~CallStackFrame(); + + APValue *getTemporary(const void *Key) { + MapTy::iterator I = Temporaries.find(Key); + return I == Temporaries.end() ? 0 : &I->second; + } + APValue &createTemporary(const void *Key, bool IsLifetimeExtended); }; /// Temporarily override 'this'. @@ -343,14 +367,37 @@ namespace { OptionalDiagnostic &operator<<(const APFloat &F) { if (Diag) { + // FIXME: Force the precision of the source value down so we don't + // print digits which are usually useless (we don't really care here if + // we truncate a digit by accident in edge cases). Ideally, + // APFloat::toString would automatically print the shortest + // representation which rounds to the correct value, but it's a bit + // tricky to implement. + unsigned precision = + llvm::APFloat::semanticsPrecision(F.getSemantics()); + precision = (precision * 59 + 195) / 196; SmallVector<char, 32> Buffer; - F.toString(Buffer); + F.toString(Buffer, precision); *Diag << StringRef(Buffer.data(), Buffer.size()); } return *this; } }; + /// A cleanup, and a flag indicating whether it is lifetime-extended. + class Cleanup { + llvm::PointerIntPair<APValue*, 1, bool> Value; + + public: + Cleanup(APValue *Val, bool IsLifetimeExtended) + : Value(Val, IsLifetimeExtended) {} + + bool isLifetimeExtended() const { return Value.getInt(); } + void endLifetime() { + *Value.getPointer() = APValue(); + } + }; + /// EvalInfo - This is a private struct used by the evaluator to capture /// information about a subexpression as it is folded. It retains information /// about the AST context, but also maintains information about the folded @@ -380,13 +427,22 @@ namespace { /// NextCallIndex - The next call index to assign. unsigned NextCallIndex; + /// StepsLeft - The remaining number of evaluation steps we're permitted + /// to perform. This is essentially a limit for the number of statements + /// we will evaluate. + unsigned StepsLeft; + /// BottomFrame - The frame in which evaluation started. This must be /// initialized after CurrentCall and CallStackDepth. CallStackFrame BottomFrame; + /// A stack of values whose lifetimes end at the end of some surrounding + /// evaluation frame. + llvm::SmallVector<Cleanup, 16> CleanupStack; + /// EvaluatingDecl - This is the declaration whose initializer is being /// evaluated, if any. - const VarDecl *EvaluatingDecl; + APValue::LValueBase EvaluatingDecl; /// EvaluatingDeclValue - This is the value being constructed for the /// declaration whose initializer is being evaluated, if any. @@ -396,24 +452,52 @@ namespace { /// notes attached to it will also be stored, otherwise they will not be. bool HasActiveDiagnostic; - /// CheckingPotentialConstantExpression - Are we checking whether the - /// expression is a potential constant expression? If so, some diagnostics - /// are suppressed. - bool CheckingPotentialConstantExpression; - - bool IntOverflowCheckMode; + enum EvaluationMode { + /// Evaluate as a constant expression. Stop if we find that the expression + /// is not a constant expression. + EM_ConstantExpression, + + /// Evaluate as a potential constant expression. Keep going if we hit a + /// construct that we can't evaluate yet (because we don't yet know the + /// value of something) but stop if we hit something that could never be + /// a constant expression. + EM_PotentialConstantExpression, + + /// Fold the expression to a constant. Stop if we hit a side-effect that + /// we can't model. + EM_ConstantFold, + + /// Evaluate the expression looking for integer overflow and similar + /// issues. Don't worry about side-effects, and try to visit all + /// subexpressions. + EM_EvaluateForOverflow, - EvalInfo(const ASTContext &C, Expr::EvalStatus &S, - bool OverflowCheckMode=false) + /// Evaluate in any way we know how. Don't worry about side-effects that + /// can't be modeled. + EM_IgnoreSideEffects + } EvalMode; + + /// Are we checking whether the expression is a potential constant + /// expression? + bool checkingPotentialConstantExpression() const { + return EvalMode == EM_PotentialConstantExpression; + } + + /// Are we checking an expression for overflow? + // FIXME: We should check for any kind of undefined or suspicious behavior + // in such constructs, not just overflow. + bool checkingForOverflow() { return EvalMode == EM_EvaluateForOverflow; } + + EvalInfo(const ASTContext &C, Expr::EvalStatus &S, EvaluationMode Mode) : Ctx(const_cast<ASTContext&>(C)), EvalStatus(S), CurrentCall(0), CallStackDepth(0), NextCallIndex(1), + StepsLeft(getLangOpts().ConstexprStepLimit), BottomFrame(*this, SourceLocation(), 0, 0, 0), - EvaluatingDecl(0), EvaluatingDeclValue(0), HasActiveDiagnostic(false), - CheckingPotentialConstantExpression(false), - IntOverflowCheckMode(OverflowCheckMode) {} + EvaluatingDecl((const ValueDecl*)0), EvaluatingDeclValue(0), + HasActiveDiagnostic(false), EvalMode(Mode) {} - void setEvaluatingDecl(const VarDecl *VD, APValue &Value) { - EvaluatingDecl = VD; + void setEvaluatingDecl(APValue::LValueBase Base, APValue &Value) { + EvaluatingDecl = Base; EvaluatingDeclValue = &Value; } @@ -422,7 +506,7 @@ namespace { bool CheckCallLimit(SourceLocation Loc) { // Don't perform any constexpr calls (other than the call we're checking) // when checking a potential constant expression. - if (CheckingPotentialConstantExpression && CallStackDepth > 1) + if (checkingPotentialConstantExpression() && CallStackDepth > 1) return false; if (NextCallIndex == 0) { // NextCallIndex has wrapped around. @@ -446,6 +530,15 @@ namespace { return (Frame->Index == CallIndex) ? Frame : 0; } + bool nextStep(const Stmt *S) { + if (!StepsLeft) { + Diag(S->getLocStart(), diag::note_constexpr_step_limit_exceeded); + return false; + } + --StepsLeft; + return true; + } + private: /// Add a diagnostic to the diagnostics list. PartialDiagnostic &addDiag(SourceLocation Loc, diag::kind DiagId) { @@ -462,22 +555,41 @@ namespace { OptionalDiagnostic Diag(SourceLocation Loc, diag::kind DiagId = diag::note_invalid_subexpr_in_const_expr, unsigned ExtraNotes = 0) { - // If we have a prior diagnostic, it will be noting that the expression - // isn't a constant expression. This diagnostic is more important. - // FIXME: We might want to show both diagnostics to the user. if (EvalStatus.Diag) { + // If we have a prior diagnostic, it will be noting that the expression + // isn't a constant expression. This diagnostic is more important, + // unless we require this evaluation to produce a constant expression. + // + // FIXME: We might want to show both diagnostics to the user in + // EM_ConstantFold mode. + if (!EvalStatus.Diag->empty()) { + switch (EvalMode) { + case EM_ConstantFold: + case EM_IgnoreSideEffects: + case EM_EvaluateForOverflow: + if (!EvalStatus.HasSideEffects) + break; + // We've had side-effects; we want the diagnostic from them, not + // some later problem. + case EM_ConstantExpression: + case EM_PotentialConstantExpression: + HasActiveDiagnostic = false; + return OptionalDiagnostic(); + } + } + unsigned CallStackNotes = CallStackDepth - 1; unsigned Limit = Ctx.getDiagnostics().getConstexprBacktraceLimit(); if (Limit) CallStackNotes = std::min(CallStackNotes, Limit + 1); - if (CheckingPotentialConstantExpression) + if (checkingPotentialConstantExpression()) CallStackNotes = 0; HasActiveDiagnostic = true; EvalStatus.Diag->clear(); EvalStatus.Diag->reserve(1 + ExtraNotes + CallStackNotes); addDiag(Loc, DiagId); - if (!CheckingPotentialConstantExpression) + if (!checkingPotentialConstantExpression()) addCallStack(Limit); return OptionalDiagnostic(&(*EvalStatus.Diag)[0].second); } @@ -494,15 +606,17 @@ namespace { return OptionalDiagnostic(); } - bool getIntOverflowCheckMode() { return IntOverflowCheckMode; } - /// Diagnose that the evaluation does not produce a C++11 core constant /// expression. + /// + /// FIXME: Stop evaluating if we're in EM_ConstantExpression or + /// EM_PotentialConstantExpression mode and we produce one of these. template<typename LocArg> OptionalDiagnostic CCEDiag(LocArg Loc, diag::kind DiagId = diag::note_invalid_subexpr_in_const_expr, unsigned ExtraNotes = 0) { - // Don't override a previous diagnostic. + // Don't override a previous diagnostic. Don't bother collecting + // diagnostics if we're evaluating for overflow. if (!EvalStatus.Diag || !EvalStatus.Diag->empty()) { HasActiveDiagnostic = false; return OptionalDiagnostic(); @@ -525,30 +639,72 @@ namespace { } } + /// Should we continue evaluation after encountering a side-effect that we + /// couldn't model? + bool keepEvaluatingAfterSideEffect() { + switch (EvalMode) { + case EM_PotentialConstantExpression: + case EM_EvaluateForOverflow: + case EM_IgnoreSideEffects: + return true; + + case EM_ConstantExpression: + case EM_ConstantFold: + return false; + } + llvm_unreachable("Missed EvalMode case"); + } + + /// Note that we have had a side-effect, and determine whether we should + /// keep evaluating. + bool noteSideEffect() { + EvalStatus.HasSideEffects = true; + return keepEvaluatingAfterSideEffect(); + } + /// Should we continue evaluation as much as possible after encountering a - /// construct which can't be folded? + /// construct which can't be reduced to a value? bool keepEvaluatingAfterFailure() { - // Should return true in IntOverflowCheckMode, so that we check for - // overflow even if some subexpressions can't be evaluated as constants. - return IntOverflowCheckMode || - (CheckingPotentialConstantExpression && - EvalStatus.Diag && EvalStatus.Diag->empty()); + if (!StepsLeft) + return false; + + switch (EvalMode) { + case EM_PotentialConstantExpression: + case EM_EvaluateForOverflow: + return true; + + case EM_ConstantExpression: + case EM_ConstantFold: + case EM_IgnoreSideEffects: + return false; + } + llvm_unreachable("Missed EvalMode case"); } }; /// Object used to treat all foldable expressions as constant expressions. struct FoldConstant { + EvalInfo &Info; bool Enabled; - - explicit FoldConstant(EvalInfo &Info) - : Enabled(Info.EvalStatus.Diag && Info.EvalStatus.Diag->empty() && - !Info.EvalStatus.HasSideEffects) { - } - // Treat the value we've computed since this object was created as constant. - void Fold(EvalInfo &Info) { - if (Enabled && !Info.EvalStatus.Diag->empty() && + bool HadNoPriorDiags; + EvalInfo::EvaluationMode OldMode; + + explicit FoldConstant(EvalInfo &Info, bool Enabled) + : Info(Info), + Enabled(Enabled), + HadNoPriorDiags(Info.EvalStatus.Diag && + Info.EvalStatus.Diag->empty() && + !Info.EvalStatus.HasSideEffects), + OldMode(Info.EvalMode) { + if (Enabled && Info.EvalMode == EvalInfo::EM_ConstantExpression) + Info.EvalMode = EvalInfo::EM_ConstantFold; + } + void keepDiagnostics() { Enabled = false; } + ~FoldConstant() { + if (Enabled && HadNoPriorDiags && !Info.EvalStatus.Diag->empty() && !Info.EvalStatus.HasSideEffects) Info.EvalStatus.Diag->clear(); + Info.EvalMode = OldMode; } }; @@ -563,11 +719,50 @@ namespace { SmallVectorImpl<PartialDiagnosticAt> *NewDiag = 0) : Info(Info), Old(Info.EvalStatus) { Info.EvalStatus.Diag = NewDiag; + // If we're speculatively evaluating, we may have skipped over some + // evaluations and missed out a side effect. + Info.EvalStatus.HasSideEffects = true; } ~SpeculativeEvaluationRAII() { Info.EvalStatus = Old; } }; + + /// RAII object wrapping a full-expression or block scope, and handling + /// the ending of the lifetime of temporaries created within it. + template<bool IsFullExpression> + class ScopeRAII { + EvalInfo &Info; + unsigned OldStackSize; + public: + ScopeRAII(EvalInfo &Info) + : Info(Info), OldStackSize(Info.CleanupStack.size()) {} + ~ScopeRAII() { + // Body moved to a static method to encourage the compiler to inline away + // instances of this class. + cleanup(Info, OldStackSize); + } + private: + static void cleanup(EvalInfo &Info, unsigned OldStackSize) { + unsigned NewEnd = OldStackSize; + for (unsigned I = OldStackSize, N = Info.CleanupStack.size(); + I != N; ++I) { + if (IsFullExpression && Info.CleanupStack[I].isLifetimeExtended()) { + // Full-expression cleanup of a lifetime-extended temporary: nothing + // to do, just move this cleanup to the right place in the stack. + std::swap(Info.CleanupStack[I], Info.CleanupStack[NewEnd]); + ++NewEnd; + } else { + // End the lifetime of the object. + Info.CleanupStack[I].endLifetime(); + } + } + Info.CleanupStack.erase(Info.CleanupStack.begin() + NewEnd, + Info.CleanupStack.end()); + } + }; + typedef ScopeRAII<false> BlockScopeRAII; + typedef ScopeRAII<true> FullExpressionRAII; } bool SubobjectDesignator::checkSubobject(EvalInfo &Info, const Expr *E, @@ -610,32 +805,16 @@ CallStackFrame::~CallStackFrame() { Info.CurrentCall = Caller; } -/// Produce a string describing the given constexpr call. -static void describeCall(CallStackFrame *Frame, raw_ostream &Out) { - unsigned ArgIndex = 0; - bool IsMemberCall = isa<CXXMethodDecl>(Frame->Callee) && - !isa<CXXConstructorDecl>(Frame->Callee) && - cast<CXXMethodDecl>(Frame->Callee)->isInstance(); - - if (!IsMemberCall) - Out << *Frame->Callee << '('; - - for (FunctionDecl::param_const_iterator I = Frame->Callee->param_begin(), - E = Frame->Callee->param_end(); I != E; ++I, ++ArgIndex) { - if (ArgIndex > (unsigned)IsMemberCall) - Out << ", "; - - const ParmVarDecl *Param = *I; - const APValue &Arg = Frame->Arguments[ArgIndex]; - Arg.printPretty(Out, Frame->Info.Ctx, Param->getType()); - - if (ArgIndex == 0 && IsMemberCall) - Out << "->" << *Frame->Callee << '('; - } - - Out << ')'; +APValue &CallStackFrame::createTemporary(const void *Key, + bool IsLifetimeExtended) { + APValue &Result = Temporaries[Key]; + assert(Result.isUninit() && "temporary created multiple times"); + Info.CleanupStack.push_back(Cleanup(&Result, IsLifetimeExtended)); + return Result; } +static void describeCall(CallStackFrame *Frame, raw_ostream &Out); + void EvalInfo::addCallStack(unsigned Limit) { // Determine which calls to skip, if any. unsigned ActiveCalls = CallStackDepth - 1; @@ -884,19 +1063,11 @@ namespace { return false; return LHS.Path == RHS.Path; } - - /// Kinds of constant expression checking, for diagnostics. - enum CheckConstantExpressionKind { - CCEK_Constant, ///< A normal constant. - CCEK_ReturnValue, ///< A constexpr function return value. - CCEK_MemberInit ///< A constexpr constructor mem-initializer. - }; } static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E); static bool EvaluateInPlace(APValue &Result, EvalInfo &Info, const LValue &This, const Expr *E, - CheckConstantExpressionKind CCEK = CCEK_Constant, bool AllowNonLiteralTypes = false); static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info); static bool EvaluatePointer(const Expr *E, LValue &Result, EvalInfo &Info); @@ -908,23 +1079,66 @@ static bool EvaluateIntegerOrLValue(const Expr *E, APValue &Result, EvalInfo &Info); static bool EvaluateFloat(const Expr *E, APFloat &Result, EvalInfo &Info); static bool EvaluateComplex(const Expr *E, ComplexValue &Res, EvalInfo &Info); +static bool EvaluateAtomic(const Expr *E, APValue &Result, EvalInfo &Info); //===----------------------------------------------------------------------===// // Misc utilities //===----------------------------------------------------------------------===// +/// Produce a string describing the given constexpr call. +static void describeCall(CallStackFrame *Frame, raw_ostream &Out) { + unsigned ArgIndex = 0; + bool IsMemberCall = isa<CXXMethodDecl>(Frame->Callee) && + !isa<CXXConstructorDecl>(Frame->Callee) && + cast<CXXMethodDecl>(Frame->Callee)->isInstance(); + + if (!IsMemberCall) + Out << *Frame->Callee << '('; + + if (Frame->This && IsMemberCall) { + APValue Val; + Frame->This->moveInto(Val); + Val.printPretty(Out, Frame->Info.Ctx, + Frame->This->Designator.MostDerivedType); + // FIXME: Add parens around Val if needed. + Out << "->" << *Frame->Callee << '('; + IsMemberCall = false; + } + + for (FunctionDecl::param_const_iterator I = Frame->Callee->param_begin(), + E = Frame->Callee->param_end(); I != E; ++I, ++ArgIndex) { + if (ArgIndex > (unsigned)IsMemberCall) + Out << ", "; + + const ParmVarDecl *Param = *I; + const APValue &Arg = Frame->Arguments[ArgIndex]; + Arg.printPretty(Out, Frame->Info.Ctx, Param->getType()); + + if (ArgIndex == 0 && IsMemberCall) + Out << "->" << *Frame->Callee << '('; + } + + Out << ')'; +} + /// Evaluate an expression to see if it had side-effects, and discard its /// result. /// \return \c true if the caller should keep evaluating. static bool EvaluateIgnoredValue(EvalInfo &Info, const Expr *E) { APValue Scratch; - if (!Evaluate(Scratch, Info, E)) { - Info.EvalStatus.HasSideEffects = true; - return Info.keepEvaluatingAfterFailure(); - } + if (!Evaluate(Scratch, Info, E)) + // We don't need the value, but we might have skipped a side effect here. + return Info.noteSideEffect(); return true; } +/// Sign- or zero-extend a value to 64 bits. If it's already 64 bits, just +/// return its existing value. +static int64_t getExtValue(const APSInt &Value) { + return Value.isSigned() ? Value.getSExtValue() + : static_cast<int64_t>(Value.getZExtValue()); +} + /// Should this call expression be treated as a string literal? static bool IsStringLiteralCall(const CallExpr *E) { unsigned Builtin = E->isBuiltinCall(); @@ -956,6 +1170,10 @@ static bool IsGlobalLValue(APValue::LValueBase B) { const CompoundLiteralExpr *CLE = cast<CompoundLiteralExpr>(E); return CLE->isFileScope() && CLE->isLValue(); } + case Expr::MaterializeTemporaryExprClass: + // A materialized temporary might have been lifetime-extended to static + // storage duration. + return cast<MaterializeTemporaryExpr>(E)->getStorageDuration() == SD_Static; // A string literal has static storage duration. case Expr::StringLiteralClass: case Expr::PredefinedExprClass: @@ -1020,7 +1238,7 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc, // Don't allow references to temporaries to escape. return false; } - assert((Info.CheckingPotentialConstantExpression || + assert((Info.checkingPotentialConstantExpression() || LVal.getLValueCallIndex() == 0) && "have call index for global lvalue"); @@ -1057,10 +1275,18 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc, /// Check that this core constant expression is of literal type, and if not, /// produce an appropriate diagnostic. -static bool CheckLiteralType(EvalInfo &Info, const Expr *E) { +static bool CheckLiteralType(EvalInfo &Info, const Expr *E, + const LValue *This = 0) { if (!E->isRValue() || E->getType()->isLiteralType(Info.Ctx)) return true; + // C++1y: A constant initializer for an object o [...] may also invoke + // constexpr constructors for o and its subobjects even if those objects + // are of non-literal class types. + if (Info.getLangOpts().CPlusPlus1y && This && + Info.EvaluatingDecl == This->getLValueBase()) + return true; + // Prvalue constant expressions must be of literal types. if (Info.getLangOpts().CPlusPlus11) Info.Diag(E, diag::note_constexpr_nonliteral) @@ -1075,6 +1301,12 @@ static bool CheckLiteralType(EvalInfo &Info, const Expr *E) { /// check that the expression is of literal type. static bool CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc, QualType Type, const APValue &Value) { + if (Value.isUninit()) { + Info.Diag(DiagLoc, diag::note_constexpr_uninitialized) + << true << Type; + return false; + } + // Core issue 1454: For a literal constant expression of array or class type, // each subobject of its value shall have been initialized by a constant // expression. @@ -1129,7 +1361,10 @@ const ValueDecl *GetLValueBaseDecl(const LValue &LVal) { } static bool IsLiteralLValue(const LValue &Value) { - return Value.Base.dyn_cast<const Expr*>() && !Value.CallIndex; + if (Value.CallIndex) + return false; + const Expr *E = Value.Base.dyn_cast<const Expr*>(); + return E && !isa<MaterializeTemporaryExpr>(E); } static bool IsWeakLValue(const LValue &Value) { @@ -1252,6 +1487,27 @@ static bool HandleIntToFloatCast(EvalInfo &Info, const Expr *E, return true; } +static bool truncateBitfieldValue(EvalInfo &Info, const Expr *E, + APValue &Value, const FieldDecl *FD) { + assert(FD->isBitField() && "truncateBitfieldValue on non-bitfield"); + + if (!Value.isInt()) { + // Trying to store a pointer-cast-to-integer into a bitfield. + // FIXME: In this case, we should provide the diagnostic for casting + // a pointer to an integer. + assert(Value.isLValue() && "integral value neither int nor lvalue?"); + Info.Diag(E); + return false; + } + + APSInt &Int = Value.getInt(); + unsigned OldBitWidth = Int.getBitWidth(); + unsigned NewBitWidth = FD->getBitWidthValue(Info.Ctx); + if (NewBitWidth < OldBitWidth) + Int = Int.trunc(NewBitWidth).extend(OldBitWidth); + return true; +} + static bool EvalAndBitcastToAPInt(EvalInfo &Info, const Expr *E, llvm::APInt &Res) { APValue SVal; @@ -1299,6 +1555,155 @@ static bool EvalAndBitcastToAPInt(EvalInfo &Info, const Expr *E, return false; } +/// Perform the given integer operation, which is known to need at most BitWidth +/// bits, and check for overflow in the original type (if that type was not an +/// unsigned type). +template<typename Operation> +static APSInt CheckedIntArithmetic(EvalInfo &Info, const Expr *E, + const APSInt &LHS, const APSInt &RHS, + unsigned BitWidth, Operation Op) { + if (LHS.isUnsigned()) + return Op(LHS, RHS); + + APSInt Value(Op(LHS.extend(BitWidth), RHS.extend(BitWidth)), false); + APSInt Result = Value.trunc(LHS.getBitWidth()); + if (Result.extend(BitWidth) != Value) { + if (Info.checkingForOverflow()) + Info.Ctx.getDiagnostics().Report(E->getExprLoc(), + diag::warn_integer_constant_overflow) + << Result.toString(10) << E->getType(); + else + HandleOverflow(Info, E, Value, E->getType()); + } + return Result; +} + +/// Perform the given binary integer operation. +static bool handleIntIntBinOp(EvalInfo &Info, const Expr *E, const APSInt &LHS, + BinaryOperatorKind Opcode, APSInt RHS, + APSInt &Result) { + switch (Opcode) { + default: + Info.Diag(E); + return false; + case BO_Mul: + Result = CheckedIntArithmetic(Info, E, LHS, RHS, LHS.getBitWidth() * 2, + std::multiplies<APSInt>()); + return true; + case BO_Add: + Result = CheckedIntArithmetic(Info, E, LHS, RHS, LHS.getBitWidth() + 1, + std::plus<APSInt>()); + return true; + case BO_Sub: + Result = CheckedIntArithmetic(Info, E, LHS, RHS, LHS.getBitWidth() + 1, + std::minus<APSInt>()); + return true; + case BO_And: Result = LHS & RHS; return true; + case BO_Xor: Result = LHS ^ RHS; return true; + case BO_Or: Result = LHS | RHS; return true; + case BO_Div: + case BO_Rem: + if (RHS == 0) { + Info.Diag(E, diag::note_expr_divide_by_zero); + return false; + } + // Check for overflow case: INT_MIN / -1 or INT_MIN % -1. + if (RHS.isNegative() && RHS.isAllOnesValue() && + LHS.isSigned() && LHS.isMinSignedValue()) + HandleOverflow(Info, E, -LHS.extend(LHS.getBitWidth() + 1), E->getType()); + Result = (Opcode == BO_Rem ? LHS % RHS : LHS / RHS); + return true; + case BO_Shl: { + if (Info.getLangOpts().OpenCL) + // OpenCL 6.3j: shift values are effectively % word size of LHS. + RHS &= APSInt(llvm::APInt(RHS.getBitWidth(), + static_cast<uint64_t>(LHS.getBitWidth() - 1)), + RHS.isUnsigned()); + else if (RHS.isSigned() && RHS.isNegative()) { + // During constant-folding, a negative shift is an opposite shift. Such + // a shift is not a constant expression. + Info.CCEDiag(E, diag::note_constexpr_negative_shift) << RHS; + RHS = -RHS; + goto shift_right; + } + shift_left: + // C++11 [expr.shift]p1: Shift width must be less than the bit width of + // the shifted type. + unsigned SA = (unsigned) RHS.getLimitedValue(LHS.getBitWidth()-1); + if (SA != RHS) { + Info.CCEDiag(E, diag::note_constexpr_large_shift) + << RHS << E->getType() << LHS.getBitWidth(); + } else if (LHS.isSigned()) { + // C++11 [expr.shift]p2: A signed left shift must have a non-negative + // operand, and must not overflow the corresponding unsigned type. + if (LHS.isNegative()) + Info.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << LHS; + else if (LHS.countLeadingZeros() < SA) + Info.CCEDiag(E, diag::note_constexpr_lshift_discards); + } + Result = LHS << SA; + return true; + } + case BO_Shr: { + if (Info.getLangOpts().OpenCL) + // OpenCL 6.3j: shift values are effectively % word size of LHS. + RHS &= APSInt(llvm::APInt(RHS.getBitWidth(), + static_cast<uint64_t>(LHS.getBitWidth() - 1)), + RHS.isUnsigned()); + else if (RHS.isSigned() && RHS.isNegative()) { + // During constant-folding, a negative shift is an opposite shift. Such a + // shift is not a constant expression. + Info.CCEDiag(E, diag::note_constexpr_negative_shift) << RHS; + RHS = -RHS; + goto shift_left; + } + shift_right: + // C++11 [expr.shift]p1: Shift width must be less than the bit width of the + // shifted type. + unsigned SA = (unsigned) RHS.getLimitedValue(LHS.getBitWidth()-1); + if (SA != RHS) + Info.CCEDiag(E, diag::note_constexpr_large_shift) + << RHS << E->getType() << LHS.getBitWidth(); + Result = LHS >> SA; + return true; + } + + case BO_LT: Result = LHS < RHS; return true; + case BO_GT: Result = LHS > RHS; return true; + case BO_LE: Result = LHS <= RHS; return true; + case BO_GE: Result = LHS >= RHS; return true; + case BO_EQ: Result = LHS == RHS; return true; + case BO_NE: Result = LHS != RHS; return true; + } +} + +/// Perform the given binary floating-point operation, in-place, on LHS. +static bool handleFloatFloatBinOp(EvalInfo &Info, const Expr *E, + APFloat &LHS, BinaryOperatorKind Opcode, + const APFloat &RHS) { + switch (Opcode) { + default: + Info.Diag(E); + return false; + case BO_Mul: + LHS.multiply(RHS, APFloat::rmNearestTiesToEven); + break; + case BO_Add: + LHS.add(RHS, APFloat::rmNearestTiesToEven); + break; + case BO_Sub: + LHS.subtract(RHS, APFloat::rmNearestTiesToEven); + break; + case BO_Div: + LHS.divide(RHS, APFloat::rmNearestTiesToEven); + break; + } + + if (LHS.isInfinity() || LHS.isNaN()) + Info.CCEDiag(E, diag::note_constexpr_float_arithmetic) << LHS.isNaN(); + return true; +} + /// Cast an lvalue referring to a base subobject to a derived class, by /// truncating the lvalue's path to the given length. static bool CastToDerivedClass(EvalInfo &Info, const Expr *E, LValue &Result, @@ -1369,6 +1774,19 @@ static bool HandleLValueBase(EvalInfo &Info, const Expr *E, LValue &Obj, return true; } +static bool HandleLValueBasePath(EvalInfo &Info, const CastExpr *E, + QualType Type, LValue &Result) { + for (CastExpr::path_const_iterator PathI = E->path_begin(), + PathE = E->path_end(); + PathI != PathE; ++PathI) { + if (!HandleLValueBase(Info, E, Result, Type->getAsCXXRecordDecl(), + *PathI)) + return false; + Type = (*PathI)->getType(); + } + return true; +} + /// Update LVal to refer to the given field, which must be a member of the type /// currently described by LVal. static bool HandleLValueMember(EvalInfo &Info, const Expr *E, LValue &LVal, @@ -1470,7 +1888,7 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E, if (const ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(VD)) { // Assume arguments of a potential constant expression are unknown // constant expressions. - if (Info.CheckingPotentialConstantExpression) + if (Info.checkingPotentialConstantExpression()) return false; if (!Frame || !Frame->Arguments) { Info.Diag(E, diag::note_invalid_subexpr_in_const_expr); @@ -1482,11 +1900,9 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E, // If this is a local variable, dig out its value. if (Frame) { - Result = &Frame->Temporaries[VD]; - // If we've carried on past an unevaluatable local variable initializer, - // we can't go any further. This can happen during potential constant - // expression checking. - return !Result->isUninit(); + Result = Frame->getTemporary(VD); + assert(Result && "missing value for local variable"); + return true; } // Dig out the initializer, and use the declaration which it's attached to. @@ -1494,16 +1910,16 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E, if (!Init || Init->isValueDependent()) { // If we're checking a potential constant expression, the variable could be // initialized later. - if (!Info.CheckingPotentialConstantExpression) + if (!Info.checkingPotentialConstantExpression()) Info.Diag(E, diag::note_invalid_subexpr_in_const_expr); return false; } // If we're currently evaluating the initializer of this declaration, use that // in-flight value. - if (Info.EvaluatingDecl == VD) { + if (Info.EvaluatingDecl.dyn_cast<const ValueDecl*>() == VD) { Result = Info.EvaluatingDeclValue; - return !Result->isUninit(); + return true; } // Never evaluate the initializer of a weak variable. We can't be sure that @@ -1615,7 +2031,7 @@ static void expandArray(APValue &Array, unsigned Index) { Array.swap(NewValue); } -/// Kinds of access we can perform on an object. +/// Kinds of access we can perform on an object, for diagnostics. enum AccessKinds { AK_Read, AK_Assign, @@ -1637,7 +2053,7 @@ struct CompleteObject { assert(Value && "missing value for complete object"); } - operator bool() const { return Value; } + LLVM_EXPLICIT operator bool() const { return Value; } }; /// Find the designated sub-object of an rvalue. @@ -1656,16 +2072,33 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, Info.Diag(E); return handler.failed(); } - if (Sub.Entries.empty()) - return handler.found(*Obj.Value, Obj.Type); - if (Info.CheckingPotentialConstantExpression && Obj.Value->isUninit()) - // This object might be initialized later. - return handler.failed(); APValue *O = Obj.Value; QualType ObjType = Obj.Type; + const FieldDecl *LastField = 0; + // Walk the designator's path to find the subobject. - for (unsigned I = 0, N = Sub.Entries.size(); I != N; ++I) { + for (unsigned I = 0, N = Sub.Entries.size(); /**/; ++I) { + if (O->isUninit()) { + if (!Info.checkingPotentialConstantExpression()) + Info.Diag(E, diag::note_constexpr_access_uninit) << handler.AccessKind; + return handler.failed(); + } + + if (I == N) { + if (!handler.found(*O, ObjType)) + return false; + + // If we modified a bit-field, truncate it to the right width. + if (handler.AccessKind != AK_Read && + LastField && LastField->isBitField() && + !truncateBitfieldValue(Info, E, *O, LastField)) + return false; + + return true; + } + + LastField = 0; if (ObjType->isArrayType()) { // Next subobject is an array element. const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(ObjType); @@ -1767,6 +2200,8 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, } return handler.failed(); } + + LastField = Field; } else { // Next subobject is a base class. const CXXRecordDecl *Derived = ObjType->getAsCXXRecordDecl(); @@ -1778,15 +2213,7 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, if (WasConstQualified) ObjType.addConst(); } - - if (O->isUninit()) { - if (!Info.CheckingPotentialConstantExpression) - Info.Diag(E, diag::note_constexpr_access_uninit) << handler.AccessKind; - return handler.failed(); - } } - - return handler.found(*O, ObjType); } namespace { @@ -1963,9 +2390,6 @@ CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, AccessKinds AK, NoteLValueLocation(Info, LVal.Base); return CompleteObject(); } - } else if (AK != AK_Read) { - Info.Diag(E, diag::note_constexpr_modify_global); - return CompleteObject(); } // C++11 DR1311: An lvalue-to-rvalue conversion on a volatile-qualified type @@ -1983,7 +2407,7 @@ CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, AccessKinds AK, // Compute value storage location and type of base object. APValue *BaseVal = 0; - QualType BaseType; + QualType BaseType = getType(LVal.Base); if (const ValueDecl *D = LVal.Base.dyn_cast<const ValueDecl*>()) { // In C++98, const, non-volatile integers initialized with ICEs are ICEs. @@ -2004,7 +2428,6 @@ CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, AccessKinds AK, } // Accesses of volatile-qualified objects are not allowed. - BaseType = VD->getType(); if (BaseType.isVolatileQualified()) { if (Info.getLangOpts().CPlusPlus) { Info.Diag(E, diag::note_constexpr_access_volatile_obj, 1) @@ -2019,8 +2442,16 @@ CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, AccessKinds AK, // Unless we're looking at a local variable or argument in a constexpr call, // the variable we're reading must be const. if (!Frame) { - assert(AK == AK_Read && "can't modify non-local"); - if (VD->isConstexpr()) { + if (Info.getLangOpts().CPlusPlus1y && + VD == Info.EvaluatingDecl.dyn_cast<const ValueDecl *>()) { + // OK, we can read and modify an object if we're in the process of + // evaluating its initializer, because its lifetime began in this + // evaluation. + } else if (AK != AK_Read) { + // All the remaining cases only permit reading. + Info.Diag(E, diag::note_constexpr_modify_global); + return CompleteObject(); + } else if (VD->isConstexpr()) { // OK, we can read this variable. } else if (BaseType->isIntegralOrEnumerationType()) { if (!BaseType.isConstQualified()) { @@ -2060,12 +2491,45 @@ CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, AccessKinds AK, const Expr *Base = LVal.Base.dyn_cast<const Expr*>(); if (!Frame) { - Info.Diag(E); - return CompleteObject(); - } + if (const MaterializeTemporaryExpr *MTE = + dyn_cast<MaterializeTemporaryExpr>(Base)) { + assert(MTE->getStorageDuration() == SD_Static && + "should have a frame for a non-global materialized temporary"); + + // Per C++1y [expr.const]p2: + // an lvalue-to-rvalue conversion [is not allowed unless it applies to] + // - a [...] glvalue of integral or enumeration type that refers to + // a non-volatile const object [...] + // [...] + // - a [...] glvalue of literal type that refers to a non-volatile + // object whose lifetime began within the evaluation of e. + // + // C++11 misses the 'began within the evaluation of e' check and + // instead allows all temporaries, including things like: + // int &&r = 1; + // int x = ++r; + // constexpr int k = r; + // Therefore we use the C++1y rules in C++11 too. + const ValueDecl *VD = Info.EvaluatingDecl.dyn_cast<const ValueDecl*>(); + const ValueDecl *ED = MTE->getExtendingDecl(); + if (!(BaseType.isConstQualified() && + BaseType->isIntegralOrEnumerationType()) && + !(VD && VD->getCanonicalDecl() == ED->getCanonicalDecl())) { + Info.Diag(E, diag::note_constexpr_access_static_temporary, 1) << AK; + Info.Note(MTE->getExprLoc(), diag::note_constexpr_temporary_here); + return CompleteObject(); + } - BaseType = Base->getType(); - BaseVal = &Frame->Temporaries[Base]; + BaseVal = Info.Ctx.getMaterializedTemporaryValue(MTE, false); + assert(BaseVal && "got reference to unevaluated temporary"); + } else { + Info.Diag(E); + return CompleteObject(); + } + } else { + BaseVal = Frame->getTemporary(Base); + assert(BaseVal && "missing value for temporary"); + } // Volatile temporary objects cannot be accessed in constant expressions. if (BaseType.isVolatileQualified()) { @@ -2080,10 +2544,22 @@ CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, AccessKinds AK, } } - // In C++1y, we can't safely access any mutable state when checking a - // potential constant expression. + // During the construction of an object, it is not yet 'const'. + // FIXME: We don't set up EvaluatingDecl for local variables or temporaries, + // and this doesn't do quite the right thing for const subobjects of the + // object under construction. + if (LVal.getLValueBase() == Info.EvaluatingDecl) { + BaseType = Info.Ctx.getCanonicalType(BaseType); + BaseType.removeLocalConst(); + } + + // In C++1y, we can't safely access any mutable state when we might be + // evaluating after an unmodeled side effect or an evaluation failure. + // + // FIXME: Not all local state is mutable. Allow local constant subobjects + // to be read here (but take care with 'mutable' fields). if (Frame && Info.getLangOpts().CPlusPlus1y && - Info.CheckingPotentialConstantExpression) + (Info.EvalStatus.HasSideEffects || Info.keepEvaluatingAfterFailure())) return CompleteObject(); return CompleteObject(BaseVal, BaseType); @@ -2159,6 +2635,124 @@ static bool isOverflowingIntegerType(ASTContext &Ctx, QualType T) { } namespace { +struct CompoundAssignSubobjectHandler { + EvalInfo &Info; + const Expr *E; + QualType PromotedLHSType; + BinaryOperatorKind Opcode; + const APValue &RHS; + + static const AccessKinds AccessKind = AK_Assign; + + typedef bool result_type; + + bool checkConst(QualType QT) { + // Assigning to a const object has undefined behavior. + if (QT.isConstQualified()) { + Info.Diag(E, diag::note_constexpr_modify_const_type) << QT; + return false; + } + return true; + } + + bool failed() { return false; } + bool found(APValue &Subobj, QualType SubobjType) { + switch (Subobj.getKind()) { + case APValue::Int: + return found(Subobj.getInt(), SubobjType); + case APValue::Float: + return found(Subobj.getFloat(), SubobjType); + case APValue::ComplexInt: + case APValue::ComplexFloat: + // FIXME: Implement complex compound assignment. + Info.Diag(E); + return false; + case APValue::LValue: + return foundPointer(Subobj, SubobjType); + default: + // FIXME: can this happen? + Info.Diag(E); + return false; + } + } + bool found(APSInt &Value, QualType SubobjType) { + if (!checkConst(SubobjType)) + return false; + + if (!SubobjType->isIntegerType() || !RHS.isInt()) { + // We don't support compound assignment on integer-cast-to-pointer + // values. + Info.Diag(E); + return false; + } + + APSInt LHS = HandleIntToIntCast(Info, E, PromotedLHSType, + SubobjType, Value); + if (!handleIntIntBinOp(Info, E, LHS, Opcode, RHS.getInt(), LHS)) + return false; + Value = HandleIntToIntCast(Info, E, SubobjType, PromotedLHSType, LHS); + return true; + } + bool found(APFloat &Value, QualType SubobjType) { + return checkConst(SubobjType) && + HandleFloatToFloatCast(Info, E, SubobjType, PromotedLHSType, + Value) && + handleFloatFloatBinOp(Info, E, Value, Opcode, RHS.getFloat()) && + HandleFloatToFloatCast(Info, E, PromotedLHSType, SubobjType, Value); + } + bool foundPointer(APValue &Subobj, QualType SubobjType) { + if (!checkConst(SubobjType)) + return false; + + QualType PointeeType; + if (const PointerType *PT = SubobjType->getAs<PointerType>()) + PointeeType = PT->getPointeeType(); + + if (PointeeType.isNull() || !RHS.isInt() || + (Opcode != BO_Add && Opcode != BO_Sub)) { + Info.Diag(E); + return false; + } + + int64_t Offset = getExtValue(RHS.getInt()); + if (Opcode == BO_Sub) + Offset = -Offset; + + LValue LVal; + LVal.setFrom(Info.Ctx, Subobj); + if (!HandleLValueArrayAdjustment(Info, E, LVal, PointeeType, Offset)) + return false; + LVal.moveInto(Subobj); + return true; + } + bool foundString(APValue &Subobj, QualType SubobjType, uint64_t Character) { + llvm_unreachable("shouldn't encounter string elements here"); + } +}; +} // end anonymous namespace + +const AccessKinds CompoundAssignSubobjectHandler::AccessKind; + +/// Perform a compound assignment of LVal <op>= RVal. +static bool handleCompoundAssignment( + EvalInfo &Info, const Expr *E, + const LValue &LVal, QualType LValType, QualType PromotedLValType, + BinaryOperatorKind Opcode, const APValue &RVal) { + if (LVal.Designator.Invalid) + return false; + + if (!Info.getLangOpts().CPlusPlus1y) { + Info.Diag(E); + return false; + } + + CompleteObject Obj = findCompleteObject(Info, E, AK_Assign, LVal, LValType); + CompoundAssignSubobjectHandler Handler = { Info, E, PromotedLValType, Opcode, + RVal }; + return Obj && findSubobject(Info, E, Obj, LVal.Designator, Handler); +} + +namespace { struct IncDecSubobjectHandler { EvalInfo &Info; const Expr *E; @@ -2326,54 +2920,53 @@ static bool EvaluateObjectArgument(EvalInfo &Info, const Expr *Object, /// lvalue referring to the result. /// /// \param Info - Information about the ongoing evaluation. -/// \param BO - The member pointer access operation. -/// \param LV - Filled in with a reference to the resulting object. +/// \param LV - An lvalue referring to the base of the member pointer. +/// \param RHS - The member pointer expression. /// \param IncludeMember - Specifies whether the member itself is included in /// the resulting LValue subobject designator. This is not possible when /// creating a bound member function. /// \return The field or method declaration to which the member pointer refers, /// or 0 if evaluation fails. static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info, - const BinaryOperator *BO, + QualType LVType, LValue &LV, + const Expr *RHS, bool IncludeMember = true) { - assert(BO->getOpcode() == BO_PtrMemD || BO->getOpcode() == BO_PtrMemI); - - bool EvalObjOK = EvaluateObjectArgument(Info, BO->getLHS(), LV); - if (!EvalObjOK && !Info.keepEvaluatingAfterFailure()) - return 0; - MemberPtr MemPtr; - if (!EvaluateMemberPointer(BO->getRHS(), MemPtr, Info)) + if (!EvaluateMemberPointer(RHS, MemPtr, Info)) return 0; // C++11 [expr.mptr.oper]p6: If the second operand is the null pointer to // member value, the behavior is undefined. - if (!MemPtr.getDecl()) - return 0; - - if (!EvalObjOK) + if (!MemPtr.getDecl()) { + // FIXME: Specific diagnostic. + Info.Diag(RHS); return 0; + } if (MemPtr.isDerivedMember()) { // This is a member of some derived class. Truncate LV appropriately. // The end of the derived-to-base path for the base object must match the // derived-to-base path for the member pointer. if (LV.Designator.MostDerivedPathLength + MemPtr.Path.size() > - LV.Designator.Entries.size()) + LV.Designator.Entries.size()) { + Info.Diag(RHS); return 0; + } unsigned PathLengthToMember = LV.Designator.Entries.size() - MemPtr.Path.size(); for (unsigned I = 0, N = MemPtr.Path.size(); I != N; ++I) { const CXXRecordDecl *LVDecl = getAsBaseClass( LV.Designator.Entries[PathLengthToMember + I]); const CXXRecordDecl *MPDecl = MemPtr.Path[I]; - if (LVDecl->getCanonicalDecl() != MPDecl->getCanonicalDecl()) + if (LVDecl->getCanonicalDecl() != MPDecl->getCanonicalDecl()) { + Info.Diag(RHS); return 0; + } } // Truncate the lvalue to the appropriate derived class. - if (!CastToDerivedClass(Info, BO, LV, MemPtr.getContainingRecord(), + if (!CastToDerivedClass(Info, RHS, LV, MemPtr.getContainingRecord(), PathLengthToMember)) return 0; } else if (!MemPtr.Path.empty()) { @@ -2382,7 +2975,6 @@ static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info, MemPtr.Path.size() + IncludeMember); // Walk down to the appropriate base class. - QualType LVType = BO->getLHS()->getType(); if (const PointerType *PT = LVType->getAs<PointerType>()) LVType = PT->getPointeeType(); const CXXRecordDecl *RD = LVType->getAsCXXRecordDecl(); @@ -2390,23 +2982,24 @@ static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info, // The first class in the path is that of the lvalue. for (unsigned I = 1, N = MemPtr.Path.size(); I != N; ++I) { const CXXRecordDecl *Base = MemPtr.Path[N - I - 1]; - if (!HandleLValueDirectBase(Info, BO, LV, RD, Base)) + if (!HandleLValueDirectBase(Info, RHS, LV, RD, Base)) return 0; RD = Base; } // Finally cast to the class containing the member. - if (!HandleLValueDirectBase(Info, BO, LV, RD, MemPtr.getContainingRecord())) + if (!HandleLValueDirectBase(Info, RHS, LV, RD, + MemPtr.getContainingRecord())) return 0; } // Add the member. Note that we cannot build bound member functions here. if (IncludeMember) { if (const FieldDecl *FD = dyn_cast<FieldDecl>(MemPtr.getDecl())) { - if (!HandleLValueMember(Info, BO, LV, FD)) + if (!HandleLValueMember(Info, RHS, LV, FD)) return 0; } else if (const IndirectFieldDecl *IFD = dyn_cast<IndirectFieldDecl>(MemPtr.getDecl())) { - if (!HandleLValueIndirectMember(Info, BO, LV, IFD)) + if (!HandleLValueIndirectMember(Info, RHS, LV, IFD)) return 0; } else { llvm_unreachable("can't construct reference to bound member function"); @@ -2416,6 +3009,24 @@ static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info, return MemPtr.getDecl(); } +static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info, + const BinaryOperator *BO, + LValue &LV, + bool IncludeMember = true) { + assert(BO->getOpcode() == BO_PtrMemD || BO->getOpcode() == BO_PtrMemI); + + if (!EvaluateObjectArgument(Info, BO->getLHS(), LV)) { + if (Info.keepEvaluatingAfterFailure()) { + MemberPtr MemPtr; + EvaluateMemberPointer(BO->getRHS(), MemPtr, Info); + } + return 0; + } + + return HandleMemberPointerAccess(Info, BO->getLHS()->getType(), LV, + BO->getRHS(), IncludeMember); +} + /// HandleBaseToDerivedCast - Apply the given base-to-derived cast operation on /// the provided lvalue, which currently refers to the base object. static bool HandleBaseToDerivedCast(EvalInfo &Info, const CastExpr *E, @@ -2465,7 +3076,9 @@ enum EvalStmtResult { /// Hit a 'continue' statement. ESR_Continue, /// Hit a 'break' statement. - ESR_Break + ESR_Break, + /// Still scanning for 'case' or 'default' statement. + ESR_CaseNotFound }; } @@ -2477,7 +3090,14 @@ static bool EvaluateDecl(EvalInfo &Info, const Decl *D) { LValue Result; Result.set(VD, Info.CurrentCall->Index); - APValue &Val = Info.CurrentCall->Temporaries[VD]; + APValue &Val = Info.CurrentCall->createTemporary(VD, true); + + if (!VD->getInit()) { + Info.Diag(D->getLocStart(), diag::note_constexpr_uninitialized) + << false << VD->getType(); + Val = APValue(); + return false; + } if (!EvaluateInPlace(Val, Info, Result, VD->getInit())) { // Wipe out any partially-computed value, to allow tracking that this @@ -2493,18 +3113,21 @@ static bool EvaluateDecl(EvalInfo &Info, const Decl *D) { /// Evaluate a condition (either a variable declaration or an expression). static bool EvaluateCond(EvalInfo &Info, const VarDecl *CondDecl, const Expr *Cond, bool &Result) { + FullExpressionRAII Scope(Info); if (CondDecl && !EvaluateDecl(Info, CondDecl)) return false; return EvaluateAsBooleanCondition(Cond, Result, Info); } static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info, - const Stmt *S); + const Stmt *S, const SwitchCase *SC = 0); /// Evaluate the body of a loop, and translate the result as appropriate. static EvalStmtResult EvaluateLoopBody(APValue &Result, EvalInfo &Info, - const Stmt *Body) { - switch (EvalStmtResult ESR = EvaluateStmt(Result, Info, Body)) { + const Stmt *Body, + const SwitchCase *Case = 0) { + BlockScopeRAII Scope(Info); + switch (EvalStmtResult ESR = EvaluateStmt(Result, Info, Body, Case)) { case ESR_Break: return ESR_Succeeded; case ESR_Succeeded: @@ -2512,21 +3135,149 @@ static EvalStmtResult EvaluateLoopBody(APValue &Result, EvalInfo &Info, return ESR_Continue; case ESR_Failed: case ESR_Returned: + case ESR_CaseNotFound: + return ESR; + } + llvm_unreachable("Invalid EvalStmtResult!"); +} + +/// Evaluate a switch statement. +static EvalStmtResult EvaluateSwitch(APValue &Result, EvalInfo &Info, + const SwitchStmt *SS) { + BlockScopeRAII Scope(Info); + + // Evaluate the switch condition. + APSInt Value; + { + FullExpressionRAII Scope(Info); + if (SS->getConditionVariable() && + !EvaluateDecl(Info, SS->getConditionVariable())) + return ESR_Failed; + if (!EvaluateInteger(SS->getCond(), Value, Info)) + return ESR_Failed; + } + + // Find the switch case corresponding to the value of the condition. + // FIXME: Cache this lookup. + const SwitchCase *Found = 0; + for (const SwitchCase *SC = SS->getSwitchCaseList(); SC; + SC = SC->getNextSwitchCase()) { + if (isa<DefaultStmt>(SC)) { + Found = SC; + continue; + } + + const CaseStmt *CS = cast<CaseStmt>(SC); + APSInt LHS = CS->getLHS()->EvaluateKnownConstInt(Info.Ctx); + APSInt RHS = CS->getRHS() ? CS->getRHS()->EvaluateKnownConstInt(Info.Ctx) + : LHS; + if (LHS <= Value && Value <= RHS) { + Found = SC; + break; + } + } + + if (!Found) + return ESR_Succeeded; + + // Search the switch body for the switch case and evaluate it from there. + switch (EvalStmtResult ESR = EvaluateStmt(Result, Info, SS->getBody(), Found)) { + case ESR_Break: + return ESR_Succeeded; + case ESR_Succeeded: + case ESR_Continue: + case ESR_Failed: + case ESR_Returned: return ESR; + case ESR_CaseNotFound: + // This can only happen if the switch case is nested within a statement + // expression. We have no intention of supporting that. + Info.Diag(Found->getLocStart(), diag::note_constexpr_stmt_expr_unsupported); + return ESR_Failed; } llvm_unreachable("Invalid EvalStmtResult!"); } // Evaluate a statement. static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info, - const Stmt *S) { - // FIXME: Mark all temporaries in the current frame as destroyed at - // the end of each full-expression. + const Stmt *S, const SwitchCase *Case) { + if (!Info.nextStep(S)) + return ESR_Failed; + + // If we're hunting down a 'case' or 'default' label, recurse through + // substatements until we hit the label. + if (Case) { + // FIXME: We don't start the lifetime of objects whose initialization we + // jump over. However, such objects must be of class type with a trivial + // default constructor that initialize all subobjects, so must be empty, + // so this almost never matters. + switch (S->getStmtClass()) { + case Stmt::CompoundStmtClass: + // FIXME: Precompute which substatement of a compound statement we + // would jump to, and go straight there rather than performing a + // linear scan each time. + case Stmt::LabelStmtClass: + case Stmt::AttributedStmtClass: + case Stmt::DoStmtClass: + break; + + case Stmt::CaseStmtClass: + case Stmt::DefaultStmtClass: + if (Case == S) + Case = 0; + break; + + case Stmt::IfStmtClass: { + // FIXME: Precompute which side of an 'if' we would jump to, and go + // straight there rather than scanning both sides. + const IfStmt *IS = cast<IfStmt>(S); + + // Wrap the evaluation in a block scope, in case it's a DeclStmt + // preceded by our switch label. + BlockScopeRAII Scope(Info); + + EvalStmtResult ESR = EvaluateStmt(Result, Info, IS->getThen(), Case); + if (ESR != ESR_CaseNotFound || !IS->getElse()) + return ESR; + return EvaluateStmt(Result, Info, IS->getElse(), Case); + } + + case Stmt::WhileStmtClass: { + EvalStmtResult ESR = + EvaluateLoopBody(Result, Info, cast<WhileStmt>(S)->getBody(), Case); + if (ESR != ESR_Continue) + return ESR; + break; + } + + case Stmt::ForStmtClass: { + const ForStmt *FS = cast<ForStmt>(S); + EvalStmtResult ESR = + EvaluateLoopBody(Result, Info, FS->getBody(), Case); + if (ESR != ESR_Continue) + return ESR; + if (FS->getInc()) { + FullExpressionRAII IncScope(Info); + if (!EvaluateIgnoredValue(Info, FS->getInc())) + return ESR_Failed; + } + break; + } + + case Stmt::DeclStmtClass: + // FIXME: If the variable has initialization that can't be jumped over, + // bail out of any immediately-surrounding compound-statement too. + default: + return ESR_CaseNotFound; + } + } + switch (S->getStmtClass()) { default: if (const Expr *E = dyn_cast<Expr>(S)) { // Don't bother evaluating beyond an expression-statement which couldn't // be evaluated. + FullExpressionRAII Scope(Info); if (!EvaluateIgnoredValue(Info, E)) return ESR_Failed; return ESR_Succeeded; @@ -2541,34 +3292,45 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info, case Stmt::DeclStmtClass: { const DeclStmt *DS = cast<DeclStmt>(S); for (DeclStmt::const_decl_iterator DclIt = DS->decl_begin(), - DclEnd = DS->decl_end(); DclIt != DclEnd; ++DclIt) + DclEnd = DS->decl_end(); DclIt != DclEnd; ++DclIt) { + // Each declaration initialization is its own full-expression. + // FIXME: This isn't quite right; if we're performing aggregate + // initialization, each braced subexpression is its own full-expression. + FullExpressionRAII Scope(Info); if (!EvaluateDecl(Info, *DclIt) && !Info.keepEvaluatingAfterFailure()) return ESR_Failed; + } return ESR_Succeeded; } case Stmt::ReturnStmtClass: { const Expr *RetExpr = cast<ReturnStmt>(S)->getRetValue(); + FullExpressionRAII Scope(Info); if (RetExpr && !Evaluate(Result, Info, RetExpr)) return ESR_Failed; return ESR_Returned; } case Stmt::CompoundStmtClass: { + BlockScopeRAII Scope(Info); + const CompoundStmt *CS = cast<CompoundStmt>(S); for (CompoundStmt::const_body_iterator BI = CS->body_begin(), BE = CS->body_end(); BI != BE; ++BI) { - EvalStmtResult ESR = EvaluateStmt(Result, Info, *BI); - if (ESR != ESR_Succeeded) + EvalStmtResult ESR = EvaluateStmt(Result, Info, *BI, Case); + if (ESR == ESR_Succeeded) + Case = 0; + else if (ESR != ESR_CaseNotFound) return ESR; } - return ESR_Succeeded; + return Case ? ESR_CaseNotFound : ESR_Succeeded; } case Stmt::IfStmtClass: { const IfStmt *IS = cast<IfStmt>(S); // Evaluate the condition, as either a var decl or as an expression. + BlockScopeRAII Scope(Info); bool Cond; if (!EvaluateCond(Info, IS->getConditionVariable(), IS->getCond(), Cond)) return ESR_Failed; @@ -2584,6 +3346,7 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info, case Stmt::WhileStmtClass: { const WhileStmt *WS = cast<WhileStmt>(S); while (true) { + BlockScopeRAII Scope(Info); bool Continue; if (!EvaluateCond(Info, WS->getConditionVariable(), WS->getCond(), Continue)) @@ -2602,10 +3365,12 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info, const DoStmt *DS = cast<DoStmt>(S); bool Continue; do { - EvalStmtResult ESR = EvaluateLoopBody(Result, Info, DS->getBody()); + EvalStmtResult ESR = EvaluateLoopBody(Result, Info, DS->getBody(), Case); if (ESR != ESR_Continue) return ESR; + Case = 0; + FullExpressionRAII CondScope(Info); if (!EvaluateAsBooleanCondition(DS->getCond(), Continue, Info)) return ESR_Failed; } while (Continue); @@ -2614,12 +3379,14 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info, case Stmt::ForStmtClass: { const ForStmt *FS = cast<ForStmt>(S); + BlockScopeRAII Scope(Info); if (FS->getInit()) { EvalStmtResult ESR = EvaluateStmt(Result, Info, FS->getInit()); if (ESR != ESR_Succeeded) return ESR; } while (true) { + BlockScopeRAII Scope(Info); bool Continue = true; if (FS->getCond() && !EvaluateCond(Info, FS->getConditionVariable(), FS->getCond(), Continue)) @@ -2631,14 +3398,18 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info, if (ESR != ESR_Continue) return ESR; - if (FS->getInc() && !EvaluateIgnoredValue(Info, FS->getInc())) - return ESR_Failed; + if (FS->getInc()) { + FullExpressionRAII IncScope(Info); + if (!EvaluateIgnoredValue(Info, FS->getInc())) + return ESR_Failed; + } } return ESR_Succeeded; } case Stmt::CXXForRangeStmtClass: { const CXXForRangeStmt *FS = cast<CXXForRangeStmt>(S); + BlockScopeRAII Scope(Info); // Initialize the __range variable. EvalStmtResult ESR = EvaluateStmt(Result, Info, FS->getRangeStmt()); @@ -2652,13 +3423,17 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info, while (true) { // Condition: __begin != __end. - bool Continue = true; - if (!EvaluateAsBooleanCondition(FS->getCond(), Continue, Info)) - return ESR_Failed; - if (!Continue) - break; + { + bool Continue = true; + FullExpressionRAII CondExpr(Info); + if (!EvaluateAsBooleanCondition(FS->getCond(), Continue, Info)) + return ESR_Failed; + if (!Continue) + break; + } // User's variable declaration, initialized by *__begin. + BlockScopeRAII InnerScope(Info); ESR = EvaluateStmt(Result, Info, FS->getLoopVarStmt()); if (ESR != ESR_Succeeded) return ESR; @@ -2676,11 +3451,27 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info, return ESR_Succeeded; } + case Stmt::SwitchStmtClass: + return EvaluateSwitch(Result, Info, cast<SwitchStmt>(S)); + case Stmt::ContinueStmtClass: return ESR_Continue; case Stmt::BreakStmtClass: return ESR_Break; + + case Stmt::LabelStmtClass: + return EvaluateStmt(Result, Info, cast<LabelStmt>(S)->getSubStmt(), Case); + + case Stmt::AttributedStmtClass: + // As a general principle, C++11 attributes can be ignored without + // any semantic impact. + return EvaluateStmt(Result, Info, cast<AttributedStmt>(S)->getSubStmt(), + Case); + + case Stmt::CaseStmtClass: + case Stmt::DefaultStmtClass: + return EvaluateStmt(Result, Info, cast<SwitchCase>(S)->getSubStmt(), Case); } } @@ -2718,10 +3509,15 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc, const FunctionDecl *Definition) { // Potential constant expressions can contain calls to declared, but not yet // defined, constexpr functions. - if (Info.CheckingPotentialConstantExpression && !Definition && + if (Info.checkingPotentialConstantExpression() && !Definition && Declaration->isConstexpr()) return false; + // Bail out with no diagnostic if the function declaration itself is invalid. + // We will have produced a relevant diagnostic while parsing it. + if (Declaration->isInvalidDecl()) + return false; + // Can we evaluate this function call? if (Definition && Definition->isConstexpr() && !Definition->isInvalidDecl()) return true; @@ -2774,6 +3570,27 @@ static bool HandleFunctionCall(SourceLocation CallLoc, return false; CallStackFrame Frame(Info, CallLoc, Callee, This, ArgValues.data()); + + // For a trivial copy or move assignment, perform an APValue copy. This is + // essential for unions, where the operations performed by the assignment + // operator cannot be represented as statements. + const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Callee); + if (MD && MD->isDefaulted() && MD->isTrivial()) { + assert(This && + (MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator())); + LValue RHS; + RHS.setFrom(Info.Ctx, ArgValues[0]); + APValue RHSValue; + if (!handleLValueToRValueConversion(Info, Args[0], Args[0]->getType(), + RHS, RHSValue)) + return false; + if (!handleAssignment(Info, Args[0], *This, MD->getThisType(Info.Ctx), + RHSValue)) + return false; + This->moveInto(Result); + return true; + } + EvalStmtResult ESR = EvaluateStmt(Result, Info, Body); if (ESR == ESR_Succeeded) { if (Callee->getResultType()->isVoidType()) @@ -2806,8 +3623,11 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This, // If it's a delegating constructor, just delegate. if (Definition->isDelegatingConstructor()) { CXXConstructorDecl::init_const_iterator I = Definition->init_begin(); - if (!EvaluateInPlace(Result, Info, This, (*I)->getInit())) - return false; + { + FullExpressionRAII InitScope(Info); + if (!EvaluateInPlace(Result, Info, This, (*I)->getInit())) + return false; + } return EvaluateStmt(Result, Info, Definition->getBody()) != ESR_Failed; } @@ -2831,6 +3651,9 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This, if (RD->isInvalidDecl()) return false; const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD); + // A scope for temporaries lifetime-extended by reference members. + BlockScopeRAII LifetimeExtendedScope(Info); + bool Success = true; unsigned BasesSeen = 0; #ifndef NDEBUG @@ -2842,6 +3665,7 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This, APValue *Value = &Result; // Determine the subobject to initialize. + FieldDecl *FD = 0; if ((*I)->isBaseInitializer()) { QualType BaseType((*I)->getBaseClass(), 0); #ifndef NDEBUG @@ -2856,7 +3680,7 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This, BaseType->getAsCXXRecordDecl(), &Layout)) return false; Value = &Result.getStructBase(BasesSeen++); - } else if (FieldDecl *FD = (*I)->getMember()) { + } else if ((FD = (*I)->getMember())) { if (!HandleLValueMember(Info, (*I)->getInit(), Subobject, FD, &Layout)) return false; if (RD->isUnion()) { @@ -2871,7 +3695,7 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This, for (IndirectFieldDecl::chain_iterator C = IFD->chain_begin(), CE = IFD->chain_end(); C != CE; ++C) { - FieldDecl *FD = cast<FieldDecl>(*C); + FD = cast<FieldDecl>(*C); CXXRecordDecl *CD = cast<CXXRecordDecl>(FD->getParent()); // Switch the union field if it differs. This happens if we had // preceding zero-initialization, and we're now initializing a union @@ -2897,9 +3721,10 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This, llvm_unreachable("unknown base initializer kind"); } - if (!EvaluateInPlace(*Value, Info, Subobject, (*I)->getInit(), - (*I)->isBaseInitializer() - ? CCEK_Constant : CCEK_MemberInit)) { + FullExpressionRAII InitScope(Info); + if (!EvaluateInPlace(*Value, Info, Subobject, (*I)->getInit()) || + (FD && FD->isBitField() && !truncateBitfieldValue(Info, (*I)->getInit(), + *Value, FD))) { // If we're checking for a potential constant expression, evaluate all // initializers even if some of them fail. if (!Info.keepEvaluatingAfterFailure()) @@ -2934,7 +3759,7 @@ private: // expression, then the conditional operator is not either. template<typename ConditionalOperator> void CheckPotentialConstantConditional(const ConditionalOperator *E) { - assert(Info.CheckingPotentialConstantExpression); + assert(Info.checkingPotentialConstantExpression()); // Speculatively evaluate both arms. { @@ -2959,7 +3784,7 @@ private: bool HandleConditionalOperator(const ConditionalOperator *E) { bool BoolResult; if (!EvaluateAsBooleanCondition(E->getCond(), BoolResult, Info)) { - if (Info.CheckingPotentialConstantExpression) + if (Info.checkingPotentialConstantExpression()) CheckPotentialConstantConditional(E); return false; } @@ -3008,15 +3833,19 @@ public: RetTy VisitUnaryPlus(const UnaryOperator *E) { return StmtVisitorTy::Visit(E->getSubExpr()); } RetTy VisitChooseExpr(const ChooseExpr *E) - { return StmtVisitorTy::Visit(E->getChosenSubExpr(Info.Ctx)); } + { return StmtVisitorTy::Visit(E->getChosenSubExpr()); } RetTy VisitGenericSelectionExpr(const GenericSelectionExpr *E) { return StmtVisitorTy::Visit(E->getResultExpr()); } RetTy VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E) { return StmtVisitorTy::Visit(E->getReplacement()); } RetTy VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E) { return StmtVisitorTy::Visit(E->getExpr()); } - RetTy VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E) - { return StmtVisitorTy::Visit(E->getExpr()); } + RetTy VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E) { + // The initializer may not have been parsed yet, or might be erroneous. + if (!E->getExpr()) + return Error(E); + return StmtVisitorTy::Visit(E->getExpr()); + } // We cannot create any objects for which cleanups are required, so there is // nothing to do here; all cleanups must come from unevaluated subexpressions. RetTy VisitExprWithCleanups(const ExprWithCleanups *E) @@ -3056,7 +3885,7 @@ public: RetTy VisitBinaryConditionalOperator(const BinaryConditionalOperator *E) { // Evaluate and cache the common expression. We treat it as a temporary, // even though it's not quite the same thing. - if (!Evaluate(Info.CurrentCall->Temporaries[E->getOpaqueValue()], + if (!Evaluate(Info.CurrentCall->createTemporary(E->getOpaqueValue(), false), Info, E->getCommon())) return false; @@ -3076,33 +3905,30 @@ public: // Always assume __builtin_constant_p(...) ? ... : ... is a potential // constant expression; we can't check whether it's potentially foldable. - if (Info.CheckingPotentialConstantExpression && IsBcpCall) + if (Info.checkingPotentialConstantExpression() && IsBcpCall) return false; - FoldConstant Fold(Info); - - if (!HandleConditionalOperator(E)) + FoldConstant Fold(Info, IsBcpCall); + if (!HandleConditionalOperator(E)) { + Fold.keepDiagnostics(); return false; - - if (IsBcpCall) - Fold.Fold(Info); + } return true; } RetTy VisitOpaqueValueExpr(const OpaqueValueExpr *E) { - APValue &Value = Info.CurrentCall->Temporaries[E]; - if (Value.isUninit()) { - const Expr *Source = E->getSourceExpr(); - if (!Source) - return Error(E); - if (Source == E) { // sanity checking. - assert(0 && "OpaqueValueExpr recursively refers to itself"); - return Error(E); - } - return StmtVisitorTy::Visit(Source); + if (APValue *Value = Info.CurrentCall->getTemporary(E)) + return DerivedSuccess(*Value, E); + + const Expr *Source = E->getSourceExpr(); + if (!Source) + return Error(E); + if (Source == E) { // sanity checking. + assert(0 && "OpaqueValueExpr recursively refers to itself"); + return Error(E); } - return DerivedSuccess(Value, E); + return StmtVisitorTy::Visit(Source); } RetTy VisitCallExpr(const CallExpr *E) { @@ -3240,8 +4066,13 @@ public: default: break; - case CK_AtomicToNonAtomic: - case CK_NonAtomicToAtomic: + case CK_AtomicToNonAtomic: { + APValue AtomicVal; + if (!EvaluateAtomic(E->getSubExpr(), AtomicVal, Info)) + return false; + return DerivedSuccess(AtomicVal, E); + } + case CK_NoOp: case CK_UserDefinedConversion: return StmtVisitorTy::Visit(E->getSubExpr()); @@ -3282,6 +4113,41 @@ public: return DerivedSuccess(RVal, UO); } + RetTy VisitStmtExpr(const StmtExpr *E) { + // We will have checked the full-expressions inside the statement expression + // when they were completed, and don't need to check them again now. + if (Info.checkingForOverflow()) + return Error(E); + + BlockScopeRAII Scope(Info); + const CompoundStmt *CS = E->getSubStmt(); + for (CompoundStmt::const_body_iterator BI = CS->body_begin(), + BE = CS->body_end(); + /**/; ++BI) { + if (BI + 1 == BE) { + const Expr *FinalExpr = dyn_cast<Expr>(*BI); + if (!FinalExpr) { + Info.Diag((*BI)->getLocStart(), + diag::note_constexpr_stmt_expr_unsupported); + return false; + } + return this->Visit(FinalExpr); + } + + APValue ReturnValue; + EvalStmtResult ESR = EvaluateStmt(ReturnValue, Info, *BI); + if (ESR != ESR_Succeeded) { + // FIXME: If the statement-expression terminated due to 'return', + // 'break', or 'continue', it would be nice to propagate that to + // the outer statement evaluation rather than bailing out. + if (ESR != ESR_Failed) + Info.Diag((*BI)->getLocStart(), + diag::note_constexpr_stmt_expr_unsupported); + return false; + } + } + } + /// Visit a value which is evaluated, but whose value is ignored. void VisitIgnoredValue(const Expr *E) { EvaluateIgnoredValue(Info, E); @@ -3374,24 +4240,14 @@ public: return ExprEvaluatorBaseTy::VisitCastExpr(E); case CK_DerivedToBase: - case CK_UncheckedDerivedToBase: { + case CK_UncheckedDerivedToBase: if (!this->Visit(E->getSubExpr())) return false; // Now figure out the necessary offset to add to the base LV to get from // the derived class to the base class. - QualType Type = E->getSubExpr()->getType(); - - for (CastExpr::path_const_iterator PathI = E->path_begin(), - PathE = E->path_end(); PathI != PathE; ++PathI) { - if (!HandleLValueBase(this->Info, E, Result, Type->getAsCXXRecordDecl(), - *PathI)) - return false; - Type = (*PathI)->getType(); - } - - return true; - } + return HandleLValueBasePath(this->Info, E, E->getSubExpr()->getType(), + Result); } } }; @@ -3420,8 +4276,12 @@ public: // * BlockExpr // * CallExpr for a MakeStringConstant builtin // - Locals and temporaries +// * MaterializeTemporaryExpr // * Any Expr, with a CallIndex indicating the function in which the temporary -// was evaluated. +// was evaluated, for cases where the MaterializeTemporaryExpr is missing +// from the AST (FIXME). +// * A MaterializeTemporaryExpr that has static storage duration, with no +// CallIndex, for a lifetime-extended temporary. // plus an offset in bytes. //===----------------------------------------------------------------------===// namespace { @@ -3511,17 +4371,78 @@ bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) { APValue *V; if (!evaluateVarDeclInit(Info, E, VD, Frame, V)) return false; + if (V->isUninit()) { + if (!Info.checkingPotentialConstantExpression()) + Info.Diag(E, diag::note_constexpr_use_uninit_reference); + return false; + } return Success(*V, E); } bool LValueExprEvaluator::VisitMaterializeTemporaryExpr( const MaterializeTemporaryExpr *E) { - if (E->getType()->isRecordType()) - return EvaluateTemporary(E->GetTemporaryExpr(), Result, Info); + // Walk through the expression to find the materialized temporary itself. + SmallVector<const Expr *, 2> CommaLHSs; + SmallVector<SubobjectAdjustment, 2> Adjustments; + const Expr *Inner = E->GetTemporaryExpr()-> + skipRValueSubobjectAdjustments(CommaLHSs, Adjustments); + + // If we passed any comma operators, evaluate their LHSs. + for (unsigned I = 0, N = CommaLHSs.size(); I != N; ++I) + if (!EvaluateIgnoredValue(Info, CommaLHSs[I])) + return false; + + // A materialized temporary with static storage duration can appear within the + // result of a constant expression evaluation, so we need to preserve its + // value for use outside this evaluation. + APValue *Value; + if (E->getStorageDuration() == SD_Static) { + Value = Info.Ctx.getMaterializedTemporaryValue(E, true); + *Value = APValue(); + Result.set(E); + } else { + Value = &Info.CurrentCall-> + createTemporary(E, E->getStorageDuration() == SD_Automatic); + Result.set(E, Info.CurrentCall->Index); + } - Result.set(E, Info.CurrentCall->Index); - return EvaluateInPlace(Info.CurrentCall->Temporaries[E], Info, - Result, E->GetTemporaryExpr()); + QualType Type = Inner->getType(); + + // Materialize the temporary itself. + if (!EvaluateInPlace(*Value, Info, Result, Inner) || + (E->getStorageDuration() == SD_Static && + !CheckConstantExpression(Info, E->getExprLoc(), Type, *Value))) { + *Value = APValue(); + return false; + } + + // Adjust our lvalue to refer to the desired subobject. + for (unsigned I = Adjustments.size(); I != 0; /**/) { + --I; + switch (Adjustments[I].Kind) { + case SubobjectAdjustment::DerivedToBaseAdjustment: + if (!HandleLValueBasePath(Info, Adjustments[I].DerivedToBase.BasePath, + Type, Result)) + return false; + Type = Adjustments[I].DerivedToBase.BasePath->getType(); + break; + + case SubobjectAdjustment::FieldAdjustment: + if (!HandleLValueMember(Info, E, Result, Adjustments[I].Field)) + return false; + Type = Adjustments[I].Field->getType(); + break; + + case SubobjectAdjustment::MemberPointerAdjustment: + if (!HandleMemberPointerAccess(this->Info, Type, Result, + Adjustments[I].Ptr.RHS)) + return false; + Type = Adjustments[I].Ptr.MPT->getPointeeType(); + break; + } + } + + return true; } bool @@ -3576,11 +4497,9 @@ bool LValueExprEvaluator::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) { APSInt Index; if (!EvaluateInteger(E->getIdx(), Index, Info)) return false; - int64_t IndexValue - = Index.isSigned() ? Index.getSExtValue() - : static_cast<int64_t>(Index.getZExtValue()); - return HandleLValueArrayAdjustment(Info, E, Result, E->getType(), IndexValue); + return HandleLValueArrayAdjustment(Info, E, Result, E->getType(), + getExtValue(Index)); } bool LValueExprEvaluator::VisitUnaryDeref(const UnaryOperator *E) { @@ -3634,14 +4553,10 @@ bool LValueExprEvaluator::VisitCompoundAssignOperator( if (!Evaluate(RHS, this->Info, CAO->getRHS())) return false; - // FIXME: - //return handleCompoundAssignment( - // this->Info, CAO, - // Result, CAO->getLHS()->getType(), CAO->getComputationLHSType(), - // RHS, CAO->getRHS()->getType(), - // CAO->getOpForCompoundAssignment(CAO->getOpcode()), - // CAO->getComputationResultType()); - return Error(CAO); + return handleCompoundAssignment( + this->Info, CAO, + Result, CAO->getLHS()->getType(), CAO->getComputationLHSType(), + CAO->getOpForCompoundAssignment(CAO->getOpcode()), RHS); } bool LValueExprEvaluator::VisitBinAssign(const BinaryOperator *E) { @@ -3705,6 +4620,9 @@ public: return Error(E); } bool VisitCXXThisExpr(const CXXThisExpr *E) { + // Can't look at 'this' when checking a potential constant expression. + if (Info.checkingPotentialConstantExpression()) + return false; if (!Info.CurrentCall->This) return Error(E); Result = *Info.CurrentCall->This; @@ -3737,9 +4655,8 @@ bool PointerExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { llvm::APSInt Offset; if (!EvaluateInteger(IExp, Offset, Info) || !EvalPtrOK) return false; - int64_t AdditionalOffset - = Offset.isSigned() ? Offset.getSExtValue() - : static_cast<int64_t>(Offset.getZExtValue()); + + int64_t AdditionalOffset = getExtValue(Offset); if (E->getOpcode() == BO_Sub) AdditionalOffset = -AdditionalOffset; @@ -3779,7 +4696,7 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { return true; case CK_DerivedToBase: - case CK_UncheckedDerivedToBase: { + case CK_UncheckedDerivedToBase: if (!EvaluatePointer(E->getSubExpr(), Result, Info)) return false; if (!Result.Base && Result.Offset.isZero()) @@ -3787,19 +4704,9 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { // Now figure out the necessary offset to add to the base LV to get from // the derived class to the base class. - QualType Type = - E->getSubExpr()->getType()->castAs<PointerType>()->getPointeeType(); - - for (CastExpr::path_const_iterator PathI = E->path_begin(), - PathE = E->path_end(); PathI != PathE; ++PathI) { - if (!HandleLValueBase(Info, E, Result, Type->getAsCXXRecordDecl(), - *PathI)) - return false; - Type = (*PathI)->getType(); - } - - return true; - } + return HandleLValueBasePath(Info, E, E->getSubExpr()->getType()-> + castAs<PointerType>()->getPointeeType(), + Result); case CK_BaseToDerived: if (!Visit(E->getSubExpr())) @@ -3839,7 +4746,7 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { return false; } else { Result.set(SubExpr, Info.CurrentCall->Index); - if (!EvaluateInPlace(Info.CurrentCall->Temporaries[SubExpr], + if (!EvaluateInPlace(Info.CurrentCall->createTemporary(SubExpr, false), Info, Result, SubExpr)) return false; } @@ -3862,7 +4769,13 @@ bool PointerExprEvaluator::VisitCallExpr(const CallExpr *E) { if (IsStringLiteralCall(E)) return Success(E); - return ExprEvaluatorBaseTy::VisitCallExpr(E); + switch (E->isBuiltinCall()) { + case Builtin::BI__builtin_addressof: + return EvaluateLValue(E->getArg(0), Result, Info); + + default: + return ExprEvaluatorBaseTy::VisitCallExpr(E); + } } //===----------------------------------------------------------------------===// @@ -3976,6 +4889,7 @@ namespace { bool VisitCastExpr(const CastExpr *E); bool VisitInitListExpr(const InitListExpr *E); bool VisitCXXConstructExpr(const CXXConstructExpr *E); + bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *E); }; } @@ -4091,10 +5005,6 @@ bool RecordExprEvaluator::VisitCastExpr(const CastExpr *E) { } bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) { - // Cannot constant-evaluate std::initializer_list inits. - if (E->initializesStdInitializerList()) - return false; - const RecordDecl *RD = E->getType()->castAs<RecordType>()->getDecl(); if (RD->isInvalidDecl()) return false; const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD); @@ -4156,8 +5066,10 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) { ThisOverrideRAII ThisOverride(*Info.CurrentCall, &This, isa<CXXDefaultInitExpr>(Init)); - if (!EvaluateInPlace(Result.getStructField(Field->getFieldIndex()), Info, - Subobject, Init)) { + APValue &FieldVal = Result.getStructField(Field->getFieldIndex()); + if (!EvaluateInPlace(FieldVal, Info, Subobject, Init) || + (Field->isBitField() && !truncateBitfieldValue(Info, Init, + FieldVal, *Field))) { if (!Info.keepEvaluatingAfterFailure()) return false; Success = false; @@ -4210,6 +5122,58 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) { Result); } +bool RecordExprEvaluator::VisitCXXStdInitializerListExpr( + const CXXStdInitializerListExpr *E) { + const ConstantArrayType *ArrayType = + Info.Ctx.getAsConstantArrayType(E->getSubExpr()->getType()); + + LValue Array; + if (!EvaluateLValue(E->getSubExpr(), Array, Info)) + return false; + + // Get a pointer to the first element of the array. + Array.addArray(Info, E, ArrayType); + + // FIXME: Perform the checks on the field types in SemaInit. + RecordDecl *Record = E->getType()->castAs<RecordType>()->getDecl(); + RecordDecl::field_iterator Field = Record->field_begin(); + if (Field == Record->field_end()) + return Error(E); + + // Start pointer. + if (!Field->getType()->isPointerType() || + !Info.Ctx.hasSameType(Field->getType()->getPointeeType(), + ArrayType->getElementType())) + return Error(E); + + // FIXME: What if the initializer_list type has base classes, etc? + Result = APValue(APValue::UninitStruct(), 0, 2); + Array.moveInto(Result.getStructField(0)); + + if (++Field == Record->field_end()) + return Error(E); + + if (Field->getType()->isPointerType() && + Info.Ctx.hasSameType(Field->getType()->getPointeeType(), + ArrayType->getElementType())) { + // End pointer. + if (!HandleLValueArrayAdjustment(Info, E, Array, + ArrayType->getElementType(), + ArrayType->getSize().getZExtValue())) + return false; + Array.moveInto(Result.getStructField(1)); + } else if (Info.Ctx.hasSameType(Field->getType(), Info.Ctx.getSizeType())) + // Length. + Result.getStructField(1) = APValue(APSInt(ArrayType->getSize())); + else + return Error(E); + + if (++Field != Record->field_end()) + return Error(E); + + return true; +} + static bool EvaluateRecord(const Expr *E, const LValue &This, APValue &Result, EvalInfo &Info) { assert(E->isRValue() && E->getType()->isRecordType() && @@ -4234,7 +5198,8 @@ public: /// Visit an expression which constructs the value of this temporary. bool VisitConstructExpr(const Expr *E) { Result.set(E, Info.CurrentCall->Index); - return EvaluateInPlace(Info.CurrentCall->Temporaries[E], Info, Result, E); + return EvaluateInPlace(Info.CurrentCall->createTemporary(E, false), + Info, Result, E); } bool VisitCastExpr(const CastExpr *E) { @@ -4393,7 +5358,7 @@ VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) { while (CountElts < NumElements) { // Handle nested vector initialization. if (CountInits < NumInits - && E->getInit(CountInits)->getType()->isExtVectorType()) { + && E->getInit(CountInits)->getType()->isVectorType()) { APValue v; if (!EvaluateVector(E->getInit(CountInits), v, Info)) return Error(E); @@ -4951,7 +5916,7 @@ static bool EvaluateBuiltinConstantP(ASTContext &Ctx, const Expr *Arg) { } else if (ArgType->isPointerType() || Arg->isGLValue()) { LValue LV; Expr::EvalStatus Status; - EvalInfo Info(Ctx, Status); + EvalInfo Info(Ctx, Status, EvalInfo::EM_ConstantFold); if ((Arg->isGLValue() ? EvaluateLValue(Arg, LV, Info) : EvaluatePointer(Arg, LV, Info)) && !Status.HasSideEffects) @@ -5045,9 +6010,37 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { case Builtin::BI__builtin_classify_type: return Success(EvaluateBuiltinClassifyType(E), E); + // FIXME: BI__builtin_clrsb + // FIXME: BI__builtin_clrsbl + // FIXME: BI__builtin_clrsbll + + case Builtin::BI__builtin_clz: + case Builtin::BI__builtin_clzl: + case Builtin::BI__builtin_clzll: { + APSInt Val; + if (!EvaluateInteger(E->getArg(0), Val, Info)) + return false; + if (!Val) + return Error(E); + + return Success(Val.countLeadingZeros(), E); + } + case Builtin::BI__builtin_constant_p: return Success(EvaluateBuiltinConstantP(Info.Ctx, E->getArg(0)), E); + case Builtin::BI__builtin_ctz: + case Builtin::BI__builtin_ctzl: + case Builtin::BI__builtin_ctzll: { + APSInt Val; + if (!EvaluateInteger(E->getArg(0), Val, Info)) + return false; + if (!Val) + return Error(E); + + return Success(Val.countTrailingZeros(), E); + } + case Builtin::BI__builtin_eh_return_data_regno: { int Operand = E->getArg(0)->EvaluateKnownConstInt(Info.Ctx).getZExtValue(); Operand = Info.Ctx.getTargetInfo().getEHDataRegisterNumber(Operand); @@ -5057,6 +6050,81 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { case Builtin::BI__builtin_expect: return Visit(E->getArg(0)); + case Builtin::BI__builtin_ffs: + case Builtin::BI__builtin_ffsl: + case Builtin::BI__builtin_ffsll: { + APSInt Val; + if (!EvaluateInteger(E->getArg(0), Val, Info)) + return false; + + unsigned N = Val.countTrailingZeros(); + return Success(N == Val.getBitWidth() ? 0 : N + 1, E); + } + + case Builtin::BI__builtin_fpclassify: { + APFloat Val(0.0); + if (!EvaluateFloat(E->getArg(5), Val, Info)) + return false; + unsigned Arg; + switch (Val.getCategory()) { + case APFloat::fcNaN: Arg = 0; break; + case APFloat::fcInfinity: Arg = 1; break; + case APFloat::fcNormal: Arg = Val.isDenormal() ? 3 : 2; break; + case APFloat::fcZero: Arg = 4; break; + } + return Visit(E->getArg(Arg)); + } + + case Builtin::BI__builtin_isinf_sign: { + APFloat Val(0.0); + return EvaluateFloat(E->getArg(0), Val, Info) && + Success(Val.isInfinity() ? (Val.isNegative() ? -1 : 1) : 0, E); + } + + case Builtin::BI__builtin_isinf: { + APFloat Val(0.0); + return EvaluateFloat(E->getArg(0), Val, Info) && + Success(Val.isInfinity() ? 1 : 0, E); + } + + case Builtin::BI__builtin_isfinite: { + APFloat Val(0.0); + return EvaluateFloat(E->getArg(0), Val, Info) && + Success(Val.isFinite() ? 1 : 0, E); + } + + case Builtin::BI__builtin_isnan: { + APFloat Val(0.0); + return EvaluateFloat(E->getArg(0), Val, Info) && + Success(Val.isNaN() ? 1 : 0, E); + } + + case Builtin::BI__builtin_isnormal: { + APFloat Val(0.0); + return EvaluateFloat(E->getArg(0), Val, Info) && + Success(Val.isNormal() ? 1 : 0, E); + } + + case Builtin::BI__builtin_parity: + case Builtin::BI__builtin_parityl: + case Builtin::BI__builtin_parityll: { + APSInt Val; + if (!EvaluateInteger(E->getArg(0), Val, Info)) + return false; + + return Success(Val.countPopulation() % 2, E); + } + + case Builtin::BI__builtin_popcount: + case Builtin::BI__builtin_popcountl: + case Builtin::BI__builtin_popcountll: { + APSInt Val; + if (!EvaluateInteger(E->getArg(0), Val, Info)) + return false; + + return Success(Val.countPopulation(), E); + } + case Builtin::BIstrlen: // A call to strlen is not a constant expression. if (Info.getLangOpts().CPlusPlus11) @@ -5065,22 +6133,47 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { else Info.CCEDiag(E, diag::note_invalid_subexpr_in_const_expr); // Fall through. - 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 (const StringLiteral *S - = dyn_cast<StringLiteral>(E->getArg(0)->IgnoreParenImpCasts())) { + case Builtin::BI__builtin_strlen: { + // As an extension, we support __builtin_strlen() as a constant expression, + // and support folding strlen() to a constant. + LValue String; + if (!EvaluatePointer(E->getArg(0), String, Info)) + return false; + + // Fast path: if it's a string literal, search the string value. + if (const StringLiteral *S = dyn_cast_or_null<StringLiteral>( + String.getLValueBase().dyn_cast<const Expr *>())) { // The string literal may have embedded null characters. Find the first // one and truncate there. - StringRef Str = S->getString(); - StringRef::size_type Pos = Str.find(0); - if (Pos != StringRef::npos) - Str = Str.substr(0, Pos); - - return Success(Str.size(), E); + StringRef Str = S->getBytes(); + int64_t Off = String.Offset.getQuantity(); + if (Off >= 0 && (uint64_t)Off <= (uint64_t)Str.size() && + S->getCharByteWidth() == 1) { + Str = Str.substr(Off); + + StringRef::size_type Pos = Str.find(0); + if (Pos != StringRef::npos) + Str = Str.substr(0, Pos); + + return Success(Str.size(), E); + } + + // Fall through to slow path to issue appropriate diagnostic. } - - return Error(E); + + // Slow path: scan the bytes of the string looking for the terminating 0. + QualType CharTy = E->getArg(0)->getType()->getPointeeType(); + for (uint64_t Strlen = 0; /**/; ++Strlen) { + APValue Char; + if (!handleLValueToRValueConversion(Info, E, CharTy, String, Char) || + !Char.isInt()) + return false; + if (!Char.getInt()) + return Success(Strlen, E); + if (!HandleLValueArrayAdjustment(Info, E, String, CharTy, 1)) + return false; + } + } case Builtin::BI__atomic_always_lock_free: case Builtin::BI__atomic_is_lock_free: @@ -5149,29 +6242,6 @@ static bool HasSameBase(const LValue &A, const LValue &B) { A.getLValueCallIndex() == B.getLValueCallIndex(); } -/// Perform the given integer operation, which is known to need at most BitWidth -/// bits, and check for overflow in the original type (if that type was not an -/// unsigned type). -template<typename Operation> -static APSInt CheckedIntArithmetic(EvalInfo &Info, const Expr *E, - const APSInt &LHS, const APSInt &RHS, - unsigned BitWidth, Operation Op) { - if (LHS.isUnsigned()) - return Op(LHS, RHS); - - APSInt Value(Op(LHS.extend(BitWidth), RHS.extend(BitWidth)), false); - APSInt Result = Value.trunc(LHS.getBitWidth()); - if (Result.extend(BitWidth) != Value) { - if (Info.getIntOverflowCheckMode()) - Info.Ctx.getDiagnostics().Report(E->getExprLoc(), - diag::warn_integer_constant_overflow) - << Result.toString(10) << E->getType(); - else - HandleOverflow(Info, E, Value, E->getType()); - } - return Result; -} - namespace { /// \brief Data recursive integer evaluator of certain binary operators. @@ -5296,36 +6366,39 @@ bool DataRecursiveIntBinOpEvaluator:: if (E->getOpcode() == BO_Comma) { // Ignore LHS but note if we could not evaluate it. if (LHSResult.Failed) - Info.EvalStatus.HasSideEffects = true; + return Info.noteSideEffect(); return true; } - + if (E->isLogicalOp()) { - bool lhsResult; - if (HandleConversionToBool(LHSResult.Val, lhsResult)) { + bool LHSAsBool; + if (!LHSResult.Failed && HandleConversionToBool(LHSResult.Val, LHSAsBool)) { // We were able to evaluate the LHS, see if we can get away with not // evaluating the RHS: 0 && X -> 0, 1 || X -> 1 - if (lhsResult == (E->getOpcode() == BO_LOr)) { - Success(lhsResult, E, LHSResult.Val); + if (LHSAsBool == (E->getOpcode() == BO_LOr)) { + Success(LHSAsBool, E, LHSResult.Val); return false; // Ignore RHS } } else { + LHSResult.Failed = true; + // Since we weren't able to evaluate the left hand side, it // must have had side effects. - Info.EvalStatus.HasSideEffects = true; - + if (!Info.noteSideEffect()) + return false; + // We can't evaluate the LHS; however, sometimes the result // is determined by the RHS: X && 0 -> 0, X || 1 -> 1. // Don't ignore RHS and suppress diagnostics from this arm. SuppressRHSDiags = true; } - + return true; } - + assert(E->getLHS()->getType()->isIntegralOrEnumerationType() && E->getRHS()->getType()->isIntegralOrEnumerationType()); - + if (LHSResult.Failed && !Info.keepEvaluatingAfterFailure()) return false; // Ignore RHS; @@ -5378,8 +6451,8 @@ bool DataRecursiveIntBinOpEvaluator:: // Handle cases like (unsigned long)&a + 4. if (E->isAdditiveOp() && LHSVal.isLValue() && RHSVal.isInt()) { Result = LHSVal; - CharUnits AdditionalOffset = CharUnits::fromQuantity( - RHSVal.getInt().getZExtValue()); + CharUnits AdditionalOffset = + CharUnits::fromQuantity(RHSVal.getInt().getZExtValue()); if (E->getOpcode() == BO_Add) Result.getLValueOffset() += AdditionalOffset; else @@ -5391,8 +6464,8 @@ bool DataRecursiveIntBinOpEvaluator:: if (E->getOpcode() == BO_Add && RHSVal.isLValue() && LHSVal.isInt()) { Result = RHSVal; - Result.getLValueOffset() += CharUnits::fromQuantity( - LHSVal.getInt().getZExtValue()); + Result.getLValueOffset() += + CharUnits::fromQuantity(LHSVal.getInt().getZExtValue()); return true; } @@ -5416,108 +6489,20 @@ bool DataRecursiveIntBinOpEvaluator:: Result = APValue(LHSAddrExpr, RHSAddrExpr); return true; } - - // All the following cases expect both operands to be an integer + + // All the remaining cases expect both operands to be an integer if (!LHSVal.isInt() || !RHSVal.isInt()) return Error(E); - - const APSInt &LHS = LHSVal.getInt(); - APSInt RHS = RHSVal.getInt(); - - switch (E->getOpcode()) { - default: - return Error(E); - case BO_Mul: - return Success(CheckedIntArithmetic(Info, E, LHS, RHS, - LHS.getBitWidth() * 2, - std::multiplies<APSInt>()), E, - Result); - case BO_Add: - return Success(CheckedIntArithmetic(Info, E, LHS, RHS, - LHS.getBitWidth() + 1, - std::plus<APSInt>()), E, Result); - case BO_Sub: - return Success(CheckedIntArithmetic(Info, E, LHS, RHS, - LHS.getBitWidth() + 1, - std::minus<APSInt>()), E, Result); - case BO_And: return Success(LHS & RHS, E, Result); - case BO_Xor: return Success(LHS ^ RHS, E, Result); - case BO_Or: return Success(LHS | RHS, E, Result); - case BO_Div: - case BO_Rem: - if (RHS == 0) - return Error(E, diag::note_expr_divide_by_zero); - // Check for overflow case: INT_MIN / -1 or INT_MIN % -1. The latter is - // not actually undefined behavior in C++11 due to a language defect. - if (RHS.isNegative() && RHS.isAllOnesValue() && - LHS.isSigned() && LHS.isMinSignedValue()) - HandleOverflow(Info, E, -LHS.extend(LHS.getBitWidth() + 1), E->getType()); - return Success(E->getOpcode() == BO_Rem ? LHS % RHS : LHS / RHS, E, - Result); - case BO_Shl: { - if (Info.getLangOpts().OpenCL) - // OpenCL 6.3j: shift values are effectively % word size of LHS. - RHS &= APSInt(llvm::APInt(RHS.getBitWidth(), - static_cast<uint64_t>(LHS.getBitWidth() - 1)), - RHS.isUnsigned()); - else if (RHS.isSigned() && RHS.isNegative()) { - // During constant-folding, a negative shift is an opposite shift. Such - // a shift is not a constant expression. - CCEDiag(E, diag::note_constexpr_negative_shift) << RHS; - RHS = -RHS; - goto shift_right; - } - - shift_left: - // C++11 [expr.shift]p1: Shift width must be less than the bit width of - // the shifted type. - unsigned SA = (unsigned) RHS.getLimitedValue(LHS.getBitWidth()-1); - if (SA != RHS) { - CCEDiag(E, diag::note_constexpr_large_shift) - << RHS << E->getType() << LHS.getBitWidth(); - } else if (LHS.isSigned()) { - // C++11 [expr.shift]p2: A signed left shift must have a non-negative - // operand, and must not overflow the corresponding unsigned type. - if (LHS.isNegative()) - CCEDiag(E, diag::note_constexpr_lshift_of_negative) << LHS; - else if (LHS.countLeadingZeros() < SA) - CCEDiag(E, diag::note_constexpr_lshift_discards); - } - - return Success(LHS << SA, E, Result); - } - case BO_Shr: { - if (Info.getLangOpts().OpenCL) - // OpenCL 6.3j: shift values are effectively % word size of LHS. - RHS &= APSInt(llvm::APInt(RHS.getBitWidth(), - static_cast<uint64_t>(LHS.getBitWidth() - 1)), - RHS.isUnsigned()); - else if (RHS.isSigned() && RHS.isNegative()) { - // During constant-folding, a negative shift is an opposite shift. Such a - // shift is not a constant expression. - CCEDiag(E, diag::note_constexpr_negative_shift) << RHS; - RHS = -RHS; - goto shift_left; - } - - shift_right: - // C++11 [expr.shift]p1: Shift width must be less than the bit width of the - // shifted type. - unsigned SA = (unsigned) RHS.getLimitedValue(LHS.getBitWidth()-1); - if (SA != RHS) - CCEDiag(E, diag::note_constexpr_large_shift) - << RHS << E->getType() << LHS.getBitWidth(); - - return Success(LHS >> SA, E, Result); - } - - case BO_LT: return Success(LHS < RHS, E, Result); - case BO_GT: return Success(LHS > RHS, E, Result); - case BO_LE: return Success(LHS <= RHS, E, Result); - case BO_GE: return Success(LHS >= RHS, E, Result); - case BO_EQ: return Success(LHS == RHS, E, Result); - case BO_NE: return Success(LHS != RHS, E, Result); - } + + // Set up the width and signedness manually, in case it can't be deduced + // from the operation we're performing. + // FIXME: Don't do this in the cases where we can deduce it. + APSInt Value(Info.Ctx.getIntWidth(E->getType()), + E->getType()->isUnsignedIntegerOrEnumerationType()); + if (!handleIntIntBinOp(Info, E, LHSVal.getInt(), E->getOpcode(), + RHSVal.getInt(), Value)) + return false; + return Success(Value, E, Result); } void DataRecursiveIntBinOpEvaluator::process(EvalResult &Result) { @@ -5737,6 +6722,15 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { if (!HandleSizeof(Info, E->getExprLoc(), ElementType, ElementSize)) return false; + // As an extension, a type may have zero size (empty struct or union in + // C, array of zero length). Pointer subtraction in such cases has + // undefined behavior, so is not constant. + if (ElementSize.isZero()) { + Info.Diag(E, diag::note_constexpr_pointer_subtraction_zero_size) + << ElementType; + return false; + } + // FIXME: LLVM and GCC both compute LHSOffset - RHSOffset at runtime, // and produce incorrect results when it overflows. Such behavior // appears to be non-conforming, but is common, so perhaps we should @@ -5999,7 +6993,7 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *OOE) { CurrentType = AT->getElementType(); CharUnits ElementSize = Info.Ctx.getTypeSizeInChars(CurrentType); Result += IdxResult.getSExtValue() * ElementSize; - break; + break; } case OffsetOfExpr::OffsetOfNode::Field: { @@ -6125,6 +7119,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) { case CK_IntegralComplexToFloatingComplex: case CK_BuiltinFnToFnPtr: case CK_ZeroToOCLEvent: + case CK_NonAtomicToAtomic: llvm_unreachable("invalid cast kind for integral value"); case CK_BitCast: @@ -6140,7 +7135,6 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) { case CK_UserDefinedConversion: case CK_LValueToRValue: case CK_AtomicToNonAtomic: - case CK_NonAtomicToAtomic: case CK_NoOp: return ExprEvaluatorBaseTy::VisitCastExpr(E); @@ -6369,6 +7363,10 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) { Result.changeSign(); return true; + // FIXME: Builtin::BI__builtin_powi + // FIXME: Builtin::BI__builtin_powif + // FIXME: Builtin::BI__builtin_powil + case Builtin::BI__builtin_copysign: case Builtin::BI__builtin_copysignf: case Builtin::BI__builtin_copysignl: { @@ -6430,28 +7428,8 @@ bool FloatExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { bool LHSOK = EvaluateFloat(E->getLHS(), Result, Info); if (!LHSOK && !Info.keepEvaluatingAfterFailure()) return false; - if (!EvaluateFloat(E->getRHS(), RHS, Info) || !LHSOK) - return false; - - switch (E->getOpcode()) { - default: return Error(E); - case BO_Mul: - Result.multiply(RHS, APFloat::rmNearestTiesToEven); - break; - case BO_Add: - Result.add(RHS, APFloat::rmNearestTiesToEven); - break; - case BO_Sub: - Result.subtract(RHS, APFloat::rmNearestTiesToEven); - break; - case BO_Div: - Result.divide(RHS, APFloat::rmNearestTiesToEven); - break; - } - - if (Result.isInfinity() || Result.isNaN()) - CCEDiag(E, diag::note_constexpr_float_arithmetic) << Result.isNaN(); - return true; + return EvaluateFloat(E->getRHS(), RHS, Info) && LHSOK && + handleFloatFloatBinOp(Info, E, Result, E->getOpcode(), RHS); } bool FloatExprEvaluator::VisitFloatingLiteral(const FloatingLiteral *E) { @@ -6613,11 +7591,11 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) { case CK_CopyAndAutoreleaseBlockObject: case CK_BuiltinFnToFnPtr: case CK_ZeroToOCLEvent: + case CK_NonAtomicToAtomic: llvm_unreachable("invalid cast kind for complex value"); case CK_LValueToRValue: case CK_AtomicToNonAtomic: - case CK_NonAtomicToAtomic: case CK_NoOp: return ExprEvaluatorBaseTy::VisitCastExpr(E); @@ -6874,6 +7852,46 @@ bool ComplexExprEvaluator::VisitInitListExpr(const InitListExpr *E) { } //===----------------------------------------------------------------------===// +// Atomic expression evaluation, essentially just handling the NonAtomicToAtomic +// implicit conversion. +//===----------------------------------------------------------------------===// + +namespace { +class AtomicExprEvaluator : + public ExprEvaluatorBase<AtomicExprEvaluator, bool> { + APValue &Result; +public: + AtomicExprEvaluator(EvalInfo &Info, APValue &Result) + : ExprEvaluatorBaseTy(Info), Result(Result) {} + + bool Success(const APValue &V, const Expr *E) { + Result = V; + return true; + } + + bool ZeroInitialization(const Expr *E) { + ImplicitValueInitExpr VIE( + E->getType()->castAs<AtomicType>()->getValueType()); + return Evaluate(Result, Info, &VIE); + } + + bool VisitCastExpr(const CastExpr *E) { + switch (E->getCastKind()) { + default: + return ExprEvaluatorBaseTy::VisitCastExpr(E); + case CK_NonAtomicToAtomic: + return Evaluate(Result, Info, E->getSubExpr()); + } + } +}; +} // end anonymous namespace + +static bool EvaluateAtomic(const Expr *E, APValue &Result, EvalInfo &Info) { + assert(E->isRValue() && E->getType()->isAtomicType()); + return AtomicExprEvaluator(Info, Result).Visit(E); +} + +//===----------------------------------------------------------------------===// // Void expression evaluation, primarily for a cast to void on the LHS of a // comma operator //===----------------------------------------------------------------------===// @@ -6910,56 +7928,62 @@ static bool EvaluateVoid(const Expr *E, EvalInfo &Info) { static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) { // In C, function designators are not lvalues, but we evaluate them as if they // are. - if (E->isGLValue() || E->getType()->isFunctionType()) { + QualType T = E->getType(); + if (E->isGLValue() || T->isFunctionType()) { LValue LV; if (!EvaluateLValue(E, LV, Info)) return false; LV.moveInto(Result); - } else if (E->getType()->isVectorType()) { + } else if (T->isVectorType()) { if (!EvaluateVector(E, Result, Info)) return false; - } else if (E->getType()->isIntegralOrEnumerationType()) { + } else if (T->isIntegralOrEnumerationType()) { if (!IntExprEvaluator(Info, Result).Visit(E)) return false; - } else if (E->getType()->hasPointerRepresentation()) { + } else if (T->hasPointerRepresentation()) { LValue LV; if (!EvaluatePointer(E, LV, Info)) return false; LV.moveInto(Result); - } else if (E->getType()->isRealFloatingType()) { + } else if (T->isRealFloatingType()) { llvm::APFloat F(0.0); if (!EvaluateFloat(E, F, Info)) return false; Result = APValue(F); - } else if (E->getType()->isAnyComplexType()) { + } else if (T->isAnyComplexType()) { ComplexValue C; if (!EvaluateComplex(E, C, Info)) return false; C.moveInto(Result); - } else if (E->getType()->isMemberPointerType()) { + } else if (T->isMemberPointerType()) { MemberPtr P; if (!EvaluateMemberPointer(E, P, Info)) return false; P.moveInto(Result); return true; - } else if (E->getType()->isArrayType()) { + } else if (T->isArrayType()) { LValue LV; LV.set(E, Info.CurrentCall->Index); - if (!EvaluateArray(E, LV, Info.CurrentCall->Temporaries[E], Info)) + APValue &Value = Info.CurrentCall->createTemporary(E, false); + if (!EvaluateArray(E, LV, Value, Info)) return false; - Result = Info.CurrentCall->Temporaries[E]; - } else if (E->getType()->isRecordType()) { + Result = Value; + } else if (T->isRecordType()) { LValue LV; LV.set(E, Info.CurrentCall->Index); - if (!EvaluateRecord(E, LV, Info.CurrentCall->Temporaries[E], Info)) + APValue &Value = Info.CurrentCall->createTemporary(E, false); + if (!EvaluateRecord(E, LV, Value, Info)) return false; - Result = Info.CurrentCall->Temporaries[E]; - } else if (E->getType()->isVoidType()) { + Result = Value; + } else if (T->isVoidType()) { if (!Info.getLangOpts().CPlusPlus11) Info.CCEDiag(E, diag::note_constexpr_nonliteral) << E->getType(); if (!EvaluateVoid(E, Info)) return false; + } else if (T->isAtomicType()) { + if (!EvaluateAtomic(E, Result, Info)) + return false; } else if (Info.getLangOpts().CPlusPlus11) { Info.Diag(E, diag::note_constexpr_nonliteral) << E->getType(); return false; @@ -6975,9 +7999,8 @@ static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) { /// cases, the in-place evaluation is essential, since later initializers for /// an object can indirectly refer to subobjects which were initialized earlier. static bool EvaluateInPlace(APValue &Result, EvalInfo &Info, const LValue &This, - const Expr *E, CheckConstantExpressionKind CCEK, - bool AllowNonLiteralTypes) { - if (!AllowNonLiteralTypes && !CheckLiteralType(Info, E)) + const Expr *E, bool AllowNonLiteralTypes) { + if (!AllowNonLiteralTypes && !CheckLiteralType(Info, E, &This)) return false; if (E->isRValue()) { @@ -7046,7 +8069,7 @@ bool Expr::EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx) const { if (FastEvaluateAsRValue(this, Result, Ctx, IsConst)) return IsConst; - EvalInfo Info(Ctx, Result); + EvalInfo Info(Ctx, Result, EvalInfo::EM_IgnoreSideEffects); return ::EvaluateAsRValue(Info, this, Result.Val); } @@ -7072,7 +8095,7 @@ bool Expr::EvaluateAsInt(APSInt &Result, const ASTContext &Ctx, } bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx) const { - EvalInfo Info(Ctx, Result); + EvalInfo Info(Ctx, Result, EvalInfo::EM_ConstantFold); LValue LV; if (!EvaluateLValue(this, LV, Info) || Result.HasSideEffects || @@ -7096,7 +8119,7 @@ bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx, Expr::EvalStatus EStatus; EStatus.Diag = &Notes; - EvalInfo InitInfo(Ctx, EStatus); + EvalInfo InitInfo(Ctx, EStatus, EvalInfo::EM_ConstantFold); InitInfo.setEvaluatingDecl(VD, Value); LValue LVal; @@ -7109,13 +8132,13 @@ bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx, if (Ctx.getLangOpts().CPlusPlus && !VD->hasLocalStorage() && !VD->getType()->isReferenceType()) { ImplicitValueInitExpr VIE(VD->getType()); - if (!EvaluateInPlace(Value, InitInfo, LVal, &VIE, CCEK_Constant, + if (!EvaluateInPlace(Value, InitInfo, LVal, &VIE, /*AllowNonLiteralTypes=*/true)) return false; } - if (!EvaluateInPlace(Value, InitInfo, LVal, this, CCEK_Constant, - /*AllowNonLiteralTypes=*/true) || + if (!EvaluateInPlace(Value, InitInfo, LVal, this, + /*AllowNonLiteralTypes=*/true) || EStatus.HasSideEffects) return false; @@ -7142,21 +8165,19 @@ APSInt Expr::EvaluateKnownConstInt(const ASTContext &Ctx, return EvalResult.Val.getInt(); } -void Expr::EvaluateForOverflow(const ASTContext &Ctx, - SmallVectorImpl<PartialDiagnosticAt> *Diags) const { +void Expr::EvaluateForOverflow(const ASTContext &Ctx) const { bool IsConst; EvalResult EvalResult; - EvalResult.Diag = Diags; if (!FastEvaluateAsRValue(this, EvalResult, Ctx, IsConst)) { - EvalInfo Info(Ctx, EvalResult, true); + EvalInfo Info(Ctx, EvalResult, EvalInfo::EM_EvaluateForOverflow); (void)::EvaluateAsRValue(Info, this, EvalResult.Val); } } - bool Expr::EvalResult::isGlobalLValue() const { - assert(Val.isLValue()); - return IsGlobalLValue(Val.getLValueBase()); - } +bool Expr::EvalResult::isGlobalLValue() const { + assert(Val.isLValue()); + return IsGlobalLValue(Val.getLValueBase()); +} /// isIntegerConstantExpr - this recursive routine will test if an expression is @@ -7200,7 +8221,7 @@ static ICEDiag NoDiag() { return ICEDiag(IK_ICE, SourceLocation()); } static ICEDiag Worst(ICEDiag A, ICEDiag B) { return A.Kind >= B.Kind ? A : B; } -static ICEDiag CheckEvalInICE(const Expr* E, ASTContext &Ctx) { +static ICEDiag CheckEvalInICE(const Expr* E, const ASTContext &Ctx) { Expr::EvalResult EVResult; if (!E->EvaluateAsRValue(EVResult, Ctx) || EVResult.HasSideEffects || !EVResult.Val.isInt()) @@ -7209,7 +8230,7 @@ static ICEDiag CheckEvalInICE(const Expr* E, ASTContext &Ctx) { return NoDiag(); } -static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { +static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { assert(!E->isValueDependent() && "Should not see value dependent exprs!"); if (!E->getType()->isIntegralOrEnumerationType()) return ICEDiag(IK_NotICE, E->getLocStart()); @@ -7250,6 +8271,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::UnresolvedLookupExprClass: case Expr::DependentScopeDeclRefExprClass: case Expr::CXXConstructExprClass: + case Expr::CXXStdInitializerListExprClass: case Expr::CXXBindTemporaryExprClass: case Expr::ExprWithCleanupsClass: case Expr::CXXTemporaryObjectExprClass: @@ -7269,6 +8291,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::ObjCSubscriptRefExprClass: case Expr::ObjCIsaExprClass: case Expr::ShuffleVectorExprClass: + case Expr::ConvertVectorExprClass: case Expr::BlockExprClass: case Expr::NoStmtClass: case Expr::OpaqueValueExprClass: @@ -7561,7 +8584,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::CXXDefaultInitExprClass: return CheckICE(cast<CXXDefaultInitExpr>(E)->getExpr(), Ctx); case Expr::ChooseExprClass: { - return CheckICE(cast<ChooseExpr>(E)->getChosenSubExpr(Ctx), Ctx); + return CheckICE(cast<ChooseExpr>(E)->getChosenSubExpr(), Ctx); } } @@ -7569,7 +8592,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { } /// Evaluate an expression as a C++11 integral constant expression. -static bool EvaluateCPlusPlus11IntegralConstantExpr(ASTContext &Ctx, +static bool EvaluateCPlusPlus11IntegralConstantExpr(const ASTContext &Ctx, const Expr *E, llvm::APSInt *Value, SourceLocation *Loc) { @@ -7587,7 +8610,8 @@ static bool EvaluateCPlusPlus11IntegralConstantExpr(ASTContext &Ctx, return true; } -bool Expr::isIntegerConstantExpr(ASTContext &Ctx, SourceLocation *Loc) const { +bool Expr::isIntegerConstantExpr(const ASTContext &Ctx, + SourceLocation *Loc) const { if (Ctx.getLangOpts().CPlusPlus11) return EvaluateCPlusPlus11IntegralConstantExpr(Ctx, this, 0, Loc); @@ -7599,7 +8623,7 @@ bool Expr::isIntegerConstantExpr(ASTContext &Ctx, SourceLocation *Loc) const { return true; } -bool Expr::isIntegerConstantExpr(llvm::APSInt &Value, ASTContext &Ctx, +bool Expr::isIntegerConstantExpr(llvm::APSInt &Value, const ASTContext &Ctx, SourceLocation *Loc, bool isEvaluated) const { if (Ctx.getLangOpts().CPlusPlus11) return EvaluateCPlusPlus11IntegralConstantExpr(Ctx, this, &Value, Loc); @@ -7611,11 +8635,11 @@ bool Expr::isIntegerConstantExpr(llvm::APSInt &Value, ASTContext &Ctx, return true; } -bool Expr::isCXX98IntegralConstantExpr(ASTContext &Ctx) const { +bool Expr::isCXX98IntegralConstantExpr(const ASTContext &Ctx) const { return CheckICE(this, Ctx).Kind == IK_ICE; } -bool Expr::isCXX11ConstantExpr(ASTContext &Ctx, APValue *Result, +bool Expr::isCXX11ConstantExpr(const ASTContext &Ctx, APValue *Result, SourceLocation *Loc) const { // We support this checking in C++98 mode in order to diagnose compatibility // issues. @@ -7625,7 +8649,7 @@ bool Expr::isCXX11ConstantExpr(ASTContext &Ctx, APValue *Result, Expr::EvalStatus Status; SmallVector<PartialDiagnosticAt, 8> Diags; Status.Diag = &Diags; - EvalInfo Info(Ctx, Status); + EvalInfo Info(Ctx, Status, EvalInfo::EM_ConstantExpression); APValue Scratch; bool IsConstExpr = ::EvaluateAsRValue(Info, this, Result ? *Result : Scratch); @@ -7653,13 +8677,13 @@ bool Expr::isPotentialConstantExpr(const FunctionDecl *FD, Expr::EvalStatus Status; Status.Diag = &Diags; - EvalInfo Info(FD->getASTContext(), Status); - Info.CheckingPotentialConstantExpression = true; + EvalInfo Info(FD->getASTContext(), Status, + EvalInfo::EM_PotentialConstantExpression); const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD); const CXXRecordDecl *RD = MD ? MD->getParent()->getCanonicalDecl() : 0; - // FIXME: Fabricate an arbitrary expression on the stack and pretend that it + // Fabricate an arbitrary expression on the stack and pretend that it // is a temporary being used as the 'this' pointer. LValue This; ImplicitValueInitExpr VIE(RD ? Info.Ctx.getRecordType(RD) : Info.Ctx.IntTy); @@ -7670,9 +8694,12 @@ bool Expr::isPotentialConstantExpr(const FunctionDecl *FD, SourceLocation Loc = FD->getLocation(); APValue Scratch; - if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD)) + if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD)) { + // Evaluate the call as a constant initializer, to allow the construction + // of objects of non-literal types. + Info.setEvaluatingDecl(This.getLValueBase(), Scratch); HandleConstructorCall(Loc, This, Args, CD, Info, Scratch); - else + } else HandleFunctionCall(Loc, FD, (MD && MD->isInstance()) ? &This : 0, Args, FD->getBody(), Info, Scratch); diff --git a/lib/AST/InheritViz.cpp b/lib/AST/InheritViz.cpp index e03632a..3d64310 100644 --- a/lib/AST/InheritViz.cpp +++ b/lib/AST/InheritViz.cpp @@ -17,9 +17,11 @@ #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> +#include <set> using namespace llvm; @@ -135,34 +137,28 @@ InheritanceHierarchyWriter::WriteNodeReference(QualType Type, /// class using GraphViz. void CXXRecordDecl::viewInheritance(ASTContext& Context) const { QualType Self = Context.getTypeDeclType(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"; + + int FD; + SmallString<128> Filename; + error_code EC = + sys::fs::createTemporaryFile(Self.getAsString(), "dot", FD, Filename); + if (EC) { + llvm::errs() << "Error: " << 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(FD, true); - if (ErrMsg.empty()) { - InheritanceHierarchyWriter Writer(Context, O); - Writer.WriteGraph(Self); - llvm::errs() << " done. \n"; + InheritanceHierarchyWriter Writer(Context, O); + Writer.WriteGraph(Self); + 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(Filename); } } diff --git a/lib/AST/ItaniumCXXABI.cpp b/lib/AST/ItaniumCXXABI.cpp index 894eb3b..5784660 100644 --- a/lib/AST/ItaniumCXXABI.cpp +++ b/lib/AST/ItaniumCXXABI.cpp @@ -20,6 +20,7 @@ #include "CXXABI.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/MangleNumberingContext.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/Type.h" #include "clang/Basic/TargetInfo.h" @@ -27,6 +28,19 @@ using namespace clang; namespace { + +/// \brief Keeps track of the mangled names of lambda expressions and block +/// literals within a particular context. +class ItaniumNumberingContext : public MangleNumberingContext { + llvm::DenseMap<IdentifierInfo*, unsigned> VarManglingNumbers; + +public: + /// Variable decls are numbered by identifier. + virtual unsigned getManglingNumber(const VarDecl *VD) { + return ++VarManglingNumbers[VD->getIdentifier()]; + } +}; + class ItaniumCXXABI : public CXXABI { protected: ASTContext &Context; @@ -61,6 +75,10 @@ public: Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0)); return Layout.getNonVirtualSize() == PointerSize; } + + virtual MangleNumberingContext *createMangleNumberingContext() const { + return new ItaniumNumberingContext(); + } }; class ARMCXXABI : public ItaniumCXXABI { diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index 5ad8021..0621d7b 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -56,23 +56,36 @@ static const DeclContext *getEffectiveDeclContext(const Decl *D) { = dyn_cast_or_null<ParmVarDecl>(RD->getLambdaContextDecl())) return ContextParam->getDeclContext(); } + + // Perform the same check for block literals. + if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) { + if (ParmVarDecl *ContextParam + = dyn_cast_or_null<ParmVarDecl>(BD->getBlockManglingContextDecl())) + return ContextParam->getDeclContext(); + } - return D->getDeclContext(); + const DeclContext *DC = D->getDeclContext(); + if (const CapturedDecl *CD = dyn_cast<CapturedDecl>(DC)) + return getEffectiveDeclContext(CD); + + return DC; } static const DeclContext *getEffectiveParentContext(const DeclContext *DC) { return getEffectiveDeclContext(cast<Decl>(DC)); } - -static const CXXRecordDecl *GetLocalClassDecl(const NamedDecl *ND) { - const DeclContext *DC = dyn_cast<DeclContext>(ND); - if (!DC) - DC = getEffectiveDeclContext(ND); + +static bool isLocalContainerContext(const DeclContext *DC) { + return isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC) || isa<BlockDecl>(DC); +} + +static const RecordDecl *GetLocalClassDecl(const Decl *D) { + const DeclContext *DC = getEffectiveDeclContext(D); while (!DC->isNamespace() && !DC->isTranslationUnit()) { - const DeclContext *Parent = getEffectiveDeclContext(cast<Decl>(DC)); - if (isa<FunctionDecl>(Parent)) - return dyn_cast<CXXRecordDecl>(DC); - DC = Parent; + if (isLocalContainerContext(DC)) + return dyn_cast<RecordDecl>(D); + D = cast<Decl>(DC); + DC = getEffectiveDeclContext(D); } return 0; } @@ -91,15 +104,16 @@ static const NamedDecl *getStructor(const NamedDecl *decl) { static const unsigned UnknownArity = ~0U; -class ItaniumMangleContext : public MangleContext { +class ItaniumMangleContextImpl : public ItaniumMangleContext { llvm::DenseMap<const TagDecl *, uint64_t> AnonStructIds; - unsigned Discriminator; + typedef std::pair<const DeclContext*, IdentifierInfo*> DiscriminatorKeyTy; + llvm::DenseMap<DiscriminatorKeyTy, unsigned> Discriminator; llvm::DenseMap<const NamedDecl*, unsigned> Uniquifier; public: - explicit ItaniumMangleContext(ASTContext &Context, - DiagnosticsEngine &Diags) - : MangleContext(Context, Diags) { } + explicit ItaniumMangleContextImpl(ASTContext &Context, + DiagnosticsEngine &Diags) + : ItaniumMangleContext(Context, Diags) {} uint64_t getAnonymousStructId(const TagDecl *TD) { std::pair<llvm::DenseMap<const TagDecl *, @@ -108,16 +122,11 @@ public: return Result.first->second; } - void startNewFunction() { - MangleContext::startNewFunction(); - mangleInitDiscriminator(); - } - /// @name Mangler Entry Points /// @{ - bool shouldMangleDeclName(const NamedDecl *D); - void mangleName(const NamedDecl *D, raw_ostream &); + bool shouldMangleCXXName(const NamedDecl *D); + void mangleCXXName(const NamedDecl *D, raw_ostream &); void mangleThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk, raw_ostream &); @@ -135,30 +144,45 @@ public: raw_ostream &); void mangleCXXRTTI(QualType T, raw_ostream &); void mangleCXXRTTIName(QualType T, raw_ostream &); + void mangleTypeName(QualType T, raw_ostream &); void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type, raw_ostream &); void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type, raw_ostream &); - void mangleItaniumGuardVariable(const VarDecl *D, raw_ostream &); + void mangleStaticGuardVariable(const VarDecl *D, raw_ostream &); + void mangleDynamicInitializer(const VarDecl *D, raw_ostream &Out); + void mangleDynamicAtExitDestructor(const VarDecl *D, raw_ostream &Out); void mangleItaniumThreadLocalInit(const VarDecl *D, raw_ostream &); void mangleItaniumThreadLocalWrapper(const VarDecl *D, raw_ostream &); - void mangleInitDiscriminator() { - Discriminator = 0; - } - bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) { - // Lambda closure types with external linkage (indicated by a - // non-zero lambda mangling number) have their own numbering scheme, so - // they do not need a discriminator. + // Lambda closure types are already numbered. if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(ND)) - if (RD->isLambda() && RD->getLambdaManglingNumber() > 0) + if (RD->isLambda()) return false; - + + // Anonymous tags are already numbered. + if (const TagDecl *Tag = dyn_cast<TagDecl>(ND)) { + if (Tag->getName().empty() && !Tag->getTypedefNameForAnonDecl()) + return false; + } + + // Use the canonical number for externally visible decls. + if (ND->isExternallyVisible()) { + unsigned discriminator = getASTContext().getManglingNumber(ND); + if (discriminator == 1) + return false; + disc = discriminator - 2; + return true; + } + + // Make up a reasonable number for internal decls. unsigned &discriminator = Uniquifier[ND]; - if (!discriminator) - discriminator = ++Discriminator; + if (!discriminator) { + const DeclContext *DC = getEffectiveDeclContext(ND); + discriminator = ++Discriminator[std::make_pair(DC, ND->getIdentifier())]; + } if (discriminator == 1) return false; disc = discriminator-2; @@ -169,7 +193,7 @@ public: /// CXXNameMangler - Manage the mangling of a single name. class CXXNameMangler { - ItaniumMangleContext &Context; + ItaniumMangleContextImpl &Context; raw_ostream &Out; /// The "structor" is the top-level declaration being mangled, if @@ -225,7 +249,7 @@ class CXXNameMangler { ASTContext &getASTContext() const { return Context.getASTContext(); } public: - CXXNameMangler(ItaniumMangleContext &C, raw_ostream &Out_, + CXXNameMangler(ItaniumMangleContextImpl &C, raw_ostream &Out_, const NamedDecl *D = 0) : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(0), SeqID(0) { @@ -233,11 +257,11 @@ public: assert(!D || (!isa<CXXDestructorDecl>(D) && !isa<CXXConstructorDecl>(D))); } - CXXNameMangler(ItaniumMangleContext &C, raw_ostream &Out_, + CXXNameMangler(ItaniumMangleContextImpl &C, raw_ostream &Out_, const CXXConstructorDecl *D, CXXCtorType Type) : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type), SeqID(0) { } - CXXNameMangler(ItaniumMangleContext &C, raw_ostream &Out_, + CXXNameMangler(ItaniumMangleContextImpl &C, raw_ostream &Out_, const CXXDestructorDecl *D, CXXDtorType Type) : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type), SeqID(0) { } @@ -305,7 +329,9 @@ private: void mangleUnscopedTemplateName(const TemplateDecl *ND); void mangleUnscopedTemplateName(TemplateName); void mangleSourceName(const IdentifierInfo *II); - void mangleLocalName(const NamedDecl *ND); + void mangleLocalName(const Decl *D); + void mangleBlockForPrefix(const BlockDecl *Block); + void mangleUnqualifiedBlock(const BlockDecl *Block); void mangleLambda(const CXXRecordDecl *Lambda); void mangleNestedName(const NamedDecl *ND, const DeclContext *DC, bool NoFunction=false); @@ -315,7 +341,7 @@ private: void manglePrefix(NestedNameSpecifier *qualifier); void manglePrefix(const DeclContext *DC, bool NoFunction=false); void manglePrefix(QualType type); - void mangleTemplatePrefix(const TemplateDecl *ND); + void mangleTemplatePrefix(const TemplateDecl *ND, bool NoFunction=false); void mangleTemplatePrefix(TemplateName Template); void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity); void mangleQualifiers(Qualifiers Quals); @@ -334,6 +360,7 @@ private: void mangleBareFunctionType(const FunctionType *T, bool MangleReturnType); void mangleNeonVectorType(const VectorType *T); + void mangleAArch64NeonVectorType(const VectorType *T); void mangleIntegerLiteral(QualType T, const llvm::APSInt &Value); void mangleMemberExpr(const Expr *base, bool isArrow, @@ -358,16 +385,7 @@ private: } -bool ItaniumMangleContext::shouldMangleDeclName(const NamedDecl *D) { - // In C, functions with no attributes never need to be mangled. Fastpath them. - if (!getASTContext().getLangOpts().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; - +bool ItaniumMangleContextImpl::shouldMangleCXXName(const NamedDecl *D) { const FunctionDecl *FD = dyn_cast<FunctionDecl>(D); if (FD) { LanguageLinkage L = FD->getLanguageLinkage(); @@ -405,7 +423,8 @@ bool ItaniumMangleContext::shouldMangleDeclName(const NamedDecl *D) { if (DC->isFunctionOrMethod() && D->hasLinkage()) while (!DC->isNamespace() && !DC->isTranslationUnit()) DC = getEffectiveParentContext(DC); - if (DC->isTranslationUnit() && D->getLinkage() != InternalLinkage) + if (DC->isTranslationUnit() && D->getFormalLinkage() != InternalLinkage && + !isa<VarTemplateSpecializationDecl>(D)) return false; } @@ -413,26 +432,6 @@ bool ItaniumMangleContext::shouldMangleDeclName(const NamedDecl *D) { } void CXXNameMangler::mangle(const NamedDecl *D, 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. We also avoid adding the marker if this is an alias for an - // LLVM intrinsic. - StringRef UserLabelPrefix = - getASTContext().getTargetInfo().getUserLabelPrefix(); - if (!UserLabelPrefix.empty() && !ALA->getLabel().startswith("llvm.")) - Out << '\01'; // LLVM IR Marker for __asm("foo") - - Out << ALA->getLabel(); - return; - } - // <mangled-name> ::= _Z <encoding> // ::= <data name> // ::= <special-name> @@ -441,6 +440,8 @@ void CXXNameMangler::mangle(const NamedDecl *D, StringRef Prefix) { mangleFunctionEncoding(FD); else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) mangleName(VD); + else if (const IndirectFieldDecl *IFD = dyn_cast<IndirectFieldDecl>(D)) + mangleName(IFD->getAnonField()); else mangleName(cast<FieldDecl>(D)); } @@ -527,6 +528,13 @@ isTemplate(const NamedDecl *ND, const TemplateArgumentList *&TemplateArgs) { return Spec->getSpecializedTemplate(); } + // Check if we have a variable template. + if (const VarTemplateSpecializationDecl *Spec = + dyn_cast<VarTemplateSpecializationDecl>(ND)) { + TemplateArgs = &Spec->getTemplateArgs(); + return Spec->getSpecializedTemplate(); + } + return 0; } @@ -550,7 +558,7 @@ void CXXNameMangler::mangleName(const NamedDecl *ND) { // is that of the containing namespace, or the translation unit. // FIXME: This is a hack; extern variables declared locally should have // a proper semantic declaration context! - if (isa<FunctionDecl>(DC) && ND->hasLinkage() && !isLambda(ND)) + if (isLocalContainerContext(DC) && ND->hasLinkage() && !isLambda(ND)) while (!DC->isNamespace() && !DC->isTranslationUnit()) DC = getEffectiveParentContext(DC); else if (GetLocalClassDecl(ND)) { @@ -573,7 +581,7 @@ void CXXNameMangler::mangleName(const NamedDecl *ND) { return; } - if (isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC)) { + if (isLocalContainerContext(DC)) { mangleLocalName(ND); return; } @@ -825,6 +833,7 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier, switch (type->getTypeClass()) { case Type::Builtin: case Type::Complex: + case Type::Decayed: case Type::Pointer: case Type::BlockPointer: case Type::LValueReference: @@ -1053,7 +1062,7 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, // static void foo(); // This naming convention is the same as that followed by GCC, // though it shouldn't actually matter. - if (ND && ND->getLinkage() == InternalLinkage && + if (ND && ND->getFormalLinkage() == InternalLinkage && getEffectiveDeclContext(ND)->isFileContext()) Out << 'L'; @@ -1129,11 +1138,11 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, } } - int UnnamedMangle = Context.getASTContext().getUnnamedTagManglingNumber(TD); - if (UnnamedMangle != -1) { + if (TD->isExternallyVisible()) { + unsigned UnnamedMangle = getASTContext().getManglingNumber(TD); Out << "Ut"; - if (UnnamedMangle != 0) - Out << llvm::utostr(UnnamedMangle - 1); + if (UnnamedMangle > 1) + Out << llvm::utostr(UnnamedMangle - 2); Out << '_'; break; } @@ -1231,14 +1240,19 @@ void CXXNameMangler::mangleNestedName(const NamedDecl *ND, Out << 'N'; if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(ND)) { - mangleQualifiers(Qualifiers::fromCVRMask(Method->getTypeQualifiers())); + Qualifiers MethodQuals = + Qualifiers::fromCVRMask(Method->getTypeQualifiers()); + // We do not consider restrict a distinguishing attribute for overloading + // purposes so we must not mangle it. + MethodQuals.removeRestrict(); + mangleQualifiers(MethodQuals); mangleRefQualifier(Method->getRefQualifier()); } // Check if we have a template. const TemplateArgumentList *TemplateArgs = 0; if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) { - mangleTemplatePrefix(TD); + mangleTemplatePrefix(TD, NoFunction); mangleTemplateArgs(*TemplateArgs); } else { @@ -1261,36 +1275,37 @@ void CXXNameMangler::mangleNestedName(const TemplateDecl *TD, Out << 'E'; } -void CXXNameMangler::mangleLocalName(const NamedDecl *ND) { +void CXXNameMangler::mangleLocalName(const Decl *D) { // <local-name> := Z <function encoding> E <entity name> [<discriminator>] // := Z <function encoding> E s [<discriminator>] // <local-name> := Z <function encoding> E d [ <parameter number> ] // _ <entity name> // <discriminator> := _ <non-negative number> - const DeclContext *DC = getEffectiveDeclContext(ND); - if (isa<ObjCMethodDecl>(DC) && isa<FunctionDecl>(ND)) { - // Don't add objc method name mangling to locally declared function - mangleUnqualifiedName(ND); - return; - } + assert(isa<NamedDecl>(D) || isa<BlockDecl>(D)); + const RecordDecl *RD = GetLocalClassDecl(D); + const DeclContext *DC = getEffectiveDeclContext(RD ? RD : D); Out << 'Z'; - if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(DC)) { - mangleObjCMethodName(MD); - } else if (const CXXRecordDecl *RD = GetLocalClassDecl(ND)) { - mangleFunctionEncoding(cast<FunctionDecl>(getEffectiveDeclContext(RD))); - Out << 'E'; + if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(DC)) + mangleObjCMethodName(MD); + else if (const BlockDecl *BD = dyn_cast<BlockDecl>(DC)) + mangleBlockForPrefix(BD); + else + mangleFunctionEncoding(cast<FunctionDecl>(DC)); + + Out << 'E'; + if (RD) { // The parameter number is omitted for the last parameter, 0 for the // second-to-last parameter, 1 for the third-to-last parameter, etc. The // <entity name> will of course contain a <closure-type-name>: Its // numbering will be local to the particular argument in which it appears // -- other default arguments do not affect its encoding. - bool SkipDiscriminator = false; - if (RD->isLambda()) { + const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD); + if (CXXRD->isLambda()) { if (const ParmVarDecl *Parm - = dyn_cast_or_null<ParmVarDecl>(RD->getLambdaContextDecl())) { + = dyn_cast_or_null<ParmVarDecl>(CXXRD->getLambdaContextDecl())) { if (const FunctionDecl *Func = dyn_cast<FunctionDecl>(Parm->getDeclContext())) { Out << 'd'; @@ -1298,34 +1313,88 @@ void CXXNameMangler::mangleLocalName(const NamedDecl *ND) { if (Num > 1) mangleNumber(Num - 2); Out << '_'; - SkipDiscriminator = true; } } } // 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*/); - - if (!SkipDiscriminator) { - unsigned disc; - if (Context.getNextDiscriminator(RD, disc)) { - if (disc < 10) - Out << '_' << disc; - else - Out << "__" << disc << '_'; + // equality ok because RD derived from ND above + if (D == RD) { + mangleUnqualifiedName(RD); + } else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) { + manglePrefix(getEffectiveDeclContext(BD), true /*NoFunction*/); + mangleUnqualifiedBlock(BD); + } else { + const NamedDecl *ND = cast<NamedDecl>(D); + mangleNestedName(ND, getEffectiveDeclContext(ND), true /*NoFunction*/); + } + } else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) { + // Mangle a block in a default parameter; see above explanation for + // lambdas. + if (const ParmVarDecl *Parm + = dyn_cast_or_null<ParmVarDecl>(BD->getBlockManglingContextDecl())) { + if (const FunctionDecl *Func + = dyn_cast<FunctionDecl>(Parm->getDeclContext())) { + Out << 'd'; + unsigned Num = Func->getNumParams() - Parm->getFunctionScopeIndex(); + if (Num > 1) + mangleNumber(Num - 2); + Out << '_'; } } - + + mangleUnqualifiedBlock(BD); + } else { + mangleUnqualifiedName(cast<NamedDecl>(D)); + } + + if (const NamedDecl *ND = dyn_cast<NamedDecl>(RD ? RD : D)) { + unsigned disc; + if (Context.getNextDiscriminator(ND, disc)) { + if (disc < 10) + Out << '_' << disc; + else + Out << "__" << disc << '_'; + } + } +} + +void CXXNameMangler::mangleBlockForPrefix(const BlockDecl *Block) { + if (GetLocalClassDecl(Block)) { + mangleLocalName(Block); return; } - else - mangleFunctionEncoding(cast<FunctionDecl>(DC)); + const DeclContext *DC = getEffectiveDeclContext(Block); + if (isLocalContainerContext(DC)) { + mangleLocalName(Block); + return; + } + manglePrefix(getEffectiveDeclContext(Block)); + mangleUnqualifiedBlock(Block); +} - Out << 'E'; - mangleUnqualifiedName(ND); +void CXXNameMangler::mangleUnqualifiedBlock(const BlockDecl *Block) { + if (Decl *Context = Block->getBlockManglingContextDecl()) { + if ((isa<VarDecl>(Context) || isa<FieldDecl>(Context)) && + Context->getDeclContext()->isRecord()) { + if (const IdentifierInfo *Name + = cast<NamedDecl>(Context)->getIdentifier()) { + mangleSourceName(Name); + Out << 'M'; + } + } + } + + // If we have a block mangling number, use it. + unsigned Number = Block->getBlockManglingNumber(); + // Otherwise, just make up a number. It doesn't matter what it is because + // the symbol in question isn't externally visible. + if (!Number) + Number = Context.getBlockId(Block, false); + Out << "Ub"; + if (Number > 1) + Out << Number - 2; + Out << '_'; } void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) { @@ -1411,16 +1480,11 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) { if (DC->isTranslationUnit()) return; - if (const BlockDecl *Block = dyn_cast<BlockDecl>(DC)) { - manglePrefix(getEffectiveParentContext(DC), NoFunction); - SmallString<64> Name; - llvm::raw_svector_ostream NameStream(Name); - Context.mangleBlock(Block, NameStream); - NameStream.flush(); - Out << Name.size() << Name; + if (NoFunction && isLocalContainerContext(DC)) return; - } - + + assert(!isLocalContainerContext(DC)); + const NamedDecl *ND = cast<NamedDecl>(DC); if (mangleSubstitution(ND)) return; @@ -1430,12 +1494,7 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) { if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) { mangleTemplatePrefix(TD); mangleTemplateArgs(*TemplateArgs); - } - else if(NoFunction && (isa<FunctionDecl>(ND) || isa<ObjCMethodDecl>(ND))) - return; - else if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(ND)) - mangleObjCMethodName(Method); - else { + } else { manglePrefix(getEffectiveDeclContext(ND), NoFunction); mangleUnqualifiedName(ND); } @@ -1466,7 +1525,8 @@ void CXXNameMangler::mangleTemplatePrefix(TemplateName Template) { mangleUnscopedTemplateName(Template); } -void CXXNameMangler::mangleTemplatePrefix(const TemplateDecl *ND) { +void CXXNameMangler::mangleTemplatePrefix(const TemplateDecl *ND, + bool NoFunction) { // <template-prefix> ::= <prefix> <template unqualified-name> // ::= <template-param> // ::= <substitution> @@ -1483,7 +1543,7 @@ void CXXNameMangler::mangleTemplatePrefix(const TemplateDecl *ND) { return; } - manglePrefix(getEffectiveDeclContext(ND)); + manglePrefix(getEffectiveDeclContext(ND), NoFunction); mangleUnqualifiedName(ND->getTemplatedDecl()); addSubstitution(ND); } @@ -1671,15 +1731,32 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals) { Out << 'K'; if (Quals.hasAddressSpace()) { - // Extension: + // Address space extension: // - // <type> ::= U <address-space-number> - // - // where <address-space-number> is a source name consisting of 'AS' - // followed by the address space <number>. + // <type> ::= U <target-addrspace> + // <type> ::= U <OpenCL-addrspace> + // <type> ::= U <CUDA-addrspace> + SmallString<64> ASString; - ASString = "AS" + llvm::utostr_32( - Context.getASTContext().getTargetAddressSpace(Quals.getAddressSpace())); + unsigned AS = Quals.getAddressSpace(); + + if (Context.getASTContext().addressSpaceMapManglingFor(AS)) { + // <target-addrspace> ::= "AS" <address-space-number> + unsigned TargetAS = Context.getASTContext().getTargetAddressSpace(AS); + ASString = "AS" + llvm::utostr_32(TargetAS); + } else { + switch (AS) { + default: llvm_unreachable("Not a language specific address space"); + // <OpenCL-addrspace> ::= "CL" [ "global" | "local" | "constant" ] + case LangAS::opencl_global: ASString = "CLglobal"; break; + case LangAS::opencl_local: ASString = "CLlocal"; break; + case LangAS::opencl_constant: ASString = "CLconstant"; break; + // <CUDA-addrspace> ::= "CU" [ "device" | "constant" | "shared" ] + case LangAS::cuda_device: ASString = "CUdevice"; break; + case LangAS::cuda_constant: ASString = "CUconstant"; break; + case LangAS::cuda_shared: ASString = "CUshared"; break; + } + } Out << 'U' << ASString.size() << ASString; } @@ -1722,7 +1799,6 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals) { 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; @@ -1905,7 +1981,6 @@ void CXXNameMangler::mangleType(const BuiltinType *T) { // <type> ::= <function-type> // <function-type> ::= [<CV-qualifiers>] F [Y] // <bare-function-type> [<ref-qualifier>] E -// (Proposal to cxx-abi-dev, 2012-05-11) void CXXNameMangler::mangleType(const FunctionProtoType *T) { // Mangle CV-qualifiers, if present. These are 'this' qualifiers, // e.g. "const" in "int (A::*)() const". @@ -2101,7 +2176,9 @@ void CXXNameMangler::mangleNeonVectorType(const VectorType *T) { 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"); + case BuiltinType::Half: EltName = "float16_t";break; + default: + llvm_unreachable("unexpected Neon vector element type"); } } const char *BaseName = 0; @@ -2117,6 +2194,71 @@ void CXXNameMangler::mangleNeonVectorType(const VectorType *T) { Out << BaseName << EltName; } +static StringRef mangleAArch64VectorBase(const BuiltinType *EltType) { + switch (EltType->getKind()) { + case BuiltinType::SChar: + return "Int8"; + case BuiltinType::Short: + return "Int16"; + case BuiltinType::Int: + return "Int32"; + case BuiltinType::LongLong: + return "Int64"; + case BuiltinType::UChar: + return "Uint8"; + case BuiltinType::UShort: + return "Uint16"; + case BuiltinType::UInt: + return "Uint32"; + case BuiltinType::ULongLong: + return "Uint64"; + case BuiltinType::Half: + return "Float16"; + case BuiltinType::Float: + return "Float32"; + case BuiltinType::Double: + return "Float64"; + default: + llvm_unreachable("Unexpected vector element base type"); + } +} + +// AArch64's ABI for Neon vector types specifies that they should be mangled as +// the equivalent internal name. The vector type must be one of the special +// types predefined by ARM. +void CXXNameMangler::mangleAArch64NeonVectorType(const VectorType *T) { + QualType EltType = T->getElementType(); + assert(EltType->isBuiltinType() && "Neon vector element not a BuiltinType"); + unsigned BitSize = + (T->getNumElements() * getASTContext().getTypeSize(EltType)); + (void)BitSize; // Silence warning. + + assert((BitSize == 64 || BitSize == 128) && + "Neon vector type not 64 or 128 bits"); + + StringRef EltName; + if (T->getVectorKind() == VectorType::NeonPolyVector) { + switch (cast<BuiltinType>(EltType)->getKind()) { + case BuiltinType::UChar: + EltName = "Poly8"; + break; + case BuiltinType::UShort: + EltName = "Poly16"; + break; + case BuiltinType::ULongLong: + EltName = "Poly64"; + break; + default: + llvm_unreachable("unexpected Neon polynomial vector element type"); + } + } else + EltName = mangleAArch64VectorBase(cast<BuiltinType>(EltType)); + + std::string TypeName = + ("__" + EltName + "x" + llvm::utostr(T->getNumElements()) + "_t").str(); + Out << TypeName.length() << TypeName; +} + // GNU extension: vector types // <type> ::= <vector-type> // <vector-type> ::= Dv <positive dimension number> _ @@ -2128,7 +2270,11 @@ void CXXNameMangler::mangleNeonVectorType(const VectorType *T) { void CXXNameMangler::mangleType(const VectorType *T) { if ((T->getVectorKind() == VectorType::NeonVector || T->getVectorKind() == VectorType::NeonPolyVector)) { - mangleNeonVectorType(T); + if (getASTContext().getTargetInfo().getTriple().getArch() == + llvm::Triple::aarch64) + mangleAArch64NeonVectorType(T); + else + mangleNeonVectorType(T); return; } Out << "Dv" << T->getNumElements() << '_'; @@ -2160,8 +2306,19 @@ void CXXNameMangler::mangleType(const ObjCInterfaceType *T) { } void CXXNameMangler::mangleType(const ObjCObjectType *T) { - // We don't allow overloading by different protocol qualification, - // so mangling them isn't necessary. + if (!T->qual_empty()) { + // Mangle protocol qualifiers. + SmallString<64> QualStr; + llvm::raw_svector_ostream QualOS(QualStr); + QualOS << "objcproto"; + ObjCObjectType::qual_iterator i = T->qual_begin(), e = T->qual_end(); + for ( ; i != e; ++i) { + StringRef name = (*i)->getName(); + QualOS << name.size() << name; + } + QualOS.flush(); + Out << 'U' << QualStr.size() << QualStr; + } mangleType(T->getBaseType()); } @@ -2422,6 +2579,7 @@ recurse: case Expr::OffsetOfExprClass: case Expr::PredefinedExprClass: case Expr::ShuffleVectorExprClass: + case Expr::ConvertVectorExprClass: case Expr::StmtExprClass: case Expr::UnaryTypeTraitExprClass: case Expr::BinaryTypeTraitExprClass: @@ -2477,6 +2635,10 @@ recurse: mangleExpression(cast<CXXDefaultInitExpr>(E)->getExpr(), Arity); break; + case Expr::CXXStdInitializerListExprClass: + mangleExpression(cast<CXXStdInitializerListExpr>(E)->getSubExpr(), Arity); + break; + case Expr::SubstNonTypeTemplateParmExprClass: mangleExpression(cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement(), Arity); @@ -2676,8 +2838,8 @@ recurse: case Expr::CXXThrowExprClass: { const CXXThrowExpr *TE = cast<CXXThrowExpr>(E); - - // Proposal from David Vandervoorde, 2010.06.30 + // <expression> ::= tw <expression> # throw expression + // ::= tr # rethrow if (TE->getSubExpr()) { Out << "tw"; mangleExpression(TE->getSubExpr()); @@ -2689,11 +2851,11 @@ recurse: case Expr::CXXTypeidExprClass: { const CXXTypeidExpr *TIE = cast<CXXTypeidExpr>(E); - - // Proposal from David Vandervoorde, 2010.06.30 + // <expression> ::= ti <type> # typeid (type) + // ::= te <expression> # typeid (expression) if (TIE->isTypeOperand()) { Out << "ti"; - mangleType(TIE->getTypeOperand()); + mangleType(TIE->getTypeOperand(Context.getASTContext())); } else { Out << "te"; mangleExpression(TIE->getExprOperand()); @@ -2703,8 +2865,8 @@ recurse: case Expr::CXXDeleteExprClass: { const CXXDeleteExpr *DE = cast<CXXDeleteExpr>(E); - - // Proposal from David Vandervoorde, 2010.06.30 + // <expression> ::= [gs] dl <expression> # [::] delete expr + // ::= [gs] da <expression> # [::] delete [] expr if (DE->isGlobalDelete()) Out << "gs"; Out << (DE->isArrayForm() ? "da" : "dl"); mangleExpression(DE->getArgument()); @@ -2935,8 +3097,6 @@ recurse: // fallthrough case Expr::CXXNullPtrLiteralExprClass: { - // Proposal from David Vandervoorde, 2010.06.30, as - // modified by ABI list discussion. Out << "LDnE"; break; } @@ -3101,7 +3261,6 @@ void CXXNameMangler::mangleTemplateArg(TemplateArgument A) { // ::= X <expression> E # expression // ::= <expr-primary> # simple expressions // ::= J <template-arg>* E # argument pack - // ::= sp <expression> # pack expansion of (C++0x) if (!A.isInstantiationDependent() || A.isDependent()) A = Context.getASTContext().getCanonicalTemplateArgument(A); @@ -3181,9 +3340,9 @@ void CXXNameMangler::mangleTemplateArg(TemplateArgument A) { break; } case TemplateArgument::Pack: { - // Note: proposal by Mike Herrick on 12/20/10 + // <template-arg> ::= J <template-arg>* E Out << 'J'; - for (TemplateArgument::pack_iterator PA = A.pack_begin(), + for (TemplateArgument::pack_iterator PA = A.pack_begin(), PAEnd = A.pack_end(); PA != PAEnd; ++PA) mangleTemplateArg(*PA); @@ -3452,8 +3611,8 @@ void CXXNameMangler::addSubstitution(uintptr_t Ptr) { /// 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, - raw_ostream &Out) { +void ItaniumMangleContextImpl::mangleCXXName(const NamedDecl *D, + 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) && @@ -3467,23 +3626,23 @@ void ItaniumMangleContext::mangleName(const NamedDecl *D, return Mangler.mangle(D); } -void ItaniumMangleContext::mangleCXXCtor(const CXXConstructorDecl *D, - CXXCtorType Type, - raw_ostream &Out) { +void ItaniumMangleContextImpl::mangleCXXCtor(const CXXConstructorDecl *D, + CXXCtorType Type, + raw_ostream &Out) { CXXNameMangler Mangler(*this, Out, D, Type); Mangler.mangle(D); } -void ItaniumMangleContext::mangleCXXDtor(const CXXDestructorDecl *D, - CXXDtorType Type, - raw_ostream &Out) { +void ItaniumMangleContextImpl::mangleCXXDtor(const CXXDestructorDecl *D, + CXXDtorType Type, + raw_ostream &Out) { CXXNameMangler Mangler(*this, Out, D, Type); Mangler.mangle(D); } -void ItaniumMangleContext::mangleThunk(const CXXMethodDecl *MD, - const ThunkInfo &Thunk, - raw_ostream &Out) { +void ItaniumMangleContextImpl::mangleThunk(const CXXMethodDecl *MD, + const ThunkInfo &Thunk, + 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> @@ -3499,21 +3658,20 @@ void ItaniumMangleContext::mangleThunk(const CXXMethodDecl *MD, Mangler.getStream() << 'c'; // Mangle the 'this' pointer adjustment. - Mangler.mangleCallOffset(Thunk.This.NonVirtual, Thunk.This.VCallOffsetOffset); - + Mangler.mangleCallOffset(Thunk.This.NonVirtual, + Thunk.This.Virtual.Itanium.VCallOffsetOffset); + // Mangle the return pointer adjustment if there is one. if (!Thunk.Return.isEmpty()) Mangler.mangleCallOffset(Thunk.Return.NonVirtual, - Thunk.Return.VBaseOffsetOffset); - + Thunk.Return.Virtual.Itanium.VBaseOffsetOffset); + Mangler.mangleFunctionEncoding(MD); } -void -ItaniumMangleContext::mangleCXXDtorThunk(const CXXDestructorDecl *DD, - CXXDtorType Type, - const ThisAdjustment &ThisAdjustment, - raw_ostream &Out) { +void ItaniumMangleContextImpl::mangleCXXDtorThunk( + const CXXDestructorDecl *DD, CXXDtorType Type, + const ThisAdjustment &ThisAdjustment, raw_ostream &Out) { // <special-name> ::= T <call-offset> <base encoding> // # base is the nominal target function of thunk CXXNameMangler Mangler(*this, Out, DD, Type); @@ -3521,15 +3679,15 @@ ItaniumMangleContext::mangleCXXDtorThunk(const CXXDestructorDecl *DD, // Mangle the 'this' pointer adjustment. Mangler.mangleCallOffset(ThisAdjustment.NonVirtual, - ThisAdjustment.VCallOffsetOffset); + ThisAdjustment.Virtual.Itanium.VCallOffsetOffset); Mangler.mangleFunctionEncoding(DD); } /// mangleGuardVariable - Returns the mangled name for a guard variable /// for the passed in VarDecl. -void ItaniumMangleContext::mangleItaniumGuardVariable(const VarDecl *D, - raw_ostream &Out) { +void ItaniumMangleContextImpl::mangleStaticGuardVariable(const VarDecl *D, + raw_ostream &Out) { // <special-name> ::= GV <object name> # Guard variable for one-time // # initialization CXXNameMangler Mangler(*this, Out); @@ -3537,24 +3695,44 @@ void ItaniumMangleContext::mangleItaniumGuardVariable(const VarDecl *D, Mangler.mangleName(D); } -void ItaniumMangleContext::mangleItaniumThreadLocalInit(const VarDecl *D, +void ItaniumMangleContextImpl::mangleDynamicInitializer(const VarDecl *MD, raw_ostream &Out) { + // These symbols are internal in the Itanium ABI, so the names don't matter. + // Clang has traditionally used this symbol and allowed LLVM to adjust it to + // avoid duplicate symbols. + Out << "__cxx_global_var_init"; +} + +void ItaniumMangleContextImpl::mangleDynamicAtExitDestructor(const VarDecl *D, + raw_ostream &Out) { + // Prefix the mangling of D with __dtor_. + CXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "__dtor_"; + if (shouldMangleDeclName(D)) + Mangler.mangle(D); + else + Mangler.getStream() << D->getName(); +} + +void ItaniumMangleContextImpl::mangleItaniumThreadLocalInit(const VarDecl *D, + raw_ostream &Out) { // <special-name> ::= TH <object name> CXXNameMangler Mangler(*this, Out); Mangler.getStream() << "_ZTH"; Mangler.mangleName(D); } -void ItaniumMangleContext::mangleItaniumThreadLocalWrapper(const VarDecl *D, - raw_ostream &Out) { +void +ItaniumMangleContextImpl::mangleItaniumThreadLocalWrapper(const VarDecl *D, + raw_ostream &Out) { // <special-name> ::= TW <object name> CXXNameMangler Mangler(*this, Out); Mangler.getStream() << "_ZTW"; Mangler.mangleName(D); } -void ItaniumMangleContext::mangleReferenceTemporary(const VarDecl *D, - raw_ostream &Out) { +void ItaniumMangleContextImpl::mangleReferenceTemporary(const VarDecl *D, + raw_ostream &Out) { // We match the GCC mangling here. // <special-name> ::= GR <object name> CXXNameMangler Mangler(*this, Out); @@ -3562,26 +3740,26 @@ void ItaniumMangleContext::mangleReferenceTemporary(const VarDecl *D, Mangler.mangleName(D); } -void ItaniumMangleContext::mangleCXXVTable(const CXXRecordDecl *RD, - raw_ostream &Out) { +void ItaniumMangleContextImpl::mangleCXXVTable(const CXXRecordDecl *RD, + 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, - raw_ostream &Out) { +void ItaniumMangleContextImpl::mangleCXXVTT(const CXXRecordDecl *RD, + 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, - raw_ostream &Out) { +void ItaniumMangleContextImpl::mangleCXXCtorVTable(const CXXRecordDecl *RD, + int64_t Offset, + const CXXRecordDecl *Type, + raw_ostream &Out) { // <special-name> ::= TC <type> <offset number> _ <base type> CXXNameMangler Mangler(*this, Out); Mangler.getStream() << "_ZTC"; @@ -3591,8 +3769,7 @@ void ItaniumMangleContext::mangleCXXCtorVTable(const CXXRecordDecl *RD, Mangler.mangleNameOrStandardSubstitution(Type); } -void ItaniumMangleContext::mangleCXXRTTI(QualType Ty, - raw_ostream &Out) { +void ItaniumMangleContextImpl::mangleCXXRTTI(QualType Ty, raw_ostream &Out) { // <special-name> ::= TI <type> # typeinfo structure assert(!Ty.hasQualifiers() && "RTTI info cannot have top-level qualifiers"); CXXNameMangler Mangler(*this, Out); @@ -3600,15 +3777,19 @@ void ItaniumMangleContext::mangleCXXRTTI(QualType Ty, Mangler.mangleType(Ty); } -void ItaniumMangleContext::mangleCXXRTTIName(QualType Ty, - raw_ostream &Out) { +void ItaniumMangleContextImpl::mangleCXXRTTIName(QualType Ty, + 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, - DiagnosticsEngine &Diags) { - return new ItaniumMangleContext(Context, Diags); +void ItaniumMangleContextImpl::mangleTypeName(QualType Ty, raw_ostream &Out) { + mangleCXXRTTIName(Ty, Out); +} + +ItaniumMangleContext * +ItaniumMangleContext::create(ASTContext &Context, DiagnosticsEngine &Diags) { + return new ItaniumMangleContextImpl(Context, Diags); } diff --git a/lib/AST/Mangle.cpp b/lib/AST/Mangle.cpp index eb79412..231ef03 100644 --- a/lib/AST/Mangle.cpp +++ b/lib/AST/Mangle.cpp @@ -10,6 +10,7 @@ // Implements generic name mangling support for blocks and Objective-C. // //===----------------------------------------------------------------------===// +#include "clang/AST/Attr.h" #include "clang/AST/Mangle.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" @@ -19,6 +20,7 @@ #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/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" @@ -34,8 +36,6 @@ 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, StringRef Outer, const BlockDecl *BD, @@ -47,23 +47,131 @@ static void mangleFunctionBlock(MangleContext &Context, Out << "__" << Outer << "_block_invoke_" << discriminator+1; } -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(); - // In-class initializers for non-static data members are lexically defined - // within the class, but are mangled as if they were specified as constructor - // member initializers. - if (isa<CXXRecordDecl>(ExpectedDC) && DC != ExpectedDC) - DC = DC->getParent(); - assert(DC == ExpectedDC && "Given decl context did not match expected!"); -#endif +void MangleContext::anchor() { } + +enum StdOrFastCC { + SOF_OTHER, + SOF_FAST, + SOF_STD +}; + +static bool isExternC(const NamedDecl *ND) { + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) + return FD->isExternC(); + return cast<VarDecl>(ND)->isExternC(); } +static StdOrFastCC getStdOrFastCallMangling(const ASTContext &Context, + const NamedDecl *ND) { + const TargetInfo &TI = Context.getTargetInfo(); + llvm::Triple Triple = TI.getTriple(); + if (!Triple.isOSWindows() || Triple.getArch() != llvm::Triple::x86) + return SOF_OTHER; + + if (Context.getLangOpts().CPlusPlus && !isExternC(ND) && + TI.getCXXABI() == TargetCXXABI::Microsoft) + return SOF_OTHER; + + const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND); + if (!FD) + return SOF_OTHER; + QualType T = FD->getType(); + + const FunctionType *FT = T->castAs<FunctionType>(); + + CallingConv CC = FT->getCallConv(); + switch (CC) { + default: + return SOF_OTHER; + case CC_X86FastCall: + return SOF_FAST; + case CC_X86StdCall: + return SOF_STD; + } } -void MangleContext::anchor() { } +bool MangleContext::shouldMangleDeclName(const NamedDecl *D) { + const ASTContext &ASTContext = getASTContext(); + + StdOrFastCC CC = getStdOrFastCallMangling(ASTContext, D); + if (CC != SOF_OTHER) + return true; + + // In C, functions with no attributes never need to be mangled. Fastpath them. + if (!getASTContext().getLangOpts().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; + + return shouldMangleCXXName(D); +} + +void MangleContext::mangleName(const NamedDecl *D, raw_ostream &Out) { + // 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. We also avoid adding the marker if this is an alias for an + // LLVM intrinsic. + StringRef UserLabelPrefix = + getASTContext().getTargetInfo().getUserLabelPrefix(); + if (!UserLabelPrefix.empty() && !ALA->getLabel().startswith("llvm.")) + Out << '\01'; // LLVM IR Marker for __asm("foo") + + Out << ALA->getLabel(); + return; + } + + const ASTContext &ASTContext = getASTContext(); + StdOrFastCC CC = getStdOrFastCallMangling(ASTContext, D); + bool MCXX = shouldMangleCXXName(D); + const TargetInfo &TI = Context.getTargetInfo(); + if (CC == SOF_OTHER || (MCXX && TI.getCXXABI() == TargetCXXABI::Microsoft)) { + mangleCXXName(D, Out); + return; + } + + Out << '\01'; + if (CC == SOF_STD) + Out << '_'; + else + Out << '@'; + + if (!MCXX) + Out << D->getIdentifier()->getName(); + else + mangleCXXName(D, Out); + + const FunctionDecl *FD = cast<FunctionDecl>(D); + const FunctionType *FT = FD->getType()->castAs<FunctionType>(); + const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT); + Out << '@'; + if (!Proto) { + Out << '0'; + return; + } + assert(!Proto->isVariadic()); + unsigned ArgWords = 0; + if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) + if (!MD->isStatic()) + ++ArgWords; + for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(), + ArgEnd = Proto->arg_type_end(); + Arg != ArgEnd; ++Arg) { + QualType AT = *Arg; + // Size should be aligned to DWORD boundary + ArgWords += llvm::RoundUpToAlignment(ASTContext.getTypeSize(AT), 32) / 32; + } + Out << 4 * ArgWords; +} void MangleContext::mangleGlobalBlock(const BlockDecl *BD, const NamedDecl *ID, @@ -85,7 +193,6 @@ void MangleContext::mangleGlobalBlock(const BlockDecl *BD, void MangleContext::mangleCtorBlock(const CXXConstructorDecl *CD, CXXCtorType CT, const BlockDecl *BD, raw_ostream &ResStream) { - checkMangleDC(CD, BD); SmallString<64> Buffer; llvm::raw_svector_ostream Out(Buffer); mangleCXXCtor(CD, CT, Out); @@ -96,7 +203,6 @@ void MangleContext::mangleCtorBlock(const CXXConstructorDecl *CD, void MangleContext::mangleDtorBlock(const CXXDestructorDecl *DD, CXXDtorType DT, const BlockDecl *BD, raw_ostream &ResStream) { - checkMangleDC(DD, BD); SmallString<64> Buffer; llvm::raw_svector_ostream Out(Buffer); mangleCXXDtor(DD, DT, Out); @@ -107,7 +213,6 @@ void MangleContext::mangleDtorBlock(const CXXDestructorDecl *DD, void MangleContext::mangleBlock(const DeclContext *DC, const BlockDecl *BD, raw_ostream &Out) { assert(!isa<CXXConstructorDecl>(DC) && !isa<CXXDestructorDecl>(DC)); - checkMangleDC(DC, BD); SmallString<64> Buffer; llvm::raw_svector_ostream Stream(Buffer); @@ -145,15 +250,3 @@ void MangleContext::mangleObjCMethodName(const ObjCMethodDecl *MD, Out << OS.str().size() << OS.str(); } - -void MangleContext::mangleBlock(const BlockDecl *BD, - raw_ostream &Out, - const NamedDecl *ID) { - 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, ID, Out); -} diff --git a/lib/AST/LambdaMangleContext.cpp b/lib/AST/MangleNumberingContext.cpp index 54f445d..91ef0e2 100644 --- a/lib/AST/LambdaMangleContext.cpp +++ b/lib/AST/MangleNumberingContext.cpp @@ -1,4 +1,4 @@ -//===--- LambdaMangleContext.cpp - Context for mangling lambdas -*- C++ -*-===// +//===--- MangleNumberingContext.cpp - Context for mangling numbers --------===// // // The LLVM Compiler Infrastructure // @@ -12,22 +12,32 @@ // //===----------------------------------------------------------------------===// -#include "clang/AST/LambdaMangleContext.h" +#include "clang/AST/MangleNumberingContext.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclCXX.h" using namespace clang; -unsigned LambdaMangleContext::getManglingNumber(CXXMethodDecl *CallOperator) { +unsigned +MangleNumberingContext::getManglingNumber(const CXXMethodDecl *CallOperator) { const FunctionProtoType *Proto = CallOperator->getType()->getAs<FunctionProtoType>(); ASTContext &Context = CallOperator->getASTContext(); - - QualType Key = - Context.getFunctionType(Context.VoidTy, - ArrayRef<QualType>(Proto->arg_type_begin(), - Proto->getNumArgs()), - FunctionProtoType::ExtProtoInfo()); + + QualType Key = Context.getFunctionType(Context.VoidTy, Proto->getArgTypes(), + FunctionProtoType::ExtProtoInfo()); Key = Context.getCanonicalType(Key); return ++ManglingNumbers[Key->castAs<FunctionProtoType>()]; } + +unsigned +MangleNumberingContext::getManglingNumber(const BlockDecl *BD) { + // FIXME: Compute a BlockPointerType? Not obvious how. + const Type *Ty = 0; + return ++ManglingNumbers[Ty]; +} + +unsigned +MangleNumberingContext::getManglingNumber(const TagDecl *TD) { + return ++TagManglingNumbers[TD->getIdentifier()]; +} diff --git a/lib/AST/MicrosoftCXXABI.cpp b/lib/AST/MicrosoftCXXABI.cpp index fd932f7..4a93ea1 100644 --- a/lib/AST/MicrosoftCXXABI.cpp +++ b/lib/AST/MicrosoftCXXABI.cpp @@ -16,6 +16,7 @@ #include "clang/AST/Attr.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/MangleNumberingContext.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/Type.h" #include "clang/Basic/TargetInfo.h" @@ -23,6 +24,22 @@ using namespace clang; namespace { + +/// \brief Numbers things which need to correspond across multiple TUs. +/// Typically these are things like static locals, lambdas, or blocks. +class MicrosoftNumberingContext : public MangleNumberingContext { + unsigned NumStaticLocals; + +public: + MicrosoftNumberingContext() : NumStaticLocals(0) { } + + /// Static locals are numbered by source order. + virtual unsigned getManglingNumber(const VarDecl *VD) { + assert(VD->isStaticLocal()); + return ++NumStaticLocals; + } +}; + class MicrosoftCXXABI : public CXXABI { ASTContext &Context; public: @@ -51,6 +68,10 @@ public: return Layout.getNonVirtualSize() == PointerSize || Layout.getNonVirtualSize() == PointerSize * 2; } + + MangleNumberingContext *createMangleNumberingContext() const { + return new MicrosoftNumberingContext(); + } }; } diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp index 1785063..5256501 100644 --- a/lib/AST/MicrosoftMangle.cpp +++ b/lib/AST/MicrosoftMangle.cpp @@ -15,6 +15,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" #include "clang/AST/CharUnits.h" +#include "clang/AST/CXXInheritance.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" @@ -22,12 +23,47 @@ #include "clang/AST/ExprCXX.h" #include "clang/Basic/ABI.h" #include "clang/Basic/DiagnosticOptions.h" -#include <map> +#include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/StringMap.h" using namespace clang; namespace { +/// \brief Retrieve the declaration context that should be used when mangling +/// the given declaration. +static const DeclContext *getEffectiveDeclContext(const Decl *D) { + // The ABI assumes that lambda closure types that occur within + // default arguments live in the context of the function. However, due to + // the way in which Clang parses and creates function declarations, this is + // not the case: the lambda closure type ends up living in the context + // where the function itself resides, because the function declaration itself + // had not yet been created. Fix the context here. + if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) { + if (RD->isLambda()) + if (ParmVarDecl *ContextParam = + dyn_cast_or_null<ParmVarDecl>(RD->getLambdaContextDecl())) + return ContextParam->getDeclContext(); + } + + // Perform the same check for block literals. + if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) { + if (ParmVarDecl *ContextParam = + dyn_cast_or_null<ParmVarDecl>(BD->getBlockManglingContextDecl())) + return ContextParam->getDeclContext(); + } + + const DeclContext *DC = D->getDeclContext(); + if (const CapturedDecl *CD = dyn_cast<CapturedDecl>(DC)) + return getEffectiveDeclContext(CD); + + return DC; +} + +static const DeclContext *getEffectiveParentContext(const DeclContext *DC) { + return getEffectiveDeclContext(cast<Decl>(DC)); +} + static const FunctionDecl *getStructor(const FunctionDecl *fn) { if (const FunctionTemplateDecl *ftd = fn->getPrimaryTemplate()) return ftd->getTemplatedDecl(); @@ -47,9 +83,7 @@ class MicrosoftCXXNameMangler { const NamedDecl *Structor; unsigned StructorType; - // FIXME: audit the performance of BackRefMap as it might do way too many - // copying of strings. - typedef std::map<std::string, unsigned> BackRefMap; + typedef llvm::StringMap<unsigned> BackRefMap; BackRefMap NameBackReferences; bool UseNameBackReferences; @@ -58,30 +92,41 @@ class MicrosoftCXXNameMangler { ASTContext &getASTContext() const { return Context.getASTContext(); } + // FIXME: If we add support for __ptr32/64 qualifiers, then we should push + // this check into mangleQualifiers(). + const bool PointersAre64Bit; + public: enum QualifierMangleMode { QMM_Drop, QMM_Mangle, QMM_Escape, QMM_Result }; MicrosoftCXXNameMangler(MangleContext &C, raw_ostream &Out_) : Context(C), Out(Out_), Structor(0), StructorType(-1), - UseNameBackReferences(true) { } + UseNameBackReferences(true), + PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(0) == + 64) { } MicrosoftCXXNameMangler(MangleContext &C, raw_ostream &Out_, const CXXDestructorDecl *D, CXXDtorType Type) : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type), - UseNameBackReferences(true) { } + UseNameBackReferences(true), + PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(0) == + 64) { } raw_ostream &getStream() const { return Out; } void mangle(const NamedDecl *D, StringRef Prefix = "\01?"); void mangleName(const NamedDecl *ND); + void mangleDeclaration(const NamedDecl *ND); void mangleFunctionEncoding(const FunctionDecl *FD); void mangleVariableEncoding(const VarDecl *VD); void mangleNumber(int64_t Number); - void mangleNumber(const llvm::APSInt &Value); void mangleType(QualType T, SourceRange Range, QualifierMangleMode QMM = QMM_Mangle); + void mangleFunctionType(const FunctionType *T, const FunctionDecl *D = 0, + bool ForceInstMethod = false); + void manglePostfix(const DeclContext *DC, bool NoFunction = false); private: void disableBackReferences() { UseNameBackReferences = false; } @@ -89,8 +134,7 @@ private: 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 mangleSourceName(StringRef Name); void mangleOperatorName(OverloadedOperatorKind OO, SourceLocation Loc); void mangleCXXDtorType(CXXDtorType T); void mangleQualifiers(Qualifiers Quals, bool IsMember); @@ -114,98 +158,111 @@ private: #undef NON_CANONICAL_TYPE #undef TYPE - void mangleType(const TagType*); - void mangleFunctionType(const FunctionType *T, const FunctionDecl *D, - bool IsStructor, bool IsInstMethod); - void mangleDecayedArrayType(const ArrayType *T, bool IsGlobal); - void mangleArrayType(const ArrayType *T, Qualifiers Quals); + void mangleType(const TagDecl *TD); + void mangleDecayedArrayType(const ArrayType *T); + void mangleArrayType(const ArrayType *T); void mangleFunctionClass(const FunctionDecl *FD); - void mangleCallingConvention(const FunctionType *T, bool IsInstMethod = false); + void mangleCallingConvention(const FunctionType *T); void mangleIntegerLiteral(const llvm::APSInt &Number, bool IsBoolean); void mangleExpression(const Expr *E); void mangleThrowSpecification(const FunctionProtoType *T); void mangleTemplateArgs(const TemplateDecl *TD, const TemplateArgumentList &TemplateArgs); - + void mangleTemplateArg(const TemplateDecl *TD, const TemplateArgument &TA); }; -/// MicrosoftMangleContext - Overrides the default MangleContext for the +/// MicrosoftMangleContextImpl - Overrides the default MangleContext for the /// Microsoft Visual C++ ABI. -class MicrosoftMangleContext : public MangleContext { +class MicrosoftMangleContextImpl : public MicrosoftMangleContext { public: - MicrosoftMangleContext(ASTContext &Context, - DiagnosticsEngine &Diags) : MangleContext(Context, Diags) { } - virtual bool shouldMangleDeclName(const NamedDecl *D); - virtual void mangleName(const NamedDecl *D, raw_ostream &Out); + MicrosoftMangleContextImpl(ASTContext &Context, DiagnosticsEngine &Diags) + : MicrosoftMangleContext(Context, Diags) {} + virtual bool shouldMangleCXXName(const NamedDecl *D); + virtual void mangleCXXName(const NamedDecl *D, raw_ostream &Out); + virtual void mangleVirtualMemPtrThunk(const CXXMethodDecl *MD, + uint64_t OffsetInVFTable, + raw_ostream &); virtual void mangleThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk, raw_ostream &); virtual void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type, const ThisAdjustment &ThisAdjustment, raw_ostream &); - virtual void mangleCXXVTable(const CXXRecordDecl *RD, - raw_ostream &); - virtual void mangleCXXVTT(const CXXRecordDecl *RD, - raw_ostream &); - virtual void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset, - const CXXRecordDecl *Type, - raw_ostream &); + virtual void mangleCXXVFTable(const CXXRecordDecl *Derived, + ArrayRef<const CXXRecordDecl *> BasePath, + raw_ostream &Out); + virtual void mangleCXXVBTable(const CXXRecordDecl *Derived, + ArrayRef<const CXXRecordDecl *> BasePath, + raw_ostream &Out); virtual void mangleCXXRTTI(QualType T, raw_ostream &); virtual void mangleCXXRTTIName(QualType T, raw_ostream &); + virtual void mangleTypeName(QualType T, raw_ostream &); virtual void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type, raw_ostream &); virtual void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type, raw_ostream &); - virtual void mangleReferenceTemporary(const clang::VarDecl *, - raw_ostream &); -}; - -} + virtual void mangleReferenceTemporary(const VarDecl *, raw_ostream &); + virtual void mangleStaticGuardVariable(const VarDecl *D, raw_ostream &Out); + virtual void mangleDynamicInitializer(const VarDecl *D, raw_ostream &Out); + virtual void mangleDynamicAtExitDestructor(const VarDecl *D, + raw_ostream &Out); -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; - } +private: + void mangleInitFiniStub(const VarDecl *D, raw_ostream &Out, char CharCode); +}; - return false; } -bool MicrosoftMangleContext::shouldMangleDeclName(const NamedDecl *D) { - // In C, functions with no attributes never need to be mangled. Fastpath them. - if (!getASTContext().getLangOpts().CPlusPlus && !D->hasAttrs()) - return false; +bool MicrosoftMangleContextImpl::shouldMangleCXXName(const NamedDecl *D) { + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + LanguageLinkage L = FD->getLanguageLinkage(); + // Overloadable functions need mangling. + if (FD->hasAttr<OverloadableAttr>()) + return true; + + // The ABI expects that we would never mangle "typical" user-defined entry + // points regardless of visibility or freestanding-ness. + // + // N.B. This is distinct from asking about "main". "main" has a lot of + // special rules associated with it in the standard while these + // user-defined entry points are outside of the purview of the standard. + // For example, there can be only one definition for "main" in a standards + // compliant program; however nothing forbids the existence of wmain and + // WinMain in the same translation unit. + if (FD->isMSVCRTEntryPoint()) + 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; + // C++ functions and those whose names are not a simple identifier need + // mangling. + if (!FD->getDeclName().isIdentifier() || L == CXXLanguageLinkage) + 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; + // C functions are not mangled. + if (L == CLanguageLinkage) + return false; + } // Otherwise, no mangling is done outside C++ mode. if (!getASTContext().getLangOpts().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) + if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { + // C variables are not mangled. + if (VD->isExternC()) return false; - } - // C functions and "main" are not mangled. - if ((FD && FD->isMain()) || isInCLinkageSpecification(D)) - return false; + // Variables at global scope with non-internal linkage are not mangled. + const DeclContext *DC = getEffectiveDeclContext(D); + // Check for extern variable declared locally. + if (DC->isFunctionOrMethod() && D->hasLinkage()) + while (!DC->isNamespace() && !DC->isTranslationUnit()) + DC = getEffectiveParentContext(DC); + + if (DC->isTranslationUnit() && D->getFormalLinkage() == InternalLinkage && + !isa<VarTemplateSpecializationDecl>(D)) + return false; + } return true; } @@ -218,14 +275,6 @@ void MicrosoftCXXNameMangler::mangle(const NamedDecl *D, // default, we emit an asm marker at the start so we get the name right. // Callers can override this with a custom 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. - Out << '\01' << ALA->getLabel(); - return; - } - // <mangled-name> ::= ? <name> <type-encoding> Out << Prefix; mangleName(D); @@ -247,27 +296,25 @@ void MicrosoftCXXNameMangler::mangle(const NamedDecl *D, 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; - + // Since MSVC operates on the type as written and not the canonical type, it + // actually matters which decl we have here. MSVC appears to choose the + // first, since it is most likely to be the declaration in a header file. + FD = FD->getFirstDecl(); + // We should never ever see a FunctionNoProtoType at this point. // We don't even know how to mangle their types anyway :). const FunctionProtoType *FT = FD->getType()->castAs<FunctionProtoType>(); - 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); + // extern "C" functions can hold entities that must be mangled. + // As it stands, these functions still need to get expressed in the full + // external name. They have their class and type omitted, replaced with '9'. + if (Context.shouldMangleDeclName(FD)) { + // First, the function class. + mangleFunctionClass(FD); - mangleFunctionType(FT, FD, InStructor, InInstMethod); + mangleFunctionType(FT, FD); + } else + Out << '9'; } void MicrosoftCXXNameMangler::mangleVariableEncoding(const VarDecl *VD) { @@ -299,12 +346,21 @@ void MicrosoftCXXNameMangler::mangleVariableEncoding(const VarDecl *VD) { // mangled as 'QAHA' instead of 'PAHB', for example. TypeLoc TL = VD->getTypeSourceInfo()->getTypeLoc(); QualType Ty = TL.getType(); - if (Ty->isPointerType() || Ty->isReferenceType()) { + if (Ty->isPointerType() || Ty->isReferenceType() || + Ty->isMemberPointerType()) { mangleType(Ty, TL.getSourceRange(), QMM_Drop); - mangleQualifiers(Ty->getPointeeType().getQualifiers(), false); + if (PointersAre64Bit) + Out << 'E'; + if (const MemberPointerType *MPT = Ty->getAs<MemberPointerType>()) { + mangleQualifiers(MPT->getPointeeType().getQualifiers(), true); + // Member pointers are suffixed with a back reference to the member + // pointer's class name. + mangleName(MPT->getClass()->getAsCXXRecordDecl()); + } else + mangleQualifiers(Ty->getPointeeType().getQualifiers(), false); } else if (const ArrayType *AT = getASTContext().getAsArrayType(Ty)) { // Global arrays are funny, too. - mangleDecayedArrayType(AT, true); + mangleDecayedArrayType(AT); if (AT->getElementType()->isArrayType()) Out << 'A'; else @@ -335,39 +391,32 @@ void MicrosoftCXXNameMangler::mangleName(const NamedDecl *ND) { } void MicrosoftCXXNameMangler::mangleNumber(int64_t Number) { - llvm::APSInt APSNumber(/*BitWidth=*/64, /*isUnsigned=*/false); - APSNumber = Number; - mangleNumber(APSNumber); -} - -void MicrosoftCXXNameMangler::mangleNumber(const llvm::APSInt &Value) { - // <number> ::= [?] <decimal digit> # 1 <= Number <= 10 - // ::= [?] <hex digit>+ @ # 0 or > 9; A = 0, B = 1, etc... - // ::= [?] @ # 0 (alternate mangling, not emitted by VC) - if (Value.isSigned() && Value.isNegative()) { + // <non-negative integer> ::= A@ # when Number == 0 + // ::= <decimal digit> # when 1 <= Number <= 10 + // ::= <hex digit>+ @ # when Number >= 10 + // + // <number> ::= [?] <non-negative integer> + + uint64_t Value = static_cast<uint64_t>(Number); + if (Number < 0) { + Value = -Value; Out << '?'; - mangleNumber(llvm::APSInt(Value.abs())); - return; } - llvm::APSInt Temp(Value); - // There's a special shorter mangling for 0, but Microsoft - // chose not to use it. Instead, 0 gets mangled as "A@". Oh well... - if (Value.uge(1) && Value.ule(10)) { - --Temp; - Temp.print(Out, false); - } else { - // We have to build up the encoding in reverse order, so it will come - // out right when we write it out. - char Encoding[64]; - char *EndPtr = Encoding+sizeof(Encoding); - char *CurPtr = EndPtr; - llvm::APSInt NibbleMask(Value.getBitWidth(), Value.isUnsigned()); - NibbleMask = 0xf; - do { - *--CurPtr = 'A' + Temp.And(NibbleMask).getLimitedValue(0xf); - Temp = Temp.lshr(4); - } while (Temp != 0); - Out.write(CurPtr, EndPtr-CurPtr); + + if (Value == 0) + Out << "A@"; + else if (Value >= 1 && Value <= 10) + Out << (Value - 1); + else { + // Numbers that are not encoded as decimal digits are represented as nibbles + // in the range of ASCII characters 'A' to 'P'. + // The number 0x123450 would be encoded as 'BCDEFA' + char EncodedNumberBuffer[sizeof(uint64_t) * 2]; + llvm::MutableArrayRef<char> BufferRef(EncodedNumberBuffer); + llvm::MutableArrayRef<char>::reverse_iterator I = BufferRef.rbegin(); + for (; Value != 0; Value >>= 4) + *I++ = 'A' + (Value & 0xf); + Out.write(I.base(), I - BufferRef.rbegin()); Out << '@'; } } @@ -403,7 +452,16 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, // Check if we have a template. const TemplateArgumentList *TemplateArgs = 0; if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) { - // We have a template. + // Function templates aren't considered for name back referencing. This + // makes sense since function templates aren't likely to occur multiple + // times in a symbol. + // FIXME: Test alias template mangling with MSVC 2013. + if (!isa<ClassTemplateDecl>(TD)) { + mangleTemplateInstantiationName(TD, *TemplateArgs); + return; + } + + // We have a class template. // Here comes the tricky thing: if we need to mangle something like // void foo(A::X<Y>, B::X<Y>), // the X<Y> part is aliased. However, if you need to mangle @@ -445,7 +503,7 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, switch (Name.getNameKind()) { case DeclarationName::Identifier: { if (const IdentifierInfo *II = Name.getAsIdentifierInfo()) { - mangleSourceName(II); + mangleSourceName(II->getName()); break; } @@ -466,13 +524,22 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, "Typedef should not be in another decl context!"); assert(D->getDeclName().getAsIdentifierInfo() && "Typedef was not named!"); - mangleSourceName(D->getDeclName().getAsIdentifierInfo()); + mangleSourceName(D->getDeclName().getAsIdentifierInfo()->getName()); break; } - // When VC encounters an anonymous type with no tag and no typedef, - // it literally emits '<unnamed-tag>'. - Out << "<unnamed-tag>"; + if (TD->hasDeclaratorForAnonDecl()) { + // Anonymous types with no tag or typedef get the name of their + // declarator mangled in. + llvm::SmallString<64> Name("<unnamed-type-"); + Name += TD->getDeclaratorForAnonDecl()->getName(); + Name += ">"; + mangleSourceName(Name.str()); + } else { + // Anonymous types with no tag, no typedef, or declarator get + // '<unnamed-tag>'. + mangleSourceName("<unnamed-tag>"); + } break; } @@ -495,9 +562,9 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, // use the type we were given. mangleCXXDtorType(static_cast<CXXDtorType>(StructorType)); else - // Otherwise, use the complete destructor name. This is relevant if a + // Otherwise, use the base destructor name. This is relevant if a // class with a destructor is declared within a destructor. - mangleCXXDtorType(Dtor_Complete); + mangleCXXDtorType(Dtor_Base); break; case DeclarationName::CXXConversionFunctionName: @@ -538,9 +605,20 @@ void MicrosoftCXXNameMangler::manglePostfix(const DeclContext *DC, return; if (const BlockDecl *BD = dyn_cast<BlockDecl>(DC)) { - Context.mangleBlock(BD, Out); + DiagnosticsEngine Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle a local inside this block yet"); + Diags.Report(BD->getLocation(), DiagID); + + // FIXME: This is completely, utterly, wrong; see ItaniumMangle + // for how this should be done. + Out << "__block_invoke" << Context.getBlockId(BD, false); Out << '@'; return manglePostfix(DC->getParent(), NoFunction); + } else if (isa<CapturedDecl>(DC)) { + // Skip CapturedDecl context. + manglePostfix(DC->getParent(), NoFunction); + return; } if (NoFunction && (isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC))) @@ -556,18 +634,19 @@ void MicrosoftCXXNameMangler::manglePostfix(const DeclContext *DC, } void MicrosoftCXXNameMangler::mangleCXXDtorType(CXXDtorType T) { + // Microsoft uses the names on the case labels for these dtor variants. Clang + // uses the Itanium terminology internally. Everything in this ABI delegates + // towards the base dtor. switch (T) { - case Dtor_Deleting: - Out << "?_G"; - return; - case Dtor_Base: - // FIXME: We should be asked to mangle base dtors. - // However, fixing this would require larger changes to the CodeGenModule. - // Please put llvm_unreachable here when CGM is changed. - // For now, just mangle a base dtor the same way as a complete dtor... - case Dtor_Complete: - Out << "?1"; - return; + // <operator-name> ::= ?1 # destructor + case Dtor_Base: Out << "?1"; return; + // <operator-name> ::= ?_D # vbase destructor + case Dtor_Complete: Out << "?_D"; return; + // <operator-name> ::= ?_G # scalar deleting destructor + case Dtor_Deleting: Out << "?_G"; return; + // <operator-name> ::= ?_E # vector deleting destructor + // FIXME: Add a vector deleting dtor type. It goes in the vtable, so we need + // it. } llvm_unreachable("Unsupported dtor type?"); } @@ -704,17 +783,16 @@ void MicrosoftCXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO, } } -void MicrosoftCXXNameMangler::mangleSourceName(const IdentifierInfo *II) { +void MicrosoftCXXNameMangler::mangleSourceName(StringRef Name) { // <source name> ::= <identifier> @ - std::string key = II->getNameStart(); BackRefMap::iterator Found; if (UseNameBackReferences) - Found = NameBackReferences.find(key); + Found = NameBackReferences.find(Name); if (!UseNameBackReferences || Found == NameBackReferences.end()) { - Out << II->getName() << '@'; + Out << Name << '@'; if (UseNameBackReferences && NameBackReferences.size() < 10) { size_t Size = NameBackReferences.size(); - NameBackReferences[key] = Size; + NameBackReferences[Name] = Size; } } else { Out << Found->second; @@ -756,7 +834,7 @@ void MicrosoftCXXNameMangler::mangleLocalName(const FunctionDecl *FD) { // functions. You could have a method baz of class C inside a function bar // inside a function foo, like so: // ?baz@C@?3??bar@?1??foo@@YAXXZ@YAXXZ@QAEXXZ - int NestLevel = getLocalNestingLevel(FD); + unsigned NestLevel = getLocalNestingLevel(FD); Out << '?'; mangleNumber(NestLevel); Out << '?'; @@ -800,7 +878,7 @@ MicrosoftCXXNameMangler::mangleIntegerLiteral(const llvm::APSInt &Value, if (IsBoolean && Value.getBoolValue()) mangleNumber(1); else - mangleNumber(Value); + mangleNumber(Value.getSExtValue()); } void @@ -812,6 +890,33 @@ MicrosoftCXXNameMangler::mangleExpression(const Expr *E) { return; } + const CXXUuidofExpr *UE = 0; + if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) { + if (UO->getOpcode() == UO_AddrOf) + UE = dyn_cast<CXXUuidofExpr>(UO->getSubExpr()); + } else + UE = dyn_cast<CXXUuidofExpr>(E); + + if (UE) { + // This CXXUuidofExpr is mangled as-if it were actually a VarDecl from + // const __s_GUID _GUID_{lower case UUID with underscores} + StringRef Uuid = UE->getUuidAsStringRef(Context.getASTContext()); + std::string Name = "_GUID_" + Uuid.lower(); + std::replace(Name.begin(), Name.end(), '-', '_'); + + // If we had to peek through an address-of operator, treat this like we are + // dealing with a pointer type. Otherwise, treat it like a const reference. + // + // N.B. This matches up with the handling of TemplateArgument::Declaration + // in mangleTemplateArg + if (UE == E) + Out << "$E?"; + else + Out << "$1?"; + Out << Name << "@@3U__s_GUID@@B"; + return; + } + // As bad as this diagnostic is, it's better than crashing. DiagnosticsEngine &Diags = Context.getDiags(); unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, @@ -827,44 +932,51 @@ MicrosoftCXXNameMangler::mangleTemplateArgs(const TemplateDecl *TD, unsigned NumTemplateArgs = TemplateArgs.size(); for (unsigned i = 0; i < NumTemplateArgs; ++i) { const TemplateArgument &TA = TemplateArgs[i]; - switch (TA.getKind()) { - case TemplateArgument::Null: - llvm_unreachable("Can't mangle null template arguments!"); - case TemplateArgument::Type: { - QualType T = TA.getAsType(); - mangleType(T, SourceRange(), QMM_Escape); - break; - } - case TemplateArgument::Declaration: - mangle(cast<NamedDecl>(TA.getAsDecl()), "$1?"); - break; - case TemplateArgument::Integral: - mangleIntegerLiteral(TA.getAsIntegral(), - TA.getIntegralType()->isBooleanType()); - break; - case TemplateArgument::Expression: - mangleExpression(TA.getAsExpr()); - break; - case TemplateArgument::Template: - case TemplateArgument::TemplateExpansion: - case TemplateArgument::NullPtr: - case TemplateArgument::Pack: { - // Issue a diagnostic. - DiagnosticsEngine &Diags = Context.getDiags(); - unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle template argument %0 of kind %select{ERROR|ERROR|" - "pointer/reference|nullptr|integral|template|template pack expansion|" - "ERROR|parameter pack}1 yet"); - Diags.Report(TD->getLocation(), DiagID) - << i + 1 - << TA.getKind() - << TD->getSourceRange(); - } - } + mangleTemplateArg(TD, TA); } Out << '@'; } +void MicrosoftCXXNameMangler::mangleTemplateArg(const TemplateDecl *TD, + const TemplateArgument &TA) { + switch (TA.getKind()) { + case TemplateArgument::Null: + llvm_unreachable("Can't mangle null template arguments!"); + case TemplateArgument::TemplateExpansion: + llvm_unreachable("Can't mangle template expansion arguments!"); + case TemplateArgument::Type: { + QualType T = TA.getAsType(); + mangleType(T, SourceRange(), QMM_Escape); + break; + } + case TemplateArgument::Declaration: { + const NamedDecl *ND = cast<NamedDecl>(TA.getAsDecl()); + mangle(ND, TA.isDeclForReferenceParam() ? "$E?" : "$1?"); + break; + } + case TemplateArgument::Integral: + mangleIntegerLiteral(TA.getAsIntegral(), + TA.getIntegralType()->isBooleanType()); + break; + case TemplateArgument::NullPtr: + Out << "$0A@"; + break; + case TemplateArgument::Expression: + mangleExpression(TA.getAsExpr()); + break; + case TemplateArgument::Pack: + // Unlike Itanium, there is no character code to indicate an argument pack. + for (TemplateArgument::pack_iterator I = TA.pack_begin(), E = TA.pack_end(); + I != E; ++I) + mangleTemplateArg(TD, *I); + break; + case TemplateArgument::Template: + mangleType(cast<TagDecl>( + TA.getAsTemplate().getAsTemplateDecl()->getTemplatedDecl())); + break; + } +} + void MicrosoftCXXNameMangler::mangleQualifiers(Qualifiers Quals, bool IsMember) { // <cvr-qualifiers> ::= [E] [F] [I] <base-cvr-qualifiers> @@ -921,6 +1033,7 @@ void MicrosoftCXXNameMangler::mangleQualifiers(Qualifiers Quals, // ::= 5 # not really based bool HasConst = Quals.hasConst(), HasVolatile = Quals.hasVolatile(); + if (!IsMember) { if (HasConst && HasVolatile) { Out << 'D'; @@ -966,20 +1079,32 @@ void MicrosoftCXXNameMangler::manglePointerQualifiers(Qualifiers Quals) { void MicrosoftCXXNameMangler::mangleArgumentType(QualType T, SourceRange Range) { - void *TypePtr = getASTContext().getCanonicalType(T).getAsOpaquePtr(); + // MSVC will backreference two canonically equivalent types that have slightly + // different manglings when mangled alone. + + // Decayed types do not match up with non-decayed versions of the same type. + // + // e.g. + // void (*x)(void) will not form a backreference with void x(void) + void *TypePtr; + if (const DecayedType *DT = T->getAs<DecayedType>()) { + TypePtr = DT->getOriginalType().getCanonicalType().getAsOpaquePtr(); + // If the original parameter was textually written as an array, + // instead treat the decayed parameter like it's const. + // + // e.g. + // int [] -> int * const + if (DT->getOriginalType()->isArrayType()) + T = T.withConst(); + } else + TypePtr = T.getCanonicalType().getAsOpaquePtr(); + ArgBackRefMap::iterator Found = TypeBackReferences.find(TypePtr); if (Found == TypeBackReferences.end()) { size_t OutSizeBefore = Out.GetNumBytesInBuffer(); - if (const ArrayType *AT = getASTContext().getAsArrayType(T)) { - mangleDecayedArrayType(AT, false); - } else if (const FunctionType *FT = T->getAs<FunctionType>()) { - Out << "P6"; - mangleFunctionType(FT, 0, false, false); - } else { - mangleType(T, Range, QMM_Drop); - } + mangleType(T, Range, QMM_Drop); // See if it's worth creating a back reference. // Only types longer than 1 character are considered @@ -996,16 +1121,18 @@ void MicrosoftCXXNameMangler::mangleArgumentType(QualType T, void MicrosoftCXXNameMangler::mangleType(QualType T, SourceRange Range, QualifierMangleMode QMM) { - // Only operate on the canonical type! - T = getASTContext().getCanonicalType(T); + // Don't use the canonical types. MSVC includes things like 'const' on + // pointer arguments to function pointers that canonicalization strips away. + T = T.getDesugaredType(getASTContext()); Qualifiers Quals = T.getLocalQualifiers(); - - if (const ArrayType *AT = dyn_cast<ArrayType>(T)) { + if (const ArrayType *AT = getASTContext().getAsArrayType(T)) { + // If there were any Quals, getAsArrayType() pushed them onto the array + // element type. if (QMM == QMM_Mangle) Out << 'A'; else if (QMM == QMM_Escape || QMM == QMM_Result) Out << "$$B"; - mangleArrayType(AT, Quals); + mangleArrayType(AT); return; } @@ -1018,7 +1145,7 @@ void MicrosoftCXXNameMangler::mangleType(QualType T, SourceRange Range, case QMM_Mangle: if (const FunctionType *FT = dyn_cast<FunctionType>(T)) { Out << '6'; - mangleFunctionType(FT, 0, false, false); + mangleFunctionType(FT); return; } mangleQualifiers(Quals, false); @@ -1151,7 +1278,7 @@ void MicrosoftCXXNameMangler::mangleType(const FunctionProtoType *T, // structor type. // FIXME: This may not be lambda-friendly. Out << "$$A6"; - mangleFunctionType(T, NULL, false, false); + mangleFunctionType(T); } void MicrosoftCXXNameMangler::mangleType(const FunctionNoProtoType *T, SourceRange) { @@ -1160,18 +1287,31 @@ void MicrosoftCXXNameMangler::mangleType(const FunctionNoProtoType *T, void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T, const FunctionDecl *D, - bool IsStructor, - bool IsInstMethod) { + bool ForceInstMethod) { // <function-type> ::= <this-cvr-qualifiers> <calling-convention> // <return-type> <argument-list> <throw-spec> const FunctionProtoType *Proto = cast<FunctionProtoType>(T); + SourceRange Range; + if (D) Range = D->getSourceRange(); + + bool IsStructor = false, IsInstMethod = ForceInstMethod; + if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(D)) { + if (MD->isInstance()) + IsInstMethod = true; + if (isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD)) + IsStructor = true; + } + // If this is a C++ instance method, mangle the CVR qualifiers for the // this pointer. - if (IsInstMethod) + if (IsInstMethod) { + if (PointersAre64Bit) + Out << 'E'; mangleQualifiers(Qualifiers::fromCVRMask(Proto->getTypeQuals()), false); + } - mangleCallingConvention(T, IsInstMethod); + mangleCallingConvention(T); // <return-type> ::= <type> // ::= @ # structors (they have no declared return type) @@ -1182,12 +1322,15 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T, // However, the FunctionType generated has 0 arguments. // FIXME: This is a temporary hack. // Maybe should fix the FunctionType creation instead? - Out << "PAXI@Z"; + Out << (PointersAre64Bit ? "PEAXI@Z" : "PAXI@Z"); return; } Out << '@'; } else { - mangleType(Proto->getResultType(), SourceRange(), QMM_Result); + QualType ResultType = Proto->getResultType(); + if (ResultType->isVoidType()) + ResultType = ResultType.getUnqualifiedType(); + mangleType(ResultType, Range, QMM_Result); } // <argument-list> ::= X # void @@ -1196,23 +1339,11 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T, if (Proto->getNumArgs() == 0 && !Proto->isVariadic()) { Out << 'X'; } else { - if (D) { - // If we got a decl, use the type-as-written to make sure arrays - // get mangled right. Note that we can't rely on the TSI - // existing if (for example) the parameter was synthesized. - for (FunctionDecl::param_const_iterator Parm = D->param_begin(), - ParmEnd = D->param_end(); Parm != ParmEnd; ++Parm) { - TypeSourceInfo *TSI = (*Parm)->getTypeSourceInfo(); - QualType Type = TSI ? TSI->getType() : (*Parm)->getType(); - mangleArgumentType(Type, (*Parm)->getSourceRange()); - } - } else { - // Happens for function pointer type arguments for example. - for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(), - ArgEnd = Proto->arg_type_end(); - Arg != ArgEnd; ++Arg) - mangleArgumentType(*Arg, SourceRange()); - } + // Happens for function pointer type arguments for example. + for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(), + ArgEnd = Proto->arg_type_end(); + Arg != ArgEnd; ++Arg) + mangleArgumentType(*Arg, Range); // <builtin-type> ::= Z # ellipsis if (Proto->isVariadic()) Out << 'Z'; @@ -1224,35 +1355,34 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T, } 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 + // <function-class> ::= <member-function> E? # E designates a 64-bit 'this' + // # pointer. in 64-bit mode *all* + // # 'this' pointers are 64-bit. + // ::= <global-function> + // <member-function> ::= A # private: near + // ::= B # private: far + // ::= C # private: static near + // ::= D # private: static far + // ::= E # private: virtual near + // ::= F # private: virtual far + // ::= I # protected: near + // ::= J # protected: far + // ::= K # protected: static near + // ::= L # protected: static far + // ::= M # protected: virtual near + // ::= N # protected: virtual far + // ::= Q # public: near + // ::= R # public: far + // ::= S # public: static near + // ::= T # public: static far + // ::= U # public: virtual near + // ::= V # public: virtual far + // <global-function> ::= Y # global near + // ::= Z # global far if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) { switch (MD->getAccess()) { - default: + case AS_none: + llvm_unreachable("Unsupported access specifier"); case AS_private: if (MD->isStatic()) Out << 'C'; @@ -1280,8 +1410,7 @@ void MicrosoftCXXNameMangler::mangleFunctionClass(const FunctionDecl *FD) { } else Out << 'Y'; } -void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T, - bool IsInstMethod) { +void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T) { // <calling-convention> ::= A # __cdecl // ::= B # __export __cdecl // ::= C # __pascal @@ -1298,20 +1427,11 @@ void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T, // that they could be in a DLL and somebody from another module could call // them.) CallingConv CC = T->getCallConv(); - if (CC == CC_Default) { - if (IsInstMethod) { - const FunctionProtoType *FPT = - T->getCanonicalTypeUnqualified().castAs<FunctionProtoType>(); - bool isVariadic = FPT->isVariadic(); - CC = getASTContext().getDefaultCXXMethodCallConv(isVariadic); - } else { - CC = CC_C; - } - } switch (CC) { default: llvm_unreachable("Unsupported CC for mangling"); - case CC_Default: + case CC_X86_64Win64: + case CC_X86_64SysV: case CC_C: Out << 'A'; break; case CC_X86Pascal: Out << 'C'; break; case CC_X86ThisCall: Out << 'E'; break; @@ -1347,13 +1467,13 @@ void MicrosoftCXXNameMangler::mangleType(const UnresolvedUsingType *T, // <class-type> ::= V <name> // <enum-type> ::= W <size> <name> void MicrosoftCXXNameMangler::mangleType(const EnumType *T, SourceRange) { - mangleType(cast<TagType>(T)); + mangleType(cast<TagType>(T)->getDecl()); } void MicrosoftCXXNameMangler::mangleType(const RecordType *T, SourceRange) { - mangleType(cast<TagType>(T)); + mangleType(cast<TagType>(T)->getDecl()); } -void MicrosoftCXXNameMangler::mangleType(const TagType *T) { - switch (T->getDecl()->getTagKind()) { +void MicrosoftCXXNameMangler::mangleType(const TagDecl *TD) { + switch (TD->getTagKind()) { case TTK_Union: Out << 'T'; break; @@ -1367,30 +1487,23 @@ void MicrosoftCXXNameMangler::mangleType(const TagType *T) { case TTK_Enum: Out << 'W'; Out << getASTContext().getTypeSizeInChars( - cast<EnumDecl>(T->getDecl())->getIntegerType()).getQuantity(); + cast<EnumDecl>(TD)->getIntegerType()).getQuantity(); break; } - mangleName(T->getDecl()); + mangleName(TD); } // <type> ::= <array-type> // <array-type> ::= <pointer-cvr-qualifiers> <cvr-qualifiers> // [Y <dimension-count> <dimension>+] -// <element-type> # as global -// ::= Q <cvr-qualifiers> [Y <dimension-count> <dimension>+] -// <element-type> # as param +// <element-type> # as global, E is never required // 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::mangleDecayedArrayType(const ArrayType *T, - bool IsGlobal) { +void MicrosoftCXXNameMangler::mangleDecayedArrayType(const ArrayType *T) { // This isn't a recursive mangling, so now we have to do it all in this // one call. - if (IsGlobal) { - manglePointerQualifiers(T->getElementType().getQualifiers()); - } else { - Out << 'Q'; - } + manglePointerQualifiers(T->getElementType().getQualifiers()); mangleType(T->getElementType(), SourceRange()); } void MicrosoftCXXNameMangler::mangleType(const ConstantArrayType *T, @@ -1409,8 +1522,7 @@ void MicrosoftCXXNameMangler::mangleType(const IncompleteArrayType *T, SourceRange) { llvm_unreachable("Should have been special cased"); } -void MicrosoftCXXNameMangler::mangleArrayType(const ArrayType *T, - Qualifiers Quals) { +void MicrosoftCXXNameMangler::mangleArrayType(const ArrayType *T) { QualType ElementTy(T, 0); SmallVector<llvm::APInt, 3> Dimensions; for (;;) { @@ -1449,8 +1561,7 @@ void MicrosoftCXXNameMangler::mangleArrayType(const ArrayType *T, mangleNumber(Dimensions.size()); for (unsigned Dim = 0; Dim < Dimensions.size(); ++Dim) mangleNumber(Dimensions[Dim].getLimitedValue()); - mangleType(getASTContext().getQualifiedType(ElementTy.getTypePtr(), Quals), - SourceRange(), QMM_Escape); + mangleType(ElementTy, SourceRange(), QMM_Escape); } // <type> ::= <pointer-to-member-type> @@ -1462,8 +1573,10 @@ void MicrosoftCXXNameMangler::mangleType(const MemberPointerType *T, if (const FunctionProtoType *FPT = PointeeType->getAs<FunctionProtoType>()) { Out << '8'; mangleName(T->getClass()->castAs<RecordType>()->getDecl()); - mangleFunctionType(FPT, NULL, false, true); + mangleFunctionType(FPT, 0, true); } else { + if (PointersAre64Bit && !T->getPointeeType()->isFunctionType()) + Out << 'E'; mangleQualifiers(PointeeType.getQualifiers(), true); mangleName(T->getClass()->castAs<RecordType>()->getDecl()); mangleType(PointeeType, Range, QMM_Drop); @@ -1490,32 +1603,43 @@ void MicrosoftCXXNameMangler::mangleType( } // <type> ::= <pointer-type> -// <pointer-type> ::= <pointer-cvr-qualifiers> <cvr-qualifiers> <type> +// <pointer-type> ::= E? <pointer-cvr-qualifiers> <cvr-qualifiers> <type> +// # the E is required for 64-bit non static pointers void MicrosoftCXXNameMangler::mangleType(const PointerType *T, SourceRange Range) { QualType PointeeTy = T->getPointeeType(); + if (PointersAre64Bit && !T->getPointeeType()->isFunctionType()) + Out << 'E'; mangleType(PointeeTy, Range); } void MicrosoftCXXNameMangler::mangleType(const ObjCObjectPointerType *T, SourceRange Range) { // Object pointers never have qualifiers. Out << 'A'; + if (PointersAre64Bit && !T->getPointeeType()->isFunctionType()) + Out << 'E'; mangleType(T->getPointeeType(), Range); } // <type> ::= <reference-type> -// <reference-type> ::= A <cvr-qualifiers> <type> +// <reference-type> ::= A E? <cvr-qualifiers> <type> +// # the E is required for 64-bit non static lvalue references void MicrosoftCXXNameMangler::mangleType(const LValueReferenceType *T, SourceRange Range) { Out << 'A'; + if (PointersAre64Bit && !T->getPointeeType()->isFunctionType()) + Out << 'E'; mangleType(T->getPointeeType(), Range); } // <type> ::= <r-value-reference-type> -// <r-value-reference-type> ::= $$Q <cvr-qualifiers> <type> +// <r-value-reference-type> ::= $$Q E? <cvr-qualifiers> <type> +// # the E is required for 64-bit non static rvalue references void MicrosoftCXXNameMangler::mangleType(const RValueReferenceType *T, SourceRange Range) { Out << "$$Q"; + if (PointersAre64Bit && !T->getPointeeType()->isFunctionType()) + Out << 'E'; mangleType(T->getPointeeType(), Range); } @@ -1598,16 +1722,12 @@ void MicrosoftCXXNameMangler::mangleType(const BlockPointerType *T, Out << "_E"; QualType pointee = T->getPointeeType(); - mangleFunctionType(pointee->castAs<FunctionProtoType>(), NULL, false, false); + mangleFunctionType(pointee->castAs<FunctionProtoType>()); } -void MicrosoftCXXNameMangler::mangleType(const InjectedClassNameType *T, - SourceRange Range) { - DiagnosticsEngine &Diags = Context.getDiags(); - unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle this injected class name type yet"); - Diags.Report(Range.getBegin(), DiagID) - << Range; +void MicrosoftCXXNameMangler::mangleType(const InjectedClassNameType *, + SourceRange) { + llvm_unreachable("Cannot mangle injected class name type."); } void MicrosoftCXXNameMangler::mangleType(const TemplateSpecializationType *T, @@ -1700,8 +1820,8 @@ void MicrosoftCXXNameMangler::mangleType(const AtomicType *T, << Range; } -void MicrosoftMangleContext::mangleName(const NamedDecl *D, - raw_ostream &Out) { +void MicrosoftMangleContextImpl::mangleCXXName(const NamedDecl *D, + 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) && @@ -1714,85 +1834,265 @@ void MicrosoftMangleContext::mangleName(const NamedDecl *D, MicrosoftCXXNameMangler Mangler(*this, Out); return Mangler.mangle(D); } -void MicrosoftMangleContext::mangleThunk(const CXXMethodDecl *MD, - const ThunkInfo &Thunk, - raw_ostream &) { - unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle thunk for this method yet"); - getDiags().Report(MD->getLocation(), DiagID); + +// <this-adjustment> ::= <no-adjustment> | <static-adjustment> | +// <virtual-adjustment> +// <no-adjustment> ::= A # private near +// ::= B # private far +// ::= I # protected near +// ::= J # protected far +// ::= Q # public near +// ::= R # public far +// <static-adjustment> ::= G <static-offset> # private near +// ::= H <static-offset> # private far +// ::= O <static-offset> # protected near +// ::= P <static-offset> # protected far +// ::= W <static-offset> # public near +// ::= X <static-offset> # public far +// <virtual-adjustment> ::= $0 <virtual-shift> <static-offset> # private near +// ::= $1 <virtual-shift> <static-offset> # private far +// ::= $2 <virtual-shift> <static-offset> # protected near +// ::= $3 <virtual-shift> <static-offset> # protected far +// ::= $4 <virtual-shift> <static-offset> # public near +// ::= $5 <virtual-shift> <static-offset> # public far +// <virtual-shift> ::= <vtordisp-shift> | <vtordispex-shift> +// <vtordisp-shift> ::= <offset-to-vtordisp> +// <vtordispex-shift> ::= <offset-to-vbptr> <vbase-offset-offset> +// <offset-to-vtordisp> +static void mangleThunkThisAdjustment(const CXXMethodDecl *MD, + const ThisAdjustment &Adjustment, + MicrosoftCXXNameMangler &Mangler, + raw_ostream &Out) { + if (!Adjustment.Virtual.isEmpty()) { + Out << '$'; + char AccessSpec; + switch (MD->getAccess()) { + case AS_none: + llvm_unreachable("Unsupported access specifier"); + case AS_private: + AccessSpec = '0'; + break; + case AS_protected: + AccessSpec = '2'; + break; + case AS_public: + AccessSpec = '4'; + } + if (Adjustment.Virtual.Microsoft.VBPtrOffset) { + Out << 'R' << AccessSpec; + Mangler.mangleNumber( + static_cast<uint32_t>(Adjustment.Virtual.Microsoft.VBPtrOffset)); + Mangler.mangleNumber( + static_cast<uint32_t>(Adjustment.Virtual.Microsoft.VBOffsetOffset)); + Mangler.mangleNumber( + static_cast<uint32_t>(Adjustment.Virtual.Microsoft.VtordispOffset)); + Mangler.mangleNumber(static_cast<uint32_t>(Adjustment.NonVirtual)); + } else { + Out << AccessSpec; + Mangler.mangleNumber( + static_cast<uint32_t>(Adjustment.Virtual.Microsoft.VtordispOffset)); + Mangler.mangleNumber(-static_cast<uint32_t>(Adjustment.NonVirtual)); + } + } else if (Adjustment.NonVirtual != 0) { + switch (MD->getAccess()) { + case AS_none: + llvm_unreachable("Unsupported access specifier"); + case AS_private: + Out << 'G'; + break; + case AS_protected: + Out << 'O'; + break; + case AS_public: + Out << 'W'; + } + Mangler.mangleNumber(-static_cast<uint32_t>(Adjustment.NonVirtual)); + } else { + switch (MD->getAccess()) { + case AS_none: + llvm_unreachable("Unsupported access specifier"); + case AS_private: + Out << 'A'; + break; + case AS_protected: + Out << 'I'; + break; + case AS_public: + Out << 'Q'; + } + } } -void MicrosoftMangleContext::mangleCXXDtorThunk(const CXXDestructorDecl *DD, - CXXDtorType Type, - const ThisAdjustment &, - raw_ostream &) { - unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle thunk for this destructor yet"); - getDiags().Report(DD->getLocation(), DiagID); + +void MicrosoftMangleContextImpl::mangleVirtualMemPtrThunk( + const CXXMethodDecl *MD, uint64_t OffsetInVFTable, raw_ostream &Out) { + bool Is64Bit = getASTContext().getTargetInfo().getPointerWidth(0) == 64; + + MicrosoftCXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "\01??_9"; + Mangler.mangleName(MD->getParent()); + Mangler.getStream() << "$B"; + Mangler.mangleNumber(OffsetInVFTable); + Mangler.getStream() << "A"; + Mangler.getStream() << (Is64Bit ? "A" : "E"); } -void MicrosoftMangleContext::mangleCXXVTable(const CXXRecordDecl *RD, + +void MicrosoftMangleContextImpl::mangleThunk(const CXXMethodDecl *MD, + const ThunkInfo &Thunk, raw_ostream &Out) { - // <mangled-name> ::= ? <operator-name> <class-name> <storage-class> - // <cvr-qualifiers> [<name>] @ - // <operator-name> ::= _7 # vftable - // ::= _8 # vbtable + MicrosoftCXXNameMangler Mangler(*this, Out); + Out << "\01?"; + Mangler.mangleName(MD); + mangleThunkThisAdjustment(MD, Thunk.This, Mangler, Out); + if (!Thunk.Return.isEmpty()) + assert(Thunk.Method != 0 && "Thunk info should hold the overridee decl"); + + const CXXMethodDecl *DeclForFPT = Thunk.Method ? Thunk.Method : MD; + Mangler.mangleFunctionType( + DeclForFPT->getType()->castAs<FunctionProtoType>(), MD); +} + +void MicrosoftMangleContextImpl::mangleCXXDtorThunk( + const CXXDestructorDecl *DD, CXXDtorType Type, + const ThisAdjustment &Adjustment, raw_ostream &Out) { + // FIXME: Actually, the dtor thunk should be emitted for vector deleting + // dtors rather than scalar deleting dtors. Just use the vector deleting dtor + // mangling manually until we support both deleting dtor types. + assert(Type == Dtor_Deleting); + MicrosoftCXXNameMangler Mangler(*this, Out, DD, Type); + Out << "\01??_E"; + Mangler.mangleName(DD->getParent()); + mangleThunkThisAdjustment(DD, Adjustment, Mangler, Out); + Mangler.mangleFunctionType(DD->getType()->castAs<FunctionProtoType>(), DD); +} + +void MicrosoftMangleContextImpl::mangleCXXVFTable( + const CXXRecordDecl *Derived, ArrayRef<const CXXRecordDecl *> BasePath, + raw_ostream &Out) { + // <mangled-name> ::= ?_7 <class-name> <storage-class> + // <cvr-qualifiers> [<name>] @ // NOTE: <cvr-qualifiers> here is always 'B' (const). <storage-class> - // is always '6' for vftables and '7' for vbtables. (The difference is - // beyond me.) - // TODO: vbtables. + // is always '6' for vftables. MicrosoftCXXNameMangler Mangler(*this, Out); Mangler.getStream() << "\01??_7"; - Mangler.mangleName(RD); - Mangler.getStream() << "6B"; - // TODO: If the class has more than one vtable, mangle in the class it came - // from. + Mangler.mangleName(Derived); + Mangler.getStream() << "6B"; // '6' for vftable, 'B' for const. + for (ArrayRef<const CXXRecordDecl *>::iterator I = BasePath.begin(), + E = BasePath.end(); + I != E; ++I) { + Mangler.mangleName(*I); + } Mangler.getStream() << '@'; } -void MicrosoftMangleContext::mangleCXXVTT(const CXXRecordDecl *RD, - 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, - raw_ostream &) { - llvm_unreachable("The MS C++ ABI does not have constructor vtables!"); + +void MicrosoftMangleContextImpl::mangleCXXVBTable( + const CXXRecordDecl *Derived, ArrayRef<const CXXRecordDecl *> BasePath, + raw_ostream &Out) { + // <mangled-name> ::= ?_8 <class-name> <storage-class> + // <cvr-qualifiers> [<name>] @ + // NOTE: <cvr-qualifiers> here is always 'B' (const). <storage-class> + // is always '7' for vbtables. + MicrosoftCXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "\01??_8"; + Mangler.mangleName(Derived); + Mangler.getStream() << "7B"; // '7' for vbtable, 'B' for const. + for (ArrayRef<const CXXRecordDecl *>::iterator I = BasePath.begin(), + E = BasePath.end(); + I != E; ++I) { + Mangler.mangleName(*I); + } + Mangler.getStream() << '@'; } -void MicrosoftMangleContext::mangleCXXRTTI(QualType T, - raw_ostream &) { + +void MicrosoftMangleContextImpl::mangleCXXRTTI(QualType T, raw_ostream &) { // FIXME: Give a location... unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error, "cannot mangle RTTI descriptors for type %0 yet"); getDiags().Report(DiagID) << T.getBaseTypeIdentifier(); } -void MicrosoftMangleContext::mangleCXXRTTIName(QualType T, - raw_ostream &) { + +void MicrosoftMangleContextImpl::mangleCXXRTTIName(QualType T, raw_ostream &) { // FIXME: Give a location... unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error, "cannot mangle the name of type %0 into RTTI descriptors yet"); getDiags().Report(DiagID) << T.getBaseTypeIdentifier(); } -void MicrosoftMangleContext::mangleCXXCtor(const CXXConstructorDecl *D, - CXXCtorType Type, - raw_ostream & Out) { + +void MicrosoftMangleContextImpl::mangleTypeName(QualType T, raw_ostream &Out) { + // This is just a made up unique string for the purposes of tbaa. undname + // does *not* know how to demangle it. + MicrosoftCXXNameMangler Mangler(*this, Out); + Mangler.getStream() << '?'; + Mangler.mangleType(T, SourceRange()); +} + +void MicrosoftMangleContextImpl::mangleCXXCtor(const CXXConstructorDecl *D, + CXXCtorType Type, + raw_ostream &Out) { MicrosoftCXXNameMangler mangler(*this, Out); mangler.mangle(D); } -void MicrosoftMangleContext::mangleCXXDtor(const CXXDestructorDecl *D, - CXXDtorType Type, - raw_ostream & Out) { + +void MicrosoftMangleContextImpl::mangleCXXDtor(const CXXDestructorDecl *D, + CXXDtorType Type, + raw_ostream &Out) { MicrosoftCXXNameMangler mangler(*this, Out, D, Type); mangler.mangle(D); } -void MicrosoftMangleContext::mangleReferenceTemporary(const clang::VarDecl *VD, - raw_ostream &) { + +void MicrosoftMangleContextImpl::mangleReferenceTemporary(const VarDecl *VD, + raw_ostream &) { unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error, "cannot mangle this reference temporary yet"); getDiags().Report(VD->getLocation(), DiagID); } -MangleContext *clang::createMicrosoftMangleContext(ASTContext &Context, - DiagnosticsEngine &Diags) { - return new MicrosoftMangleContext(Context, Diags); +void MicrosoftMangleContextImpl::mangleStaticGuardVariable(const VarDecl *VD, + raw_ostream &Out) { + // <guard-name> ::= ?_B <postfix> @51 + // ::= ?$S <guard-num> @ <postfix> @4IA + + // The first mangling is what MSVC uses to guard static locals in inline + // functions. It uses a different mangling in external functions to support + // guarding more than 32 variables. MSVC rejects inline functions with more + // than 32 static locals. We don't fully implement the second mangling + // because those guards are not externally visible, and instead use LLVM's + // default renaming when creating a new guard variable. + MicrosoftCXXNameMangler Mangler(*this, Out); + + bool Visible = VD->isExternallyVisible(); + // <operator-name> ::= ?_B # local static guard + Mangler.getStream() << (Visible ? "\01??_B" : "\01?$S1@"); + Mangler.manglePostfix(VD->getDeclContext()); + Mangler.getStream() << (Visible ? "@51" : "@4IA"); +} + +void MicrosoftMangleContextImpl::mangleInitFiniStub(const VarDecl *D, + raw_ostream &Out, + char CharCode) { + MicrosoftCXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "\01??__" << CharCode; + Mangler.mangleName(D); + // This is the function class mangling. These stubs are global, non-variadic, + // cdecl functions that return void and take no args. + Mangler.getStream() << "YAXXZ"; +} + +void MicrosoftMangleContextImpl::mangleDynamicInitializer(const VarDecl *D, + raw_ostream &Out) { + // <initializer-name> ::= ?__E <name> YAXXZ + mangleInitFiniStub(D, Out, 'E'); +} + +void +MicrosoftMangleContextImpl::mangleDynamicAtExitDestructor(const VarDecl *D, + raw_ostream &Out) { + // <destructor-name> ::= ?__F <name> YAXXZ + mangleInitFiniStub(D, Out, 'F'); +} + +MicrosoftMangleContext * +MicrosoftMangleContext::create(ASTContext &Context, DiagnosticsEngine &Diags) { + return new MicrosoftMangleContextImpl(Context, Diags); } diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp index 79cc21a..b03c4e0 100644 --- a/lib/AST/NestedNameSpecifier.cpp +++ b/lib/AST/NestedNameSpecifier.cpp @@ -566,8 +566,7 @@ void NestedNameSpecifierLocBuilder::MakeTrivial(ASTContext &Context, for (NestedNameSpecifier *NNS = Qualifier; NNS; NNS = NNS->getPrefix()) Stack.push_back(NNS); while (!Stack.empty()) { - NestedNameSpecifier *NNS = Stack.back(); - Stack.pop_back(); + NestedNameSpecifier *NNS = Stack.pop_back_val(); switch (NNS->getKind()) { case NestedNameSpecifier::Identifier: case NestedNameSpecifier::Namespace: diff --git a/lib/AST/ParentMap.cpp b/lib/AST/ParentMap.cpp index 1135928..ff44d93 100644 --- a/lib/AST/ParentMap.cpp +++ b/lib/AST/ParentMap.cpp @@ -14,6 +14,7 @@ #include "clang/AST/ParentMap.h" #include "clang/AST/Decl.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" #include "llvm/ADT/DenseMap.h" using namespace clang; @@ -33,6 +34,11 @@ static void BuildParentMap(MapTy& M, Stmt* S, assert(OVMode == OV_Transparent && "Should not appear alongside OVEs"); PseudoObjectExpr *POE = cast<PseudoObjectExpr>(S); + // If we are rebuilding the map, clear out any existing state. + if (M[POE->getSyntacticForm()]) + for (Stmt::child_range I = S->children(); I; ++I) + M[*I] = 0; + M[POE->getSyntacticForm()] = S; BuildParentMap(M, POE->getSyntacticForm(), OV_Transparent); @@ -62,13 +68,19 @@ static void BuildParentMap(MapTy& M, Stmt* S, break; } - case Stmt::OpaqueValueExprClass: - if (OVMode == OV_Transparent) { - OpaqueValueExpr *OVE = cast<OpaqueValueExpr>(S); + case Stmt::OpaqueValueExprClass: { + // FIXME: This isn't correct; it assumes that multiple OpaqueValueExprs + // share a single source expression, but in the AST a single + // OpaqueValueExpr is shared among multiple parent expressions. + // The right thing to do is to give the OpaqueValueExpr its syntactic + // parent, then not reassign that when traversing the semantic expressions. + OpaqueValueExpr *OVE = cast<OpaqueValueExpr>(S); + if (OVMode == OV_Transparent || !M[OVE->getSourceExpr()]) { M[OVE->getSourceExpr()] = S; BuildParentMap(M, OVE->getSourceExpr(), OV_Transparent); } break; + } default: for (Stmt::child_range I = S->children(); I; ++I) { if (*I) { @@ -98,6 +110,13 @@ void ParentMap::addStmt(Stmt* S) { } } +void ParentMap::setParent(const Stmt *S, const Stmt *Parent) { + assert(S); + assert(Parent); + MapTy *M = reinterpret_cast<MapTy *>(Impl); + M->insert(std::make_pair(const_cast<Stmt *>(S), const_cast<Stmt *>(Parent))); +} + Stmt* ParentMap::getParent(Stmt* S) const { MapTy* M = (MapTy*) Impl; MapTy::iterator I = M->find(S); @@ -139,8 +158,9 @@ bool ParentMap::isConsumedExpr(Expr* E) const { Stmt *P = getParent(E); Stmt *DirectChild = E; - // Ignore parents that are parentheses or casts. - while (P && (isa<ParenExpr>(P) || isa<CastExpr>(P))) { + // Ignore parents that don't guarantee consumption. + while (P && (isa<ParenExpr>(P) || isa<CastExpr>(P) || + isa<ExprWithCleanups>(P))) { DirectChild = P; P = getParent(P); } diff --git a/lib/AST/RawCommentList.cpp b/lib/AST/RawCommentList.cpp index 92b96dc..1fa7cea 100644 --- a/lib/AST/RawCommentList.cpp +++ b/lib/AST/RawCommentList.cpp @@ -68,8 +68,7 @@ RawComment::RawComment(const SourceManager &SourceMgr, SourceRange SR, bool Merged, bool ParseAllComments) : Range(SR), RawTextValid(false), BriefTextValid(false), IsAttached(false), IsAlmostTrailingComment(false), - ParseAllComments(ParseAllComments), - BeginLineValid(false), EndLineValid(false) { + ParseAllComments(ParseAllComments) { // Extract raw comment text, if possible. if (SR.getBegin() == SR.getEnd() || getRawText(SourceMgr).empty()) { Kind = RCK_Invalid; @@ -90,26 +89,6 @@ RawComment::RawComment(const SourceManager &SourceMgr, SourceRange SR, } } -unsigned RawComment::getBeginLine(const SourceManager &SM) const { - if (BeginLineValid) - return BeginLine; - - std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Range.getBegin()); - BeginLine = SM.getLineNumber(LocInfo.first, LocInfo.second); - BeginLineValid = true; - return BeginLine; -} - -unsigned RawComment::getEndLine(const SourceManager &SM) const { - if (EndLineValid) - return EndLine; - - std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Range.getEnd()); - EndLine = SM.getLineNumber(LocInfo.first, LocInfo.second); - EndLineValid = true; - return EndLine; -} - StringRef RawComment::getRawTextSlow(const SourceManager &SourceMgr) const { FileID BeginFileID; FileID EndFileID; @@ -184,13 +163,9 @@ comments::FullComment *RawComment::parse(const ASTContext &Context, return P.parseFullComment(); } -namespace { -bool containsOnlyWhitespace(StringRef Str) { - return Str.find_first_not_of(" \t\f\v\r\n") == StringRef::npos; -} - -bool onlyWhitespaceBetween(SourceManager &SM, - SourceLocation Loc1, SourceLocation Loc2) { +static bool onlyWhitespaceBetween(SourceManager &SM, + SourceLocation Loc1, SourceLocation Loc2, + unsigned MaxNewlinesAllowed) { std::pair<FileID, unsigned> Loc1Info = SM.getDecomposedLoc(Loc1); std::pair<FileID, unsigned> Loc2Info = SM.getDecomposedLoc(Loc2); @@ -203,10 +178,38 @@ bool onlyWhitespaceBetween(SourceManager &SM, if (Invalid) return false; - StringRef Text(Buffer + Loc1Info.second, Loc2Info.second - Loc1Info.second); - return containsOnlyWhitespace(Text); + unsigned NumNewlines = 0; + assert(Loc1Info.second <= Loc2Info.second && "Loc1 after Loc2!"); + // Look for non-whitespace characters and remember any newlines seen. + for (unsigned I = Loc1Info.second; I != Loc2Info.second; ++I) { + switch (Buffer[I]) { + default: + return false; + case ' ': + case '\t': + case '\f': + case '\v': + break; + case '\r': + case '\n': + ++NumNewlines; + + // Check if we have found more than the maximum allowed number of + // newlines. + if (NumNewlines > MaxNewlinesAllowed) + return false; + + // Collapse \r\n and \n\r into a single newline. + if (I + 1 != Loc2Info.second && + (Buffer[I + 1] == '\n' || Buffer[I + 1] == '\r') && + Buffer[I] != Buffer[I + 1]) + ++I; + break; + } + } + + return true; } -} // unnamed namespace void RawCommentList::addComment(const RawComment &RC, llvm::BumpPtrAllocator &Allocator) { @@ -215,23 +218,13 @@ void RawCommentList::addComment(const RawComment &RC, // Check if the comments are not in source order. while (!Comments.empty() && - !SourceMgr.isBeforeInTranslationUnit( - Comments.back()->getSourceRange().getBegin(), - RC.getSourceRange().getBegin())) { + !SourceMgr.isBeforeInTranslationUnit(Comments.back()->getLocStart(), + RC.getLocStart())) { // If they are, just pop a few last comments that don't fit. // This happens if an \#include directive contains comments. Comments.pop_back(); } - if (OnlyWhitespaceSeen) { - if (!onlyWhitespaceBetween(SourceMgr, - PrevCommentEndLoc, - RC.getSourceRange().getBegin())) - OnlyWhitespaceSeen = false; - } - - PrevCommentEndLoc = RC.getSourceRange().getEnd(); - // Ordinary comments are not interesting for us. if (RC.isOrdinary()) return; @@ -240,7 +233,6 @@ void RawCommentList::addComment(const RawComment &RC, // anything to merge it with). if (Comments.empty()) { Comments.push_back(new (Allocator) RawComment(RC)); - OnlyWhitespaceSeen = true; return; } @@ -250,21 +242,13 @@ void RawCommentList::addComment(const RawComment &RC, // Merge comments only if there is only whitespace between them. // Can't merge trailing and non-trailing comments. // Merge comments if they are on same or consecutive lines. - bool Merged = false; - if (OnlyWhitespaceSeen && - (C1.isTrailingComment() == C2.isTrailingComment())) { - unsigned C1EndLine = C1.getEndLine(SourceMgr); - unsigned C2BeginLine = C2.getBeginLine(SourceMgr); - if (C1EndLine + 1 == C2BeginLine || C1EndLine == C2BeginLine) { - SourceRange MergedRange(C1.getSourceRange().getBegin(), - C2.getSourceRange().getEnd()); - *Comments.back() = RawComment(SourceMgr, MergedRange, true, - RC.isParseAllComments()); - Merged = true; - } - } - if (!Merged) + if (C1.isTrailingComment() == C2.isTrailingComment() && + onlyWhitespaceBetween(SourceMgr, C1.getLocEnd(), C2.getLocStart(), + /*MaxNewlinesAllowed=*/1)) { + SourceRange MergedRange(C1.getLocStart(), C2.getLocEnd()); + *Comments.back() = RawComment(SourceMgr, MergedRange, true, + RC.isParseAllComments()); + } else { Comments.push_back(new (Allocator) RawComment(RC)); - - OnlyWhitespaceSeen = true; + } } diff --git a/lib/AST/RecordLayout.cpp b/lib/AST/RecordLayout.cpp index f6cfe63..71e44ec 100644 --- a/lib/AST/RecordLayout.cpp +++ b/lib/AST/RecordLayout.cpp @@ -43,7 +43,8 @@ ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx, CharUnits size, // Constructor for C++ records. ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx, CharUnits size, CharUnits alignment, - bool hasOwnVFPtr, CharUnits vbptroffset, + bool hasOwnVFPtr, bool hasExtendableVFPtr, + CharUnits vbptroffset, CharUnits datasize, const uint64_t *fieldoffsets, unsigned fieldcount, @@ -52,6 +53,8 @@ ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx, CharUnits SizeOfLargestEmptySubobject, const CXXRecordDecl *PrimaryBase, bool IsPrimaryBaseVirtual, + const CXXRecordDecl *BaseSharingVBPtr, + bool AlignAfterVBases, const BaseOffsetsMapTy& BaseOffsets, const VBaseOffsetsMapTy& VBaseOffsets) : Size(size), DataSize(datasize), Alignment(alignment), FieldOffsets(0), @@ -71,6 +74,10 @@ ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx, CXXInfo->VBaseOffsets = VBaseOffsets; CXXInfo->HasOwnVFPtr = hasOwnVFPtr; CXXInfo->VBPtrOffset = vbptroffset; + CXXInfo->HasExtendableVFPtr = hasExtendableVFPtr; + CXXInfo->BaseSharingVBPtr = BaseSharingVBPtr; + CXXInfo->AlignAfterVBases = AlignAfterVBases; + #ifndef NDEBUG if (const CXXRecordDecl *PrimaryBase = getPrimaryBase()) { diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index 42c3ba3..4390e66 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -211,7 +211,7 @@ void EmptySubobjectMap::AddSubobjectAtOffset(const CXXRecordDecl *RD, if (!RD->isEmpty()) return; - // If we have empty structures inside an union, we can assign both + // If we have empty structures inside a union, we can assign both // the same offset. Just avoid pushing them twice in the list. ClassVectorTy& Classes = EmptyClassOffsets[Offset]; if (std::find(Classes.begin(), Classes.end(), RD) != Classes.end()) @@ -573,10 +573,14 @@ protected: unsigned IsMsStruct : 1; - /// UnfilledBitsInLastByte - If the last field laid out was a bitfield, - /// this contains the number of bits in the last byte that can be used for - /// an adjacent bitfield if necessary. - unsigned char UnfilledBitsInLastByte; + /// UnfilledBitsInLastUnit - If the last field laid out was a bitfield, + /// this contains the number of bits in the last unit that can be used for + /// an adjacent bitfield if necessary. The unit in question is usually + /// a byte, but larger units are used if IsMsStruct. + unsigned char UnfilledBitsInLastUnit; + /// LastBitfieldTypeSize - If IsMsStruct, represents the size of the type + /// of the previous field if it was a bitfield. + unsigned char LastBitfieldTypeSize; /// MaxFieldAlignment - The maximum allowed field alignment. This is set by /// #pragma pack. @@ -588,8 +592,6 @@ protected: CharUnits NonVirtualSize; CharUnits NonVirtualAlignment; - FieldDecl *ZeroLengthBitfield; - /// PrimaryBase - the primary base class (if one exists) of the class /// we're laying out. const CXXRecordDecl *PrimaryBase; @@ -602,9 +604,6 @@ protected: /// pointer, as opposed to inheriting one from a primary base class. bool HasOwnVFPtr; - /// VBPtrOffset - Virtual base table offset. Only for MS layout. - CharUnits VBPtrOffset; - typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsetsMapTy; /// Bases - base classes and their offsets in the record. @@ -646,13 +645,12 @@ protected: Alignment(CharUnits::One()), UnpackedAlignment(CharUnits::One()), ExternalLayout(false), InferAlignment(false), Packed(false), IsUnion(false), IsMac68kAlign(false), IsMsStruct(false), - UnfilledBitsInLastByte(0), MaxFieldAlignment(CharUnits::Zero()), + UnfilledBitsInLastUnit(0), LastBitfieldTypeSize(0), + MaxFieldAlignment(CharUnits::Zero()), DataSize(0), NonVirtualSize(CharUnits::Zero()), NonVirtualAlignment(CharUnits::One()), - ZeroLengthBitfield(0), PrimaryBase(0), - PrimaryBaseIsVirtual(false), + PrimaryBase(0), PrimaryBaseIsVirtual(false), HasOwnVFPtr(false), - VBPtrOffset(CharUnits::fromQuantity(-1)), FirstNearlyEmptyVBase(0) { } /// Reset this RecordLayoutBuilder to a fresh state, using the given @@ -680,12 +678,6 @@ protected: return Context.getTargetInfo().getCXXABI(); } - bool isMicrosoftCXXABI() const { - return getCXXABI().isMicrosoft(); - } - - void MSLayoutVirtualBases(const CXXRecordDecl *RD); - /// BaseSubobjectInfoAllocator - Allocator for BaseSubobjectInfo objects. llvm::SpecificBumpPtrAllocator<BaseSubobjectInfo> BaseSubobjectInfoAllocator; @@ -727,21 +719,12 @@ protected: void AddPrimaryVirtualBaseOffsets(const BaseSubobjectInfo *Info, CharUnits Offset); - bool needsVFTable(const CXXRecordDecl *RD) const; - bool hasNewVirtualFunction(const CXXRecordDecl *RD, - bool IgnoreDestructor = false) const; - bool isPossiblePrimaryBase(const CXXRecordDecl *Base) const; - - void computeVtordisps(const CXXRecordDecl *RD, - ClassSetTy &VtordispVBases); - /// LayoutVirtualBases - Lays out all the virtual bases. void LayoutVirtualBases(const CXXRecordDecl *RD, const CXXRecordDecl *MostDerivedClass); /// LayoutVirtualBase - Lays out a single virtual base. - void LayoutVirtualBase(const BaseSubobjectInfo *Base, - bool IsVtordispNeed = false); + void LayoutVirtualBase(const BaseSubobjectInfo *Base); /// LayoutBase - Will lay out a base and return the offset where it was /// placed, in chars. @@ -851,7 +834,7 @@ void RecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) { const CXXRecordDecl *Base = cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); - if (isPossiblePrimaryBase(Base)) { + if (Base->isDynamicClass()) { // We found it. PrimaryBase = Base; PrimaryBaseIsVirtual = false; @@ -859,12 +842,6 @@ void RecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) { } } - // The Microsoft ABI doesn't have primary virtual bases. - if (isMicrosoftCXXABI()) { - assert(!PrimaryBase && "Should not get here with a primary base!"); - return; - } - // Under the Itanium ABI, if there is no non-virtual primary base class, // try to compute the primary virtual base. The primary virtual base is // the first nearly empty virtual base that is not an indirect primary @@ -1043,7 +1020,7 @@ RecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) { // If this class needs a vtable/vf-table and didn't get one from a // primary base, add it in now. - } else if (needsVFTable(RD)) { + } else if (RD->isDynamicClass()) { assert(DataSize == 0 && "Vtable pointer must be at offset zero!"); CharUnits PtrWidth = Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0)); @@ -1055,26 +1032,17 @@ RecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) { setDataSize(getSize()); } - bool HasDirectVirtualBases = false; - bool HasNonVirtualBaseWithVBTable = false; - // Now lay out the non-virtual bases. for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), E = RD->bases_end(); I != E; ++I) { - // Ignore virtual bases, but remember that we saw one. - if (I->isVirtual()) { - HasDirectVirtualBases = true; + // Ignore virtual bases. + if (I->isVirtual()) continue; - } const CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(I->getType()->castAs<RecordType>()->getDecl()); - // Remember if this base has virtual bases itself. - if (BaseDecl->getNumVBases()) - HasNonVirtualBaseWithVBTable = true; - // Skip the primary base, because we've already laid it out. The // !PrimaryBaseIsVirtual check is required because we might have a // non-virtual base of the same type as a primary virtual base. @@ -1087,37 +1055,6 @@ RecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) { LayoutNonVirtualBase(BaseInfo); } - - // In the MS ABI, add the vb-table pointer if we need one, which is - // whenever we have a virtual base and we can't re-use a vb-table - // pointer from a non-virtual base. - if (isMicrosoftCXXABI() && - HasDirectVirtualBases && !HasNonVirtualBaseWithVBTable) { - CharUnits PtrWidth = - Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0)); - CharUnits PtrAlign = - Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerAlign(0)); - - // MSVC potentially over-aligns the vb-table pointer by giving it - // the max alignment of all the non-virtual objects in the class. - // This is completely unnecessary, but we're not here to pass - // judgment. - // - // Note that we've only laid out the non-virtual bases, so on the - // first pass Alignment won't be set correctly here, but if the - // vb-table doesn't end up aligned correctly we'll come through - // and redo the layout from scratch with the right alignment. - // - // TODO: Instead of doing this, just lay out the fields as if the - // vb-table were at offset zero, then retroactively bump the field - // offsets up. - PtrAlign = std::max(PtrAlign, Alignment); - - EnsureVTablePointerAlignment(PtrAlign); - VBPtrOffset = getSize(); - setSize(getSize() + PtrWidth); - setDataSize(getSize()); - } } void RecordLayoutBuilder::LayoutNonVirtualBase(const BaseSubobjectInfo *Base) { @@ -1166,249 +1103,6 @@ RecordLayoutBuilder::AddPrimaryVirtualBaseOffsets(const BaseSubobjectInfo *Info, } } -/// needsVFTable - Return true if this class needs a vtable or vf-table -/// when laid out as a base class. These are treated the same because -/// they're both always laid out at offset zero. -/// -/// This function assumes that the class has no primary base. -bool RecordLayoutBuilder::needsVFTable(const CXXRecordDecl *RD) const { - assert(!PrimaryBase); - - // In the Itanium ABI, every dynamic class needs a vtable: even if - // this class has no virtual functions as a base class (i.e. it's - // non-polymorphic or only has virtual functions from virtual - // bases),x it still needs a vtable to locate its virtual bases. - if (!isMicrosoftCXXABI()) - return RD->isDynamicClass(); - - // In the MS ABI, we need a vfptr if the class has virtual functions - // other than those declared by its virtual bases. The AST doesn't - // tell us that directly, and checking manually for virtual - // functions that aren't overrides is expensive, but there are - // some important shortcuts: - - // - Non-polymorphic classes have no virtual functions at all. - if (!RD->isPolymorphic()) return false; - - // - Polymorphic classes with no virtual bases must either declare - // virtual functions directly or inherit them, but in the latter - // case we would have a primary base. - if (RD->getNumVBases() == 0) return true; - - return hasNewVirtualFunction(RD); -} - -/// Does the given class inherit non-virtually from any of the classes -/// in the given set? -static bool hasNonVirtualBaseInSet(const CXXRecordDecl *RD, - const ClassSetTy &set) { - for (CXXRecordDecl::base_class_const_iterator - I = RD->bases_begin(), E = RD->bases_end(); I != E; ++I) { - // Ignore virtual links. - if (I->isVirtual()) continue; - - // Check whether the set contains the base. - const CXXRecordDecl *base = I->getType()->getAsCXXRecordDecl(); - if (set.count(base)) - return true; - - // Otherwise, recurse and propagate. - if (hasNonVirtualBaseInSet(base, set)) - return true; - } - - return false; -} - -/// Does the given method (B::foo()) already override a method (A::foo()) -/// such that A requires a vtordisp in B? If so, we don't need to add a -/// new vtordisp for B in a yet-more-derived class C providing C::foo(). -static bool overridesMethodRequiringVtorDisp(const ASTContext &Context, - const CXXMethodDecl *M) { - CXXMethodDecl::method_iterator - I = M->begin_overridden_methods(), E = M->end_overridden_methods(); - if (I == E) return false; - - const ASTRecordLayout::VBaseOffsetsMapTy &offsets = - Context.getASTRecordLayout(M->getParent()).getVBaseOffsetsMap(); - do { - const CXXMethodDecl *overridden = *I; - - // If the overridden method's class isn't recognized as a virtual - // base in the derived class, ignore it. - ASTRecordLayout::VBaseOffsetsMapTy::const_iterator - it = offsets.find(overridden->getParent()); - if (it == offsets.end()) continue; - - // Otherwise, check if the overridden method's class needs a vtordisp. - if (it->second.hasVtorDisp()) return true; - - } while (++I != E); - return false; -} - -/// In the Microsoft ABI, decide which of the virtual bases require a -/// vtordisp field. -void RecordLayoutBuilder::computeVtordisps(const CXXRecordDecl *RD, - ClassSetTy &vtordispVBases) { - // Bail out if we have no virtual bases. - assert(RD->getNumVBases()); - - // Build up the set of virtual bases that we haven't decided yet. - ClassSetTy undecidedVBases; - for (CXXRecordDecl::base_class_const_iterator - I = RD->vbases_begin(), E = RD->vbases_end(); I != E; ++I) { - const CXXRecordDecl *vbase = I->getType()->getAsCXXRecordDecl(); - undecidedVBases.insert(vbase); - } - assert(!undecidedVBases.empty()); - - // A virtual base requires a vtordisp field in a derived class if it - // requires a vtordisp field in a base class. Walk all the direct - // bases and collect this information. - for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), - E = RD->bases_end(); I != E; ++I) { - const CXXRecordDecl *base = I->getType()->getAsCXXRecordDecl(); - const ASTRecordLayout &baseLayout = Context.getASTRecordLayout(base); - - // Iterate over the set of virtual bases provided by this class. - for (ASTRecordLayout::VBaseOffsetsMapTy::const_iterator - VI = baseLayout.getVBaseOffsetsMap().begin(), - VE = baseLayout.getVBaseOffsetsMap().end(); VI != VE; ++VI) { - // If it doesn't need a vtordisp in this base, ignore it. - if (!VI->second.hasVtorDisp()) continue; - - // If we've already seen it and decided it needs a vtordisp, ignore it. - if (!undecidedVBases.erase(VI->first)) - continue; - - // Add it. - vtordispVBases.insert(VI->first); - - // Quit as soon as we've decided everything. - if (undecidedVBases.empty()) - return; - } - } - - // Okay, we have virtual bases that we haven't yet decided about. A - // virtual base requires a vtordisp if any the non-destructor - // virtual methods declared in this class directly override a method - // provided by that virtual base. (If so, we need to emit a thunk - // for that method, to be used in the construction vftable, which - // applies an additional 'vtordisp' this-adjustment.) - - // Collect the set of bases directly overridden by any method in this class. - // It's possible that some of these classes won't be virtual bases, or won't be - // provided by virtual bases, or won't be virtual bases in the overridden - // instance but are virtual bases elsewhere. Only the last matters for what - // we're doing, and we can ignore those: if we don't directly override - // a method provided by a virtual copy of a base class, but we do directly - // override a method provided by a non-virtual copy of that base class, - // then we must indirectly override the method provided by the virtual base, - // and so we should already have collected it in the loop above. - ClassSetTy overriddenBases; - for (CXXRecordDecl::method_iterator - M = RD->method_begin(), E = RD->method_end(); M != E; ++M) { - // Ignore non-virtual methods and destructors. - if (isa<CXXDestructorDecl>(*M) || !M->isVirtual()) - continue; - - for (CXXMethodDecl::method_iterator I = M->begin_overridden_methods(), - E = M->end_overridden_methods(); I != E; ++I) { - const CXXMethodDecl *overriddenMethod = (*I); - - // Ignore methods that override methods from vbases that require - // require vtordisps. - if (overridesMethodRequiringVtorDisp(Context, overriddenMethod)) - continue; - - // As an optimization, check immediately whether we're overriding - // something from the undecided set. - const CXXRecordDecl *overriddenBase = overriddenMethod->getParent(); - if (undecidedVBases.erase(overriddenBase)) { - vtordispVBases.insert(overriddenBase); - if (undecidedVBases.empty()) return; - - // We can't 'continue;' here because one of our undecided - // vbases might non-virtually inherit from this base. - // Consider: - // struct A { virtual void foo(); }; - // struct B : A {}; - // struct C : virtual A, virtual B { virtual void foo(); }; - // We need a vtordisp for B here. - } - - // Otherwise, just collect it. - overriddenBases.insert(overriddenBase); - } - } - - // Walk the undecided v-bases and check whether they (non-virtually) - // provide any of the overridden bases. We don't need to consider - // virtual links because the vtordisp inheres to the layout - // subobject containing the base. - for (ClassSetTy::const_iterator - I = undecidedVBases.begin(), E = undecidedVBases.end(); I != E; ++I) { - if (hasNonVirtualBaseInSet(*I, overriddenBases)) - vtordispVBases.insert(*I); - } -} - -/// hasNewVirtualFunction - Does the given polymorphic class declare a -/// virtual function that does not override a method from any of its -/// base classes? -bool -RecordLayoutBuilder::hasNewVirtualFunction(const CXXRecordDecl *RD, - bool IgnoreDestructor) const { - if (!RD->getNumBases()) - return true; - - for (CXXRecordDecl::method_iterator method = RD->method_begin(); - method != RD->method_end(); - ++method) { - if (method->isVirtual() && !method->size_overridden_methods() && - !(IgnoreDestructor && method->getKind() == Decl::CXXDestructor)) { - return true; - } - } - return false; -} - -/// isPossiblePrimaryBase - Is the given base class an acceptable -/// primary base class? -bool -RecordLayoutBuilder::isPossiblePrimaryBase(const CXXRecordDecl *base) const { - // In the Itanium ABI, a class can be a primary base class if it has - // a vtable for any reason. - if (!isMicrosoftCXXABI()) - return base->isDynamicClass(); - - // In the MS ABI, a class can only be a primary base class if it - // provides a vf-table at a static offset. That means it has to be - // non-virtual base. The existence of a separate vb-table means - // that it's possible to get virtual functions only from a virtual - // base, which we have to guard against. - - // First off, it has to have virtual functions. - if (!base->isPolymorphic()) return false; - - // If it has no virtual bases, then the vfptr must be at a static offset. - if (!base->getNumVBases()) return true; - - // Otherwise, the necessary information is cached in the layout. - const ASTRecordLayout &layout = Context.getASTRecordLayout(base); - - // If the base has its own vfptr, it can be a primary base. - if (layout.hasOwnVFPtr()) return true; - - // If the base has a primary base class, then it can be a primary base. - if (layout.getPrimaryBase()) return true; - - // Otherwise it can't. - return false; -} - void RecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD, const CXXRecordDecl *MostDerivedClass) { @@ -1458,39 +1152,7 @@ RecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD, } } -void RecordLayoutBuilder::MSLayoutVirtualBases(const CXXRecordDecl *RD) { - if (!RD->getNumVBases()) - return; - - ClassSetTy VtordispVBases; - computeVtordisps(RD, VtordispVBases); - - // This is substantially simplified because there are no virtual - // primary bases. - for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(), - E = RD->vbases_end(); I != E; ++I) { - const CXXRecordDecl *BaseDecl = I->getType()->getAsCXXRecordDecl(); - const BaseSubobjectInfo *BaseInfo = VirtualBaseInfo.lookup(BaseDecl); - assert(BaseInfo && "Did not find virtual base info!"); - - // If this base requires a vtordisp, add enough space for an int field. - // This is apparently always 32-bits, even on x64. - bool vtordispNeeded = false; - if (VtordispVBases.count(BaseDecl)) { - CharUnits IntSize = - CharUnits::fromQuantity(Context.getTargetInfo().getIntWidth() / 8); - - setSize(getSize() + IntSize); - setDataSize(getSize()); - vtordispNeeded = true; - } - - LayoutVirtualBase(BaseInfo, vtordispNeeded); - } -} - -void RecordLayoutBuilder::LayoutVirtualBase(const BaseSubobjectInfo *Base, - bool IsVtordispNeed) { +void RecordLayoutBuilder::LayoutVirtualBase(const BaseSubobjectInfo *Base) { assert(!Base->Derived && "Trying to lay out a primary virtual base!"); // Layout the base. @@ -1499,10 +1161,9 @@ void RecordLayoutBuilder::LayoutVirtualBase(const BaseSubobjectInfo *Base, // Add its base class offset. assert(!VBases.count(Base->Class) && "vbase offset already exists!"); VBases.insert(std::make_pair(Base->Class, - ASTRecordLayout::VBaseInfo(Offset, IsVtordispNeed))); + ASTRecordLayout::VBaseInfo(Offset, false))); - if (!isMicrosoftCXXABI()) - AddPrimaryVirtualBaseOffsets(Base, Offset); + AddPrimaryVirtualBaseOffsets(Base, Offset); } CharUnits RecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) { @@ -1530,18 +1191,19 @@ CharUnits RecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) { } } + CharUnits UnpackedBaseAlign = Layout.getNonVirtualAlign(); + CharUnits BaseAlign = (Packed) ? CharUnits::One() : UnpackedBaseAlign; + // If we have an empty base class, try to place it at offset 0. if (Base->Class->isEmpty() && (!HasExternalLayout || Offset == CharUnits::Zero()) && EmptySubobjects->CanPlaceBaseAtOffset(Base, CharUnits::Zero())) { setSize(std::max(getSize(), Layout.getSize())); + UpdateAlignment(BaseAlign, UnpackedBaseAlign); return CharUnits::Zero(); } - 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); @@ -1655,24 +1317,8 @@ void RecordLayoutBuilder::Layout(const CXXRecordDecl *RD) { Context.getTargetInfo().getCharAlign())); NonVirtualAlignment = Alignment; - if (isMicrosoftCXXABI()) { - if (NonVirtualSize != NonVirtualSize.RoundUpToAlignment(Alignment)) { - CharUnits AlignMember = - NonVirtualSize.RoundUpToAlignment(Alignment) - NonVirtualSize; - - setSize(getSize() + AlignMember); - setDataSize(getSize()); - - NonVirtualSize = Context.toCharUnitsFromBits( - llvm::RoundUpToAlignment(getSizeInBits(), - Context.getTargetInfo().getCharAlign())); - } - - MSLayoutVirtualBases(RD); - } else { - // Lay out the virtual bases and add the primary virtual base offsets. - LayoutVirtualBases(RD, RD); - } + // Lay out the virtual bases and add the primary virtual base offsets. + LayoutVirtualBases(RD, RD); // Finally, round the size of the total struct up to the alignment // of the struct itself. @@ -1728,123 +1374,9 @@ void RecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D) { void RecordLayoutBuilder::LayoutFields(const RecordDecl *D) { // Layout each field, for now, just sequentially, respecting alignment. In // the future, this will need to be tweakable by targets. - const FieldDecl *LastFD = 0; - ZeroLengthBitfield = 0; - unsigned RemainingInAlignment = 0; for (RecordDecl::field_iterator Field = D->field_begin(), - FieldEnd = D->field_end(); Field != FieldEnd; ++Field) { - if (IsMsStruct) { - FieldDecl *FD = *Field; - if (Context.ZeroBitfieldFollowsBitfield(FD, LastFD)) - ZeroLengthBitfield = FD; - // Zero-length bitfields following non-bitfield members are - // ignored: - else if (Context.ZeroBitfieldFollowsNonBitfield(FD, LastFD)) - continue; - // FIXME. streamline these conditions into a simple one. - else if (Context.BitfieldFollowsBitfield(FD, LastFD) || - Context.BitfieldFollowsNonBitfield(FD, LastFD) || - Context.NonBitfieldFollowsBitfield(FD, LastFD)) { - // 1) Adjacent bit fields are packed into the same 1-, 2-, or - // 4-byte allocation unit if the integral types are the same - // size and if the next bit field fits into the current - // allocation unit without crossing the boundary imposed by the - // common alignment requirements of the bit fields. - // 2) Establish a new alignment for a bitfield following - // a non-bitfield if size of their types differ. - // 3) Establish a new alignment for a non-bitfield following - // a bitfield if size of their types differ. - std::pair<uint64_t, unsigned> FieldInfo = - Context.getTypeInfo(FD->getType()); - uint64_t TypeSize = FieldInfo.first; - unsigned FieldAlign = FieldInfo.second; - // This check is needed for 'long long' in -m32 mode. - if (TypeSize > FieldAlign && - (Context.hasSameType(FD->getType(), - Context.UnsignedLongLongTy) - ||Context.hasSameType(FD->getType(), - Context.LongLongTy))) - FieldAlign = TypeSize; - FieldInfo = Context.getTypeInfo(LastFD->getType()); - uint64_t TypeSizeLastFD = FieldInfo.first; - unsigned FieldAlignLastFD = FieldInfo.second; - // This check is needed for 'long long' in -m32 mode. - if (TypeSizeLastFD > FieldAlignLastFD && - (Context.hasSameType(LastFD->getType(), - Context.UnsignedLongLongTy) - || Context.hasSameType(LastFD->getType(), - Context.LongLongTy))) - FieldAlignLastFD = TypeSizeLastFD; - - if (TypeSizeLastFD != TypeSize) { - if (RemainingInAlignment && - LastFD && LastFD->isBitField() && - LastFD->getBitWidthValue(Context)) { - // If previous field was a bitfield with some remaining unfilled - // bits, pad the field so current field starts on its type boundary. - uint64_t FieldOffset = - getDataSizeInBits() - UnfilledBitsInLastByte; - uint64_t NewSizeInBits = RemainingInAlignment + FieldOffset; - setDataSize(llvm::RoundUpToAlignment(NewSizeInBits, - Context.getTargetInfo().getCharAlign())); - setSize(std::max(getSizeInBits(), getDataSizeInBits())); - RemainingInAlignment = 0; - } - - uint64_t UnpaddedFieldOffset = - getDataSizeInBits() - UnfilledBitsInLastByte; - FieldAlign = std::max(FieldAlign, FieldAlignLastFD); - - // The maximum field alignment overrides the aligned attribute. - if (!MaxFieldAlignment.isZero()) { - unsigned MaxFieldAlignmentInBits = - Context.toBits(MaxFieldAlignment); - FieldAlign = std::min(FieldAlign, MaxFieldAlignmentInBits); - } - - uint64_t NewSizeInBits = - llvm::RoundUpToAlignment(UnpaddedFieldOffset, FieldAlign); - setDataSize(llvm::RoundUpToAlignment(NewSizeInBits, - Context.getTargetInfo().getCharAlign())); - UnfilledBitsInLastByte = getDataSizeInBits() - NewSizeInBits; - setSize(std::max(getSizeInBits(), getDataSizeInBits())); - } - if (FD->isBitField()) { - uint64_t FieldSize = FD->getBitWidthValue(Context); - assert (FieldSize > 0 && "LayoutFields - ms_struct layout"); - if (RemainingInAlignment < FieldSize) - RemainingInAlignment = TypeSize - FieldSize; - else - RemainingInAlignment -= FieldSize; - } - } - else if (FD->isBitField()) { - uint64_t FieldSize = FD->getBitWidthValue(Context); - std::pair<uint64_t, unsigned> FieldInfo = - Context.getTypeInfo(FD->getType()); - uint64_t TypeSize = FieldInfo.first; - RemainingInAlignment = TypeSize - FieldSize; - } - LastFD = FD; - } - else if (!Context.getTargetInfo().useBitFieldTypeAlignment() && - Context.getTargetInfo().useZeroLengthBitfieldAlignment()) { - if (Field->isBitField() && Field->getBitWidthValue(Context) == 0) - ZeroLengthBitfield = *Field; - } + FieldEnd = D->field_end(); Field != FieldEnd; ++Field) LayoutField(*Field); - } - if (IsMsStruct && RemainingInAlignment && - LastFD && LastFD->isBitField() && LastFD->getBitWidthValue(Context)) { - // If we ended a bitfield before the full length of the type then - // pad the struct out to the full length of the last type. - uint64_t FieldOffset = - getDataSizeInBits() - UnfilledBitsInLastByte; - uint64_t NewSizeInBits = RemainingInAlignment + FieldOffset; - setDataSize(llvm::RoundUpToAlignment(NewSizeInBits, - Context.getTargetInfo().getCharAlign())); - setSize(std::max(getSizeInBits(), getDataSizeInBits())); - } } void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize, @@ -1878,10 +1410,11 @@ void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize, CharUnits TypeAlign = Context.getTypeAlignInChars(Type); // We're not going to use any of the unfilled bits in the last byte. - UnfilledBitsInLastByte = 0; + UnfilledBitsInLastUnit = 0; + LastBitfieldTypeSize = 0; uint64_t FieldOffset; - uint64_t UnpaddedFieldOffset = getDataSizeInBits() - UnfilledBitsInLastByte; + uint64_t UnpaddedFieldOffset = getDataSizeInBits() - UnfilledBitsInLastUnit; if (IsUnion) { setDataSize(std::max(getDataSizeInBits(), FieldSize)); @@ -1896,7 +1429,7 @@ void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize, setDataSize(llvm::RoundUpToAlignment(NewSizeInBits, Context.getTargetInfo().getCharAlign())); - UnfilledBitsInLastByte = getDataSizeInBits() - NewSizeInBits; + UnfilledBitsInLastUnit = getDataSizeInBits() - NewSizeInBits; } // Place this field at the current location. @@ -1914,49 +1447,43 @@ void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize, void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { bool FieldPacked = Packed || D->hasAttr<PackedAttr>(); - uint64_t UnpaddedFieldOffset = getDataSizeInBits() - UnfilledBitsInLastByte; - uint64_t FieldOffset = IsUnion ? 0 : UnpaddedFieldOffset; uint64_t FieldSize = D->getBitWidthValue(Context); - std::pair<uint64_t, unsigned> FieldInfo = Context.getTypeInfo(D->getType()); uint64_t TypeSize = FieldInfo.first; unsigned FieldAlign = FieldInfo.second; - - // This check is needed for 'long long' in -m32 mode. - if (IsMsStruct && (TypeSize > FieldAlign) && - (Context.hasSameType(D->getType(), - Context.UnsignedLongLongTy) - || Context.hasSameType(D->getType(), Context.LongLongTy))) - FieldAlign = TypeSize; - if (ZeroLengthBitfield) { - std::pair<uint64_t, unsigned> FieldInfo; - unsigned ZeroLengthBitfieldAlignment; - if (IsMsStruct) { - // If a zero-length bitfield is inserted after a bitfield, - // and the alignment of the zero-length bitfield is - // greater than the member that follows it, `bar', `bar' - // will be aligned as the type of the zero-length bitfield. - if (ZeroLengthBitfield != D) { - FieldInfo = Context.getTypeInfo(ZeroLengthBitfield->getType()); - ZeroLengthBitfieldAlignment = FieldInfo.second; - // Ignore alignment of subsequent zero-length bitfields. - if ((ZeroLengthBitfieldAlignment > FieldAlign) || (FieldSize == 0)) - FieldAlign = ZeroLengthBitfieldAlignment; - if (FieldSize) - ZeroLengthBitfield = 0; - } - } else { - // The alignment of a zero-length bitfield affects the alignment - // of the next member. The alignment is the max of the zero - // length bitfield's alignment and a target specific fixed value. - unsigned ZeroLengthBitfieldBoundary = - Context.getTargetInfo().getZeroLengthBitfieldBoundary(); - if (ZeroLengthBitfieldBoundary > FieldAlign) - FieldAlign = ZeroLengthBitfieldBoundary; + if (IsMsStruct) { + // The field alignment for integer types in ms_struct structs is + // always the size. + FieldAlign = TypeSize; + // Ignore zero-length bitfields after non-bitfields in ms_struct structs. + if (!FieldSize && !LastBitfieldTypeSize) + FieldAlign = 1; + // If a bitfield is followed by a bitfield of a different size, don't + // pack the bits together in ms_struct structs. + if (LastBitfieldTypeSize != TypeSize) { + UnfilledBitsInLastUnit = 0; + LastBitfieldTypeSize = 0; } } + uint64_t UnpaddedFieldOffset = getDataSizeInBits() - UnfilledBitsInLastUnit; + uint64_t FieldOffset = IsUnion ? 0 : UnpaddedFieldOffset; + + bool ZeroLengthBitfield = false; + if (!Context.getTargetInfo().useBitFieldTypeAlignment() && + Context.getTargetInfo().useZeroLengthBitfieldAlignment() && + FieldSize == 0) { + // The alignment of a zero-length bitfield affects the alignment + // of the next member. The alignment is the max of the zero + // length bitfield's alignment and a target specific fixed value. + ZeroLengthBitfield = true; + unsigned ZeroLengthBitfieldBoundary = + Context.getTargetInfo().getZeroLengthBitfieldBoundary(); + if (ZeroLengthBitfieldBoundary > FieldAlign) + FieldAlign = ZeroLengthBitfieldBoundary; + } + if (FieldSize > TypeSize) { LayoutWideBitField(FieldSize, TypeSize, FieldPacked, D); return; @@ -1982,6 +1509,13 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { UnpackedFieldAlign = std::min(UnpackedFieldAlign, MaxFieldAlignmentInBits); } + // ms_struct bitfields always have to start at a round alignment. + if (IsMsStruct && !LastBitfieldTypeSize) { + FieldOffset = llvm::RoundUpToAlignment(FieldOffset, FieldAlign); + UnpackedFieldOffset = llvm::RoundUpToAlignment(UnpackedFieldOffset, + UnpackedFieldAlign); + } + // Check if we need to add padding to give the field the correct alignment. if (FieldSize == 0 || (MaxFieldAlignment.isZero() && @@ -1996,12 +1530,11 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { // Padding members don't affect overall alignment, unless zero length bitfield // alignment is enabled. - if (!D->getIdentifier() && !Context.getTargetInfo().useZeroLengthBitfieldAlignment()) + if (!D->getIdentifier() && + !Context.getTargetInfo().useZeroLengthBitfieldAlignment() && + !IsMsStruct) FieldAlign = UnpackedFieldAlign = 1; - if (!IsMsStruct) - ZeroLengthBitfield = 0; - if (ExternalLayout) FieldOffset = updateExternalFieldOffset(D, FieldOffset); @@ -2017,11 +1550,29 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { // FIXME: I think FieldSize should be TypeSize here. setDataSize(std::max(getDataSizeInBits(), FieldSize)); } else { - uint64_t NewSizeInBits = FieldOffset + FieldSize; - - setDataSize(llvm::RoundUpToAlignment(NewSizeInBits, - Context.getTargetInfo().getCharAlign())); - UnfilledBitsInLastByte = getDataSizeInBits() - NewSizeInBits; + if (IsMsStruct && FieldSize) { + // Under ms_struct, a bitfield always takes up space equal to the size + // of the type. We can't just change the alignment computation on the + // other codepath because of the way this interacts with #pragma pack: + // in a packed struct, we need to allocate misaligned space in the + // struct to hold the bitfield. + if (!UnfilledBitsInLastUnit) { + setDataSize(FieldOffset + TypeSize); + UnfilledBitsInLastUnit = TypeSize - FieldSize; + } else if (UnfilledBitsInLastUnit < FieldSize) { + setDataSize(getDataSizeInBits() + TypeSize); + UnfilledBitsInLastUnit = TypeSize - FieldSize; + } else { + UnfilledBitsInLastUnit -= FieldSize; + } + LastBitfieldTypeSize = TypeSize; + } else { + uint64_t NewSizeInBits = FieldOffset + FieldSize; + uint64_t BitfieldAlignment = Context.getTargetInfo().getCharAlign(); + setDataSize(llvm::RoundUpToAlignment(NewSizeInBits, BitfieldAlignment)); + UnfilledBitsInLastUnit = getDataSizeInBits() - NewSizeInBits; + LastBitfieldTypeSize = 0; + } } // Update the size. @@ -2038,10 +1589,11 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) { return; } - uint64_t UnpaddedFieldOffset = getDataSizeInBits() - UnfilledBitsInLastByte; + uint64_t UnpaddedFieldOffset = getDataSizeInBits() - UnfilledBitsInLastUnit; // Reset the unfilled bits. - UnfilledBitsInLastByte = 0; + UnfilledBitsInLastUnit = 0; + LastBitfieldTypeSize = 0; bool FieldPacked = Packed || D->hasAttr<PackedAttr>(); CharUnits FieldOffset = @@ -2069,30 +1621,6 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) { FieldSize = FieldInfo.first; FieldAlign = FieldInfo.second; - if (ZeroLengthBitfield) { - CharUnits ZeroLengthBitfieldBoundary = - Context.toCharUnitsFromBits( - Context.getTargetInfo().getZeroLengthBitfieldBoundary()); - if (ZeroLengthBitfieldBoundary == CharUnits::Zero()) { - // If a zero-length bitfield is inserted after a bitfield, - // and the alignment of the zero-length bitfield is - // greater than the member that follows it, `bar', `bar' - // will be aligned as the type of the zero-length bitfield. - std::pair<CharUnits, CharUnits> FieldInfo = - Context.getTypeInfoInChars(ZeroLengthBitfield->getType()); - CharUnits ZeroLengthBitfieldAlignment = FieldInfo.second; - if (ZeroLengthBitfieldAlignment > FieldAlign) - FieldAlign = ZeroLengthBitfieldAlignment; - } else if (ZeroLengthBitfieldBoundary > FieldAlign) { - // Align 'bar' based on a fixed alignment specified by the target. - assert(Context.getTargetInfo().useZeroLengthBitfieldAlignment() && - "ZeroLengthBitfieldBoundary should only be used in conjunction" - " with useZeroLengthBitfieldAlignment."); - FieldAlign = ZeroLengthBitfieldBoundary; - } - ZeroLengthBitfield = 0; - } - if (IsMsStruct) { // If MS bitfield layout is required, figure out what type is being // laid out and align the field to the width of that type. @@ -2189,7 +1717,7 @@ void RecordLayoutBuilder::FinishLayout(const NamedDecl *D) { // Finally, round the size of the record up to the alignment of the // record itself. - uint64_t UnpaddedSize = getSizeInBits() - UnfilledBitsInLastByte; + uint64_t UnpaddedSize = getSizeInBits() - UnfilledBitsInLastUnit; uint64_t UnpackedSizeInBits = llvm::RoundUpToAlignment(getSizeInBits(), Context.toBits(UnpackedAlignment)); @@ -2209,13 +1737,6 @@ void RecordLayoutBuilder::FinishLayout(const NamedDecl *D) { return; } - - // MSVC doesn't round up to the alignment of the record with virtual bases. - if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) { - if (isMicrosoftCXXABI() && RD->getNumVBases()) - return; - } - // Set the size to the final size. setSize(RoundedSize); @@ -2354,7 +1875,7 @@ static const CXXMethodDecl *computeKeyFunction(ASTContext &Context, // A class that is not externally visible doesn't have a key function. (Or // at least, there's no point to assigning a key function to such a class; // this doesn't affect the ABI.) - if (RD->getLinkage() != ExternalLinkage) + if (!RD->isExternallyVisible()) return 0; // Template instantiations don't have key functions,see Itanium C++ ABI 5.2.6. @@ -2453,6 +1974,732 @@ static bool mustSkipTailPadding(TargetCXXABI ABI, const CXXRecordDecl *RD) { llvm_unreachable("bad tail-padding use kind"); } +static bool isMsLayout(const RecordDecl* D) { + return D->getASTContext().getTargetInfo().getCXXABI().isMicrosoft(); +} + +// This section contains an implementation of struct layout that is, up to the +// included tests, compatible with cl.exe (2012). The layout produced is +// significantly different than those produced by the Itanium ABI. Here we note +// the most important differences. +// +// * The alignment of bitfields in unions is ignored when computing the +// alignment of the union. +// * The existance of zero-width bitfield that occurs after anything other than +// a non-zero length bitfield is ignored. +// * The Itanium equivalent vtable pointers are split into a vfptr (virtual +// function pointer) and a vbptr (virtual base pointer). They can each be +// shared with a, non-virtual bases. These bases need not be the same. vfptrs +// always occur at offset 0. vbptrs can occur at an +// arbitrary offset and are placed after non-virtual bases but before fields. +// * Virtual bases sometimes require a 'vtordisp' field that is laid out before +// the virtual base and is used in conjunction with virtual overrides during +// construction and destruction. +// * vfptrs are allocated in a block of memory equal to the alignment of the +// fields and non-virtual bases at offset 0 in 32 bit mode and in a pointer +// sized block of memory in 64 bit mode. +// * vbptrs are allocated in a block of memory equal to the alignment of the +// fields and non-virtual bases. This block is at a potentially unaligned +// offset. If the allocation slot is unaligned and the alignment is less than +// or equal to the pointer size, additional space is allocated so that the +// pointer can be aligned properly. This causes very strange effects on the +// placement of objects after the allocated block. (see the code). +// * vtordisps are allocated in a block of memory with size and alignment equal +// to the alignment of the completed structure (before applying __declspec( +// align())). The vtordisp always occur at the end of the allocation block, +// immediately prior to the virtual base. +// * The last zero sized non-virtual base is allocated after the placement of +// vbptr if one exists and can be placed at the end of the struct, potentially +// aliasing either the first member or another struct allocated after this +// one. +// * The last zero size virtual base may be placed at the end of the struct. +// and can potentially alias a zero sized type in the next struct. +// * If the last field is a non-zero length bitfield and we have any virtual +// bases then some extra padding is added before the virtual bases for no +// obvious reason. +// * When laying out empty non-virtual bases, an extra byte of padding is added +// if the non-virtual base before the empty non-virtual base has a vbptr. + + +namespace { +struct MicrosoftRecordLayoutBuilder { + typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsetsMapTy; + MicrosoftRecordLayoutBuilder(const ASTContext &Context) : Context(Context) {} +private: + MicrosoftRecordLayoutBuilder(const MicrosoftRecordLayoutBuilder &) + LLVM_DELETED_FUNCTION; + void operator=(const MicrosoftRecordLayoutBuilder &) LLVM_DELETED_FUNCTION; +public: + + void layout(const RecordDecl *RD); + void cxxLayout(const CXXRecordDecl *RD); + /// \brief Initializes size and alignment and honors some flags. + void initializeLayout(const RecordDecl *RD); + /// \brief Initialized C++ layout, compute alignment and virtual alignment and + /// existance of vfptrs and vbptrs. Alignment is needed before the vfptr is + /// laid out. + void initializeCXXLayout(const CXXRecordDecl *RD); + void layoutVFPtr(const CXXRecordDecl *RD); + void layoutNonVirtualBases(const CXXRecordDecl *RD); + void layoutNonVirtualBase(const CXXRecordDecl *RD); + void layoutVBPtr(const CXXRecordDecl *RD); + /// \brief Lays out the fields of the record. Also rounds size up to + /// alignment. + void layoutFields(const RecordDecl *RD); + void layoutField(const FieldDecl *FD); + void layoutBitField(const FieldDecl *FD); + /// \brief Lays out a single zero-width bit-field in the record and handles + /// special cases associated with zero-width bit-fields. + void layoutZeroWidthBitField(const FieldDecl *FD); + void layoutVirtualBases(const CXXRecordDecl *RD); + void layoutVirtualBase(const CXXRecordDecl *RD, bool HasVtordisp); + /// \brief Flushes the lazy virtual base and conditionally rounds up to + /// alignment. + void finalizeCXXLayout(const CXXRecordDecl *RD); + void honorDeclspecAlign(const RecordDecl *RD); + + /// \brief Updates the alignment of the type. This function doesn't take any + /// properties (such as packedness) into account. getAdjustedFieldInfo() + /// adjustes for packedness. + void updateAlignment(CharUnits NewAlignment) { + Alignment = std::max(Alignment, NewAlignment); + } + /// \brief Gets the size and alignment taking attributes into account. + std::pair<CharUnits, CharUnits> getAdjustedFieldInfo(const FieldDecl *FD); + /// \brief Places a field at offset 0. + void placeFieldAtZero() { FieldOffsets.push_back(0); } + /// \brief Places a field at an offset in CharUnits. + void placeFieldAtOffset(CharUnits FieldOffset) { + FieldOffsets.push_back(Context.toBits(FieldOffset)); + } + /// \brief Places a bitfield at a bit offset. + void placeFieldAtBitOffset(uint64_t FieldOffset) { + FieldOffsets.push_back(FieldOffset); + } + /// \brief Compute the set of virtual bases for which vtordisps are required. + llvm::SmallPtrSet<const CXXRecordDecl *, 2> + computeVtorDispSet(const CXXRecordDecl *RD); + + const ASTContext &Context; + /// \brief The size of the record being laid out. + CharUnits Size; + /// \brief The current alignment of the record layout. + CharUnits Alignment; + /// \brief The collection of field offsets. + SmallVector<uint64_t, 16> FieldOffsets; + /// \brief The maximum allowed field alignment. This is set by #pragma pack. + CharUnits MaxFieldAlignment; + /// \brief Alignment does not occur for virtual bases unless something + /// forces it to by explicitly using __declspec(align()) + bool AlignAfterVBases : 1; + bool IsUnion : 1; + /// \brief True if the last field laid out was a bitfield and was not 0 + /// width. + bool LastFieldIsNonZeroWidthBitfield : 1; + /// \brief The size of the allocation of the currently active bitfield. + /// This value isn't meaningful unless LastFieldIsNonZeroWidthBitfield + /// is true. + CharUnits CurrentBitfieldSize; + /// \brief The number of remaining bits in our last bitfield allocation. + /// This value isn't meaningful unless LastFieldIsNonZeroWidthBitfield is + /// true. + unsigned RemainingBitsInField; + + /// \brief The data alignment of the record layout. + CharUnits DataSize; + /// \brief The alignment of the non-virtual portion of the record layout + /// without the impact of the virtual pointers. + /// Only used for C++ layouts. + CharUnits BasesAndFieldsAlignment; + /// \brief The alignment of the non-virtual portion of the record layout + /// Only used for C++ layouts. + CharUnits NonVirtualAlignment; + /// \brief The additional alignment imposed by the virtual bases. + CharUnits VirtualAlignment; + /// \brief The primary base class (if one exists). + const CXXRecordDecl *PrimaryBase; + /// \brief The class we share our vb-pointer with. + const CXXRecordDecl *SharedVBPtrBase; + /// \brief True if the class has a vftable pointer that can be extended + /// by this class or classes derived from it. Such a vfptr will always occur + /// at offset 0. + bool HasExtendableVFPtr : 1; + /// \brief True if the class has a (not necessarily its own) vbtable pointer. + bool HasVBPtr : 1; + /// \brief Offset to the virtual base table pointer (if one exists). + CharUnits VBPtrOffset; + /// \brief Base classes and their offsets in the record. + BaseOffsetsMapTy Bases; + /// \brief virtual base classes and their offsets in the record. + ASTRecordLayout::VBaseOffsetsMapTy VBases; + /// \brief The size of a pointer. + CharUnits PointerSize; + /// \brief The alignment of a pointer. + CharUnits PointerAlignment; + /// \brief Holds an empty base we haven't yet laid out. + const CXXRecordDecl *LazyEmptyBase; + /// \brief Lets us know if the last base we laid out was empty. Only used + /// when adjusting the placement of a last zero-sized base in 64 bit mode. + bool LastBaseWasEmpty; + /// \brief Lets us know if we're in 64-bit mode + bool Is64BitMode; + /// \brief True if the last non-virtual base has a vbptr. + bool LastNonVirtualBaseHasVBPtr; +}; +} // namespace + +std::pair<CharUnits, CharUnits> +MicrosoftRecordLayoutBuilder::getAdjustedFieldInfo(const FieldDecl *FD) { + std::pair<CharUnits, CharUnits> FieldInfo = + Context.getTypeInfoInChars(FD->getType()); + + // If we're not on win32 and using ms_struct the field alignment will be wrong + // for 64 bit types, so we fix that here. + if (FD->getASTContext().getTargetInfo().getTriple().getOS() != + llvm::Triple::Win32) { + QualType T = Context.getBaseElementType(FD->getType()); + if (const BuiltinType *BTy = T->getAs<BuiltinType>()) { + CharUnits TypeSize = Context.getTypeSizeInChars(BTy); + if (TypeSize > FieldInfo.second) + FieldInfo.second = TypeSize; + } + } + + // Respect packed attribute. + if (FD->hasAttr<PackedAttr>()) + FieldInfo.second = CharUnits::One(); + // Respect pack pragma. + else if (!MaxFieldAlignment.isZero()) + FieldInfo.second = std::min(FieldInfo.second, MaxFieldAlignment); + // Respect alignment attributes. + if (unsigned fieldAlign = FD->getMaxAlignment()) { + CharUnits FieldAlign = Context.toCharUnitsFromBits(fieldAlign); + AlignAfterVBases = true; + FieldInfo.second = std::max(FieldInfo.second, FieldAlign); + } + return FieldInfo; +} + +void MicrosoftRecordLayoutBuilder::initializeLayout(const RecordDecl *RD) { + IsUnion = RD->isUnion(); + Is64BitMode = Context.getTargetInfo().getPointerWidth(0) == 64; + + Size = CharUnits::Zero(); + Alignment = CharUnits::One(); + AlignAfterVBases = false; + + // Compute the maximum field alignment. + MaxFieldAlignment = CharUnits::Zero(); + // Honor the default struct packing maximum alignment flag. + if (unsigned DefaultMaxFieldAlignment = Context.getLangOpts().PackStruct) + MaxFieldAlignment = CharUnits::fromQuantity(DefaultMaxFieldAlignment); + // Honor the packing attribute. + if (const MaxFieldAlignmentAttr *MFAA = RD->getAttr<MaxFieldAlignmentAttr>()) + MaxFieldAlignment = Context.toCharUnitsFromBits(MFAA->getAlignment()); + // Packed attribute forces max field alignment to be 1. + if (RD->hasAttr<PackedAttr>()) + MaxFieldAlignment = CharUnits::One(); +} + +void MicrosoftRecordLayoutBuilder::layout(const RecordDecl *RD) { + initializeLayout(RD); + layoutFields(RD); + honorDeclspecAlign(RD); +} + +void MicrosoftRecordLayoutBuilder::cxxLayout(const CXXRecordDecl *RD) { + initializeLayout(RD); + initializeCXXLayout(RD); + layoutVFPtr(RD); + layoutNonVirtualBases(RD); + layoutVBPtr(RD); + layoutFields(RD); + DataSize = Size; + NonVirtualAlignment = Alignment; + layoutVirtualBases(RD); + finalizeCXXLayout(RD); + honorDeclspecAlign(RD); +} + +void +MicrosoftRecordLayoutBuilder::initializeCXXLayout(const CXXRecordDecl *RD) { + // Calculate pointer size and alignment. + PointerSize = + Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0)); + PointerAlignment = PointerSize; + if (!MaxFieldAlignment.isZero()) + PointerAlignment = std::min(PointerAlignment, MaxFieldAlignment); + + // Initialize information about the bases. + HasVBPtr = false; + HasExtendableVFPtr = false; + SharedVBPtrBase = 0; + PrimaryBase = 0; + VirtualAlignment = CharUnits::One(); + AlignAfterVBases = Is64BitMode; + + // 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 + // base class, if one exists. + for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), + e = RD->bases_end(); + i != e; ++i) { + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); + const ASTRecordLayout &Layout = Context.getASTRecordLayout(BaseDecl); + // Handle forced alignment. + if (Layout.getAlignAfterVBases()) + AlignAfterVBases = true; + // Handle virtual bases. + if (i->isVirtual()) { + VirtualAlignment = std::max(VirtualAlignment, Layout.getAlignment()); + HasVBPtr = true; + continue; + } + // We located a primary base class! + if (!PrimaryBase && Layout.hasExtendableVFPtr()) { + PrimaryBase = BaseDecl; + HasExtendableVFPtr = true; + } + // We located a base to share a VBPtr with! + if (!SharedVBPtrBase && Layout.hasVBPtr()) { + SharedVBPtrBase = BaseDecl; + HasVBPtr = true; + } + updateAlignment(Layout.getAlignment()); + } + + // Use LayoutFields to compute the alignment of the fields. The layout + // is discarded. This is the simplest way to get all of the bit-field + // behavior correct and is not actually very expensive. + layoutFields(RD); + Size = CharUnits::Zero(); + BasesAndFieldsAlignment = Alignment; + FieldOffsets.clear(); +} + +void MicrosoftRecordLayoutBuilder::layoutVFPtr(const CXXRecordDecl *RD) { + // If we have a primary base then our VFPtr was already laid out + if (PrimaryBase) + return; + + // Look at all of our methods to determine if we need a VFPtr. We need a + // vfptr if we define a new virtual function. + if (!HasExtendableVFPtr && RD->isDynamicClass()) + for (CXXRecordDecl::method_iterator i = RD->method_begin(), + e = RD->method_end(); + !HasExtendableVFPtr && i != e; ++i) + HasExtendableVFPtr = i->isVirtual() && i->size_overridden_methods() == 0; + if (!HasExtendableVFPtr) + return; + + // MSVC 32 (but not 64) potentially over-aligns the vf-table pointer by giving + // it the max alignment of all the non-virtual data in the class. The + // resulting layout is essentially { vftbl, { nvdata } }. This is completely + // unnecessary, but we're not here to pass judgment. + updateAlignment(PointerAlignment); + if (Is64BitMode) + Size = Size.RoundUpToAlignment(PointerAlignment) + PointerSize; + else + Size = Size.RoundUpToAlignment(PointerAlignment) + Alignment; +} + +void +MicrosoftRecordLayoutBuilder::layoutNonVirtualBases(const CXXRecordDecl *RD) { + LazyEmptyBase = 0; + LastBaseWasEmpty = false; + LastNonVirtualBaseHasVBPtr = false; + + // Lay out the primary base first. + if (PrimaryBase) + layoutNonVirtualBase(PrimaryBase); + + // Iterate through the bases and lay out the non-virtual ones. + for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), + e = RD->bases_end(); + i != e; ++i) { + if (i->isVirtual()) + continue; + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(i->getType()->castAs<RecordType>()->getDecl()); + if (BaseDecl != PrimaryBase) + layoutNonVirtualBase(BaseDecl); + } +} + +void +MicrosoftRecordLayoutBuilder::layoutNonVirtualBase(const CXXRecordDecl *RD) { + const ASTRecordLayout *Layout = RD ? &Context.getASTRecordLayout(RD) : 0; + + // If we have a lazy empty base we haven't laid out yet, do that now. + if (LazyEmptyBase) { + const ASTRecordLayout &LazyLayout = + Context.getASTRecordLayout(LazyEmptyBase); + Size = Size.RoundUpToAlignment(LazyLayout.getAlignment()); + // If the last non-virtual base has a vbptr we add a byte of padding for no + // obvious reason. + if (LastNonVirtualBaseHasVBPtr) + Size++; + Bases.insert(std::make_pair(LazyEmptyBase, Size)); + // Empty bases only consume space when followed by another empty base. + if (RD && Layout->getNonVirtualSize().isZero()) { + LastBaseWasEmpty = true; + Size++; + } + LazyEmptyBase = 0; + LastNonVirtualBaseHasVBPtr = false; + } + + // RD is null when flushing the final lazy base. + if (!RD) + return; + + if (Layout->getNonVirtualSize().isZero()) { + LazyEmptyBase = RD; + return; + } + + // Insert the base here. + CharUnits BaseOffset = Size.RoundUpToAlignment(Layout->getAlignment()); + Bases.insert(std::make_pair(RD, BaseOffset)); + Size = BaseOffset + Layout->getDataSize(); + // Note: we don't update alignment here because it was accounted + // for during initalization. + LastBaseWasEmpty = false; + LastNonVirtualBaseHasVBPtr = Layout->hasVBPtr(); +} + +void MicrosoftRecordLayoutBuilder::layoutVBPtr(const CXXRecordDecl *RD) { + if (!HasVBPtr) + VBPtrOffset = CharUnits::fromQuantity(-1); + else if (SharedVBPtrBase) { + const ASTRecordLayout &Layout = Context.getASTRecordLayout(SharedVBPtrBase); + VBPtrOffset = Bases[SharedVBPtrBase] + Layout.getVBPtrOffset(); + } else { + VBPtrOffset = Size.RoundUpToAlignment(PointerAlignment); + CharUnits OldSize = Size; + Size = VBPtrOffset + PointerSize; + if (BasesAndFieldsAlignment <= PointerAlignment) { + // Handle strange padding rules for the lazily placed base. I have no + // explanation for why the last virtual base is padded in such an odd way. + // Two things to note about this padding are that the rules are different + // if the alignment of the bases+fields is <= to the alignemnt of a + // pointer and that the rule in 64-bit mode behaves differently depending + // on if the second to last base was also zero sized. + Size += OldSize % BasesAndFieldsAlignment.getQuantity(); + } else { + if (Is64BitMode) + Size += LastBaseWasEmpty ? CharUnits::One() : CharUnits::Zero(); + else + Size = OldSize + BasesAndFieldsAlignment; + } + updateAlignment(PointerAlignment); + } + + // Flush the lazy empty base. + layoutNonVirtualBase(0); +} + +void MicrosoftRecordLayoutBuilder::layoutFields(const RecordDecl *RD) { + LastFieldIsNonZeroWidthBitfield = false; + for (RecordDecl::field_iterator Field = RD->field_begin(), + FieldEnd = RD->field_end(); + Field != FieldEnd; ++Field) + layoutField(*Field); + Size = Size.RoundUpToAlignment(Alignment); +} + +void MicrosoftRecordLayoutBuilder::layoutField(const FieldDecl *FD) { + if (FD->isBitField()) { + layoutBitField(FD); + return; + } + LastFieldIsNonZeroWidthBitfield = false; + + std::pair<CharUnits, CharUnits> FieldInfo = getAdjustedFieldInfo(FD); + CharUnits FieldSize = FieldInfo.first; + CharUnits FieldAlign = FieldInfo.second; + + updateAlignment(FieldAlign); + if (IsUnion) { + placeFieldAtZero(); + Size = std::max(Size, FieldSize); + } else { + // Round up the current record size to the field's alignment boundary. + CharUnits FieldOffset = Size.RoundUpToAlignment(FieldAlign); + placeFieldAtOffset(FieldOffset); + Size = FieldOffset + FieldSize; + } +} + +void MicrosoftRecordLayoutBuilder::layoutBitField(const FieldDecl *FD) { + unsigned Width = FD->getBitWidthValue(Context); + if (Width == 0) { + layoutZeroWidthBitField(FD); + return; + } + + std::pair<CharUnits, CharUnits> FieldInfo = getAdjustedFieldInfo(FD); + CharUnits FieldSize = FieldInfo.first; + CharUnits FieldAlign = FieldInfo.second; + + // Clamp the bitfield to a containable size for the sake of being able + // to lay them out. Sema will throw an error. + if (Width > Context.toBits(FieldSize)) + Width = Context.toBits(FieldSize); + + // Check to see if this bitfield fits into an existing allocation. Note: + // MSVC refuses to pack bitfields of formal types with different sizes + // into the same allocation. + if (!IsUnion && LastFieldIsNonZeroWidthBitfield && + CurrentBitfieldSize == FieldSize && Width <= RemainingBitsInField) { + placeFieldAtBitOffset(Context.toBits(Size) - RemainingBitsInField); + RemainingBitsInField -= Width; + return; + } + + LastFieldIsNonZeroWidthBitfield = true; + CurrentBitfieldSize = FieldSize; + if (IsUnion) { + placeFieldAtZero(); + Size = std::max(Size, FieldSize); + // TODO: Add a Sema warning that MS ignores bitfield alignment in unions. + } else { + // Allocate a new block of memory and place the bitfield in it. + CharUnits FieldOffset = Size.RoundUpToAlignment(FieldAlign); + placeFieldAtOffset(FieldOffset); + Size = FieldOffset + FieldSize; + updateAlignment(FieldAlign); + RemainingBitsInField = Context.toBits(FieldSize) - Width; + } +} + +void +MicrosoftRecordLayoutBuilder::layoutZeroWidthBitField(const FieldDecl *FD) { + // Zero-width bitfields are ignored unless they follow a non-zero-width + // bitfield. + std::pair<CharUnits, CharUnits> FieldInfo = getAdjustedFieldInfo(FD); + CharUnits FieldSize = FieldInfo.first; + CharUnits FieldAlign = FieldInfo.second; + + if (!LastFieldIsNonZeroWidthBitfield) { + placeFieldAtOffset(IsUnion ? CharUnits::Zero() : Size); + // TODO: Add a Sema warning that MS ignores alignment for zero + // sized bitfields that occur after zero-size bitfields or non bitfields. + return; + } + + LastFieldIsNonZeroWidthBitfield = false; + if (IsUnion) { + placeFieldAtZero(); + Size = std::max(Size, FieldSize); + } else { + // Round up the current record size to the field's alignment boundary. + CharUnits FieldOffset = Size.RoundUpToAlignment(FieldAlign); + placeFieldAtOffset(FieldOffset); + Size = FieldOffset; + updateAlignment(FieldAlign); + } +} + +void MicrosoftRecordLayoutBuilder::layoutVirtualBases(const CXXRecordDecl *RD) { + if (!HasVBPtr) + return; + + updateAlignment(VirtualAlignment); + + // Zero-sized v-bases obey the alignment attribute so apply it here. The + // alignment attribute is normally accounted for in FinalizeLayout. + if (unsigned MaxAlign = RD->getMaxAlignment()) + updateAlignment(Context.toCharUnitsFromBits(MaxAlign)); + + llvm::SmallPtrSet<const CXXRecordDecl *, 2> HasVtordisp = + computeVtorDispSet(RD); + + // If the last field we laid out was a non-zero length bitfield then add some + // extra padding for no obvious reason. + if (LastFieldIsNonZeroWidthBitfield) + Size += CurrentBitfieldSize; + + // Iterate through the virtual bases and lay them out. + for (CXXRecordDecl::base_class_const_iterator i = RD->vbases_begin(), + e = RD->vbases_end(); + i != e; ++i) { + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(i->getType()->castAs<RecordType>()->getDecl()); + layoutVirtualBase(BaseDecl, HasVtordisp.count(BaseDecl)); + } +} + +void MicrosoftRecordLayoutBuilder::layoutVirtualBase(const CXXRecordDecl *RD, + bool HasVtordisp) { + if (LazyEmptyBase) { + const ASTRecordLayout &LazyLayout = + Context.getASTRecordLayout(LazyEmptyBase); + Size = Size.RoundUpToAlignment(LazyLayout.getAlignment()); + VBases.insert( + std::make_pair(LazyEmptyBase, ASTRecordLayout::VBaseInfo(Size, false))); + // Empty bases only consume space when followed by another empty base. + // The space consumed is in an Alignment sized/aligned block and the v-base + // is placed at its alignment offset into the chunk, unless its alignment + // is less than 4 bytes, at which it is placed at 4 byte offset in the + // chunk. We have no idea why. + if (RD && Context.getASTRecordLayout(RD).getNonVirtualSize().isZero()) + Size = Size.RoundUpToAlignment(Alignment) + CharUnits::fromQuantity(4); + LazyEmptyBase = 0; + } + + // RD is null when flushing the final lazy virtual base. + if (!RD) + return; + + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + if (Layout.getNonVirtualSize().isZero() && !HasVtordisp) { + LazyEmptyBase = RD; + return; + } + + CharUnits BaseNVSize = Layout.getNonVirtualSize(); + CharUnits BaseAlign = Layout.getAlignment(); + + // vtordisps are always 4 bytes (even in 64-bit mode) + if (HasVtordisp) + Size = Size.RoundUpToAlignment(Alignment) + CharUnits::fromQuantity(4); + Size = Size.RoundUpToAlignment(BaseAlign); + + // Insert the base here. + CharUnits BaseOffset = Size.RoundUpToAlignment(BaseAlign); + VBases.insert( + std::make_pair(RD, ASTRecordLayout::VBaseInfo(BaseOffset, HasVtordisp))); + Size = BaseOffset + BaseNVSize; + // Note: we don't update alignment here because it was accounted for in + // InitializeLayout. +} + +void MicrosoftRecordLayoutBuilder::finalizeCXXLayout(const CXXRecordDecl *RD) { + // Flush the lazy virtual base. + layoutVirtualBase(0, false); + + if (RD->vbases_begin() == RD->vbases_end() || AlignAfterVBases) + Size = Size.RoundUpToAlignment(Alignment); + + if (Size.isZero()) + Size = Alignment; +} + +void MicrosoftRecordLayoutBuilder::honorDeclspecAlign(const RecordDecl *RD) { + if (unsigned MaxAlign = RD->getMaxAlignment()) { + AlignAfterVBases = true; + updateAlignment(Context.toCharUnitsFromBits(MaxAlign)); + Size = Size.RoundUpToAlignment(Alignment); + } +} + +static bool +RequiresVtordisp(const llvm::SmallPtrSet<const CXXRecordDecl *, 2> &HasVtordisp, + const CXXRecordDecl *RD) { + if (HasVtordisp.count(RD)) + return true; + // If any of a virtual bases non-virtual bases (recursively) requires a + // vtordisp than so does this virtual base. + for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), + e = RD->bases_end(); + i != e; ++i) + if (!i->isVirtual() && + RequiresVtordisp( + HasVtordisp, + cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()))) + return true; + return false; +} + +llvm::SmallPtrSet<const CXXRecordDecl *, 2> +MicrosoftRecordLayoutBuilder::computeVtorDispSet(const CXXRecordDecl *RD) { + llvm::SmallPtrSet<const CXXRecordDecl *, 2> HasVtordisp; + + // If any of our bases need a vtordisp for this type, so do we. Check our + // direct bases for vtordisp requirements. + for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), + e = RD->bases_end(); + i != e; ++i) { + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); + const ASTRecordLayout &Layout = Context.getASTRecordLayout(BaseDecl); + for (ASTRecordLayout::VBaseOffsetsMapTy::const_iterator + bi = Layout.getVBaseOffsetsMap().begin(), + be = Layout.getVBaseOffsetsMap().end(); + bi != be; ++bi) + if (bi->second.hasVtorDisp()) + HasVtordisp.insert(bi->first); + } + + // If we define a constructor or destructor and override a function that is + // defined in a virtual base's vtable, that virtual bases need a vtordisp. + // Here we collect a list of classes with vtables for which our virtual bases + // actually live. The virtual bases with this property will require + // vtordisps. In addition, virtual bases that contain non-virtual bases that + // define functions we override also require vtordisps, this case is checked + // explicitly below. + if (RD->hasUserDeclaredConstructor() || RD->hasUserDeclaredDestructor()) { + llvm::SmallPtrSet<const CXXMethodDecl *, 8> Work; + // Seed the working set with our non-destructor virtual methods. + for (CXXRecordDecl::method_iterator i = RD->method_begin(), + e = RD->method_end(); + i != e; ++i) + if ((*i)->isVirtual() && !isa<CXXDestructorDecl>(*i)) + Work.insert(*i); + while (!Work.empty()) { + const CXXMethodDecl *MD = *Work.begin(); + CXXMethodDecl::method_iterator i = MD->begin_overridden_methods(), + e = MD->end_overridden_methods(); + if (i == e) + // If a virtual method has no-overrides it lives in its parent's vtable. + HasVtordisp.insert(MD->getParent()); + else + Work.insert(i, e); + // We've finished processing this element, remove it from the working set. + Work.erase(MD); + } + } + + // Re-check all of our vbases for vtordisp requirements (in case their + // non-virtual bases have vtordisp requirements). + for (CXXRecordDecl::base_class_const_iterator i = RD->vbases_begin(), + e = RD->vbases_end(); + i != e; ++i) { + const CXXRecordDecl *BaseDecl = i->getType()->getAsCXXRecordDecl(); + if (!HasVtordisp.count(BaseDecl) && RequiresVtordisp(HasVtordisp, BaseDecl)) + HasVtordisp.insert(BaseDecl); + } + + return HasVtordisp; +} + +/// \brief 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::BuildMicrosoftASTRecordLayout(const RecordDecl *D) const { + MicrosoftRecordLayoutBuilder Builder(*this); + if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) { + Builder.cxxLayout(RD); + return new (*this) ASTRecordLayout( + *this, Builder.Size, Builder.Alignment, + Builder.HasExtendableVFPtr && !Builder.PrimaryBase, + Builder.HasExtendableVFPtr, + Builder.VBPtrOffset, Builder.DataSize, Builder.FieldOffsets.data(), + Builder.FieldOffsets.size(), Builder.DataSize, + Builder.NonVirtualAlignment, CharUnits::Zero(), Builder.PrimaryBase, + false, Builder.SharedVBPtrBase, Builder.AlignAfterVBases, Builder.Bases, + Builder.VBases); + } else { + Builder.layout(D); + return new (*this) ASTRecordLayout( + *this, Builder.Size, Builder.Alignment, Builder.Size, + Builder.FieldOffsets.data(), Builder.FieldOffsets.size()); + } +} + /// getASTRecordLayout - Get or compute information about the layout of the /// specified record (struct/union/class), which indicates its size and field /// position information. @@ -2468,6 +2715,7 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const { D = D->getDefinition(); assert(D && "Cannot get layout of forward declarations!"); + assert(!D->isInvalidDecl() && "Cannot get layout of invalid decl!"); assert(D->isCompleteDefinition() && "Cannot layout type before complete!"); // Look up this layout, if already laid out, return what we have. @@ -2476,27 +2724,15 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const { const ASTRecordLayout *Entry = ASTRecordLayouts[D]; if (Entry) return *Entry; - const ASTRecordLayout *NewEntry; + const ASTRecordLayout *NewEntry = 0; - if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) { + if (isMsLayout(D) && !D->getASTContext().getExternalSource()) { + NewEntry = BuildMicrosoftASTRecordLayout(D); + } else if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) { EmptySubobjectMap EmptySubobjects(*this, RD); RecordLayoutBuilder Builder(*this, &EmptySubobjects); Builder.Layout(RD); - // MSVC gives the vb-table pointer an alignment equal to that of - // the non-virtual part of the structure. That's an inherently - // multi-pass operation. If our first pass doesn't give us - // adequate alignment, try again with the specified minimum - // alignment. This is *much* more maintainable than computing the - // alignment in advance in a separately-coded pass; it's also - // significantly more efficient in the common case where the - // vb-table doesn't need extra padding. - if (Builder.VBPtrOffset != CharUnits::fromQuantity(-1) && - (Builder.VBPtrOffset % Builder.NonVirtualAlignment) != 0) { - Builder.resetWithTargetAlignment(Builder.NonVirtualAlignment); - Builder.Layout(RD); - } - // In certain situations, we are allowed to lay out objects in the // tail-padding of base classes. This is ABI-dependent. // FIXME: this should be stored in the record layout. @@ -2508,12 +2744,12 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const { skipTailPadding ? Builder.getSize() : Builder.getDataSize(); CharUnits NonVirtualSize = skipTailPadding ? DataSize : Builder.NonVirtualSize; - NewEntry = new (*this) ASTRecordLayout(*this, Builder.getSize(), Builder.Alignment, Builder.HasOwnVFPtr, - Builder.VBPtrOffset, + RD->isDynamicClass(), + CharUnits::fromQuantity(-1), DataSize, Builder.FieldOffsets.data(), Builder.FieldOffsets.size(), @@ -2522,6 +2758,7 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const { EmptySubobjects.SizeOfLargestEmptySubobject, Builder.PrimaryBase, Builder.PrimaryBaseIsVirtual, + 0, true, Builder.Bases, Builder.VBases); } else { RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0); @@ -2538,43 +2775,45 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const { ASTRecordLayouts[D] = NewEntry; if (getLangOpts().DumpRecordLayouts) { - llvm::errs() << "\n*** Dumping AST Record Layout\n"; - DumpRecordLayout(D, llvm::errs(), getLangOpts().DumpRecordLayoutsSimple); + llvm::outs() << "\n*** Dumping AST Record Layout\n"; + DumpRecordLayout(D, llvm::outs(), getLangOpts().DumpRecordLayoutsSimple); } return *NewEntry; } const CXXMethodDecl *ASTContext::getCurrentKeyFunction(const CXXRecordDecl *RD) { + if (!getTargetInfo().getCXXABI().hasKeyFunctions()) + return 0; + assert(RD->getDefinition() && "Cannot get key function for forward decl!"); RD = cast<CXXRecordDecl>(RD->getDefinition()); - const CXXMethodDecl *&entry = KeyFunctions[RD]; - if (!entry) { - entry = computeKeyFunction(*this, RD); - } + LazyDeclPtr &Entry = KeyFunctions[RD]; + if (!Entry) + Entry = const_cast<CXXMethodDecl*>(computeKeyFunction(*this, RD)); - return entry; + return cast_or_null<CXXMethodDecl>(Entry.get(getExternalSource())); } -void ASTContext::setNonKeyFunction(const CXXMethodDecl *method) { - assert(method == method->getFirstDeclaration() && +void ASTContext::setNonKeyFunction(const CXXMethodDecl *Method) { + assert(Method == Method->getFirstDecl() && "not working with method declaration from class definition"); // Look up the cache entry. Since we're working with the first // declaration, its parent must be the class definition, which is // the correct key for the KeyFunctions hash. - llvm::DenseMap<const CXXRecordDecl*, const CXXMethodDecl*>::iterator - i = KeyFunctions.find(method->getParent()); + llvm::DenseMap<const CXXRecordDecl*, LazyDeclPtr>::iterator + I = KeyFunctions.find(Method->getParent()); // If it's not cached, there's nothing to do. - if (i == KeyFunctions.end()) return; + if (I == KeyFunctions.end()) return; // If it is cached, check whether it's the target method, and if so, // remove it from the cache. - if (i->second == method) { + if (I->second.get(getExternalSource()) == Method) { // FIXME: remember that we did this for module / chained PCH state? - KeyFunctions.erase(i); + KeyFunctions.erase(I); } } @@ -2676,16 +2915,19 @@ static void DumpCXXRecordLayout(raw_ostream &OS, IndentLevel++; const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); - bool HasVfptr = Layout.hasOwnVFPtr(); - bool HasVbptr = Layout.getVBPtrOffset() != CharUnits::fromQuantity(-1); + bool HasOwnVFPtr = Layout.hasOwnVFPtr(); + bool HasOwnVBPtr = Layout.hasOwnVBPtr(); // Vtable pointer. - if (RD->isDynamicClass() && !PrimaryBase && - !C.getTargetInfo().getCXXABI().isMicrosoft()) { + if (RD->isDynamicClass() && !PrimaryBase && !isMsLayout(RD)) { PrintOffset(OS, Offset, IndentLevel); OS << '(' << *RD << " vtable pointer)\n"; + } else if (HasOwnVFPtr) { + PrintOffset(OS, Offset, IndentLevel); + // vfptr (for Microsoft C++ ABI) + OS << '(' << *RD << " vftable pointer)\n"; } - + // Dump (non-virtual) bases for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), E = RD->bases_end(); I != E; ++I) { @@ -2704,12 +2946,8 @@ static void DumpCXXRecordLayout(raw_ostream &OS, /*IncludeVirtualBases=*/false); } - // vfptr and vbptr (for Microsoft C++ ABI) - if (HasVfptr) { - PrintOffset(OS, Offset, IndentLevel); - OS << '(' << *RD << " vftable pointer)\n"; - } - if (HasVbptr) { + // vbptr (for Microsoft C++ ABI) + if (HasOwnVBPtr) { PrintOffset(OS, Offset + Layout.getVBPtrOffset(), IndentLevel); OS << '(' << *RD << " vbtable pointer)\n"; } @@ -2762,7 +3000,8 @@ static void DumpCXXRecordLayout(raw_ostream &OS, PrintIndentNoOffset(OS, IndentLevel - 1); OS << "[sizeof=" << Layout.getSize().getQuantity(); - OS << ", dsize=" << Layout.getDataSize().getQuantity(); + if (!isMsLayout(RD)) + OS << ", dsize=" << Layout.getDataSize().getQuantity(); OS << ", align=" << Layout.getAlignment().getQuantity() << '\n'; PrintIndentNoOffset(OS, IndentLevel - 1); @@ -2789,7 +3028,8 @@ void ASTContext::DumpRecordLayout(const RecordDecl *RD, OS << "\nLayout: "; OS << "<ASTRecordLayout\n"; OS << " Size:" << toBits(Info.getSize()) << "\n"; - OS << " DataSize:" << toBits(Info.getDataSize()) << "\n"; + if (!isMsLayout(RD)) + OS << " DataSize:" << toBits(Info.getDataSize()) << "\n"; OS << " Alignment:" << toBits(Info.getAlignment()) << "\n"; OS << " FieldOffsets: ["; for (unsigned i = 0, e = Info.getFieldCount(); i != e; ++i) { diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index 5b29c07..de85161 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -18,6 +18,7 @@ #include "clang/AST/Stmt.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtObjC.h" +#include "clang/AST/StmtOpenMP.h" #include "clang/AST/Type.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/TargetInfo.h" @@ -48,16 +49,11 @@ static StmtClassNameTable &getStmtInfoTableEntry(Stmt::StmtClass E) { return StmtClassInfo[E]; } -void *Stmt::operator new(size_t bytes, ASTContext& C, - unsigned alignment) throw() { +void *Stmt::operator new(size_t bytes, const ASTContext& C, + unsigned alignment) { return ::operator new(bytes, C, alignment); } -void *Stmt::operator new(size_t bytes, ASTContext* C, - unsigned alignment) throw() { - return ::operator new(bytes, *C, alignment); -} - const char *Stmt::getStmtClassName() const { return getStmtInfoTableEntry((StmtClass) StmtBits.sClass).Name; } @@ -139,6 +135,7 @@ namespace { template <class T> good implements_children(children_t T::*) { return good(); } + LLVM_ATTRIBUTE_UNUSED static inline bad implements_children(children_t Stmt::*) { return bad(); } @@ -147,6 +144,7 @@ namespace { template <class T> good implements_getLocStart(getLocStart_t T::*) { return good(); } + LLVM_ATTRIBUTE_UNUSED static inline bad implements_getLocStart(getLocStart_t Stmt::*) { return bad(); } @@ -155,20 +153,22 @@ namespace { template <class T> good implements_getLocEnd(getLocEnd_t T::*) { return good(); } + LLVM_ATTRIBUTE_UNUSED static inline bad implements_getLocEnd(getLocEnd_t Stmt::*) { return bad(); } #define ASSERT_IMPLEMENTS_children(type) \ - (void) sizeof(is_good(implements_children(&type::children))) + (void) is_good(implements_children(&type::children)) #define ASSERT_IMPLEMENTS_getLocStart(type) \ - (void) sizeof(is_good(implements_getLocStart(&type::getLocStart))) + (void) is_good(implements_getLocStart(&type::getLocStart)) #define ASSERT_IMPLEMENTS_getLocEnd(type) \ - (void) sizeof(is_good(implements_getLocEnd(&type::getLocEnd))) + (void) is_good(implements_getLocEnd(&type::getLocEnd)) } /// Check whether the various Stmt classes implement their member /// functions. +LLVM_ATTRIBUTE_UNUSED static inline void check_implementations() { #define ABSTRACT_STMT(type) #define STMT(type, base) \ @@ -252,7 +252,7 @@ SourceLocation Stmt::getLocEnd() const { llvm_unreachable("unknown statement kind"); } -CompoundStmt::CompoundStmt(ASTContext &C, ArrayRef<Stmt*> Stmts, +CompoundStmt::CompoundStmt(const ASTContext &C, ArrayRef<Stmt*> Stmts, SourceLocation LB, SourceLocation RB) : Stmt(CompoundStmtClass), LBracLoc(LB), RBracLoc(RB) { CompoundStmtBits.NumStmts = Stmts.size(); @@ -268,7 +268,8 @@ CompoundStmt::CompoundStmt(ASTContext &C, ArrayRef<Stmt*> Stmts, std::copy(Stmts.begin(), Stmts.end(), Body); } -void CompoundStmt::setStmts(ASTContext &C, Stmt **Stmts, unsigned NumStmts) { +void CompoundStmt::setStmts(const ASTContext &C, Stmt **Stmts, + unsigned NumStmts) { if (this->Body) C.Deallocate(Body); this->CompoundStmtBits.NumStmts = NumStmts; @@ -281,7 +282,7 @@ const char *LabelStmt::getName() const { return getDecl()->getIdentifier()->getNameStart(); } -AttributedStmt *AttributedStmt::Create(ASTContext &C, SourceLocation Loc, +AttributedStmt *AttributedStmt::Create(const ASTContext &C, SourceLocation Loc, ArrayRef<const Attr*> Attrs, Stmt *SubStmt) { void *Mem = C.Allocate(sizeof(AttributedStmt) + @@ -290,7 +291,8 @@ AttributedStmt *AttributedStmt::Create(ASTContext &C, SourceLocation Loc, return new (Mem) AttributedStmt(Loc, Attrs, SubStmt); } -AttributedStmt *AttributedStmt::CreateEmpty(ASTContext &C, unsigned NumAttrs) { +AttributedStmt *AttributedStmt::CreateEmpty(const ASTContext &C, + unsigned NumAttrs) { assert(NumAttrs > 0 && "NumAttrs should be greater than zero"); void *Mem = C.Allocate(sizeof(AttributedStmt) + sizeof(Attr*) * (NumAttrs - 1), @@ -298,29 +300,7 @@ AttributedStmt *AttributedStmt::CreateEmpty(ASTContext &C, unsigned NumAttrs) { return new (Mem) AttributedStmt(EmptyShell(), NumAttrs); } -bool Stmt::hasImplicitControlFlow() const { - switch (StmtBits.sClass) { - default: - return false; - - case CallExprClass: - case ConditionalOperatorClass: - case ChooseExprClass: - case StmtExprClass: - case DeclStmtClass: - return true; - - case Stmt::BinaryOperatorClass: { - const BinaryOperator* B = cast<BinaryOperator>(this); - if (B->isLogicalOp() || B->getOpcode() == BO_Comma) - return true; - else - return false; - } - } -} - -std::string AsmStmt::generateAsmString(ASTContext &C) const { +std::string AsmStmt::generateAsmString(const ASTContext &C) const { if (const GCCAsmStmt *gccAsmStmt = dyn_cast<GCCAsmStmt>(this)) return gccAsmStmt->generateAsmString(C); if (const MSAsmStmt *msAsmStmt = dyn_cast<MSAsmStmt>(this)) @@ -406,14 +386,14 @@ StringRef GCCAsmStmt::getInputConstraint(unsigned i) const { return getInputConstraintLiteral(i)->getString(); } -void GCCAsmStmt::setOutputsAndInputsAndClobbers(ASTContext &C, - IdentifierInfo **Names, - StringLiteral **Constraints, - Stmt **Exprs, - unsigned NumOutputs, - unsigned NumInputs, - StringLiteral **Clobbers, - unsigned NumClobbers) { +void GCCAsmStmt::setOutputsAndInputsAndClobbers(const ASTContext &C, + IdentifierInfo **Names, + StringLiteral **Constraints, + Stmt **Exprs, + unsigned NumOutputs, + unsigned NumInputs, + StringLiteral **Clobbers, + unsigned NumClobbers) { this->NumOutputs = NumOutputs; this->NumInputs = NumInputs; this->NumClobbers = NumClobbers; @@ -461,7 +441,7 @@ int GCCAsmStmt::getNamedOperand(StringRef SymbolicName) const { /// it into pieces. If the asm string is erroneous, emit errors and return /// true, otherwise return false. unsigned GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces, - ASTContext &C, unsigned &DiagOffs) const { + const ASTContext &C, unsigned &DiagOffs) const { StringRef Str = getAsmString()->getString(); const char *StrStart = Str.begin(); const char *StrEnd = Str.end(); @@ -599,7 +579,7 @@ unsigned GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces, } /// Assemble final IR asm string (GCC-style). -std::string GCCAsmStmt::generateAsmString(ASTContext &C) const { +std::string GCCAsmStmt::generateAsmString(const ASTContext &C) const { // Analyze the asm string to decompose it into its pieces. We know that Sema // has already done this, so it is guaranteed to be successful. SmallVector<GCCAsmStmt::AsmStringPiece, 4> Pieces; @@ -620,7 +600,7 @@ std::string GCCAsmStmt::generateAsmString(ASTContext &C) const { } /// Assemble final IR asm string (MS-style). -std::string MSAsmStmt::generateAsmString(ASTContext &C) const { +std::string MSAsmStmt::generateAsmString(const ASTContext &C) const { // FIXME: This needs to be translated into the IR string representation. return AsmStr; } @@ -646,12 +626,12 @@ QualType CXXCatchStmt::getCaughtType() const { // Constructors //===----------------------------------------------------------------------===// -GCCAsmStmt::GCCAsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple, - bool isvolatile, unsigned numoutputs, unsigned numinputs, - IdentifierInfo **names, StringLiteral **constraints, - Expr **exprs, StringLiteral *asmstr, - unsigned numclobbers, StringLiteral **clobbers, - SourceLocation rparenloc) +GCCAsmStmt::GCCAsmStmt(const ASTContext &C, SourceLocation asmloc, + bool issimple, bool isvolatile, unsigned numoutputs, + unsigned numinputs, IdentifierInfo **names, + StringLiteral **constraints, Expr **exprs, + StringLiteral *asmstr, unsigned numclobbers, + StringLiteral **clobbers, SourceLocation rparenloc) : AsmStmt(GCCAsmStmtClass, asmloc, issimple, isvolatile, numoutputs, numinputs, numclobbers), RParenLoc(rparenloc), AsmStr(asmstr) { @@ -670,7 +650,7 @@ GCCAsmStmt::GCCAsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple, std::copy(clobbers, clobbers + NumClobbers, Clobbers); } -MSAsmStmt::MSAsmStmt(ASTContext &C, SourceLocation asmloc, +MSAsmStmt::MSAsmStmt(const ASTContext &C, SourceLocation asmloc, SourceLocation lbraceloc, bool issimple, bool isvolatile, ArrayRef<Token> asmtoks, unsigned numoutputs, unsigned numinputs, @@ -684,15 +664,14 @@ MSAsmStmt::MSAsmStmt(ASTContext &C, SourceLocation asmloc, initialize(C, asmstr, asmtoks, constraints, exprs, clobbers); } -static StringRef copyIntoContext(ASTContext &C, StringRef str) { +static StringRef copyIntoContext(const ASTContext &C, StringRef str) { size_t size = str.size(); char *buffer = new (C) char[size]; memcpy(buffer, str.data(), size); return StringRef(buffer, size); } -void MSAsmStmt::initialize(ASTContext &C, - StringRef asmstr, +void MSAsmStmt::initialize(const ASTContext &C, StringRef asmstr, ArrayRef<Token> asmtoks, ArrayRef<StringRef> constraints, ArrayRef<Expr*> exprs, @@ -731,7 +710,7 @@ ObjCForCollectionStmt::ObjCForCollectionStmt(Stmt *Elem, Expr *Collect, SourceLocation RPL) : Stmt(ObjCForCollectionStmtClass) { SubExprs[ELEM] = Elem; - SubExprs[COLLECTION] = reinterpret_cast<Stmt*>(Collect); + SubExprs[COLLECTION] = Collect; SubExprs[BODY] = Body; ForLoc = FCL; RParenLoc = RPL; @@ -752,7 +731,7 @@ ObjCAtTryStmt::ObjCAtTryStmt(SourceLocation atTryLoc, Stmt *atTryStmt, Stmts[NumCatchStmts + 1] = atFinallyStmt; } -ObjCAtTryStmt *ObjCAtTryStmt::Create(ASTContext &Context, +ObjCAtTryStmt *ObjCAtTryStmt::Create(const ASTContext &Context, SourceLocation atTryLoc, Stmt *atTryStmt, Stmt **CatchStmts, @@ -765,9 +744,9 @@ ObjCAtTryStmt *ObjCAtTryStmt::Create(ASTContext &Context, atFinallyStmt); } -ObjCAtTryStmt *ObjCAtTryStmt::CreateEmpty(ASTContext &Context, - unsigned NumCatchStmts, - bool HasFinally) { +ObjCAtTryStmt *ObjCAtTryStmt::CreateEmpty(const ASTContext &Context, + unsigned NumCatchStmts, + bool HasFinally) { unsigned Size = sizeof(ObjCAtTryStmt) + (1 + NumCatchStmts + HasFinally) * sizeof(Stmt *); void *Mem = Context.Allocate(Size, llvm::alignOf<ObjCAtTryStmt>()); @@ -782,7 +761,7 @@ SourceLocation ObjCAtTryStmt::getLocEnd() const { return getTryBody()->getLocEnd(); } -CXXTryStmt *CXXTryStmt::Create(ASTContext &C, SourceLocation tryLoc, +CXXTryStmt *CXXTryStmt::Create(const ASTContext &C, SourceLocation tryLoc, Stmt *tryBlock, ArrayRef<Stmt*> handlers) { std::size_t Size = sizeof(CXXTryStmt); Size += ((handlers.size() + 1) * sizeof(Stmt)); @@ -791,7 +770,7 @@ CXXTryStmt *CXXTryStmt::Create(ASTContext &C, SourceLocation tryLoc, return new (Mem) CXXTryStmt(tryLoc, tryBlock, handlers); } -CXXTryStmt *CXXTryStmt::Create(ASTContext &C, EmptyShell Empty, +CXXTryStmt *CXXTryStmt::Create(const ASTContext &C, EmptyShell Empty, unsigned numHandlers) { std::size_t Size = sizeof(CXXTryStmt); Size += ((numHandlers + 1) * sizeof(Stmt)); @@ -815,8 +794,8 @@ CXXForRangeStmt::CXXForRangeStmt(DeclStmt *Range, DeclStmt *BeginEndStmt, : Stmt(CXXForRangeStmtClass), ForLoc(FL), ColonLoc(CL), RParenLoc(RPL) { SubExprs[RANGE] = Range; SubExprs[BEGINEND] = BeginEndStmt; - SubExprs[COND] = reinterpret_cast<Stmt*>(Cond); - SubExprs[INC] = reinterpret_cast<Stmt*>(Inc); + SubExprs[COND] = Cond; + SubExprs[INC] = Inc; SubExprs[LOOPVAR] = LoopVar; SubExprs[BODY] = Body; } @@ -842,12 +821,12 @@ const VarDecl *CXXForRangeStmt::getLoopVariable() const { return const_cast<CXXForRangeStmt*>(this)->getLoopVariable(); } -IfStmt::IfStmt(ASTContext &C, SourceLocation IL, VarDecl *var, Expr *cond, +IfStmt::IfStmt(const ASTContext &C, SourceLocation IL, VarDecl *var, Expr *cond, Stmt *then, SourceLocation EL, Stmt *elsev) : Stmt(IfStmtClass), IfLoc(IL), ElseLoc(EL) { setConditionVariable(C, var); - SubExprs[COND] = reinterpret_cast<Stmt*>(cond); + SubExprs[COND] = cond; SubExprs[THEN] = then; SubExprs[ELSE] = elsev; } @@ -860,7 +839,7 @@ VarDecl *IfStmt::getConditionVariable() const { return cast<VarDecl>(DS->getSingleDecl()); } -void IfStmt::setConditionVariable(ASTContext &C, VarDecl *V) { +void IfStmt::setConditionVariable(const ASTContext &C, VarDecl *V) { if (!V) { SubExprs[VAR] = 0; return; @@ -871,15 +850,15 @@ void IfStmt::setConditionVariable(ASTContext &C, VarDecl *V) { VarRange.getEnd()); } -ForStmt::ForStmt(ASTContext &C, Stmt *Init, Expr *Cond, VarDecl *condVar, +ForStmt::ForStmt(const ASTContext &C, Stmt *Init, Expr *Cond, VarDecl *condVar, Expr *Inc, Stmt *Body, SourceLocation FL, SourceLocation LP, SourceLocation RP) : Stmt(ForStmtClass), ForLoc(FL), LParenLoc(LP), RParenLoc(RP) { SubExprs[INIT] = Init; setConditionVariable(C, condVar); - SubExprs[COND] = reinterpret_cast<Stmt*>(Cond); - SubExprs[INC] = reinterpret_cast<Stmt*>(Inc); + SubExprs[COND] = Cond; + SubExprs[INC] = Inc; SubExprs[BODY] = Body; } @@ -891,7 +870,7 @@ VarDecl *ForStmt::getConditionVariable() const { return cast<VarDecl>(DS->getSingleDecl()); } -void ForStmt::setConditionVariable(ASTContext &C, VarDecl *V) { +void ForStmt::setConditionVariable(const ASTContext &C, VarDecl *V) { if (!V) { SubExprs[CONDVAR] = 0; return; @@ -902,11 +881,11 @@ void ForStmt::setConditionVariable(ASTContext &C, VarDecl *V) { VarRange.getEnd()); } -SwitchStmt::SwitchStmt(ASTContext &C, VarDecl *Var, Expr *cond) +SwitchStmt::SwitchStmt(const ASTContext &C, VarDecl *Var, Expr *cond) : Stmt(SwitchStmtClass), FirstCase(0), AllEnumCasesCovered(0) { setConditionVariable(C, Var); - SubExprs[COND] = reinterpret_cast<Stmt*>(cond); + SubExprs[COND] = cond; SubExprs[BODY] = NULL; } @@ -918,7 +897,7 @@ VarDecl *SwitchStmt::getConditionVariable() const { return cast<VarDecl>(DS->getSingleDecl()); } -void SwitchStmt::setConditionVariable(ASTContext &C, VarDecl *V) { +void SwitchStmt::setConditionVariable(const ASTContext &C, VarDecl *V) { if (!V) { SubExprs[VAR] = 0; return; @@ -935,11 +914,11 @@ Stmt *SwitchCase::getSubStmt() { return cast<DefaultStmt>(this)->getSubStmt(); } -WhileStmt::WhileStmt(ASTContext &C, VarDecl *Var, Expr *cond, Stmt *body, +WhileStmt::WhileStmt(const ASTContext &C, VarDecl *Var, Expr *cond, Stmt *body, SourceLocation WL) : Stmt(WhileStmtClass) { setConditionVariable(C, Var); - SubExprs[COND] = reinterpret_cast<Stmt*>(cond); + SubExprs[COND] = cond; SubExprs[BODY] = body; WhileLoc = WL; } @@ -952,7 +931,7 @@ VarDecl *WhileStmt::getConditionVariable() const { return cast<VarDecl>(DS->getSingleDecl()); } -void WhileStmt::setConditionVariable(ASTContext &C, VarDecl *V) { +void WhileStmt::setConditionVariable(const ASTContext &C, VarDecl *V) { if (!V) { SubExprs[VAR] = 0; return; @@ -991,10 +970,8 @@ SEHTryStmt::SEHTryStmt(bool IsCXXTry, Children[HANDLER] = Handler; } -SEHTryStmt* SEHTryStmt::Create(ASTContext &C, - bool IsCXXTry, - SourceLocation TryLoc, - Stmt *TryBlock, +SEHTryStmt* SEHTryStmt::Create(const ASTContext &C, bool IsCXXTry, + SourceLocation TryLoc, Stmt *TryBlock, Stmt *Handler) { return new(C) SEHTryStmt(IsCXXTry,TryLoc,TryBlock,Handler); } @@ -1013,14 +990,12 @@ SEHExceptStmt::SEHExceptStmt(SourceLocation Loc, : Stmt(SEHExceptStmtClass), Loc(Loc) { - Children[FILTER_EXPR] = reinterpret_cast<Stmt*>(FilterExpr); + Children[FILTER_EXPR] = FilterExpr; Children[BLOCK] = Block; } -SEHExceptStmt* SEHExceptStmt::Create(ASTContext &C, - SourceLocation Loc, - Expr *FilterExpr, - Stmt *Block) { +SEHExceptStmt* SEHExceptStmt::Create(const ASTContext &C, SourceLocation Loc, + Expr *FilterExpr, Stmt *Block) { return new(C) SEHExceptStmt(Loc,FilterExpr,Block); } @@ -1031,8 +1006,7 @@ SEHFinallyStmt::SEHFinallyStmt(SourceLocation Loc, Block(Block) {} -SEHFinallyStmt* SEHFinallyStmt::Create(ASTContext &C, - SourceLocation Loc, +SEHFinallyStmt* SEHFinallyStmt::Create(const ASTContext &C, SourceLocation Loc, Stmt *Block) { return new(C)SEHFinallyStmt(Loc,Block); } @@ -1079,7 +1053,7 @@ CapturedStmt::CapturedStmt(EmptyShell Empty, unsigned NumCaptures) getStoredStmts()[NumCaptures] = 0; } -CapturedStmt *CapturedStmt::Create(ASTContext &Context, Stmt *S, +CapturedStmt *CapturedStmt::Create(const ASTContext &Context, Stmt *S, CapturedRegionKind Kind, ArrayRef<Capture> Captures, ArrayRef<Expr *> CaptureInits, @@ -1107,7 +1081,7 @@ CapturedStmt *CapturedStmt::Create(ASTContext &Context, Stmt *S, return new (Mem) CapturedStmt(S, Kind, Captures, CaptureInits, CD, RD); } -CapturedStmt *CapturedStmt::CreateDeserialized(ASTContext &Context, +CapturedStmt *CapturedStmt::CreateDeserialized(const ASTContext &Context, unsigned NumCaptures) { unsigned Size = sizeof(CapturedStmt) + sizeof(Stmt *) * (NumCaptures + 1); if (NumCaptures > 0) { @@ -1128,7 +1102,7 @@ Stmt::child_range CapturedStmt::children() { bool CapturedStmt::capturesVariable(const VarDecl *Var) const { for (const_capture_iterator I = capture_begin(), E = capture_end(); I != E; ++I) { - if (I->capturesThis()) + if (!I->capturesVariable()) continue; // This does not handle variable redeclarations. This should be @@ -1140,3 +1114,107 @@ bool CapturedStmt::capturesVariable(const VarDecl *Var) const { return false; } + +StmtRange OMPClause::children() { + switch(getClauseKind()) { + default : break; +#define OPENMP_CLAUSE(Name, Class) \ + case OMPC_ ## Name : return static_cast<Class *>(this)->children(); +#include "clang/Basic/OpenMPKinds.def" + } + llvm_unreachable("unknown OMPClause"); +} + +OMPPrivateClause *OMPPrivateClause::Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc, + ArrayRef<Expr *> VL) { + void *Mem = C.Allocate(sizeof(OMPPrivateClause) + sizeof(Expr *) * VL.size(), + llvm::alignOf<OMPPrivateClause>()); + OMPPrivateClause *Clause = new (Mem) OMPPrivateClause(StartLoc, LParenLoc, + EndLoc, VL.size()); + Clause->setVarRefs(VL); + return Clause; +} + +OMPPrivateClause *OMPPrivateClause::CreateEmpty(const ASTContext &C, + unsigned N) { + void *Mem = C.Allocate(sizeof(OMPPrivateClause) + sizeof(Expr *) * N, + llvm::alignOf<OMPPrivateClause>()); + return new (Mem) OMPPrivateClause(N); +} + +OMPFirstprivateClause *OMPFirstprivateClause::Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc, + ArrayRef<Expr *> VL) { + void *Mem = C.Allocate(sizeof(OMPFirstprivateClause) + + sizeof(Expr *) * VL.size(), + llvm::alignOf<OMPFirstprivateClause>()); + OMPFirstprivateClause *Clause = new (Mem) OMPFirstprivateClause(StartLoc, + LParenLoc, + EndLoc, + VL.size()); + Clause->setVarRefs(VL); + return Clause; +} + +OMPFirstprivateClause *OMPFirstprivateClause::CreateEmpty(const ASTContext &C, + unsigned N) { + void *Mem = C.Allocate(sizeof(OMPFirstprivateClause) + sizeof(Expr *) * N, + llvm::alignOf<OMPFirstprivateClause>()); + return new (Mem) OMPFirstprivateClause(N); +} + +OMPSharedClause *OMPSharedClause::Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc, + ArrayRef<Expr *> VL) { + void *Mem = C.Allocate(sizeof(OMPSharedClause) + sizeof(Expr *) * VL.size(), + llvm::alignOf<OMPSharedClause>()); + OMPSharedClause *Clause = new (Mem) OMPSharedClause(StartLoc, LParenLoc, + EndLoc, VL.size()); + Clause->setVarRefs(VL); + return Clause; +} + +OMPSharedClause *OMPSharedClause::CreateEmpty(const ASTContext &C, + unsigned N) { + void *Mem = C.Allocate(sizeof(OMPSharedClause) + sizeof(Expr *) * N, + llvm::alignOf<OMPSharedClause>()); + return new (Mem) OMPSharedClause(N); +} + +void OMPExecutableDirective::setClauses(ArrayRef<OMPClause *> Clauses) { + assert(Clauses.size() == this->Clauses.size() && + "Number of clauses is not the same as the preallocated buffer"); + std::copy(Clauses.begin(), Clauses.end(), this->Clauses.begin()); +} + +OMPParallelDirective *OMPParallelDirective::Create( + const ASTContext &C, + SourceLocation StartLoc, + SourceLocation EndLoc, + ArrayRef<OMPClause *> Clauses, + Stmt *AssociatedStmt) { + void *Mem = C.Allocate(sizeof(OMPParallelDirective) + + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *), + llvm::alignOf<OMPParallelDirective>()); + OMPParallelDirective *Dir = new (Mem) OMPParallelDirective(StartLoc, EndLoc, + Clauses.size()); + Dir->setClauses(Clauses); + Dir->setAssociatedStmt(AssociatedStmt); + return Dir; +} + +OMPParallelDirective *OMPParallelDirective::CreateEmpty(const ASTContext &C, + unsigned N, + EmptyShell) { + void *Mem = C.Allocate(sizeof(OMPParallelDirective) + + sizeof(OMPClause *) * N + sizeof(Stmt *), + llvm::alignOf<OMPParallelDirective>()); + return new (Mem) OMPParallelDirective(N); +} diff --git a/lib/AST/StmtIterator.cpp b/lib/AST/StmtIterator.cpp index 9bf4aea..6e85375 100644 --- a/lib/AST/StmtIterator.cpp +++ b/lib/AST/StmtIterator.cpp @@ -40,14 +40,7 @@ void StmtIteratorBase::NextVA() { if (p) return; - if (inDecl()) { - if (VarDecl* VD = dyn_cast<VarDecl>(decl)) - if (VD->Init) - return; - - NextDecl(); - } - else if (inDeclGroup()) { + if (inDeclGroup()) { if (VarDecl* VD = dyn_cast<VarDecl>(*DGI)) if (VD->Init) return; @@ -55,40 +48,26 @@ void StmtIteratorBase::NextVA() { NextDecl(); } else { - assert (inSizeOfTypeVA()); - assert(!decl); + assert(inSizeOfTypeVA()); RawVAPtr = 0; } } void StmtIteratorBase::NextDecl(bool ImmediateAdvance) { assert (getVAPtr() == NULL); + assert(inDeclGroup()); - if (inDecl()) { - assert(decl); + if (ImmediateAdvance) + ++DGI; - // FIXME: SIMPLIFY AWAY. - if (ImmediateAdvance) - decl = 0; - else if (HandleDecl(decl)) + for ( ; DGI != DGE; ++DGI) + if (HandleDecl(*DGI)) return; - } - else { - assert(inDeclGroup()); - - if (ImmediateAdvance) - ++DGI; - - for ( ; DGI != DGE; ++DGI) - if (HandleDecl(*DGI)) - return; - } RawVAPtr = 0; } bool StmtIteratorBase::HandleDecl(Decl* D) { - if (VarDecl* VD = dyn_cast<VarDecl>(D)) { if (const VariableArrayType* VAPtr = FindVA(VD->getType().getTypePtr())) { setVAPtr(VAPtr); @@ -113,43 +92,23 @@ bool StmtIteratorBase::HandleDecl(Decl* D) { return false; } -StmtIteratorBase::StmtIteratorBase(Decl *d, Stmt **s) - : stmt(s), decl(d), RawVAPtr(d ? DeclMode : 0) { - if (decl) - NextDecl(false); -} - StmtIteratorBase::StmtIteratorBase(Decl** dgi, Decl** dge) : stmt(0), DGI(dgi), RawVAPtr(DeclGroupMode), DGE(dge) { NextDecl(false); } StmtIteratorBase::StmtIteratorBase(const VariableArrayType* t) - : stmt(0), decl(0), RawVAPtr(SizeOfTypeVAMode) { + : stmt(0), DGI(0), RawVAPtr(SizeOfTypeVAMode) { RawVAPtr |= reinterpret_cast<uintptr_t>(t); } Stmt*& StmtIteratorBase::GetDeclExpr() const { - if (const VariableArrayType* VAPtr = getVAPtr()) { assert (VAPtr->SizeExpr); return const_cast<Stmt*&>(VAPtr->SizeExpr); } - assert (inDecl() || inDeclGroup()); - - if (inDeclGroup()) { - VarDecl* VD = cast<VarDecl>(*DGI); - return *VD->getInitAddress(); - } - - assert (inDecl()); - - if (VarDecl* VD = dyn_cast<VarDecl>(decl)) { - assert (VD->Init); - return *VD->getInitAddress(); - } - - EnumConstantDecl* ECD = cast<EnumConstantDecl>(decl); - return ECD->Init; + assert (inDeclGroup()); + VarDecl* VD = cast<VarDecl>(*DGI); + return *VD->getInitAddress(); } diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 9203dc1..0ecb5b5 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -580,6 +580,87 @@ void StmtPrinter::VisitSEHFinallyStmt(SEHFinallyStmt *Node) { } //===----------------------------------------------------------------------===// +// OpenMP clauses printing methods +//===----------------------------------------------------------------------===// + +namespace { +class OMPClausePrinter : public OMPClauseVisitor<OMPClausePrinter> { + raw_ostream &OS; + /// \brief Process clauses with list of variables. + template <typename T> + void VisitOMPClauseList(T *Node, char StartSym); +public: + OMPClausePrinter(raw_ostream &OS) : OS(OS) { } +#define OPENMP_CLAUSE(Name, Class) \ + void Visit##Class(Class *S); +#include "clang/Basic/OpenMPKinds.def" +}; + +void OMPClausePrinter::VisitOMPDefaultClause(OMPDefaultClause *Node) { + OS << "default(" + << getOpenMPSimpleClauseTypeName(OMPC_default, Node->getDefaultKind()) + << ")"; +} + +template<typename T> +void OMPClausePrinter::VisitOMPClauseList(T *Node, char StartSym) { + for (typename T::varlist_iterator I = Node->varlist_begin(), + E = Node->varlist_end(); + I != E; ++I) + OS << (I == Node->varlist_begin() ? StartSym : ',') + << *cast<NamedDecl>(cast<DeclRefExpr>(*I)->getDecl()); +} + +void OMPClausePrinter::VisitOMPPrivateClause(OMPPrivateClause *Node) { + if (!Node->varlist_empty()) { + OS << "private"; + VisitOMPClauseList(Node, '('); + OS << ")"; + } +} + +void OMPClausePrinter::VisitOMPFirstprivateClause(OMPFirstprivateClause *Node) { + if (!Node->varlist_empty()) { + OS << "firstprivate"; + VisitOMPClauseList(Node, '('); + OS << ")"; + } +} + +void OMPClausePrinter::VisitOMPSharedClause(OMPSharedClause *Node) { + if (!Node->varlist_empty()) { + OS << "shared"; + VisitOMPClauseList(Node, '('); + OS << ")"; + } +} + +} + +//===----------------------------------------------------------------------===// +// OpenMP directives printing methods +//===----------------------------------------------------------------------===// + +void StmtPrinter::VisitOMPParallelDirective(OMPParallelDirective *Node) { + Indent() << "#pragma omp parallel "; + + OMPClausePrinter Printer(OS); + ArrayRef<OMPClause *> Clauses = Node->clauses(); + for (ArrayRef<OMPClause *>::iterator I = Clauses.begin(), E = Clauses.end(); + I != E; ++I) + if (*I && !(*I)->isImplicit()) { + Printer.Visit(*I); + OS << ' '; + } + OS << "\n"; + if (Node->getAssociatedStmt()) { + assert(isa<CapturedStmt>(Node->getAssociatedStmt()) && + "Expected captured statement!"); + Stmt *CS = cast<CapturedStmt>(Node->getAssociatedStmt())->getCapturedStmt(); + PrintStmt(CS); + } +} +//===----------------------------------------------------------------------===// // Expr printing methods. //===----------------------------------------------------------------------===// @@ -657,6 +738,9 @@ void StmtPrinter::VisitPredefinedExpr(PredefinedExpr *Node) { case PredefinedExpr::Function: OS << "__FUNCTION__"; break; + case PredefinedExpr::FuncDName: + OS << "__FUNCDNAME__"; + break; case PredefinedExpr::LFunction: OS << "L__FUNCTION__"; break; @@ -1019,6 +1103,14 @@ void StmtPrinter::VisitShuffleVectorExpr(ShuffleVectorExpr *Node) { OS << ")"; } +void StmtPrinter::VisitConvertVectorExpr(ConvertVectorExpr *Node) { + OS << "__builtin_convertvector("; + PrintExpr(Node->getSrcExpr()); + OS << ", "; + Node->getType().print(OS, Policy); + OS << ")"; +} + void StmtPrinter::VisitInitListExpr(InitListExpr* Node) { if (Node->getSyntacticForm()) { Visit(Node->getSyntacticForm()); @@ -1226,7 +1318,7 @@ void StmtPrinter::VisitCXXConstCastExpr(CXXConstCastExpr *Node) { void StmtPrinter::VisitCXXTypeidExpr(CXXTypeidExpr *Node) { OS << "typeid("; if (Node->isTypeOperand()) { - Node->getTypeOperand().print(OS, Policy); + Node->getTypeOperandSourceInfo()->getType().print(OS, Policy); } else { PrintExpr(Node->getExprOperand()); } @@ -1236,7 +1328,7 @@ void StmtPrinter::VisitCXXTypeidExpr(CXXTypeidExpr *Node) { void StmtPrinter::VisitCXXUuidofExpr(CXXUuidofExpr *Node) { OS << "__uuidof("; if (Node->isTypeOperand()) { - Node->getTypeOperand().print(OS, Policy); + Node->getTypeOperandSourceInfo()->getType().print(OS, Policy); } else { PrintExpr(Node->getExprOperand()); } @@ -1339,6 +1431,8 @@ void StmtPrinter::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *Node) { for (CXXTemporaryObjectExpr::arg_iterator Arg = Node->arg_begin(), ArgEnd = Node->arg_end(); Arg != ArgEnd; ++Arg) { + if (Arg->isDefaultArgument()) + break; if (Arg != Node->arg_begin()) OS << ", "; PrintExpr(*Arg); @@ -1377,17 +1471,18 @@ void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) { break; case LCK_ByRef: - if (Node->getCaptureDefault() != LCD_ByRef) + if (Node->getCaptureDefault() != LCD_ByRef || C->isInitCapture()) OS << '&'; OS << C->getCapturedVar()->getName(); break; case LCK_ByCopy: - if (Node->getCaptureDefault() != LCD_ByCopy) - OS << '='; OS << C->getCapturedVar()->getName(); break; } + + if (C->isInitCapture()) + PrintExpr(C->getCapturedVar()->getInit()); } OS << ']'; @@ -1525,6 +1620,10 @@ void StmtPrinter::VisitCXXConstructExpr(CXXConstructExpr *E) { OS << " }"; } +void StmtPrinter::VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E) { + PrintExpr(E->getSubExpr()); +} + void StmtPrinter::VisitExprWithCleanups(ExprWithCleanups *E) { // Just forward to the sub expression. PrintExpr(E->getSubExpr()); @@ -1616,6 +1715,7 @@ static const char *getTypeTraitName(UnaryTypeTrait UTT) { case UTT_IsReference: return "__is_reference"; case UTT_IsRvalueReference: return "__is_rvalue_reference"; case UTT_IsScalar: return "__is_scalar"; + case UTT_IsSealed: return "__is_sealed"; case UTT_IsSigned: return "__is_signed"; case UTT_IsStandardLayout: return "__is_standard_layout"; case UTT_IsTrivial: return "__is_trivial"; @@ -1886,7 +1986,7 @@ void StmtPrinter::VisitAsTypeExpr(AsTypeExpr *Node) { // Stmt method implementations //===----------------------------------------------------------------------===// -void Stmt::dumpPretty(ASTContext &Context) const { +void Stmt::dumpPretty(const ASTContext &Context) const { printPretty(llvm::errs(), 0, PrintingPolicy(Context.getLangOpts())); } diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index 8ade242..6805e62 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -252,6 +252,52 @@ StmtProfiler::VisitObjCAutoreleasePoolStmt(const ObjCAutoreleasePoolStmt *S) { VisitStmt(S); } +namespace { +class OMPClauseProfiler : public ConstOMPClauseVisitor<OMPClauseProfiler> { + StmtProfiler *Profiler; + /// \brief Process clauses with list of variables. + template <typename T> + void VisitOMPClauseList(T *Node); +public: + OMPClauseProfiler(StmtProfiler *P) : Profiler(P) { } +#define OPENMP_CLAUSE(Name, Class) \ + void Visit##Class(const Class *C); +#include "clang/Basic/OpenMPKinds.def" +}; + +void OMPClauseProfiler::VisitOMPDefaultClause(const OMPDefaultClause *C) { } + +template<typename T> +void OMPClauseProfiler::VisitOMPClauseList(T *Node) { + for (typename T::varlist_const_iterator I = Node->varlist_begin(), + E = Node->varlist_end(); + I != E; ++I) + Profiler->VisitStmt(*I); +} + +void OMPClauseProfiler::VisitOMPPrivateClause(const OMPPrivateClause *C) { + VisitOMPClauseList(C); +} +void OMPClauseProfiler::VisitOMPFirstprivateClause( + const OMPFirstprivateClause *C) { + VisitOMPClauseList(C); +} +void OMPClauseProfiler::VisitOMPSharedClause(const OMPSharedClause *C) { + VisitOMPClauseList(C); +} +} + +void +StmtProfiler::VisitOMPParallelDirective(const OMPParallelDirective *S) { + VisitStmt(S); + OMPClauseProfiler P(this); + ArrayRef<OMPClause *> Clauses = S->clauses(); + for (ArrayRef<OMPClause *>::iterator I = Clauses.begin(), E = Clauses.end(); + I != E; ++I) + if (*I) + P.Visit(*I); +} + void StmtProfiler::VisitExpr(const Expr *S) { VisitStmt(S); } @@ -417,6 +463,10 @@ void StmtProfiler::VisitShuffleVectorExpr(const ShuffleVectorExpr *S) { VisitExpr(S); } +void StmtProfiler::VisitConvertVectorExpr(const ConvertVectorExpr *S) { + VisitExpr(S); +} + void StmtProfiler::VisitChooseExpr(const ChooseExpr *S) { VisitExpr(S); } @@ -758,16 +808,21 @@ void StmtProfiler::VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *S) { VisitExpr(S); } +void StmtProfiler::VisitCXXStdInitializerListExpr( + const CXXStdInitializerListExpr *S) { + VisitExpr(S); +} + void StmtProfiler::VisitCXXTypeidExpr(const CXXTypeidExpr *S) { VisitExpr(S); if (S->isTypeOperand()) - VisitType(S->getTypeOperand()); + VisitType(S->getTypeOperandSourceInfo()->getType()); } void StmtProfiler::VisitCXXUuidofExpr(const CXXUuidofExpr *S) { VisitExpr(S); if (S->isTypeOperand()) - VisitType(S->getTypeOperand()); + VisitType(S->getTypeOperandSourceInfo()->getType()); } void StmtProfiler::VisitMSPropertyRefExpr(const MSPropertyRefExpr *S) { @@ -822,9 +877,14 @@ StmtProfiler::VisitLambdaExpr(const LambdaExpr *S) { CEnd = S->explicit_capture_end(); C != CEnd; ++C) { ID.AddInteger(C->getCaptureKind()); - if (C->capturesVariable()) { + switch (C->getCaptureKind()) { + case LCK_This: + break; + case LCK_ByRef: + case LCK_ByCopy: VisitDecl(C->getCapturedVar()); ID.AddBoolean(C->isPackExpansion()); + break; } } // Note: If we actually needed to be able to match lambda @@ -863,7 +923,14 @@ StmtProfiler::VisitCXXPseudoDestructorExpr(const CXXPseudoDestructorExpr *S) { VisitExpr(S); ID.AddBoolean(S->isArrow()); VisitNestedNameSpecifier(S->getQualifier()); - VisitType(S->getDestroyedType()); + ID.AddBoolean(S->getScopeTypeInfo() != 0); + if (S->getScopeTypeInfo()) + VisitType(S->getScopeTypeInfo()->getType()); + ID.AddBoolean(S->getDestroyedTypeInfo() != 0); + if (S->getDestroyedTypeInfo()) + VisitType(S->getDestroyedType()); + else + ID.AddPointer(S->getDestroyedTypeIdentifier()); } void StmtProfiler::VisitOverloadExpr(const OverloadExpr *S) { diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp index d68b95e..16efb79 100644 --- a/lib/AST/TemplateBase.cpp +++ b/lib/AST/TemplateBase.cpp @@ -55,8 +55,8 @@ static void printIntegral(const TemplateArgument &TemplArg, //===----------------------------------------------------------------------===// TemplateArgument::TemplateArgument(ASTContext &Ctx, const llvm::APSInt &Value, - QualType Type) - : Kind(Integral) { + QualType Type) { + Integer.Kind = Integral; // Copy the APSInt value into our decomposed form. Integer.BitWidth = Value.getBitWidth(); Integer.IsUnsigned = Value.isUnsigned(); @@ -225,7 +225,7 @@ bool TemplateArgument::containsUnexpandedParameterPack() const { } Optional<unsigned> TemplateArgument::getNumTemplateExpansions() const { - assert(Kind == TemplateExpansion); + assert(getKind() == TemplateExpansion); if (TemplateArg.NumExpansions) return TemplateArg.NumExpansions - 1; @@ -234,8 +234,8 @@ Optional<unsigned> TemplateArgument::getNumTemplateExpansions() const { void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) const { - ID.AddInteger(Kind); - switch (Kind) { + ID.AddInteger(getKind()); + switch (getKind()) { case Null: break; @@ -243,6 +243,10 @@ void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID, getAsType().Profile(ID); break; + case NullPtr: + getNullPtrType().Profile(ID); + break; + case Declaration: ID.AddPointer(getAsDecl()? getAsDecl()->getCanonicalDecl() : 0); break; @@ -291,7 +295,7 @@ bool TemplateArgument::structurallyEquals(const TemplateArgument &Other) const { case Template: case TemplateExpansion: case NullPtr: - return TypeOrValue == Other.TypeOrValue; + return TypeOrValue.V == Other.TypeOrValue.V; case Declaration: return getAsDecl() == Other.getAsDecl() && @@ -353,9 +357,10 @@ void TemplateArgument::print(const PrintingPolicy &Policy, case Declaration: { NamedDecl *ND = cast<NamedDecl>(getAsDecl()); + Out << '&'; if (ND->getDeclName()) { // FIXME: distinguish between pointer and reference args? - Out << *ND; + ND->printQualifiedName(Out); } else { Out << "<anonymous>"; } @@ -449,68 +454,6 @@ SourceRange TemplateArgumentLoc::getSourceRange() const { llvm_unreachable("Invalid TemplateArgument Kind!"); } -TemplateArgumentLoc TemplateArgumentLoc::getPackExpansionPattern( - SourceLocation &Ellipsis, 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 = - ExpansionTSInfo->getTypeLoc().castAs<PackExpansionTypeLoc>(); - 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(), - getTemplateQualifierLoc(), - getTemplateNameLoc()); - - case TemplateArgument::Declaration: - case TemplateArgument::NullPtr: - case TemplateArgument::Template: - case TemplateArgument::Integral: - case TemplateArgument::Pack: - case TemplateArgument::Null: - return TemplateArgumentLoc(); - } - - llvm_unreachable("Invalid TemplateArgument Kind!"); -} - const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB, const TemplateArgument &Arg) { switch (Arg.getKind()) { diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index fa16fac..7421bae 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -93,7 +93,7 @@ unsigned ConstantArrayType::getNumAddressingBits(ASTContext &Context, if ((ElementSize >> 32) == 0 && NumElements.getBitWidth() <= 64 && (NumElements.getZExtValue() >> 32) == 0) { uint64_t TotalSize = NumElements.getZExtValue() * ElementSize; - return 64 - llvm::CountLeadingZeros_64(TotalSize); + return 64 - llvm::countLeadingZeros(TotalSize); } // Otherwise, use APSInt to handle arbitrary sized values. @@ -111,11 +111,12 @@ unsigned ConstantArrayType::getNumAddressingBits(ASTContext &Context, unsigned ConstantArrayType::getMaxSizeBits(ASTContext &Context) { unsigned Bits = Context.getTypeSize(Context.getSizeType()); - // GCC appears to only allow 63 bits worth of address space when compiling - // for 64-bit, so we do the same. - if (Bits == 64) - --Bits; - + // Limit the number of bits in size_t so that maximal bit size fits 64 bit + // integer (see PR8256). We can do this as currently there is no hardware + // that supports full 64-bit virtual space. + if (Bits > 61) + Bits = 61; + return Bits; } @@ -337,6 +338,10 @@ template <> const TemplateSpecializationType *Type::getAs() const { return getAsSugar<TemplateSpecializationType>(this); } +template <> const AttributedType *Type::getAs() const { + return getAsSugar<AttributedType>(this); +} + /// 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. @@ -357,23 +362,6 @@ const Type *Type::getUnqualifiedDesugaredType() const { } } } - -bool Type::isDerivedType() const { - switch (CanonicalType->getTypeClass()) { - case Pointer: - case VariableArray: - case ConstantArray: - case IncompleteArray: - case FunctionProto: - case FunctionNoProto: - case LValueReference: - case RValueReference: - case Record: - return true; - default: - return false; - } -} bool Type::isClassType() const { if (const RecordType *RT = getAs<RecordType>()) return RT->getDecl()->isClass(); @@ -750,9 +738,9 @@ bool Type::isSignedIntegerOrEnumerationType() const { bool Type::hasSignedIntegerRepresentation() const { if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType)) - return VT->getElementType()->isSignedIntegerType(); + return VT->getElementType()->isSignedIntegerOrEnumerationType(); else - return isSignedIntegerType(); + return isSignedIntegerOrEnumerationType(); } /// isUnsignedIntegerType - Return true if this is an integer type that is @@ -790,9 +778,9 @@ bool Type::isUnsignedIntegerOrEnumerationType() const { bool Type::hasUnsignedIntegerRepresentation() const { if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType)) - return VT->getElementType()->isUnsignedIntegerType(); + return VT->getElementType()->isUnsignedIntegerOrEnumerationType(); else - return isUnsignedIntegerType(); + return isUnsignedIntegerOrEnumerationType(); } bool Type::isFloatingType() const { @@ -1109,15 +1097,18 @@ bool QualType::isTriviallyCopyableType(ASTContext &Context) const { } } - // C++0x [basic.types]p9 + // C++11 [basic.types]p9 // Scalar types, trivially copyable class types, arrays of such types, and - // cv-qualified versions of these types are collectively called trivial - // types. + // non-volatile const-qualified versions of these types are collectively + // called trivially copyable types. QualType CanonicalType = getCanonicalType(); if (CanonicalType->isDependentType()) return false; + if (CanonicalType.isVolatileQualified()) + return false; + // Return false for incomplete types after skipping any incomplete array types // which are expressly allowed by the standard and thus our API. if (CanonicalType->isIncompleteType()) @@ -1142,7 +1133,7 @@ bool QualType::isTriviallyCopyableType(ASTContext &Context) const { -bool Type::isLiteralType(ASTContext &Ctx) const { +bool Type::isLiteralType(const ASTContext &Ctx) const { if (isDependentType()) return false; @@ -1196,6 +1187,15 @@ bool Type::isLiteralType(ASTContext &Ctx) const { return true; } + // We treat _Atomic T as a literal type if T is a literal type. + if (const AtomicType *AT = BaseTy->getAs<AtomicType>()) + return AT->getValueType()->isLiteralType(Ctx); + + // If this type hasn't been deduced yet, then conservatively assume that + // it'll work out to be a literal type. + if (isa<AutoType>(BaseTy->getCanonicalTypeInternal())) + return true; + return false; } @@ -1521,7 +1521,7 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const { case Double: return "double"; case LongDouble: return "long double"; case WChar_S: - case WChar_U: return "wchar_t"; + case WChar_U: return Policy.MSWChar ? "__wchar_t" : "wchar_t"; case Char16: return "char16_t"; case Char32: return "char32_t"; case NullPtr: return "nullptr_t"; @@ -1548,7 +1548,7 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const { llvm_unreachable("Invalid builtin type."); } -QualType QualType::getNonLValueExprType(ASTContext &Context) const { +QualType QualType::getNonLValueExprType(const ASTContext &Context) const { if (const ReferenceType *RefType = getTypePtr()->getAs<ReferenceType>()) return RefType->getPointeeType(); @@ -1566,14 +1566,13 @@ QualType QualType::getNonLValueExprType(ASTContext &Context) const { StringRef FunctionType::getNameForCallConv(CallingConv CC) { switch (CC) { - case CC_Default: - llvm_unreachable("no name for default cc"); - case CC_C: return "cdecl"; case CC_X86StdCall: return "stdcall"; case CC_X86FastCall: return "fastcall"; case CC_X86ThisCall: return "thiscall"; case CC_X86Pascal: return "pascal"; + case CC_X86_64Win64: return "ms_abi"; + case CC_X86_64SysV: return "sysv_abi"; case CC_AAPCS: return "aapcs"; case CC_AAPCS_VFP: return "aapcs-vfp"; case CC_PnaclCall: return "pnaclcall"; @@ -1664,7 +1663,7 @@ FunctionProtoType::FunctionProtoType(QualType result, ArrayRef<QualType> args, } FunctionProtoType::NoexceptResult -FunctionProtoType::getNoexceptSpec(ASTContext &ctx) const { +FunctionProtoType::getNoexceptSpec(const ASTContext &ctx) const { ExceptionSpecificationType est = getExceptionSpecType(); if (est == EST_BasicNoexcept) return NR_Nothrow; @@ -1849,6 +1848,49 @@ bool TagType::isBeingDefined() const { return getDecl()->isBeingDefined(); } +bool AttributedType::isMSTypeSpec() const { + switch (getAttrKind()) { + default: return false; + case attr_ptr32: + case attr_ptr64: + case attr_sptr: + case attr_uptr: + return true; + } + llvm_unreachable("invalid attr kind"); +} + +bool AttributedType::isCallingConv() const { + switch (getAttrKind()) { + case attr_ptr32: + case attr_ptr64: + case attr_sptr: + case attr_uptr: + case attr_address_space: + case attr_regparm: + case attr_vector_size: + case attr_neon_vector_type: + case attr_neon_polyvector_type: + case attr_objc_gc: + case attr_objc_ownership: + case attr_noreturn: + return false; + case attr_pcs: + case attr_pcs_vfp: + case attr_cdecl: + case attr_fastcall: + case attr_stdcall: + case attr_thiscall: + case attr_pascal: + case attr_ms_abi: + case attr_sysv_abi: + case attr_pnaclcall: + case attr_inteloclbicc: + return true; + } + llvm_unreachable("invalid attr kind"); +} + CXXRecordDecl *InjectedClassNameType::getDecl() const { return cast<CXXRecordDecl>(getInterestingTagDecl(Decl)); } @@ -1908,7 +1950,8 @@ anyDependentTemplateArguments(const TemplateArgumentLoc *Args, unsigned N, return false; } -bool TemplateSpecializationType:: +#ifndef NDEBUG +static bool anyDependentTemplateArguments(const TemplateArgument *Args, unsigned N, bool &InstantiationDependent) { for (unsigned i = 0; i != N; ++i) { @@ -1922,6 +1965,7 @@ anyDependentTemplateArguments(const TemplateArgument *Args, unsigned N, } return false; } +#endif TemplateSpecializationType:: TemplateSpecializationType(TemplateName T, @@ -1945,8 +1989,8 @@ TemplateSpecializationType(TemplateName T, (void)InstantiationDependent; assert((!Canon.isNull() || T.isDependent() || - anyDependentTemplateArguments(Args, NumArgs, - InstantiationDependent)) && + ::anyDependentTemplateArguments(Args, NumArgs, + InstantiationDependent)) && "No canonical type for non-dependent class template specialization"); TemplateArgument *TemplateArgs @@ -2124,7 +2168,7 @@ static CachedProperties computeCachedProperties(const Type *T) { // - 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 - Linkage L = Tag->getLinkage(); + Linkage L = Tag->getLinkageInternal(); bool IsLocalOrUnnamed = Tag->getDeclContext()->isFunctionOrMethod() || !Tag->hasNameForLinkage(); @@ -2166,7 +2210,7 @@ static CachedProperties computeCachedProperties(const Type *T) { return result; } case Type::ObjCInterface: { - Linkage L = cast<ObjCInterfaceType>(T)->getDecl()->getLinkage(); + Linkage L = cast<ObjCInterfaceType>(T)->getDecl()->getLinkageInternal(); return CachedProperties(L, false); } case Type::ObjCObject: diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp index 03d4030..22a51bc 100644 --- a/lib/AST/TypeLoc.cpp +++ b/lib/AST/TypeLoc.cpp @@ -41,12 +41,30 @@ SourceRange TypeLoc::getLocalSourceRangeImpl(TypeLoc TL) { } namespace { + class TypeAligner : public TypeLocVisitor<TypeAligner, unsigned> { + public: +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#define TYPELOC(CLASS, PARENT) \ + unsigned Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \ + return TyLoc.getLocalDataAlignment(); \ + } +#include "clang/AST/TypeLocNodes.def" + }; +} + +/// \brief Returns the alignment of the type source info data block. +unsigned TypeLoc::getLocalAlignmentForType(QualType Ty) { + if (Ty.isNull()) return 1; + return TypeAligner().Visit(TypeLoc(Ty, 0)); +} + +namespace { class TypeSizer : public TypeLocVisitor<TypeSizer, unsigned> { public: #define ABSTRACT_TYPELOC(CLASS, PARENT) #define TYPELOC(CLASS, PARENT) \ unsigned Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \ - return TyLoc.getFullDataSize(); \ + return TyLoc.getLocalDataSize(); \ } #include "clang/AST/TypeLocNodes.def" }; @@ -54,8 +72,18 @@ namespace { /// \brief Returns the size of the type source info data block. unsigned TypeLoc::getFullDataSizeForType(QualType Ty) { - if (Ty.isNull()) return 0; - return TypeSizer().Visit(TypeLoc(Ty, 0)); + unsigned Total = 0; + TypeLoc TyLoc(Ty, 0); + unsigned MaxAlign = 1; + while (!TyLoc.isNull()) { + unsigned Align = getLocalAlignmentForType(TyLoc.getType()); + MaxAlign = std::max(Align, MaxAlign); + Total = llvm::RoundUpToAlignment(Total, Align); + Total += TypeSizer().Visit(TyLoc); + TyLoc = TyLoc.getNextTypeLoc(); + } + Total = llvm::RoundUpToAlignment(Total, MaxAlign); + return Total; } namespace { @@ -329,10 +357,13 @@ void TemplateSpecializationTypeLoc::initializeArgLocs(ASTContext &Context, for (unsigned i = 0, e = NumArgs; i != e; ++i) { switch (Args[i].getKind()) { case TemplateArgument::Null: - case TemplateArgument::Declaration: + llvm_unreachable("Impossible TemplateArgument"); + case TemplateArgument::Integral: + case TemplateArgument::Declaration: case TemplateArgument::NullPtr: - llvm_unreachable("Impossible TemplateArgument"); + ArgInfos[i] = TemplateArgumentLocInfo(); + break; case TemplateArgument::Expression: ArgInfos[i] = TemplateArgumentLocInfo(Args[i].getAsExpr()); @@ -347,18 +378,16 @@ void TemplateSpecializationTypeLoc::initializeArgLocs(ASTContext &Context, case TemplateArgument::Template: case TemplateArgument::TemplateExpansion: { NestedNameSpecifierLocBuilder Builder; - TemplateName Template = Args[i].getAsTemplate(); + TemplateName Template = Args[i].getAsTemplateOrTemplatePattern(); if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) Builder.MakeTrivial(Context, DTN->getQualifier(), Loc); else if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) Builder.MakeTrivial(Context, QTN->getQualifier(), Loc); - + ArgInfos[i] = TemplateArgumentLocInfo( - Builder.getWithLocInContext(Context), - Loc, - Args[i].getKind() == TemplateArgument::Template - ? SourceLocation() - : Loc); + Builder.getWithLocInContext(Context), Loc, + Args[i].getKind() == TemplateArgument::Template ? SourceLocation() + : Loc); break; } diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index 0437076..571e3db 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -36,7 +36,8 @@ namespace { public: explicit IncludeStrongLifetimeRAII(PrintingPolicy &Policy) : Policy(Policy), Old(Policy.SuppressStrongLifetime) { - Policy.SuppressStrongLifetime = false; + if (!Policy.SuppressLifetimeQualifiers) + Policy.SuppressStrongLifetime = false; } ~IncludeStrongLifetimeRAII() { @@ -81,10 +82,11 @@ namespace { class TypePrinter { PrintingPolicy Policy; bool HasEmptyPlaceHolder; + bool InsideCCAttribute; public: explicit TypePrinter(const PrintingPolicy &Policy) - : Policy(Policy), HasEmptyPlaceHolder(false) { } + : Policy(Policy), HasEmptyPlaceHolder(false), InsideCCAttribute(false) { } void print(const Type *ty, Qualifiers qs, raw_ostream &OS, StringRef PlaceHolder); @@ -166,6 +168,7 @@ bool TypePrinter::canPrefixQualifiers(const Type *T, TC = Subst->getReplacementType()->getTypeClass(); switch (TC) { + case Type::Auto: case Type::Builtin: case Type::Complex: case Type::UnresolvedUsing: @@ -201,6 +204,7 @@ bool TypePrinter::canPrefixQualifiers(const Type *T, NeedARCStrongQualifier = true; // Fall through + case Type::Decayed: case Type::Pointer: case Type::BlockPointer: case Type::LValueReference: @@ -215,7 +219,6 @@ bool TypePrinter::canPrefixQualifiers(const Type *T, case Type::Attributed: case Type::PackExpansion: case Type::SubstTemplateTypeParm: - case Type::Auto: CanPrefixQualifiers = false; break; } @@ -468,6 +471,14 @@ void TypePrinter::printVariableArrayAfter(const VariableArrayType *T, printAfter(T->getElementType(), OS); } +void TypePrinter::printDecayedBefore(const DecayedType *T, raw_ostream &OS) { + // Print as though it's a pointer. + printBefore(T->getDecayedType(), OS); +} +void TypePrinter::printDecayedAfter(const DecayedType *T, raw_ostream &OS) { + printAfter(T->getDecayedType(), OS); +} + void TypePrinter::printDependentSizedArrayBefore( const DependentSizedArrayType *T, raw_ostream &OS) { @@ -621,36 +632,51 @@ void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T, OS << ')'; FunctionType::ExtInfo Info = T->getExtInfo(); - switch(Info.getCC()) { - case CC_Default: break; - case CC_C: - OS << " __attribute__((cdecl))"; - break; - case CC_X86StdCall: - OS << " __attribute__((stdcall))"; - break; - case CC_X86FastCall: - OS << " __attribute__((fastcall))"; - break; - case CC_X86ThisCall: - OS << " __attribute__((thiscall))"; - break; - case CC_X86Pascal: - OS << " __attribute__((pascal))"; - break; - case CC_AAPCS: - OS << " __attribute__((pcs(\"aapcs\")))"; - break; - case CC_AAPCS_VFP: - OS << " __attribute__((pcs(\"aapcs-vfp\")))"; - break; - case CC_PnaclCall: - OS << " __attribute__((pnaclcall))"; - break; - case CC_IntelOclBicc: - OS << " __attribute__((intel_ocl_bicc))"; - break; + + if (!InsideCCAttribute) { + switch (Info.getCC()) { + case CC_C: + // The C calling convention is the default on the vast majority of platforms + // we support. If the user wrote it explicitly, it will usually be printed + // while traversing the AttributedType. If the type has been desugared, let + // the canonical spelling be the implicit calling convention. + // FIXME: It would be better to be explicit in certain contexts, such as a + // cdecl function typedef used to declare a member function with the + // Microsoft C++ ABI. + break; + case CC_X86StdCall: + OS << " __attribute__((stdcall))"; + break; + case CC_X86FastCall: + OS << " __attribute__((fastcall))"; + break; + case CC_X86ThisCall: + OS << " __attribute__((thiscall))"; + break; + case CC_X86Pascal: + OS << " __attribute__((pascal))"; + break; + case CC_AAPCS: + OS << " __attribute__((pcs(\"aapcs\")))"; + break; + case CC_AAPCS_VFP: + OS << " __attribute__((pcs(\"aapcs-vfp\")))"; + break; + case CC_PnaclCall: + OS << " __attribute__((pnaclcall))"; + break; + case CC_IntelOclBicc: + OS << " __attribute__((intel_ocl_bicc))"; + break; + case CC_X86_64Win64: + OS << " __attribute__((ms_abi))"; + break; + case CC_X86_64SysV: + OS << " __attribute__((sysv_abi))"; + break; + } } + if (Info.getNoReturn()) OS << " __attribute__((noreturn))"; if (Info.getRegParm()) @@ -989,6 +1015,8 @@ void TypePrinter::printInjectedClassNameAfter(const InjectedClassNameType *T, void TypePrinter::printElaboratedBefore(const ElaboratedType *T, raw_ostream &OS) { + if (Policy.SuppressTag && isa<TagType>(T->getNamedType())) + return; OS << TypeWithKeyword::getKeywordName(T->getKeyword()); if (T->getKeyword() != ETK_None) OS << " "; @@ -1072,6 +1100,17 @@ void TypePrinter::printAttributedBefore(const AttributedType *T, return printBefore(T->getEquivalentType(), OS); printBefore(T->getModifiedType(), OS); + + if (T->isMSTypeSpec()) { + switch (T->getAttrKind()) { + default: return; + case AttributedType::attr_ptr32: OS << " __ptr32"; break; + case AttributedType::attr_ptr64: OS << " __ptr64"; break; + case AttributedType::attr_sptr: OS << " __sptr"; break; + case AttributedType::attr_uptr: OS << " __uptr"; break; + } + spaceBeforePlaceHolder(OS); + } } void TypePrinter::printAttributedAfter(const AttributedType *T, @@ -1082,8 +1121,18 @@ void TypePrinter::printAttributedAfter(const AttributedType *T, return printAfter(T->getEquivalentType(), OS); // TODO: not all attributes are GCC-style attributes. + if (T->isMSTypeSpec()) + return; + + // If this is a calling convention attribute, don't print the implicit CC from + // the modified type. + SaveAndRestore<bool> MaybeSuppressCC(InsideCCAttribute, T->isCallingConv()); + + printAfter(T->getModifiedType(), OS); + OS << " __attribute__(("; switch (T->getAttrKind()) { + default: llvm_unreachable("This attribute should have been handled already"); case AttributedType::attr_address_space: OS << "address_space("; OS << T->getEquivalentType().getAddressSpace(); @@ -1115,6 +1164,8 @@ void TypePrinter::printAttributedAfter(const AttributedType *T, } case AttributedType::attr_regparm: { + // FIXME: When Sema learns to form this AttributedType, avoid printing the + // attribute again in printFunctionProtoAfter. OS << "regparm("; QualType t = T->getEquivalentType(); while (!t->isFunctionType()) @@ -1154,13 +1205,19 @@ void TypePrinter::printAttributedAfter(const AttributedType *T, OS << ')'; break; + // FIXME: When Sema learns to form this AttributedType, avoid printing the + // attribute again in printFunctionProtoAfter. case AttributedType::attr_noreturn: OS << "noreturn"; break; + case AttributedType::attr_cdecl: OS << "cdecl"; break; case AttributedType::attr_fastcall: OS << "fastcall"; break; case AttributedType::attr_stdcall: OS << "stdcall"; break; case AttributedType::attr_thiscall: OS << "thiscall"; break; case AttributedType::attr_pascal: OS << "pascal"; break; - case AttributedType::attr_pcs: { + case AttributedType::attr_ms_abi: OS << "ms_abi"; break; + case AttributedType::attr_sysv_abi: OS << "sysv_abi"; break; + case AttributedType::attr_pcs: + case AttributedType::attr_pcs_vfp: { OS << "pcs("; QualType t = T->getEquivalentType(); while (!t->isFunctionType()) @@ -1266,18 +1323,19 @@ TemplateSpecializationType::PrintTemplateArgumentList( bool needSpace = false; for (unsigned Arg = 0; Arg < NumArgs; ++Arg) { - if (Arg > 0) - OS << ", "; - // Print the argument into a string. SmallString<128> Buf; llvm::raw_svector_ostream ArgOS(Buf); if (Args[Arg].getKind() == TemplateArgument::Pack) { + if (Args[Arg].pack_size() && Arg > 0) + OS << ", "; PrintTemplateArgumentList(ArgOS, Args[Arg].pack_begin(), Args[Arg].pack_size(), Policy, true); } else { + if (Arg > 0) + OS << ", "; Args[Arg].print(Policy, ArgOS); } StringRef ArgString = ArgOS.str(); diff --git a/lib/AST/VTableBuilder.cpp b/lib/AST/VTableBuilder.cpp index f80232f..5f7ae0f 100644 --- a/lib/AST/VTableBuilder.cpp +++ b/lib/AST/VTableBuilder.cpp @@ -34,7 +34,8 @@ struct BaseOffset { const CXXRecordDecl *DerivedClass; /// VirtualBase - If the path from the derived class to the base class - /// involves a virtual base class, this holds its declaration. + /// involves virtual base classes, this holds the declaration of the last + /// virtual base in this path (i.e. closest to the base class). const CXXRecordDecl *VirtualBase; /// NonVirtualOffset - The offset from the derived class to the base class. @@ -62,7 +63,7 @@ public: /// Method - The method decl of the overrider. const CXXMethodDecl *Method; - /// Offset - the base offset of the overrider in the layout class. + /// Offset - the base offset of the overrider's parent in the layout class. CharUnits Offset; OverriderInfo() : Method(0), Offset(CharUnits::Zero()) { } @@ -146,8 +147,6 @@ public: }; -#define DUMP_OVERRIDERS 0 - FinalOverriders::FinalOverriders(const CXXRecordDecl *MostDerivedClass, CharUnits MostDerivedClassOffset, const CXXRecordDecl *LayoutClass) @@ -219,16 +218,14 @@ static BaseOffset ComputeBaseOffset(ASTContext &Context, const CXXRecordDecl *VirtualBase = 0; // First, look for the virtual base class. - for (unsigned I = 0, E = Path.size(); I != E; ++I) { - const CXXBasePathElement &Element = Path[I]; - + for (int I = Path.size(), E = 0; I != E; --I) { + const CXXBasePathElement &Element = Path[I - 1]; + if (Element.Base->isVirtual()) { - // FIXME: Can we break when we find the first virtual base? - // (If we can't, can't we just iterate over the path in reverse order?) - NonVirtualStart = I + 1; + NonVirtualStart = I; QualType VBaseType = Element.Base->getType(); - VirtualBase = - cast<CXXRecordDecl>(VBaseType->getAs<RecordType>()->getDecl()); + VirtualBase = VBaseType->getAsCXXRecordDecl(); + break; } } @@ -239,8 +236,7 @@ static BaseOffset ComputeBaseOffset(ASTContext &Context, // Check the base class offset. const ASTRecordLayout &Layout = Context.getASTRecordLayout(Element.Class); - const RecordType *BaseType = Element.Base->getType()->getAs<RecordType>(); - const CXXRecordDecl *Base = cast<CXXRecordDecl>(BaseType->getDecl()); + const CXXRecordDecl *Base = Element.Base->getType()->getAsCXXRecordDecl(); NonVirtualOffset += Layout.getBaseClassOffset(Base); } @@ -343,8 +339,7 @@ FinalOverriders::ComputeBaseOffsets(BaseSubobject Base, bool IsVirtual, // Traverse our bases. for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), E = RD->bases_end(); I != E; ++I) { - const CXXRecordDecl *BaseDecl = - cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + const CXXRecordDecl *BaseDecl = I->getType()->getAsCXXRecordDecl(); CharUnits BaseOffset; CharUnits BaseOffsetInLayoutClass; @@ -381,8 +376,7 @@ void FinalOverriders::dump(raw_ostream &Out, BaseSubobject Base, for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), E = RD->bases_end(); I != E; ++I) { - const CXXRecordDecl *BaseDecl = - cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + const CXXRecordDecl *BaseDecl = I->getType()->getAsCXXRecordDecl(); // Ignore bases that don't have any virtual member functions. if (!BaseDecl->isPolymorphic()) @@ -418,7 +412,7 @@ void FinalOverriders::dump(raw_ostream &Out, BaseSubobject Base, Out << " " << MD->getQualifiedNameAsString() << " - ("; Out << Overrider.Method->getQualifiedNameAsString(); - Out << ", " << ", " << Overrider.Offset.getQuantity() << ')'; + Out << ", " << Overrider.Offset.getQuantity() << ')'; BaseOffset Offset; if (!Overrider.Method->isPure()) @@ -727,8 +721,7 @@ void VCallAndVBaseOffsetBuilder::AddVCallOffsets(BaseSubobject Base, if (I->isVirtual()) continue; - const CXXRecordDecl *BaseDecl = - cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + const CXXRecordDecl *BaseDecl = I->getType()->getAsCXXRecordDecl(); if (BaseDecl == PrimaryBase) continue; @@ -750,8 +743,7 @@ VCallAndVBaseOffsetBuilder::AddVBaseOffsets(const CXXRecordDecl *RD, // Add vbase offsets. for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), E = RD->bases_end(); I != E; ++I) { - const CXXRecordDecl *BaseDecl = - cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + const CXXRecordDecl *BaseDecl = I->getType()->getAsCXXRecordDecl(); // Check if this is a virtual base that we haven't visited before. if (I->isVirtual() && VisitedVirtualBases.insert(BaseDecl)) { @@ -775,8 +767,8 @@ VCallAndVBaseOffsetBuilder::AddVBaseOffsets(const CXXRecordDecl *RD, } } -/// VTableBuilder - Class for building vtable layout information. -class VTableBuilder { +/// ItaniumVTableBuilder - Class for building vtable layout information. +class ItaniumVTableBuilder { public: /// PrimaryBasesSetVectorTy - A set vector of direct and indirect /// primary bases. @@ -789,9 +781,11 @@ public: typedef llvm::DenseMap<BaseSubobject, uint64_t> AddressPointsMapTy; + typedef llvm::DenseMap<GlobalDecl, int64_t> MethodVTableIndicesTy; + private: /// VTables - Global vtable information. - VTableContext &VTables; + ItaniumVTableContext &VTables; /// MostDerivedClass - The most derived class for which we're building this /// vtable. @@ -861,7 +855,11 @@ private: /// MethodInfoMap - The information for all methods in the vtable we're /// currently building. MethodInfoMapTy MethodInfoMap; - + + /// MethodVTableIndices - Contains the index (relative to the vtable address + /// point) where the function pointer for a virtual function is stored. + MethodVTableIndicesTy MethodVTableIndices; + typedef llvm::DenseMap<uint64_t, ThunkInfo> VTableThunksMapTy; /// VTableThunks - The thunks by vtable index in the vtable currently being @@ -984,24 +982,22 @@ private: } public: - VTableBuilder(VTableContext &VTables, const CXXRecordDecl *MostDerivedClass, - CharUnits MostDerivedClassOffset, - bool MostDerivedClassIsVirtual, const - CXXRecordDecl *LayoutClass) - : VTables(VTables), MostDerivedClass(MostDerivedClass), - MostDerivedClassOffset(MostDerivedClassOffset), - MostDerivedClassIsVirtual(MostDerivedClassIsVirtual), - LayoutClass(LayoutClass), Context(MostDerivedClass->getASTContext()), - Overriders(MostDerivedClass, MostDerivedClassOffset, LayoutClass) { + ItaniumVTableBuilder(ItaniumVTableContext &VTables, + const CXXRecordDecl *MostDerivedClass, + CharUnits MostDerivedClassOffset, + bool MostDerivedClassIsVirtual, + const CXXRecordDecl *LayoutClass) + : VTables(VTables), MostDerivedClass(MostDerivedClass), + MostDerivedClassOffset(MostDerivedClassOffset), + MostDerivedClassIsVirtual(MostDerivedClassIsVirtual), + LayoutClass(LayoutClass), Context(MostDerivedClass->getASTContext()), + Overriders(MostDerivedClass, MostDerivedClassOffset, LayoutClass) { + assert(!Context.getTargetInfo().getCXXABI().isMicrosoft()); LayoutVTable(); if (Context.getLangOpts().DumpVTableLayouts) - dumpLayout(llvm::errs()); - } - - bool isMicrosoftABI() const { - return VTables.isMicrosoftABI(); + dumpLayout(llvm::outs()); } uint64_t getNumThunks() const { @@ -1024,6 +1020,14 @@ public: return AddressPoints; } + MethodVTableIndicesTy::const_iterator vtable_indices_begin() const { + return MethodVTableIndices.begin(); + } + + MethodVTableIndicesTy::const_iterator vtable_indices_end() const { + return MethodVTableIndices.end(); + } + /// getNumVTableComponents - Return the number of components in the vtable /// currently built. uint64_t getNumVTableComponents() const { @@ -1058,12 +1062,13 @@ public: void dumpLayout(raw_ostream&); }; -void VTableBuilder::AddThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk) { +void ItaniumVTableBuilder::AddThunk(const CXXMethodDecl *MD, + const ThunkInfo &Thunk) { assert(!isBuildingConstructorVTable() && "Can't add thunks for construction vtable"); - SmallVector<ThunkInfo, 1> &ThunksVector = Thunks[MD]; - + SmallVectorImpl<ThunkInfo> &ThunksVector = Thunks[MD]; + // Check if we have this thunk already. if (std::find(ThunksVector.begin(), ThunksVector.end(), Thunk) != ThunksVector.end()) @@ -1074,24 +1079,45 @@ void VTableBuilder::AddThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk) { typedef llvm::SmallPtrSet<const CXXMethodDecl *, 8> OverriddenMethodsSetTy; -/// ComputeAllOverriddenMethods - Given a method decl, will return a set of all -/// the overridden methods that the function decl overrides. -static void -ComputeAllOverriddenMethods(const CXXMethodDecl *MD, - OverriddenMethodsSetTy& OverriddenMethods) { +/// Visit all the methods overridden by the given method recursively, +/// in a depth-first pre-order. The Visitor's visitor method returns a bool +/// indicating whether to continue the recursion for the given overridden +/// method (i.e. returning false stops the iteration). +template <class VisitorTy> +static void +visitAllOverriddenMethods(const CXXMethodDecl *MD, VisitorTy &Visitor) { assert(MD->isVirtual() && "Method is not virtual!"); for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), E = MD->end_overridden_methods(); I != E; ++I) { const CXXMethodDecl *OverriddenMD = *I; - - OverriddenMethods.insert(OverriddenMD); - - ComputeAllOverriddenMethods(OverriddenMD, OverriddenMethods); + if (!Visitor.visit(OverriddenMD)) + continue; + visitAllOverriddenMethods(OverriddenMD, Visitor); } } -void VTableBuilder::ComputeThisAdjustments() { +namespace { + struct OverriddenMethodsCollector { + OverriddenMethodsSetTy *Methods; + + bool visit(const CXXMethodDecl *MD) { + // Don't recurse on this method if we've already collected it. + return Methods->insert(MD); + } + }; +} + +/// ComputeAllOverriddenMethods - Given a method decl, will return a set of all +/// the overridden methods that the function decl overrides. +static void +ComputeAllOverriddenMethods(const CXXMethodDecl *MD, + OverriddenMethodsSetTy& OverriddenMethods) { + OverriddenMethodsCollector Collector = { &OverriddenMethods }; + visitAllOverriddenMethods(MD, Collector); +} + +void ItaniumVTableBuilder::ComputeThisAdjustments() { // Now go through the method info map and see if any of the methods need // 'this' pointer adjustments. for (MethodInfoMapTy::const_iterator I = MethodInfoMap.begin(), @@ -1160,8 +1186,6 @@ void VTableBuilder::ComputeThisAdjustments() { break; case VTableComponent::CK_DeletingDtorPointer: // We've already added the thunk when we saw the complete dtor pointer. - // FIXME: check how this works in the Microsoft ABI - // while working on the multiple inheritance patch. continue; } @@ -1170,7 +1194,8 @@ void VTableBuilder::ComputeThisAdjustments() { } } -ReturnAdjustment VTableBuilder::ComputeReturnAdjustment(BaseOffset Offset) { +ReturnAdjustment +ItaniumVTableBuilder::ComputeReturnAdjustment(BaseOffset Offset) { ReturnAdjustment Adjustment; if (!Offset.isEmpty()) { @@ -1178,10 +1203,10 @@ ReturnAdjustment VTableBuilder::ComputeReturnAdjustment(BaseOffset Offset) { // Get the virtual base offset offset. if (Offset.DerivedClass == MostDerivedClass) { // We can get the offset offset directly from our map. - Adjustment.VBaseOffsetOffset = + Adjustment.Virtual.Itanium.VBaseOffsetOffset = VBaseOffsetOffsets.lookup(Offset.VirtualBase).getQuantity(); } else { - Adjustment.VBaseOffsetOffset = + Adjustment.Virtual.Itanium.VBaseOffsetOffset = VTables.getVirtualBaseOffsetOffset(Offset.DerivedClass, Offset.VirtualBase).getQuantity(); } @@ -1193,9 +1218,8 @@ ReturnAdjustment VTableBuilder::ComputeReturnAdjustment(BaseOffset Offset) { return Adjustment; } -BaseOffset -VTableBuilder::ComputeThisAdjustmentBaseOffset(BaseSubobject Base, - BaseSubobject Derived) const { +BaseOffset ItaniumVTableBuilder::ComputeThisAdjustmentBaseOffset( + BaseSubobject Base, BaseSubobject Derived) const { const CXXRecordDecl *BaseRD = Base.getBase(); const CXXRecordDecl *DerivedRD = Derived.getBase(); @@ -1240,11 +1264,10 @@ VTableBuilder::ComputeThisAdjustmentBaseOffset(BaseSubobject Base, return BaseOffset(); } - -ThisAdjustment -VTableBuilder::ComputeThisAdjustment(const CXXMethodDecl *MD, - CharUnits BaseOffsetInLayoutClass, - FinalOverriders::OverriderInfo Overrider) { + +ThisAdjustment ItaniumVTableBuilder::ComputeThisAdjustment( + const CXXMethodDecl *MD, CharUnits BaseOffsetInLayoutClass, + FinalOverriders::OverriderInfo Overrider) { // Ignore adjustments for pure virtual member functions. if (Overrider.Method->isPure()) return ThisAdjustment(); @@ -1281,7 +1304,7 @@ VTableBuilder::ComputeThisAdjustment(const CXXMethodDecl *MD, VCallOffsets = Builder.getVCallOffsets(); } - Adjustment.VCallOffsetOffset = + Adjustment.Virtual.Itanium.VCallOffsetOffset = VCallOffsets.getVCallOffsetOffset(MD).getQuantity(); } @@ -1290,23 +1313,16 @@ VTableBuilder::ComputeThisAdjustment(const CXXMethodDecl *MD, return Adjustment; } - -void -VTableBuilder::AddMethod(const CXXMethodDecl *MD, - ReturnAdjustment ReturnAdjustment) { + +void ItaniumVTableBuilder::AddMethod(const CXXMethodDecl *MD, + ReturnAdjustment ReturnAdjustment) { if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) { assert(ReturnAdjustment.isEmpty() && "Destructor can't have return adjustment!"); - // FIXME: Should probably add a layer of abstraction for vtable generation. - if (!isMicrosoftABI()) { - // Add both the complete destructor and the deleting destructor. - Components.push_back(VTableComponent::MakeCompleteDtor(DD)); - Components.push_back(VTableComponent::MakeDeletingDtor(DD)); - } else { - // Add the scalar deleting destructor. - Components.push_back(VTableComponent::MakeDeletingDtor(DD)); - } + // Add both the complete destructor and the deleting destructor. + Components.push_back(VTableComponent::MakeCompleteDtor(DD)); + Components.push_back(VTableComponent::MakeDeletingDtor(DD)); } else { // Add the return adjustment if necessary. if (!ReturnAdjustment.isEmpty()) @@ -1328,9 +1344,9 @@ VTableBuilder::AddMethod(const CXXMethodDecl *MD, /// /// OverridesIndirectMethodInBase will return true if given C::f as the method /// and { A } as the set of bases. -static bool -OverridesIndirectMethodInBases(const CXXMethodDecl *MD, - VTableBuilder::PrimaryBasesSetVectorTy &Bases) { +static bool OverridesIndirectMethodInBases( + const CXXMethodDecl *MD, + ItaniumVTableBuilder::PrimaryBasesSetVectorTy &Bases) { if (Bases.count(MD->getParent())) return true; @@ -1346,11 +1362,10 @@ OverridesIndirectMethodInBases(const CXXMethodDecl *MD, return false; } -bool -VTableBuilder::IsOverriderUsed(const CXXMethodDecl *Overrider, - CharUnits BaseOffsetInLayoutClass, - const CXXRecordDecl *FirstBaseInPrimaryBaseChain, - CharUnits FirstBaseOffsetInLayoutClass) const { +bool ItaniumVTableBuilder::IsOverriderUsed( + const CXXMethodDecl *Overrider, CharUnits BaseOffsetInLayoutClass, + const CXXRecordDecl *FirstBaseInPrimaryBaseChain, + CharUnits FirstBaseOffsetInLayoutClass) const { // If the base and the first base in the primary base chain have the same // offsets, then this overrider will be used. if (BaseOffsetInLayoutClass == FirstBaseOffsetInLayoutClass) @@ -1364,8 +1379,8 @@ VTableBuilder::IsOverriderUsed(const CXXMethodDecl *Overrider, // that the overrider will be used. if (Overrider->getParent() == FirstBaseInPrimaryBaseChain) return true; - - VTableBuilder::PrimaryBasesSetVectorTy PrimaryBases; + + ItaniumVTableBuilder::PrimaryBasesSetVectorTy PrimaryBases; const CXXRecordDecl *RD = FirstBaseInPrimaryBaseChain; PrimaryBases.insert(RD); @@ -1409,18 +1424,21 @@ VTableBuilder::IsOverriderUsed(const CXXMethodDecl *Overrider, return OverridesIndirectMethodInBases(Overrider, PrimaryBases); } +typedef llvm::SmallSetVector<const CXXRecordDecl *, 8> BasesSetVectorTy; + /// FindNearestOverriddenMethod - Given a method, returns the overridden method /// from the nearest base. Returns null if no method was found. -static const CXXMethodDecl * +/// The Bases are expected to be sorted in a base-to-derived order. +static const CXXMethodDecl * FindNearestOverriddenMethod(const CXXMethodDecl *MD, - VTableBuilder::PrimaryBasesSetVectorTy &Bases) { + BasesSetVectorTy &Bases) { OverriddenMethodsSetTy OverriddenMethods; ComputeAllOverriddenMethods(MD, OverriddenMethods); for (int I = Bases.size(), E = 0; I != E; --I) { const CXXRecordDecl *PrimaryBase = Bases[I - 1]; - // Now check the overriden methods. + // Now check the overridden methods. for (OverriddenMethodsSetTy::const_iterator I = OverriddenMethods.begin(), E = OverriddenMethods.end(); I != E; ++I) { const CXXMethodDecl *OverriddenMD = *I; @@ -1432,13 +1450,22 @@ FindNearestOverriddenMethod(const CXXMethodDecl *MD, } return 0; -} +} + +void ItaniumVTableBuilder::AddMethods( + BaseSubobject Base, CharUnits BaseOffsetInLayoutClass, + const CXXRecordDecl *FirstBaseInPrimaryBaseChain, + CharUnits FirstBaseOffsetInLayoutClass, + PrimaryBasesSetVectorTy &PrimaryBases) { + // Itanium C++ ABI 2.5.2: + // The order of the virtual function pointers in a virtual table is the + // order of declaration of the corresponding member functions in the class. + // + // There is an entry for any virtual function declared in a class, + // whether it is a new function or overrides a base class function, + // unless it overrides a function from the primary base, and conversion + // between their return types does not require an adjustment. -void -VTableBuilder::AddMethods(BaseSubobject Base, CharUnits BaseOffsetInLayoutClass, - const CXXRecordDecl *FirstBaseInPrimaryBaseChain, - CharUnits FirstBaseOffsetInLayoutClass, - PrimaryBasesSetVectorTy &PrimaryBases) { const CXXRecordDecl *RD = Base.getBase(); const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); @@ -1476,6 +1503,11 @@ VTableBuilder::AddMethods(BaseSubobject Base, CharUnits BaseOffsetInLayoutClass, llvm_unreachable("Found a duplicate primary base!"); } + const CXXDestructorDecl *ImplicitVirtualDtor = 0; + + typedef llvm::SmallVector<const CXXMethodDecl *, 8> NewVirtualFunctionsTy; + NewVirtualFunctionsTy NewVirtualFunctions; + // Now go through all virtual member functions and add them. for (CXXRecordDecl::method_iterator I = RD->method_begin(), E = RD->method_end(); I != E; ++I) { @@ -1520,7 +1552,7 @@ VTableBuilder::AddMethods(BaseSubobject Base, CharUnits BaseOffsetInLayoutClass, ComputeThisAdjustment(OverriddenMD, BaseOffsetInLayoutClass, Overrider); - if (ThisAdjustment.VCallOffsetOffset && + if (ThisAdjustment.Virtual.Itanium.VCallOffsetOffset && Overrider.Method->getParent() == MostDerivedClass) { // There's no return adjustment from OverriddenMD and MD, @@ -1541,6 +1573,33 @@ VTableBuilder::AddMethods(BaseSubobject Base, CharUnits BaseOffsetInLayoutClass, } } + if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) { + if (MD->isImplicit()) { + // Itanium C++ ABI 2.5.2: + // If a class has an implicitly-defined virtual destructor, + // its entries come after the declared virtual function pointers. + + assert(!ImplicitVirtualDtor && + "Did already see an implicit virtual dtor!"); + ImplicitVirtualDtor = DD; + continue; + } + } + + NewVirtualFunctions.push_back(MD); + } + + if (ImplicitVirtualDtor) + NewVirtualFunctions.push_back(ImplicitVirtualDtor); + + for (NewVirtualFunctionsTy::const_iterator I = NewVirtualFunctions.begin(), + E = NewVirtualFunctions.end(); I != E; ++I) { + const CXXMethodDecl *MD = *I; + + // Get the final overrider. + FinalOverriders::OverriderInfo Overrider = + Overriders.getOverrider(MD, Base.getBaseOffset()); + // Insert the method info for this method. MethodInfo MethodInfo(Base.getBaseOffset(), BaseOffsetInLayoutClass, Components.size()); @@ -1557,7 +1616,7 @@ VTableBuilder::AddMethods(BaseSubobject Base, CharUnits BaseOffsetInLayoutClass, Components.push_back(VTableComponent::MakeUnusedFunction(OverriderMD)); continue; } - + // Check if this overrider needs a return adjustment. // We don't want to do this for pure virtual member functions. BaseOffset ReturnAdjustmentOffset; @@ -1573,7 +1632,7 @@ VTableBuilder::AddMethods(BaseSubobject Base, CharUnits BaseOffsetInLayoutClass, } } -void VTableBuilder::LayoutVTable() { +void ItaniumVTableBuilder::LayoutVTable() { LayoutPrimaryAndSecondaryVTables(BaseSubobject(MostDerivedClass, CharUnits::Zero()), /*BaseIsMorallyVirtual=*/false, @@ -1594,12 +1653,10 @@ void VTableBuilder::LayoutVTable() { if (IsAppleKext) Components.push_back(VTableComponent::MakeVCallOffset(CharUnits::Zero())); } - -void -VTableBuilder::LayoutPrimaryAndSecondaryVTables(BaseSubobject Base, - bool BaseIsMorallyVirtual, - bool BaseIsVirtualInLayoutClass, - CharUnits OffsetInLayoutClass) { + +void ItaniumVTableBuilder::LayoutPrimaryAndSecondaryVTables( + BaseSubobject Base, bool BaseIsMorallyVirtual, + bool BaseIsVirtualInLayoutClass, CharUnits OffsetInLayoutClass) { assert(Base.getBase()->isDynamicClass() && "class does not have a vtable!"); // Add vcall and vbase offsets for this vtable. @@ -1621,18 +1678,12 @@ VTableBuilder::LayoutPrimaryAndSecondaryVTables(BaseSubobject Base, if (Base.getBase() == MostDerivedClass) VBaseOffsetOffsets = Builder.getVBaseOffsetOffsets(); - // FIXME: Should probably add a layer of abstraction for vtable generation. - if (!isMicrosoftABI()) { - // Add the offset to top. - CharUnits OffsetToTop = MostDerivedClassOffset - OffsetInLayoutClass; - Components.push_back(VTableComponent::MakeOffsetToTop(OffsetToTop)); + // Add the offset to top. + CharUnits OffsetToTop = MostDerivedClassOffset - OffsetInLayoutClass; + Components.push_back(VTableComponent::MakeOffsetToTop(OffsetToTop)); - // Next, add the RTTI. - Components.push_back(VTableComponent::MakeRTTI(MostDerivedClass)); - } else { - // FIXME: unclear what to do with RTTI in MS ABI as emitting it anywhere - // breaks the vftable layout. Just skip RTTI for now, can't mangle anyway. - } + // Next, add the RTTI. + Components.push_back(VTableComponent::MakeRTTI(MostDerivedClass)); uint64_t AddressPoint = Components.size(); @@ -1642,11 +1693,28 @@ VTableBuilder::LayoutPrimaryAndSecondaryVTables(BaseSubobject Base, Base.getBase(), OffsetInLayoutClass, PrimaryBases); + const CXXRecordDecl *RD = Base.getBase(); + if (RD == MostDerivedClass) { + assert(MethodVTableIndices.empty()); + for (MethodInfoMapTy::const_iterator I = MethodInfoMap.begin(), + E = MethodInfoMap.end(); I != E; ++I) { + const CXXMethodDecl *MD = I->first; + const MethodInfo &MI = I->second; + if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) { + MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] + = MI.VTableIndex - AddressPoint; + MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] + = MI.VTableIndex + 1 - AddressPoint; + } else { + MethodVTableIndices[MD] = MI.VTableIndex - AddressPoint; + } + } + } + // Compute 'this' pointer adjustments. ComputeThisAdjustments(); // Add all address points. - const CXXRecordDecl *RD = Base.getBase(); while (true) { AddressPoints.insert(std::make_pair( BaseSubobject(RD, OffsetInLayoutClass), @@ -1678,9 +1746,10 @@ VTableBuilder::LayoutPrimaryAndSecondaryVTables(BaseSubobject Base, LayoutSecondaryVTables(Base, BaseIsMorallyVirtual, OffsetInLayoutClass); } -void VTableBuilder::LayoutSecondaryVTables(BaseSubobject Base, - bool BaseIsMorallyVirtual, - CharUnits OffsetInLayoutClass) { +void +ItaniumVTableBuilder::LayoutSecondaryVTables(BaseSubobject Base, + bool BaseIsMorallyVirtual, + CharUnits OffsetInLayoutClass) { // Itanium C++ ABI 2.5.2: // Following the primary virtual table of a derived class are secondary // virtual tables for each of its proper base classes, except any primary @@ -1696,8 +1765,7 @@ void VTableBuilder::LayoutSecondaryVTables(BaseSubobject Base, if (I->isVirtual()) continue; - const CXXRecordDecl *BaseDecl = - cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + const CXXRecordDecl *BaseDecl = I->getType()->getAsCXXRecordDecl(); // Ignore bases that don't have a vtable. if (!BaseDecl->isDynamicClass()) @@ -1737,10 +1805,9 @@ void VTableBuilder::LayoutSecondaryVTables(BaseSubobject Base, } } -void -VTableBuilder::DeterminePrimaryVirtualBases(const CXXRecordDecl *RD, - CharUnits OffsetInLayoutClass, - VisitedVirtualBasesSetTy &VBases) { +void ItaniumVTableBuilder::DeterminePrimaryVirtualBases( + const CXXRecordDecl *RD, CharUnits OffsetInLayoutClass, + VisitedVirtualBasesSetTy &VBases) { const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); // Check if this base has a primary base. @@ -1773,8 +1840,7 @@ VTableBuilder::DeterminePrimaryVirtualBases(const CXXRecordDecl *RD, // Traverse bases, looking for more primary virtual bases. for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), E = RD->bases_end(); I != E; ++I) { - const CXXRecordDecl *BaseDecl = - cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + const CXXRecordDecl *BaseDecl = I->getType()->getAsCXXRecordDecl(); CharUnits BaseOffsetInLayoutClass; @@ -1796,17 +1862,15 @@ VTableBuilder::DeterminePrimaryVirtualBases(const CXXRecordDecl *RD, } } -void -VTableBuilder::LayoutVTablesForVirtualBases(const CXXRecordDecl *RD, - VisitedVirtualBasesSetTy &VBases) { +void ItaniumVTableBuilder::LayoutVTablesForVirtualBases( + const CXXRecordDecl *RD, VisitedVirtualBasesSetTy &VBases) { // Itanium C++ ABI 2.5.2: // Then come the virtual base virtual tables, also in inheritance graph // order, and again excluding primary bases (which share virtual tables with // the classes for which they are primary). for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), E = RD->bases_end(); I != E; ++I) { - const CXXRecordDecl *BaseDecl = - cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + const CXXRecordDecl *BaseDecl = I->getType()->getAsCXXRecordDecl(); // Check if this base needs a vtable. (If it's virtual, not a primary base // of some other class, and we haven't visited it before). @@ -1836,8 +1900,25 @@ VTableBuilder::LayoutVTablesForVirtualBases(const CXXRecordDecl *RD, } } +struct ItaniumThunkInfoComparator { + bool operator() (const ThunkInfo &LHS, const ThunkInfo &RHS) { + assert(LHS.Method == 0); + assert(RHS.Method == 0); + + if (LHS.This != RHS.This) + return LHS.This < RHS.This; + + if (LHS.Return != RHS.Return) + return LHS.Return < RHS.Return; + + return false; + } +}; + /// dumpLayout - Dump the vtable layout. -void VTableBuilder::dumpLayout(raw_ostream& Out) { +void ItaniumVTableBuilder::dumpLayout(raw_ostream &Out) { + // FIXME: write more tests that actually use the dumpLayout output to prevent + // ItaniumVTableBuilder regressions. if (isBuildingConstructorVTable()) { Out << "Construction vtable for ('"; @@ -1915,8 +1996,8 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) { Out << "\n [return adjustment: "; Out << Thunk.Return.NonVirtual << " non-virtual"; - if (Thunk.Return.VBaseOffsetOffset) { - Out << ", " << Thunk.Return.VBaseOffsetOffset; + if (Thunk.Return.Virtual.Itanium.VBaseOffsetOffset) { + Out << ", " << Thunk.Return.Virtual.Itanium.VBaseOffsetOffset; Out << " vbase offset offset"; } @@ -1928,8 +2009,8 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) { Out << "\n [this adjustment: "; Out << Thunk.This.NonVirtual << " non-virtual"; - if (Thunk.This.VCallOffsetOffset) { - Out << ", " << Thunk.This.VCallOffsetOffset; + if (Thunk.This.Virtual.Itanium.VCallOffsetOffset) { + Out << ", " << Thunk.This.Virtual.Itanium.VCallOffsetOffset; Out << " vcall offset offset"; } @@ -1950,8 +2031,6 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) { Out << DD->getQualifiedNameAsString(); if (IsComplete) Out << "() [complete]"; - else if (isMicrosoftABI()) - Out << "() [scalar deleting]"; else Out << "() [deleting]"; @@ -1965,8 +2044,8 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) { Out << "\n [this adjustment: "; Out << Thunk.This.NonVirtual << " non-virtual"; - if (Thunk.This.VCallOffsetOffset) { - Out << ", " << Thunk.This.VCallOffsetOffset; + if (Thunk.This.Virtual.Itanium.VCallOffsetOffset) { + Out << ", " << Thunk.This.Virtual.Itanium.VCallOffsetOffset; Out << " vcall offset offset"; } @@ -2078,7 +2157,8 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) { const CXXMethodDecl *MD = I->second; ThunkInfoVectorTy ThunksVector = Thunks[MD]; - std::sort(ThunksVector.begin(), ThunksVector.end()); + std::sort(ThunksVector.begin(), ThunksVector.end(), + ItaniumThunkInfoComparator()); Out << "Thunks for '" << MethodName << "' (" << ThunksVector.size(); Out << (ThunksVector.size() == 1 ? " entry" : " entries") << ").\n"; @@ -2090,10 +2170,10 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) { // If this function pointer has a return pointer adjustment, dump it. if (!Thunk.Return.isEmpty()) { - Out << "return adjustment: " << Thunk.This.NonVirtual; + Out << "return adjustment: " << Thunk.Return.NonVirtual; Out << " non-virtual"; - if (Thunk.Return.VBaseOffsetOffset) { - Out << ", " << Thunk.Return.VBaseOffsetOffset; + if (Thunk.Return.Virtual.Itanium.VBaseOffsetOffset) { + Out << ", " << Thunk.Return.Virtual.Itanium.VBaseOffsetOffset; Out << " vbase offset offset"; } @@ -2106,8 +2186,8 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) { Out << "this adjustment: "; Out << Thunk.This.NonVirtual << " non-virtual"; - if (Thunk.This.VCallOffsetOffset) { - Out << ", " << Thunk.This.VCallOffsetOffset; + if (Thunk.This.Virtual.Itanium.VCallOffsetOffset) { + Out << ", " << Thunk.This.Virtual.Itanium.VCallOffsetOffset; Out << " vcall offset offset"; } } @@ -2136,18 +2216,14 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) { MD); if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) { - // FIXME: Should add a layer of abstraction for vtable generation. - if (!isMicrosoftABI()) { - IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Complete))] - = MethodName + " [complete]"; - IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Deleting))] - = MethodName + " [deleting]"; - } else { - IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Deleting))] - = MethodName + " [scalar deleting]"; - } + GlobalDecl GD(DD, Dtor_Complete); + assert(MethodVTableIndices.count(GD)); + uint64_t VTableIndex = MethodVTableIndices[GD]; + IndicesMap[VTableIndex] = MethodName + " [complete]"; + IndicesMap[VTableIndex + 1] = MethodName + " [deleting]"; } else { - IndicesMap[VTables.getMethodVTableIndex(MD)] = MethodName; + assert(MethodVTableIndices.count(MD)); + IndicesMap[MethodVTableIndices[MD]] = MethodName; } } @@ -2162,14 +2238,24 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) { uint64_t VTableIndex = I->first; const std::string &MethodName = I->second; - Out << llvm::format(" %4" PRIu64 " | ", VTableIndex) << MethodName + Out << llvm::format("%4" PRIu64 " | ", VTableIndex) << MethodName << '\n'; } } Out << '\n'; } - + +struct VTableThunksComparator { + bool operator()(const VTableLayout::VTableThunkTy &LHS, + const VTableLayout::VTableThunkTy &RHS) { + if (LHS.first == RHS.first) { + assert(LHS.second == RHS.second && + "Different thunks should have unique indices!"); + } + return LHS.first < RHS.first; + } +}; } VTableLayout::VTableLayout(uint64_t NumVTableComponents, @@ -2188,183 +2274,38 @@ VTableLayout::VTableLayout(uint64_t NumVTableComponents, this->VTableComponents.get()); std::copy(VTableThunks, VTableThunks+NumVTableThunks, this->VTableThunks.get()); + std::sort(this->VTableThunks.get(), + this->VTableThunks.get() + NumVTableThunks, + VTableThunksComparator()); } VTableLayout::~VTableLayout() { } -VTableContext::VTableContext(ASTContext &Context) - : Context(Context), - IsMicrosoftABI(Context.getTargetInfo().getCXXABI().isMicrosoft()) { +ItaniumVTableContext::ItaniumVTableContext(ASTContext &Context) + : IsMicrosoftABI(Context.getTargetInfo().getCXXABI().isMicrosoft()) { } -VTableContext::~VTableContext() { +ItaniumVTableContext::~ItaniumVTableContext() { llvm::DeleteContainerSeconds(VTableLayouts); } -static void -CollectPrimaryBases(const CXXRecordDecl *RD, ASTContext &Context, - VTableBuilder::PrimaryBasesSetVectorTy &PrimaryBases) { - const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); - - if (!PrimaryBase) - return; - - CollectPrimaryBases(PrimaryBase, Context, PrimaryBases); - - if (!PrimaryBases.insert(PrimaryBase)) - llvm_unreachable("Found a duplicate primary base!"); -} - -void VTableContext::ComputeMethodVTableIndices(const CXXRecordDecl *RD) { - - // Itanium C++ ABI 2.5.2: - // The order of the virtual function pointers in a virtual table is the - // order of declaration of the corresponding member functions in the class. - // - // There is an entry for any virtual function declared in a class, - // whether it is a new function or overrides a base class function, - // unless it overrides a function from the primary base, and conversion - // between their return types does not require an adjustment. - - int64_t CurrentIndex = 0; - - const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); - - if (PrimaryBase) { - assert(PrimaryBase->isCompleteDefinition() && - "Should have the definition decl of the primary base!"); - - // Since the record decl shares its vtable pointer with the primary base - // we need to start counting at the end of the primary base's vtable. - CurrentIndex = getNumVirtualFunctionPointers(PrimaryBase); - } - - // Collect all the primary bases, so we can check whether methods override - // a method from the base. - VTableBuilder::PrimaryBasesSetVectorTy PrimaryBases; - CollectPrimaryBases(RD, Context, PrimaryBases); - - const CXXDestructorDecl *ImplicitVirtualDtor = 0; - - for (CXXRecordDecl::method_iterator i = RD->method_begin(), - e = RD->method_end(); i != e; ++i) { - const CXXMethodDecl *MD = *i; - - // We only want virtual methods. - if (!MD->isVirtual()) - continue; - - // Check if this method overrides a method in the primary base. - if (const CXXMethodDecl *OverriddenMD = - FindNearestOverriddenMethod(MD, PrimaryBases)) { - // Check if converting from the return type of the method to the - // return type of the overridden method requires conversion. - if (ComputeReturnAdjustmentBaseOffset(Context, MD, - OverriddenMD).isEmpty()) { - // This index is shared between the index in the vtable of the primary - // base class. - if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) { - const CXXDestructorDecl *OverriddenDD = - cast<CXXDestructorDecl>(OverriddenMD); - - if (!isMicrosoftABI()) { - // Add both the complete and deleting entries. - MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] = - getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Complete)); - MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] = - getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting)); - } else { - // Add the scalar deleting destructor. - MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] = - getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting)); - } - } else { - MethodVTableIndices[MD] = getMethodVTableIndex(OverriddenMD); - } - - // We don't need to add an entry for this method. - continue; - } - } - - if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) { - if (MD->isImplicit()) { - assert(!ImplicitVirtualDtor && - "Did already see an implicit virtual dtor!"); - ImplicitVirtualDtor = DD; - continue; - } - - if (!isMicrosoftABI()) { - // Add the complete dtor. - MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] = CurrentIndex++; - - // Add the deleting dtor. - MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] = CurrentIndex++; - } else { - // Add the scalar deleting dtor. - MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] = CurrentIndex++; - } - } else { - // Add the entry. - MethodVTableIndices[MD] = CurrentIndex++; - } - } - - if (ImplicitVirtualDtor) { - // Itanium C++ ABI 2.5.2: - // If a class has an implicitly-defined virtual destructor, - // its entries come after the declared virtual function pointers. - - if (isMicrosoftABI()) { - ErrorUnsupported("implicit virtual destructor in the Microsoft ABI", - ImplicitVirtualDtor->getLocation()); - } - - // Add the complete dtor. - MethodVTableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Complete)] = - CurrentIndex++; - - // Add the deleting dtor. - MethodVTableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Deleting)] = - CurrentIndex++; - } - - NumVirtualFunctionPointers[RD] = CurrentIndex; -} - -uint64_t VTableContext::getNumVirtualFunctionPointers(const CXXRecordDecl *RD) { - llvm::DenseMap<const CXXRecordDecl *, uint64_t>::iterator I = - NumVirtualFunctionPointers.find(RD); - if (I != NumVirtualFunctionPointers.end()) - return I->second; - - ComputeMethodVTableIndices(RD); - - I = NumVirtualFunctionPointers.find(RD); - assert(I != NumVirtualFunctionPointers.end() && "Did not find entry!"); - return I->second; -} - -uint64_t VTableContext::getMethodVTableIndex(GlobalDecl GD) { +uint64_t ItaniumVTableContext::getMethodVTableIndex(GlobalDecl GD) { MethodVTableIndicesTy::iterator I = MethodVTableIndices.find(GD); if (I != MethodVTableIndices.end()) return I->second; const CXXRecordDecl *RD = cast<CXXMethodDecl>(GD.getDecl())->getParent(); - ComputeMethodVTableIndices(RD); + computeVTableRelatedInformation(RD); I = MethodVTableIndices.find(GD); assert(I != MethodVTableIndices.end() && "Did not find index!"); return I->second; } -CharUnits -VTableContext::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD, - const CXXRecordDecl *VBase) { +CharUnits +ItaniumVTableContext::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD, + const CXXRecordDecl *VBase) { ClassPairTy ClassPair(RD, VBase); VirtualBaseClassOffsetOffsetsMapTy::iterator I = @@ -2393,30 +2334,35 @@ VTableContext::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD, return I->second; } -static VTableLayout *CreateVTableLayout(const VTableBuilder &Builder) { +static VTableLayout *CreateVTableLayout(const ItaniumVTableBuilder &Builder) { SmallVector<VTableLayout::VTableThunkTy, 1> VTableThunks(Builder.vtable_thunks_begin(), Builder.vtable_thunks_end()); - std::sort(VTableThunks.begin(), VTableThunks.end()); return new VTableLayout(Builder.getNumVTableComponents(), Builder.vtable_component_begin(), VTableThunks.size(), VTableThunks.data(), Builder.getAddressPoints(), - Builder.isMicrosoftABI()); + /*IsMicrosoftABI=*/false); } -void VTableContext::ComputeVTableRelatedInformation(const CXXRecordDecl *RD) { +void +ItaniumVTableContext::computeVTableRelatedInformation(const CXXRecordDecl *RD) { + assert(!IsMicrosoftABI && "Shouldn't be called in this ABI!"); + const VTableLayout *&Entry = VTableLayouts[RD]; // Check if we've computed this information before. if (Entry) return; - VTableBuilder Builder(*this, RD, CharUnits::Zero(), - /*MostDerivedClassIsVirtual=*/0, RD); + ItaniumVTableBuilder Builder(*this, RD, CharUnits::Zero(), + /*MostDerivedClassIsVirtual=*/0, RD); Entry = CreateVTableLayout(Builder); + MethodVTableIndices.insert(Builder.vtable_indices_begin(), + Builder.vtable_indices_end()); + // Add the known thunks. Thunks.insert(Builder.thunks_begin(), Builder.thunks_end()); @@ -2426,16 +2372,16 @@ void VTableContext::ComputeVTableRelatedInformation(const CXXRecordDecl *RD) { if (!RD->getNumVBases()) return; - const RecordType *VBaseRT = - RD->vbases_begin()->getType()->getAs<RecordType>(); - const CXXRecordDecl *VBase = cast<CXXRecordDecl>(VBaseRT->getDecl()); + const CXXRecordDecl *VBase = + RD->vbases_begin()->getType()->getAsCXXRecordDecl(); if (VirtualBaseClassOffsetOffsets.count(std::make_pair(RD, VBase))) return; - - for (VTableBuilder::VBaseOffsetOffsetsMapTy::const_iterator I = - Builder.getVBaseOffsetOffsets().begin(), - E = Builder.getVBaseOffsetOffsets().end(); I != E; ++I) { + + for (ItaniumVTableBuilder::VBaseOffsetOffsetsMapTy::const_iterator + I = Builder.getVBaseOffsetOffsets().begin(), + E = Builder.getVBaseOffsetOffsets().end(); + I != E; ++I) { // Insert all types. ClassPairTy ClassPair(RD, I->first); @@ -2443,20 +2389,1040 @@ void VTableContext::ComputeVTableRelatedInformation(const CXXRecordDecl *RD) { } } -void VTableContext::ErrorUnsupported(StringRef Feature, - SourceLocation Location) { - clang::DiagnosticsEngine &Diags = Context.getDiagnostics(); - unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, - "v-table layout for %0 is not supported yet"); - Diags.Report(Context.getFullLoc(Location), DiagID) << Feature; +VTableLayout *ItaniumVTableContext::createConstructionVTableLayout( + const CXXRecordDecl *MostDerivedClass, CharUnits MostDerivedClassOffset, + bool MostDerivedClassIsVirtual, const CXXRecordDecl *LayoutClass) { + ItaniumVTableBuilder Builder(*this, MostDerivedClass, MostDerivedClassOffset, + MostDerivedClassIsVirtual, LayoutClass); + return CreateVTableLayout(Builder); } -VTableLayout *VTableContext::createConstructionVTableLayout( - const CXXRecordDecl *MostDerivedClass, - CharUnits MostDerivedClassOffset, - bool MostDerivedClassIsVirtual, - const CXXRecordDecl *LayoutClass) { - VTableBuilder Builder(*this, MostDerivedClass, MostDerivedClassOffset, - MostDerivedClassIsVirtual, LayoutClass); - return CreateVTableLayout(Builder); +namespace { + +// Vtables in the Microsoft ABI are different from the Itanium ABI. +// +// The main differences are: +// 1. Separate vftable and vbtable. +// +// 2. Each subobject with a vfptr gets its own vftable rather than an address +// point in a single vtable shared between all the subobjects. +// Each vftable is represented by a separate section and virtual calls +// must be done using the vftable which has a slot for the function to be +// called. +// +// 3. Virtual method definitions expect their 'this' parameter to point to the +// first vfptr whose table provides a compatible overridden method. In many +// cases, this permits the original vf-table entry to directly call +// the method instead of passing through a thunk. +// +// A compatible overridden method is one which does not have a non-trivial +// covariant-return adjustment. +// +// The first vfptr is the one with the lowest offset in the complete-object +// layout of the defining class, and the method definition will subtract +// that constant offset from the parameter value to get the real 'this' +// value. Therefore, if the offset isn't really constant (e.g. if a virtual +// function defined in a virtual base is overridden in a more derived +// virtual base and these bases have a reverse order in the complete +// object), the vf-table may require a this-adjustment thunk. +// +// 4. vftables do not contain new entries for overrides that merely require +// this-adjustment. Together with #3, this keeps vf-tables smaller and +// eliminates the need for this-adjustment thunks in many cases, at the cost +// of often requiring redundant work to adjust the "this" pointer. +// +// 5. Instead of VTT and constructor vtables, vbtables and vtordisps are used. +// Vtordisps are emitted into the class layout if a class has +// a) a user-defined ctor/dtor +// and +// b) a method overriding a method in a virtual base. + +class VFTableBuilder { +public: + typedef MicrosoftVTableContext::MethodVFTableLocation MethodVFTableLocation; + + typedef llvm::DenseMap<GlobalDecl, MethodVFTableLocation> + MethodVFTableLocationsTy; + +private: + /// VTables - Global vtable information. + MicrosoftVTableContext &VTables; + + /// Context - The ASTContext which we will use for layout information. + ASTContext &Context; + + /// MostDerivedClass - The most derived class for which we're building this + /// vtable. + const CXXRecordDecl *MostDerivedClass; + + const ASTRecordLayout &MostDerivedClassLayout; + + VFPtrInfo WhichVFPtr; + + /// FinalOverriders - The final overriders of the most derived class. + const FinalOverriders Overriders; + + /// Components - The components of the vftable being built. + SmallVector<VTableComponent, 64> Components; + + MethodVFTableLocationsTy MethodVFTableLocations; + + /// MethodInfo - Contains information about a method in a vtable. + /// (Used for computing 'this' pointer adjustment thunks. + struct MethodInfo { + /// VBTableIndex - The nonzero index in the vbtable that + /// this method's base has, or zero. + const uint64_t VBTableIndex; + + /// VFTableIndex - The index in the vftable that this method has. + const uint64_t VFTableIndex; + + /// Shadowed - Indicates if this vftable slot is shadowed by + /// a slot for a covariant-return override. If so, it shouldn't be printed + /// or used for vcalls in the most derived class. + bool Shadowed; + + MethodInfo(uint64_t VBTableIndex, uint64_t VFTableIndex) + : VBTableIndex(VBTableIndex), VFTableIndex(VFTableIndex), + Shadowed(false) {} + + MethodInfo() : VBTableIndex(0), VFTableIndex(0), Shadowed(false) {} + }; + + typedef llvm::DenseMap<const CXXMethodDecl *, MethodInfo> MethodInfoMapTy; + + /// MethodInfoMap - The information for all methods in the vftable we're + /// currently building. + MethodInfoMapTy MethodInfoMap; + + typedef llvm::DenseMap<uint64_t, ThunkInfo> VTableThunksMapTy; + + /// VTableThunks - The thunks by vftable index in the vftable currently being + /// built. + VTableThunksMapTy VTableThunks; + + typedef SmallVector<ThunkInfo, 1> ThunkInfoVectorTy; + typedef llvm::DenseMap<const CXXMethodDecl *, ThunkInfoVectorTy> ThunksMapTy; + + /// Thunks - A map that contains all the thunks needed for all methods in the + /// most derived class for which the vftable is currently being built. + ThunksMapTy Thunks; + + /// AddThunk - Add a thunk for the given method. + void AddThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk) { + SmallVector<ThunkInfo, 1> &ThunksVector = Thunks[MD]; + + // Check if we have this thunk already. + if (std::find(ThunksVector.begin(), ThunksVector.end(), Thunk) != + ThunksVector.end()) + return; + + ThunksVector.push_back(Thunk); + } + + /// ComputeThisOffset - Returns the 'this' argument offset for the given + /// method in the given subobject, relative to the beginning of the + /// MostDerivedClass. + CharUnits ComputeThisOffset(const CXXMethodDecl *MD, + BaseSubobject Base, + FinalOverriders::OverriderInfo Overrider); + + void CalculateVtordispAdjustment(FinalOverriders::OverriderInfo Overrider, + CharUnits ThisOffset, ThisAdjustment &TA); + + /// AddMethod - Add a single virtual member function to the vftable + /// components vector. + void AddMethod(const CXXMethodDecl *MD, ThunkInfo TI) { + if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) { + assert(TI.Return.isEmpty() && + "Destructor can't have return adjustment!"); + Components.push_back(VTableComponent::MakeDeletingDtor(DD)); + } else { + if (!TI.isEmpty()) + VTableThunks[Components.size()] = TI; + Components.push_back(VTableComponent::MakeFunction(MD)); + } + } + + /// AddMethods - Add the methods of this base subobject and the relevant + /// subbases to the vftable we're currently laying out. + void AddMethods(BaseSubobject Base, unsigned BaseDepth, + const CXXRecordDecl *LastVBase, + BasesSetVectorTy &VisitedBases); + + void LayoutVFTable() { + // FIXME: add support for RTTI when we have proper LLVM support for symbols + // pointing to the middle of a section. + + BasesSetVectorTy VisitedBases; + AddMethods(BaseSubobject(MostDerivedClass, CharUnits::Zero()), 0, 0, + VisitedBases); + + assert(MethodVFTableLocations.empty()); + for (MethodInfoMapTy::const_iterator I = MethodInfoMap.begin(), + E = MethodInfoMap.end(); I != E; ++I) { + const CXXMethodDecl *MD = I->first; + const MethodInfo &MI = I->second; + // Skip the methods that the MostDerivedClass didn't override + // and the entries shadowed by return adjusting thunks. + if (MD->getParent() != MostDerivedClass || MI.Shadowed) + continue; + MethodVFTableLocation Loc(MI.VBTableIndex, WhichVFPtr.LastVBase, + WhichVFPtr.VFPtrOffset, MI.VFTableIndex); + if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) { + MethodVFTableLocations[GlobalDecl(DD, Dtor_Deleting)] = Loc; + } else { + MethodVFTableLocations[MD] = Loc; + } + } + } + + void ErrorUnsupported(StringRef Feature, SourceLocation Location) { + clang::DiagnosticsEngine &Diags = Context.getDiagnostics(); + unsigned DiagID = Diags.getCustomDiagID( + DiagnosticsEngine::Error, "v-table layout for %0 is not supported yet"); + Diags.Report(Context.getFullLoc(Location), DiagID) << Feature; + } + +public: + VFTableBuilder(MicrosoftVTableContext &VTables, + const CXXRecordDecl *MostDerivedClass, VFPtrInfo Which) + : VTables(VTables), + Context(MostDerivedClass->getASTContext()), + MostDerivedClass(MostDerivedClass), + MostDerivedClassLayout(Context.getASTRecordLayout(MostDerivedClass)), + WhichVFPtr(Which), + Overriders(MostDerivedClass, CharUnits(), MostDerivedClass) { + LayoutVFTable(); + + if (Context.getLangOpts().DumpVTableLayouts) + dumpLayout(llvm::outs()); + } + + uint64_t getNumThunks() const { return Thunks.size(); } + + ThunksMapTy::const_iterator thunks_begin() const { return Thunks.begin(); } + + ThunksMapTy::const_iterator thunks_end() const { return Thunks.end(); } + + MethodVFTableLocationsTy::const_iterator vtable_indices_begin() const { + return MethodVFTableLocations.begin(); + } + + MethodVFTableLocationsTy::const_iterator vtable_indices_end() const { + return MethodVFTableLocations.end(); + } + + uint64_t getNumVTableComponents() const { return Components.size(); } + + const VTableComponent *vtable_component_begin() const { + return Components.begin(); + } + + const VTableComponent *vtable_component_end() const { + return Components.end(); + } + + VTableThunksMapTy::const_iterator vtable_thunks_begin() const { + return VTableThunks.begin(); + } + + VTableThunksMapTy::const_iterator vtable_thunks_end() const { + return VTableThunks.end(); + } + + void dumpLayout(raw_ostream &); +}; + +/// InitialOverriddenDefinitionCollector - Finds the set of least derived bases +/// that define the given method. +struct InitialOverriddenDefinitionCollector { + BasesSetVectorTy Bases; + OverriddenMethodsSetTy VisitedOverriddenMethods; + + bool visit(const CXXMethodDecl *OverriddenMD) { + if (OverriddenMD->size_overridden_methods() == 0) + Bases.insert(OverriddenMD->getParent()); + // Don't recurse on this method if we've already collected it. + return VisitedOverriddenMethods.insert(OverriddenMD); + } +}; + +static bool BaseInSet(const CXXBaseSpecifier *Specifier, + CXXBasePath &Path, void *BasesSet) { + BasesSetVectorTy *Bases = (BasesSetVectorTy *)BasesSet; + return Bases->count(Specifier->getType()->getAsCXXRecordDecl()); +} + +CharUnits +VFTableBuilder::ComputeThisOffset(const CXXMethodDecl *MD, + BaseSubobject Base, + FinalOverriders::OverriderInfo Overrider) { + InitialOverriddenDefinitionCollector Collector; + visitAllOverriddenMethods(MD, Collector); + + CXXBasePaths Paths; + Base.getBase()->lookupInBases(BaseInSet, &Collector.Bases, Paths); + + // This will hold the smallest this offset among overridees of MD. + // This implies that an offset of a non-virtual base will dominate an offset + // of a virtual base to potentially reduce the number of thunks required + // in the derived classes that inherit this method. + CharUnits Ret; + bool First = true; + + for (CXXBasePaths::paths_iterator I = Paths.begin(), E = Paths.end(); + I != E; ++I) { + const CXXBasePath &Path = (*I); + CharUnits ThisOffset = Base.getBaseOffset(); + CharUnits LastVBaseOffset; + + // For each path from the overrider to the parents of the overridden methods, + // traverse the path, calculating the this offset in the most derived class. + for (int J = 0, F = Path.size(); J != F; ++J) { + const CXXBasePathElement &Element = Path[J]; + QualType CurTy = Element.Base->getType(); + const CXXRecordDecl *PrevRD = Element.Class, + *CurRD = CurTy->getAsCXXRecordDecl(); + const ASTRecordLayout &Layout = Context.getASTRecordLayout(PrevRD); + + if (Element.Base->isVirtual()) { + LastVBaseOffset = MostDerivedClassLayout.getVBaseClassOffset(CurRD); + if (Overrider.Method->getParent() == PrevRD) { + // This one's interesting. If the final overrider is in a vbase B of the + // most derived class and it overrides a method of the B's own vbase A, + // it uses A* as "this". In its prologue, it can cast A* to B* with + // a static offset. This offset is used regardless of the actual + // offset of A from B in the most derived class, requiring an + // this-adjusting thunk in the vftable if A and B are laid out + // differently in the most derived class. + ThisOffset += Layout.getVBaseClassOffset(CurRD); + } else { + ThisOffset = LastVBaseOffset; + } + } else { + ThisOffset += Layout.getBaseClassOffset(CurRD); + } + } + + if (isa<CXXDestructorDecl>(MD)) { + if (LastVBaseOffset.isZero()) { + // If a "Base" class has at least one non-virtual base with a virtual + // destructor, the "Base" virtual destructor will take the address + // of the "Base" subobject as the "this" argument. + return Base.getBaseOffset(); + } else { + // A virtual destructor of a virtual base takes the address of the + // virtual base subobject as the "this" argument. + return LastVBaseOffset; + } + } + + if (Ret > ThisOffset || First) { + First = false; + Ret = ThisOffset; + } + } + + assert(!First && "Method not found in the given subobject?"); + return Ret; +} + +void VFTableBuilder::CalculateVtordispAdjustment( + FinalOverriders::OverriderInfo Overrider, CharUnits ThisOffset, + ThisAdjustment &TA) { + const ASTRecordLayout::VBaseOffsetsMapTy &VBaseMap = + MostDerivedClassLayout.getVBaseOffsetsMap(); + const ASTRecordLayout::VBaseOffsetsMapTy::const_iterator &VBaseMapEntry = + VBaseMap.find(WhichVFPtr.LastVBase); + assert(VBaseMapEntry != VBaseMap.end()); + + // Check if we need a vtordisp adjustment at all. + if (!VBaseMapEntry->second.hasVtorDisp()) + return; + + CharUnits VFPtrVBaseOffset = VBaseMapEntry->second.VBaseOffset; + // The implicit vtordisp field is located right before the vbase. + TA.Virtual.Microsoft.VtordispOffset = + (VFPtrVBaseOffset - WhichVFPtr.VFPtrFullOffset).getQuantity() - 4; + + // If the final overrider is defined in either: + // - the most derived class or its non-virtual base or + // - the same vbase as the initial declaration, + // a simple vtordisp thunk will suffice. + const CXXRecordDecl *OverriderRD = Overrider.Method->getParent(); + if (OverriderRD == MostDerivedClass) + return; + + const CXXRecordDecl *OverriderVBase = + ComputeBaseOffset(Context, OverriderRD, MostDerivedClass).VirtualBase; + if (!OverriderVBase || OverriderVBase == WhichVFPtr.LastVBase) + return; + + // Otherwise, we need to do use the dynamic offset of the final overrider + // in order to get "this" adjustment right. + TA.Virtual.Microsoft.VBPtrOffset = + (VFPtrVBaseOffset + WhichVFPtr.VFPtrOffset - + MostDerivedClassLayout.getVBPtrOffset()).getQuantity(); + TA.Virtual.Microsoft.VBOffsetOffset = + Context.getTypeSizeInChars(Context.IntTy).getQuantity() * + VTables.getVBTableIndex(MostDerivedClass, OverriderVBase); + + TA.NonVirtual = (ThisOffset - Overrider.Offset).getQuantity(); +} + +static void GroupNewVirtualOverloads( + const CXXRecordDecl *RD, + SmallVector<const CXXMethodDecl *, 10> &VirtualMethods) { + // Put the virtual methods into VirtualMethods in the proper order: + // 1) Group overloads by declaration name. New groups are added to the + // vftable in the order of their first declarations in this class + // (including overrides). + // 2) In each group, new overloads appear in the reverse order of declaration. + typedef SmallVector<const CXXMethodDecl *, 1> MethodGroup; + SmallVector<MethodGroup, 10> Groups; + typedef llvm::DenseMap<DeclarationName, unsigned> VisitedGroupIndicesTy; + VisitedGroupIndicesTy VisitedGroupIndices; + for (CXXRecordDecl::method_iterator I = RD->method_begin(), + E = RD->method_end(); I != E; ++I) { + const CXXMethodDecl *MD = *I; + if (!MD->isVirtual()) + continue; + + VisitedGroupIndicesTy::iterator J; + bool Inserted; + llvm::tie(J, Inserted) = VisitedGroupIndices.insert( + std::make_pair(MD->getDeclName(), Groups.size())); + if (Inserted) + Groups.push_back(MethodGroup(1, MD)); + else + Groups[J->second].push_back(MD); + } + + for (unsigned I = 0, E = Groups.size(); I != E; ++I) + VirtualMethods.append(Groups[I].rbegin(), Groups[I].rend()); +} + +void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth, + const CXXRecordDecl *LastVBase, + BasesSetVectorTy &VisitedBases) { + const CXXRecordDecl *RD = Base.getBase(); + if (!RD->isPolymorphic()) + return; + + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + + // See if this class expands a vftable of the base we look at, which is either + // the one defined by the vfptr base path or the primary base of the current class. + const CXXRecordDecl *NextBase = 0, *NextLastVBase = LastVBase; + CharUnits NextBaseOffset; + if (BaseDepth < WhichVFPtr.PathToBaseWithVFPtr.size()) { + NextBase = WhichVFPtr.PathToBaseWithVFPtr[BaseDepth]; + if (Layout.getVBaseOffsetsMap().count(NextBase)) { + NextLastVBase = NextBase; + NextBaseOffset = MostDerivedClassLayout.getVBaseClassOffset(NextBase); + } else { + NextBaseOffset = + Base.getBaseOffset() + Layout.getBaseClassOffset(NextBase); + } + } else if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) { + assert(!Layout.isPrimaryBaseVirtual() && + "No primary virtual bases in this ABI"); + NextBase = PrimaryBase; + NextBaseOffset = Base.getBaseOffset(); + } + + if (NextBase) { + AddMethods(BaseSubobject(NextBase, NextBaseOffset), BaseDepth + 1, + NextLastVBase, VisitedBases); + if (!VisitedBases.insert(NextBase)) + llvm_unreachable("Found a duplicate primary base!"); + } + + SmallVector<const CXXMethodDecl*, 10> VirtualMethods; + // Put virtual methods in the proper order. + GroupNewVirtualOverloads(RD, VirtualMethods); + + // Now go through all virtual member functions and add them to the current + // vftable. This is done by + // - replacing overridden methods in their existing slots, as long as they + // don't require return adjustment; calculating This adjustment if needed. + // - adding new slots for methods of the current base not present in any + // sub-bases; + // - adding new slots for methods that require Return adjustment. + // We keep track of the methods visited in the sub-bases in MethodInfoMap. + for (unsigned I = 0, E = VirtualMethods.size(); I != E; ++I) { + const CXXMethodDecl *MD = VirtualMethods[I]; + + FinalOverriders::OverriderInfo Overrider = + Overriders.getOverrider(MD, Base.getBaseOffset()); + ThisAdjustment ThisAdjustmentOffset; + bool ForceThunk = false; + + // Check if this virtual member function overrides + // a method in one of the visited bases. + if (const CXXMethodDecl *OverriddenMD = + FindNearestOverriddenMethod(MD, VisitedBases)) { + MethodInfoMapTy::iterator OverriddenMDIterator = + MethodInfoMap.find(OverriddenMD); + + // If the overridden method went to a different vftable, skip it. + if (OverriddenMDIterator == MethodInfoMap.end()) + continue; + + MethodInfo &OverriddenMethodInfo = OverriddenMDIterator->second; + + // Create a this-adjusting thunk if needed. + CharUnits TI = ComputeThisOffset(MD, Base, Overrider); + if (TI != WhichVFPtr.VFPtrFullOffset) { + ThisAdjustmentOffset.NonVirtual = + (TI - WhichVFPtr.VFPtrFullOffset).getQuantity(); + } + + if (WhichVFPtr.LastVBase) + CalculateVtordispAdjustment(Overrider, TI, ThisAdjustmentOffset); + + if (!ThisAdjustmentOffset.isEmpty()) { + VTableThunks[OverriddenMethodInfo.VFTableIndex].This = + ThisAdjustmentOffset; + AddThunk(MD, VTableThunks[OverriddenMethodInfo.VFTableIndex]); + } + + if (MD->getResultType() == OverriddenMD->getResultType()) { + // No return adjustment needed - just replace the overridden method info + // with the current info. + MethodInfo MI(OverriddenMethodInfo.VBTableIndex, + OverriddenMethodInfo.VFTableIndex); + MethodInfoMap.erase(OverriddenMDIterator); + + assert(!MethodInfoMap.count(MD) && + "Should not have method info for this method yet!"); + MethodInfoMap.insert(std::make_pair(MD, MI)); + continue; + } else { + // In case we need a return adjustment, we'll add a new slot for + // the overrider and put a return-adjusting thunk where the overridden + // method was in the vftable. + // For now, just mark the overriden method as shadowed by a new slot. + OverriddenMethodInfo.Shadowed = true; + ForceThunk = true; + + // Also apply this adjustment to the shadowed slots. + if (!ThisAdjustmentOffset.isEmpty()) { + // FIXME: this is O(N^2), can be O(N). + const CXXMethodDecl *SubOverride = OverriddenMD; + while ((SubOverride = + FindNearestOverriddenMethod(SubOverride, VisitedBases))) { + MethodInfoMapTy::iterator SubOverrideIterator = + MethodInfoMap.find(SubOverride); + if (SubOverrideIterator == MethodInfoMap.end()) + break; + MethodInfo &SubOverrideMI = SubOverrideIterator->second; + assert(SubOverrideMI.Shadowed); + VTableThunks[SubOverrideMI.VFTableIndex].This = + ThisAdjustmentOffset; + AddThunk(MD, VTableThunks[SubOverrideMI.VFTableIndex]); + } + } + } + } else if (Base.getBaseOffset() != WhichVFPtr.VFPtrFullOffset || + MD->size_overridden_methods()) { + // Skip methods that don't belong to the vftable of the current class, + // e.g. each method that wasn't seen in any of the visited sub-bases + // but overrides multiple methods of other sub-bases. + continue; + } + + // If we got here, MD is a method not seen in any of the sub-bases or + // it requires return adjustment. Insert the method info for this method. + unsigned VBIndex = + LastVBase ? VTables.getVBTableIndex(MostDerivedClass, LastVBase) : 0; + MethodInfo MI(VBIndex, Components.size()); + + assert(!MethodInfoMap.count(MD) && + "Should not have method info for this method yet!"); + MethodInfoMap.insert(std::make_pair(MD, MI)); + + const CXXMethodDecl *OverriderMD = Overrider.Method; + + // Check if this overrider needs a return adjustment. + // We don't want to do this for pure virtual member functions. + BaseOffset ReturnAdjustmentOffset; + ReturnAdjustment ReturnAdjustment; + if (!OverriderMD->isPure()) { + ReturnAdjustmentOffset = + ComputeReturnAdjustmentBaseOffset(Context, OverriderMD, MD); + } + if (!ReturnAdjustmentOffset.isEmpty()) { + ForceThunk = true; + ReturnAdjustment.NonVirtual = + ReturnAdjustmentOffset.NonVirtualOffset.getQuantity(); + if (ReturnAdjustmentOffset.VirtualBase) { + const ASTRecordLayout &DerivedLayout = + Context.getASTRecordLayout(ReturnAdjustmentOffset.DerivedClass); + ReturnAdjustment.Virtual.Microsoft.VBPtrOffset = + DerivedLayout.getVBPtrOffset().getQuantity(); + ReturnAdjustment.Virtual.Microsoft.VBIndex = + VTables.getVBTableIndex(ReturnAdjustmentOffset.DerivedClass, + ReturnAdjustmentOffset.VirtualBase); + } + } + + AddMethod(OverriderMD, ThunkInfo(ThisAdjustmentOffset, ReturnAdjustment, + ForceThunk ? MD : 0)); + } +} + +void PrintBasePath(const VFPtrInfo::BasePath &Path, raw_ostream &Out) { + for (VFPtrInfo::BasePath::const_reverse_iterator I = Path.rbegin(), + E = Path.rend(); I != E; ++I) { + Out << "'" << (*I)->getQualifiedNameAsString() << "' in "; + } +} + +struct MicrosoftThunkInfoStableSortComparator { + bool operator() (const ThunkInfo &LHS, const ThunkInfo &RHS) { + if (LHS.This != RHS.This) + return LHS.This < RHS.This; + + if (LHS.Return != RHS.Return) + return LHS.Return < RHS.Return; + + // Keep different thunks with the same adjustments in the order they + // were put into the vector. + return false; + } +}; + +static void dumpMicrosoftThunkAdjustment(const ThunkInfo &TI, raw_ostream &Out, + bool ContinueFirstLine) { + const ReturnAdjustment &R = TI.Return; + bool Multiline = false; + const char *LinePrefix = "\n "; + if (!R.isEmpty()) { + if (!ContinueFirstLine) + Out << LinePrefix; + Out << "[return adjustment: "; + if (R.Virtual.Microsoft.VBPtrOffset) + Out << "vbptr at offset " << R.Virtual.Microsoft.VBPtrOffset << ", "; + if (R.Virtual.Microsoft.VBIndex) + Out << "vbase #" << R.Virtual.Microsoft.VBIndex << ", "; + Out << R.NonVirtual << " non-virtual]"; + Multiline = true; + } + + const ThisAdjustment &T = TI.This; + if (!T.isEmpty()) { + if (Multiline || !ContinueFirstLine) + Out << LinePrefix; + Out << "[this adjustment: "; + if (!TI.This.Virtual.isEmpty()) { + assert(T.Virtual.Microsoft.VtordispOffset < 0); + Out << "vtordisp at " << T.Virtual.Microsoft.VtordispOffset << ", "; + if (T.Virtual.Microsoft.VBPtrOffset) { + Out << "vbptr at " << T.Virtual.Microsoft.VBPtrOffset + << " to the left, "; + assert(T.Virtual.Microsoft.VBOffsetOffset > 0); + Out << LinePrefix << " vboffset at " + << T.Virtual.Microsoft.VBOffsetOffset << " in the vbtable, "; + } + } + Out << T.NonVirtual << " non-virtual]"; + } +} + +void VFTableBuilder::dumpLayout(raw_ostream &Out) { + Out << "VFTable for "; + PrintBasePath(WhichVFPtr.PathToBaseWithVFPtr, Out); + Out << "'" << MostDerivedClass->getQualifiedNameAsString(); + Out << "' (" << Components.size() << " entries).\n"; + + for (unsigned I = 0, E = Components.size(); I != E; ++I) { + Out << llvm::format("%4d | ", I); + + const VTableComponent &Component = Components[I]; + + // Dump the component. + switch (Component.getKind()) { + case VTableComponent::CK_RTTI: + Out << Component.getRTTIDecl()->getQualifiedNameAsString() << " RTTI"; + break; + + case VTableComponent::CK_FunctionPointer: { + const CXXMethodDecl *MD = Component.getFunctionDecl(); + + std::string Str = PredefinedExpr::ComputeName( + PredefinedExpr::PrettyFunctionNoVirtual, MD); + Out << Str; + if (MD->isPure()) + Out << " [pure]"; + + if (MD->isDeleted()) { + ErrorUnsupported("deleted methods", MD->getLocation()); + Out << " [deleted]"; + } + + ThunkInfo Thunk = VTableThunks.lookup(I); + if (!Thunk.isEmpty()) + dumpMicrosoftThunkAdjustment(Thunk, Out, /*ContinueFirstLine=*/false); + + break; + } + + case VTableComponent::CK_DeletingDtorPointer: { + const CXXDestructorDecl *DD = Component.getDestructorDecl(); + + Out << DD->getQualifiedNameAsString(); + Out << "() [scalar deleting]"; + + if (DD->isPure()) + Out << " [pure]"; + + ThunkInfo Thunk = VTableThunks.lookup(I); + if (!Thunk.isEmpty()) { + assert(Thunk.Return.isEmpty() && + "No return adjustment needed for destructors!"); + dumpMicrosoftThunkAdjustment(Thunk, Out, /*ContinueFirstLine=*/false); + } + + break; + } + + default: + DiagnosticsEngine &Diags = Context.getDiagnostics(); + unsigned DiagID = Diags.getCustomDiagID( + DiagnosticsEngine::Error, + "Unexpected vftable component type %0 for component number %1"); + Diags.Report(MostDerivedClass->getLocation(), DiagID) + << I << Component.getKind(); + } + + Out << '\n'; + } + + Out << '\n'; + + if (!Thunks.empty()) { + // We store the method names in a map to get a stable order. + std::map<std::string, const CXXMethodDecl *> MethodNamesAndDecls; + + for (ThunksMapTy::const_iterator I = Thunks.begin(), E = Thunks.end(); + I != E; ++I) { + const CXXMethodDecl *MD = I->first; + std::string MethodName = PredefinedExpr::ComputeName( + PredefinedExpr::PrettyFunctionNoVirtual, MD); + + MethodNamesAndDecls.insert(std::make_pair(MethodName, MD)); + } + + for (std::map<std::string, const CXXMethodDecl *>::const_iterator + I = MethodNamesAndDecls.begin(), + E = MethodNamesAndDecls.end(); + I != E; ++I) { + const std::string &MethodName = I->first; + const CXXMethodDecl *MD = I->second; + + ThunkInfoVectorTy ThunksVector = Thunks[MD]; + std::stable_sort(ThunksVector.begin(), ThunksVector.end(), + MicrosoftThunkInfoStableSortComparator()); + + Out << "Thunks for '" << MethodName << "' (" << ThunksVector.size(); + Out << (ThunksVector.size() == 1 ? " entry" : " entries") << ").\n"; + + for (unsigned I = 0, E = ThunksVector.size(); I != E; ++I) { + const ThunkInfo &Thunk = ThunksVector[I]; + + Out << llvm::format("%4d | ", I); + dumpMicrosoftThunkAdjustment(Thunk, Out, /*ContinueFirstLine=*/true); + Out << '\n'; + } + + Out << '\n'; + } + } +} +} + +void MicrosoftVTableContext::enumerateVFPtrs( + const CXXRecordDecl *MostDerivedClass, + const ASTRecordLayout &MostDerivedClassLayout, BaseSubobject Base, + const CXXRecordDecl *LastVBase, + const VFPtrInfo::BasePath &PathFromCompleteClass, + BasesSetVectorTy &VisitedVBases, + VFPtrListTy &Result) { + const CXXRecordDecl *CurrentClass = Base.getBase(); + CharUnits OffsetInCompleteClass = Base.getBaseOffset(); + const ASTRecordLayout &CurrentClassLayout = + Context.getASTRecordLayout(CurrentClass); + + if (CurrentClassLayout.hasOwnVFPtr()) { + if (LastVBase) { + uint64_t VBIndex = getVBTableIndex(MostDerivedClass, LastVBase); + assert(VBIndex > 0 && "vbases must have vbindex!"); + CharUnits VFPtrOffset = + OffsetInCompleteClass - + MostDerivedClassLayout.getVBaseClassOffset(LastVBase); + Result.push_back(VFPtrInfo(VBIndex, LastVBase, VFPtrOffset, + PathFromCompleteClass, OffsetInCompleteClass)); + } else { + Result.push_back(VFPtrInfo(OffsetInCompleteClass, PathFromCompleteClass)); + } + } + + for (CXXRecordDecl::base_class_const_iterator I = CurrentClass->bases_begin(), + E = CurrentClass->bases_end(); I != E; ++I) { + const CXXRecordDecl *BaseDecl = I->getType()->getAsCXXRecordDecl(); + + CharUnits NextBaseOffset; + const CXXRecordDecl *NextLastVBase; + if (I->isVirtual()) { + if (!VisitedVBases.insert(BaseDecl)) + continue; + NextBaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); + NextLastVBase = BaseDecl; + } else { + NextBaseOffset = OffsetInCompleteClass + + CurrentClassLayout.getBaseClassOffset(BaseDecl); + NextLastVBase = LastVBase; + } + + VFPtrInfo::BasePath NewPath = PathFromCompleteClass; + NewPath.push_back(BaseDecl); + BaseSubobject NextBase(BaseDecl, NextBaseOffset); + + enumerateVFPtrs(MostDerivedClass, MostDerivedClassLayout, NextBase, + NextLastVBase, NewPath, VisitedVBases, Result); + } +} + +/// CalculatePathToMangle - Calculate the subset of records that should be used +/// to mangle the vftable for the given vfptr. +/// Should only be called if a class has multiple vftables. +static void +CalculatePathToMangle(const CXXRecordDecl *RD, VFPtrInfo &VFPtr) { + // FIXME: In some rare cases this code produces a slightly incorrect mangling. + // It's very likely that the vbtable mangling code can be adjusted to mangle + // both vftables and vbtables correctly. + + VFPtrInfo::BasePath &FullPath = VFPtr.PathToBaseWithVFPtr; + if (FullPath.empty()) { + // Mangle the class's own vftable. + assert(RD->getNumVBases() && + "Something's wrong: if the most derived " + "class has more than one vftable, it can only have its own " + "vftable if it has vbases"); + VFPtr.PathToMangle.push_back(RD); + return; + } + + unsigned Begin = 0; + + // First, skip all the bases before the vbase. + if (VFPtr.LastVBase) { + while (FullPath[Begin] != VFPtr.LastVBase) { + Begin++; + assert(Begin < FullPath.size()); + } + } + + // Then, put the rest of the base path in the reverse order. + for (unsigned I = FullPath.size(); I != Begin; --I) { + const CXXRecordDecl *CurBase = FullPath[I - 1], + *ItsBase = (I == 1) ? RD : FullPath[I - 2]; + bool BaseIsVirtual = false; + for (CXXRecordDecl::base_class_const_iterator J = ItsBase->bases_begin(), + F = ItsBase->bases_end(); J != F; ++J) { + if (J->getType()->getAsCXXRecordDecl() == CurBase) { + BaseIsVirtual = J->isVirtual(); + break; + } + } + + // Should skip the current base if it is a non-virtual base with no siblings. + if (BaseIsVirtual || ItsBase->getNumBases() != 1) + VFPtr.PathToMangle.push_back(CurBase); + } +} + +void MicrosoftVTableContext::enumerateVFPtrs( + const CXXRecordDecl *ForClass, + MicrosoftVTableContext::VFPtrListTy &Result) { + Result.clear(); + const ASTRecordLayout &ClassLayout = Context.getASTRecordLayout(ForClass); + BasesSetVectorTy VisitedVBases; + enumerateVFPtrs(ForClass, ClassLayout, + BaseSubobject(ForClass, CharUnits::Zero()), 0, + VFPtrInfo::BasePath(), VisitedVBases, Result); + if (Result.size() > 1) { + for (unsigned I = 0, E = Result.size(); I != E; ++I) + CalculatePathToMangle(ForClass, Result[I]); + } +} + +void MicrosoftVTableContext::computeVTableRelatedInformation( + const CXXRecordDecl *RD) { + assert(RD->isDynamicClass()); + + // Check if we've computed this information before. + if (VFPtrLocations.count(RD)) + return; + + const VTableLayout::AddressPointsMapTy EmptyAddressPointsMap; + + VFPtrListTy &VFPtrs = VFPtrLocations[RD]; + enumerateVFPtrs(RD, VFPtrs); + + MethodVFTableLocationsTy NewMethodLocations; + for (VFPtrListTy::iterator I = VFPtrs.begin(), E = VFPtrs.end(); + I != E; ++I) { + VFTableBuilder Builder(*this, RD, *I); + + VFTableIdTy id(RD, I->VFPtrFullOffset); + assert(VFTableLayouts.count(id) == 0); + SmallVector<VTableLayout::VTableThunkTy, 1> VTableThunks( + Builder.vtable_thunks_begin(), Builder.vtable_thunks_end()); + VFTableLayouts[id] = new VTableLayout( + Builder.getNumVTableComponents(), Builder.vtable_component_begin(), + VTableThunks.size(), VTableThunks.data(), EmptyAddressPointsMap, true); + NewMethodLocations.insert(Builder.vtable_indices_begin(), + Builder.vtable_indices_end()); + Thunks.insert(Builder.thunks_begin(), Builder.thunks_end()); + } + + MethodVFTableLocations.insert(NewMethodLocations.begin(), + NewMethodLocations.end()); + if (Context.getLangOpts().DumpVTableLayouts) + dumpMethodLocations(RD, NewMethodLocations, llvm::outs()); +} + +void MicrosoftVTableContext::dumpMethodLocations( + const CXXRecordDecl *RD, const MethodVFTableLocationsTy &NewMethods, + raw_ostream &Out) { + // Compute the vtable indices for all the member functions. + // Store them in a map keyed by the location so we'll get a sorted table. + std::map<MethodVFTableLocation, std::string> IndicesMap; + bool HasNonzeroOffset = false; + + for (MethodVFTableLocationsTy::const_iterator I = NewMethods.begin(), + E = NewMethods.end(); I != E; ++I) { + const CXXMethodDecl *MD = cast<const CXXMethodDecl>(I->first.getDecl()); + assert(MD->isVirtual()); + + std::string MethodName = PredefinedExpr::ComputeName( + PredefinedExpr::PrettyFunctionNoVirtual, MD); + + if (isa<CXXDestructorDecl>(MD)) { + IndicesMap[I->second] = MethodName + " [scalar deleting]"; + } else { + IndicesMap[I->second] = MethodName; + } + + if (!I->second.VFPtrOffset.isZero() || I->second.VBTableIndex != 0) + HasNonzeroOffset = true; + } + + // Print the vtable indices for all the member functions. + if (!IndicesMap.empty()) { + Out << "VFTable indices for "; + Out << "'" << RD->getQualifiedNameAsString(); + Out << "' (" << IndicesMap.size() << " entries).\n"; + + CharUnits LastVFPtrOffset = CharUnits::fromQuantity(-1); + uint64_t LastVBIndex = 0; + for (std::map<MethodVFTableLocation, std::string>::const_iterator + I = IndicesMap.begin(), + E = IndicesMap.end(); + I != E; ++I) { + CharUnits VFPtrOffset = I->first.VFPtrOffset; + uint64_t VBIndex = I->first.VBTableIndex; + if (HasNonzeroOffset && + (VFPtrOffset != LastVFPtrOffset || VBIndex != LastVBIndex)) { + assert(VBIndex > LastVBIndex || VFPtrOffset > LastVFPtrOffset); + Out << " -- accessible via "; + if (VBIndex) + Out << "vbtable index " << VBIndex << ", "; + Out << "vfptr at offset " << VFPtrOffset.getQuantity() << " --\n"; + LastVFPtrOffset = VFPtrOffset; + LastVBIndex = VBIndex; + } + + uint64_t VTableIndex = I->first.Index; + const std::string &MethodName = I->second; + Out << llvm::format("%4" PRIu64 " | ", VTableIndex) << MethodName << '\n'; + } + Out << '\n'; + } +} + +void MicrosoftVTableContext::computeVBTableRelatedInformation( + const CXXRecordDecl *RD) { + if (ComputedVBTableIndices.count(RD)) + return; + ComputedVBTableIndices.insert(RD); + + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + BasesSetVectorTy VisitedBases; + + // First, see if the Derived class shared the vbptr with a non-virtual base. + if (const CXXRecordDecl *VBPtrBase = Layout.getBaseSharingVBPtr()) { + // If the Derived class shares the vbptr with a non-virtual base, + // it inherits its vbase indices. + computeVBTableRelatedInformation(VBPtrBase); + for (CXXRecordDecl::base_class_const_iterator I = VBPtrBase->vbases_begin(), + E = VBPtrBase->vbases_end(); I != E; ++I) { + const CXXRecordDecl *SubVBase = I->getType()->getAsCXXRecordDecl(); + assert(VBTableIndices.count(ClassPairTy(VBPtrBase, SubVBase))); + VBTableIndices[ClassPairTy(RD, SubVBase)] = + VBTableIndices[ClassPairTy(VBPtrBase, SubVBase)]; + VisitedBases.insert(SubVBase); + } + } + + // New vbases are added to the end of the vbtable. + // Skip the self entry and vbases visited in the non-virtual base, if any. + unsigned VBTableIndex = 1 + VisitedBases.size(); + for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(), + E = RD->vbases_end(); I != E; ++I) { + const CXXRecordDecl *CurVBase = I->getType()->getAsCXXRecordDecl(); + if (VisitedBases.insert(CurVBase)) + VBTableIndices[ClassPairTy(RD, CurVBase)] = VBTableIndex++; + } +} + +const MicrosoftVTableContext::VFPtrListTy & +MicrosoftVTableContext::getVFPtrOffsets(const CXXRecordDecl *RD) { + computeVTableRelatedInformation(RD); + + assert(VFPtrLocations.count(RD) && "Couldn't find vfptr locations"); + return VFPtrLocations[RD]; +} + +const VTableLayout & +MicrosoftVTableContext::getVFTableLayout(const CXXRecordDecl *RD, + CharUnits VFPtrOffset) { + computeVTableRelatedInformation(RD); + + VFTableIdTy id(RD, VFPtrOffset); + assert(VFTableLayouts.count(id) && "Couldn't find a VFTable at this offset"); + return *VFTableLayouts[id]; +} + +const MicrosoftVTableContext::MethodVFTableLocation & +MicrosoftVTableContext::getMethodVFTableLocation(GlobalDecl GD) { + assert(cast<CXXMethodDecl>(GD.getDecl())->isVirtual() && + "Only use this method for virtual methods or dtors"); + if (isa<CXXDestructorDecl>(GD.getDecl())) + assert(GD.getDtorType() == Dtor_Deleting); + + MethodVFTableLocationsTy::iterator I = MethodVFTableLocations.find(GD); + if (I != MethodVFTableLocations.end()) + return I->second; + + const CXXRecordDecl *RD = cast<CXXMethodDecl>(GD.getDecl())->getParent(); + + computeVTableRelatedInformation(RD); + + I = MethodVFTableLocations.find(GD); + assert(I != MethodVFTableLocations.end() && "Did not find index!"); + return I->second; } |