diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 11:06:01 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 11:06:01 +0000 |
commit | 486754660bb926339aefcf012a3f848592babb8b (patch) | |
tree | ecdbc446c9876f4f120f701c243373cd3cb43db3 /lib/AST | |
parent | 55e6d896ad333f07bb3b1ba487df214fc268a4ab (diff) |
Vendor import of clang trunk r338150:vendor/clang/clang-trunk-r338150
Diffstat (limited to 'lib/AST')
47 files changed, 7284 insertions, 3555 deletions
diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp index 488ad3373ca3..c45b52a65a4d 100644 --- a/lib/AST/APValue.cpp +++ b/lib/AST/APValue.cpp @@ -23,14 +23,57 @@ using namespace clang; namespace { struct LVBase { - llvm::PointerIntPair<APValue::LValueBase, 1, bool> BaseAndIsOnePastTheEnd; + APValue::LValueBase Base; CharUnits Offset; unsigned PathLength; - unsigned CallIndex; - bool IsNullPtr; + bool IsNullPtr : 1; + bool IsOnePastTheEnd : 1; }; } +void *APValue::LValueBase::getOpaqueValue() const { + return Ptr.getOpaqueValue(); +} + +bool APValue::LValueBase::isNull() const { + return Ptr.isNull(); +} + +APValue::LValueBase::operator bool () const { + return static_cast<bool>(Ptr); +} + +clang::APValue::LValueBase +llvm::DenseMapInfo<clang::APValue::LValueBase>::getEmptyKey() { + return clang::APValue::LValueBase( + DenseMapInfo<clang::APValue::LValueBase::PtrTy>::getEmptyKey(), + DenseMapInfo<unsigned>::getEmptyKey(), + DenseMapInfo<unsigned>::getEmptyKey()); +} + +clang::APValue::LValueBase +llvm::DenseMapInfo<clang::APValue::LValueBase>::getTombstoneKey() { + return clang::APValue::LValueBase( + DenseMapInfo<clang::APValue::LValueBase::PtrTy>::getTombstoneKey(), + DenseMapInfo<unsigned>::getTombstoneKey(), + DenseMapInfo<unsigned>::getTombstoneKey()); +} + +unsigned llvm::DenseMapInfo<clang::APValue::LValueBase>::getHashValue( + const clang::APValue::LValueBase &Base) { + llvm::FoldingSetNodeID ID; + ID.AddPointer(Base.getOpaqueValue()); + ID.AddInteger(Base.getCallIndex()); + ID.AddInteger(Base.getVersion()); + return ID.ComputeHash(); +} + +bool llvm::DenseMapInfo<clang::APValue::LValueBase>::isEqual( + const clang::APValue::LValueBase &LHS, + const clang::APValue::LValueBase &RHS) { + return LHS == RHS; +} + struct APValue::LV : LVBase { static const unsigned InlinePathSpace = (DataSize - sizeof(LVBase)) / sizeof(LValuePathEntry); @@ -150,11 +193,10 @@ APValue::APValue(const APValue &RHS) : Kind(Uninitialized) { MakeLValue(); if (RHS.hasLValuePath()) setLValue(RHS.getLValueBase(), RHS.getLValueOffset(), RHS.getLValuePath(), - RHS.isLValueOnePastTheEnd(), RHS.getLValueCallIndex(), - RHS.isNullPointer()); + RHS.isLValueOnePastTheEnd(), RHS.isNullPointer()); else setLValue(RHS.getLValueBase(), RHS.getLValueOffset(), NoLValuePath(), - RHS.getLValueCallIndex(), RHS.isNullPointer()); + RHS.isNullPointer()); break; case Array: MakeArray(RHS.getArrayInitializedElts(), RHS.getArraySize()); @@ -552,12 +594,12 @@ std::string APValue::getAsString(ASTContext &Ctx, QualType Ty) const { const APValue::LValueBase APValue::getLValueBase() const { assert(isLValue() && "Invalid accessor"); - return ((const LV*)(const void*)Data.buffer)->BaseAndIsOnePastTheEnd.getPointer(); + return ((const LV*)(const void*)Data.buffer)->Base; } bool APValue::isLValueOnePastTheEnd() const { assert(isLValue() && "Invalid accessor"); - return ((const LV*)(const void*)Data.buffer)->BaseAndIsOnePastTheEnd.getInt(); + return ((const LV*)(const void*)Data.buffer)->IsOnePastTheEnd; } CharUnits &APValue::getLValueOffset() { @@ -578,7 +620,12 @@ ArrayRef<APValue::LValuePathEntry> APValue::getLValuePath() const { unsigned APValue::getLValueCallIndex() const { assert(isLValue() && "Invalid accessor"); - return ((const LV*)(const char*)Data.buffer)->CallIndex; + return ((const LV*)(const char*)Data.buffer)->Base.getCallIndex(); +} + +unsigned APValue::getLValueVersion() const { + assert(isLValue() && "Invalid accessor"); + return ((const LV*)(const char*)Data.buffer)->Base.getVersion(); } bool APValue::isNullPointer() const { @@ -587,26 +634,24 @@ bool APValue::isNullPointer() const { } void APValue::setLValue(LValueBase B, const CharUnits &O, NoLValuePath, - unsigned CallIndex, bool IsNullPtr) { + bool IsNullPtr) { assert(isLValue() && "Invalid accessor"); LV &LVal = *((LV*)(char*)Data.buffer); - LVal.BaseAndIsOnePastTheEnd.setPointer(B); - LVal.BaseAndIsOnePastTheEnd.setInt(false); + LVal.Base = B; + LVal.IsOnePastTheEnd = false; LVal.Offset = O; - LVal.CallIndex = CallIndex; LVal.resizePath((unsigned)-1); LVal.IsNullPtr = IsNullPtr; } void APValue::setLValue(LValueBase B, const CharUnits &O, ArrayRef<LValuePathEntry> Path, bool IsOnePastTheEnd, - unsigned CallIndex, bool IsNullPtr) { + bool IsNullPtr) { assert(isLValue() && "Invalid accessor"); LV &LVal = *((LV*)(char*)Data.buffer); - LVal.BaseAndIsOnePastTheEnd.setPointer(B); - LVal.BaseAndIsOnePastTheEnd.setInt(IsOnePastTheEnd); + LVal.Base = B; + LVal.IsOnePastTheEnd = IsOnePastTheEnd; LVal.Offset = O; - LVal.CallIndex = CallIndex; LVal.resizePath(Path.size()); memcpy(LVal.getPath(), Path.data(), Path.size() * sizeof(LValuePathEntry)); LVal.IsNullPtr = IsNullPtr; diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 3dc961d4f12b..25dc4441aafd 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -47,6 +47,7 @@ #include "clang/Basic/AddressSpaces.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/CommentOptions.h" +#include "clang/Basic/ExceptionSpecificationType.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/LangOptions.h" @@ -130,35 +131,34 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const { return nullptr; // User can not attach documentation to implicit instantiations. - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + if (const auto *FD = dyn_cast<FunctionDecl>(D)) { if (FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) return nullptr; } - if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { + if (const auto *VD = dyn_cast<VarDecl>(D)) { if (VD->isStaticDataMember() && VD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) return nullptr; } - if (const CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(D)) { + if (const auto *CRD = dyn_cast<CXXRecordDecl>(D)) { if (CRD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) return nullptr; } - if (const ClassTemplateSpecializationDecl *CTSD = - dyn_cast<ClassTemplateSpecializationDecl>(D)) { + if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) { TemplateSpecializationKind TSK = CTSD->getSpecializationKind(); if (TSK == TSK_ImplicitInstantiation || TSK == TSK_Undeclared) return nullptr; } - if (const EnumDecl *ED = dyn_cast<EnumDecl>(D)) { + if (const auto *ED = dyn_cast<EnumDecl>(D)) { if (ED->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) return nullptr; } - if (const TagDecl *TD = dyn_cast<TagDecl>(D)) { + if (const auto *TD = dyn_cast<TagDecl>(D)) { // When tag declaration (but not definition!) is part of the // decl-specifier-seq of some other declaration, it doesn't get comment if (TD->isEmbeddedInDeclarator() && !TD->isCompleteDefinition()) @@ -201,7 +201,7 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const { // declared via a macro. Try using declaration's starting location as // the "declaration location". DeclLoc = D->getLocStart(); - } else if (const TagDecl *TD = dyn_cast<TagDecl>(D)) { + } else if (const auto *TD = dyn_cast<TagDecl>(D)) { // If location of the tag decl is inside a macro, but the spelling of // the tag name comes from a macro argument, it looks like a special // macro like NS_ENUM is being used to define the tag decl. In that @@ -226,8 +226,7 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const { // for is usually among the last two comments we parsed -- check them // first. RawComment CommentAtDeclLoc( - SourceMgr, SourceRange(DeclLoc), false, - LangOpts.CommentOpts.ParseAllComments); + SourceMgr, SourceRange(DeclLoc), LangOpts.CommentOpts, false); BeforeThanCompare<RawComment> Compare(SourceMgr); ArrayRef<RawComment *>::iterator MaybeBeforeDecl = RawComments.end() - 1; bool Found = Compare(*MaybeBeforeDecl, &CommentAtDeclLoc); @@ -253,7 +252,8 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const { // First check whether we have a trailing comment. if (Comment != RawComments.end() && - (*Comment)->isDocumentation() && (*Comment)->isTrailingComment() && + ((*Comment)->isDocumentation() || LangOpts.CommentOpts.ParseAllComments) + && (*Comment)->isTrailingComment() && (isa<FieldDecl>(D) || isa<EnumConstantDecl>(D) || isa<VarDecl>(D) || isa<ObjCMethodDecl>(D) || isa<ObjCPropertyDecl>(D))) { std::pair<FileID, unsigned> CommentBeginDecomp @@ -275,7 +275,9 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const { --Comment; // Check that we actually have a non-member Doxygen comment. - if (!(*Comment)->isDocumentation() || (*Comment)->isTrailingComment()) + if (!((*Comment)->isDocumentation() || + LangOpts.CommentOpts.ParseAllComments) || + (*Comment)->isTrailingComment()) return nullptr; // Decompose the end of the comment. @@ -310,7 +312,7 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const { /// refer to the actual template. /// If we have an implicit instantiation, adjust 'D' to refer to template. static const Decl *adjustDeclToTemplate(const Decl *D) { - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + if (const auto *FD = dyn_cast<FunctionDecl>(D)) { // Is this function declaration part of a function template? if (const FunctionTemplateDecl *FTD = FD->getDescribedFunctionTemplate()) return FTD; @@ -330,7 +332,7 @@ static const Decl *adjustDeclToTemplate(const Decl *D) { return D; } - if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { + if (const auto *VD = dyn_cast<VarDecl>(D)) { // Static data member is instantiated from a member definition of a class // template? if (VD->isStaticDataMember()) @@ -339,15 +341,14 @@ static const Decl *adjustDeclToTemplate(const Decl *D) { return D; } - if (const CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(D)) { + if (const auto *CRD = dyn_cast<CXXRecordDecl>(D)) { // Is this class declaration part of a class template? if (const ClassTemplateDecl *CTD = CRD->getDescribedClassTemplate()) return CTD; // Class is an implicit instantiation of a class template or partial // specialization? - if (const ClassTemplateSpecializationDecl *CTSD = - dyn_cast<ClassTemplateSpecializationDecl>(CRD)) { + if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(CRD)) { if (CTSD->getSpecializationKind() != TSK_ImplicitInstantiation) return D; llvm::PointerUnion<ClassTemplateDecl *, @@ -366,7 +367,7 @@ static const Decl *adjustDeclToTemplate(const Decl *D) { return D; } - if (const EnumDecl *ED = dyn_cast<EnumDecl>(D)) { + if (const auto *ED = dyn_cast<EnumDecl>(D)) { // Enum is instantiated from a member definition of a class template? if (const EnumDecl *MemberDecl = ED->getInstantiatedFromMemberEnum()) return MemberDecl; @@ -428,7 +429,7 @@ const RawComment *ASTContext::getRawCommentForAnyRedecl( } // If we found a comment, it should be a documentation comment. - assert(!RC || RC->isDocumentation()); + assert(!RC || RC->isDocumentation() || LangOpts.CommentOpts.ParseAllComments); if (OriginalDecl) *OriginalDecl = OriginalDeclForRC; @@ -451,7 +452,7 @@ const RawComment *ASTContext::getRawCommentForAnyRedecl( static void addRedeclaredMethods(const ObjCMethodDecl *ObjCMethod, SmallVectorImpl<const NamedDecl *> &Redeclared) { const DeclContext *DC = ObjCMethod->getDeclContext(); - if (const ObjCImplDecl *IMD = dyn_cast<ObjCImplDecl>(DC)) { + if (const auto *IMD = dyn_cast<ObjCImplDecl>(DC)) { const ObjCInterfaceDecl *ID = IMD->getClassInterface(); if (!ID) return; @@ -467,7 +468,7 @@ static void addRedeclaredMethods(const ObjCMethodDecl *ObjCMethod, comments::FullComment *ASTContext::cloneFullComment(comments::FullComment *FC, const Decl *D) const { - comments::DeclInfo *ThisDeclInfo = new (*this) comments::DeclInfo; + auto *ThisDeclInfo = new (*this) comments::DeclInfo; ThisDeclInfo->CommentDecl = D; ThisDeclInfo->IsFilled = false; ThisDeclInfo->fill(); @@ -511,7 +512,7 @@ comments::FullComment *ASTContext::getCommentForDecl( if (!RC) { if (isa<ObjCMethodDecl>(D) || isa<FunctionDecl>(D)) { SmallVector<const NamedDecl*, 8> Overridden; - const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(D); + const auto *OMD = dyn_cast<ObjCMethodDecl>(D); if (OMD && OMD->isPropertyAccessor()) if (const ObjCPropertyDecl *PDecl = OMD->findPropertyDecl()) if (comments::FullComment *FC = getCommentForDecl(PDecl, PP)) @@ -523,28 +524,28 @@ comments::FullComment *ASTContext::getCommentForDecl( if (comments::FullComment *FC = getCommentForDecl(Overridden[i], PP)) return cloneFullComment(FC, D); } - else if (const TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) { + else if (const auto *TD = dyn_cast<TypedefNameDecl>(D)) { // Attach any tag type's documentation to its typedef if latter // does not have one of its own. QualType QT = TD->getUnderlyingType(); - if (const TagType *TT = QT->getAs<TagType>()) + if (const auto *TT = QT->getAs<TagType>()) if (const Decl *TD = TT->getDecl()) if (comments::FullComment *FC = getCommentForDecl(TD, PP)) return cloneFullComment(FC, D); } - else if (const ObjCInterfaceDecl *IC = dyn_cast<ObjCInterfaceDecl>(D)) { + else if (const auto *IC = dyn_cast<ObjCInterfaceDecl>(D)) { while (IC->getSuperClass()) { IC = IC->getSuperClass(); if (comments::FullComment *FC = getCommentForDecl(IC, PP)) return cloneFullComment(FC, D); } } - else if (const ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(D)) { + else if (const auto *CD = dyn_cast<ObjCCategoryDecl>(D)) { if (const ObjCInterfaceDecl *IC = CD->getClassInterface()) if (comments::FullComment *FC = getCommentForDecl(IC, PP)) return cloneFullComment(FC, D); } - else if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) { + else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) { if (!(RD = RD->getDefinition())) return nullptr; // Check non-virtual bases. @@ -604,13 +605,13 @@ ASTContext::CanonicalTemplateTemplateParm::Profile(llvm::FoldingSetNodeID &ID, for (TemplateParameterList::const_iterator P = Params->begin(), PEnd = Params->end(); P != PEnd; ++P) { - if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*P)) { + if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(*P)) { ID.AddInteger(0); ID.AddBoolean(TTP->isParameterPack()); continue; } - if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) { + if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) { ID.AddInteger(1); ID.AddBoolean(NTTP->isParameterPack()); ID.AddPointer(NTTP->getType().getCanonicalType().getAsOpaquePtr()); @@ -626,7 +627,7 @@ ASTContext::CanonicalTemplateTemplateParm::Profile(llvm::FoldingSetNodeID &ID, continue; } - TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*P); + auto *TTP = cast<TemplateTemplateParmDecl>(*P); ID.AddInteger(2); Profile(ID, TTP); } @@ -651,7 +652,7 @@ ASTContext::getCanonicalTemplateTemplateParmDecl( for (TemplateParameterList::const_iterator P = Params->begin(), PEnd = Params->end(); P != PEnd; ++P) { - if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*P)) + if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(*P)) CanonParams.push_back( TemplateTypeParmDecl::Create(*this, getTranslationUnitDecl(), SourceLocation(), @@ -659,8 +660,7 @@ ASTContext::getCanonicalTemplateTemplateParmDecl( TTP->getDepth(), TTP->getIndex(), nullptr, false, TTP->isParameterPack())); - else if (NonTypeTemplateParmDecl *NTTP - = dyn_cast<NonTypeTemplateParmDecl>(*P)) { + else if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) { QualType T = getCanonicalType(NTTP->getType()); TypeSourceInfo *TInfo = getTrivialTypeSourceInfo(T); NonTypeTemplateParmDecl *Param; @@ -788,10 +788,12 @@ ASTContext::ASTContext(LangOptions &LOpts, SourceManager &SM, SubstTemplateTemplateParmPacks(this_()), SourceMgr(SM), LangOpts(LOpts), SanitizerBL(new SanitizerBlacklist(LangOpts.SanitizerBlacklistFiles, SM)), XRayFilter(new XRayFunctionFilter(LangOpts.XRayAlwaysInstrumentFiles, - LangOpts.XRayNeverInstrumentFiles, SM)), + LangOpts.XRayNeverInstrumentFiles, + LangOpts.XRayAttrListFiles, SM)), PrintingPolicy(LOpts), Idents(idents), Selectors(sels), BuiltinInfo(builtins), DeclarationNames(*this), Comments(SM), - CommentCommandTraits(BumpAlloc, LOpts.CommentOpts), LastSDM(nullptr, 0) { + CommentCommandTraits(BumpAlloc, LOpts.CommentOpts), + CompCategories(this_()), LastSDM(nullptr, 0) { TUDecl = TranslationUnitDecl::Create(*this); } @@ -812,13 +814,13 @@ ASTContext::~ASTContext() { const ASTRecordLayout*>::iterator I = ObjCLayouts.begin(), E = ObjCLayouts.end(); I != E; ) // Increment in loop to prevent using deallocated memory. - if (ASTRecordLayout *R = const_cast<ASTRecordLayout*>((I++)->second)) + if (auto *R = const_cast<ASTRecordLayout *>((I++)->second)) R->Destroy(*this); for (llvm::DenseMap<const RecordDecl*, const ASTRecordLayout*>::iterator I = ASTRecordLayouts.begin(), E = ASTRecordLayouts.end(); I != E; ) { // Increment in loop to prevent using deallocated memory. - if (ASTRecordLayout *R = const_cast<ASTRecordLayout*>((I++)->second)) + if (auto *R = const_cast<ASTRecordLayout *>((I++)->second)) R->Destroy(*this); } @@ -966,7 +968,7 @@ void ASTContext::PerModuleInitializers::resolve(ASTContext &Ctx) { void ASTContext::addModuleInitializer(Module *M, Decl *D) { // One special case: if we add a module initializer that imports another // module, and that module's only initializer is an ImportDecl, simplify. - if (auto *ID = dyn_cast<ImportDecl>(D)) { + if (const auto *ID = dyn_cast<ImportDecl>(D)) { auto It = ModuleInitializers.find(ID->getImportedModule()); // Maybe the ImportDecl does nothing at all. (Common case.) @@ -997,7 +999,7 @@ void ASTContext::addLazyModuleInitializers(Module *M, ArrayRef<uint32_t> IDs) { IDs.begin(), IDs.end()); } -ArrayRef<Decl*> ASTContext::getModuleInitializers(Module *M) { +ArrayRef<Decl *> ASTContext::getModuleInitializers(Module *M) { auto It = ModuleInitializers.find(M); if (It == ModuleInitializers.end()) return None; @@ -1079,7 +1081,7 @@ TypedefDecl *ASTContext::getUInt128Decl() const { } void ASTContext::InitBuiltinType(CanQualType &R, BuiltinType::Kind K) { - BuiltinType *Ty = new (*this, TypeAlignment) BuiltinType(K); + auto *Ty = new (*this, TypeAlignment) BuiltinType(K); R = CanQualType::CreateUnsafe(QualType(Ty, 0)); Types.push_back(Ty); } @@ -1132,6 +1134,32 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target, // C11 extension ISO/IEC TS 18661-3 InitBuiltinType(Float16Ty, BuiltinType::Float16); + // ISO/IEC JTC1 SC22 WG14 N1169 Extension + InitBuiltinType(ShortAccumTy, BuiltinType::ShortAccum); + InitBuiltinType(AccumTy, BuiltinType::Accum); + InitBuiltinType(LongAccumTy, BuiltinType::LongAccum); + InitBuiltinType(UnsignedShortAccumTy, BuiltinType::UShortAccum); + InitBuiltinType(UnsignedAccumTy, BuiltinType::UAccum); + InitBuiltinType(UnsignedLongAccumTy, BuiltinType::ULongAccum); + InitBuiltinType(ShortFractTy, BuiltinType::ShortFract); + InitBuiltinType(FractTy, BuiltinType::Fract); + InitBuiltinType(LongFractTy, BuiltinType::LongFract); + InitBuiltinType(UnsignedShortFractTy, BuiltinType::UShortFract); + InitBuiltinType(UnsignedFractTy, BuiltinType::UFract); + InitBuiltinType(UnsignedLongFractTy, BuiltinType::ULongFract); + InitBuiltinType(SatShortAccumTy, BuiltinType::SatShortAccum); + InitBuiltinType(SatAccumTy, BuiltinType::SatAccum); + InitBuiltinType(SatLongAccumTy, BuiltinType::SatLongAccum); + InitBuiltinType(SatUnsignedShortAccumTy, BuiltinType::SatUShortAccum); + InitBuiltinType(SatUnsignedAccumTy, BuiltinType::SatUAccum); + InitBuiltinType(SatUnsignedLongAccumTy, BuiltinType::SatULongAccum); + InitBuiltinType(SatShortFractTy, BuiltinType::SatShortFract); + InitBuiltinType(SatFractTy, BuiltinType::SatFract); + InitBuiltinType(SatLongFractTy, BuiltinType::SatLongFract); + InitBuiltinType(SatUnsignedShortFractTy, BuiltinType::SatUShortFract); + InitBuiltinType(SatUnsignedFractTy, BuiltinType::SatUFract); + InitBuiltinType(SatUnsignedLongFractTy, BuiltinType::SatULongFract); + // GNU extension, 128-bit integers. InitBuiltinType(Int128Ty, BuiltinType::Int128); InitBuiltinType(UnsignedInt128Ty, BuiltinType::UInt128); @@ -1150,6 +1178,9 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target, WIntTy = getFromTargetType(Target.getWIntType()); + // C++20 (proposed) + InitBuiltinType(Char8Ty, BuiltinType::Char8); + if (LangOpts.CPlusPlus) // C++0x 3.9.1p5, extension for C++ InitBuiltinType(Char16Ty, BuiltinType::Char16); else // C99 @@ -1254,7 +1285,7 @@ AttrVec& ASTContext::getDeclAttrs(const Decl *D) { return *Result; } -/// \brief Erase the attributes corresponding to the given declaration. +/// Erase the attributes corresponding to the given declaration. void ASTContext::eraseDeclAttrs(const Decl *D) { llvm::DenseMap<const Decl*, AttrVec*>::iterator Pos = DeclAttrs.find(D); if (Pos != DeclAttrs.end()) { @@ -1276,7 +1307,7 @@ ASTContext::getTemplateOrSpecializationInfo(const VarDecl *Var) { llvm::DenseMap<const VarDecl *, TemplateOrSpecializationInfo>::iterator Pos = TemplateOrInstantiation.find(Var); if (Pos == TemplateOrInstantiation.end()) - return TemplateOrSpecializationInfo(); + return {}; return Pos->second; } @@ -1412,13 +1443,13 @@ void ASTContext::getOverriddenMethods( SmallVectorImpl<const NamedDecl *> &Overridden) const { assert(D); - if (const CXXMethodDecl *CXXMethod = dyn_cast<CXXMethodDecl>(D)) { + if (const auto *CXXMethod = dyn_cast<CXXMethodDecl>(D)) { Overridden.append(overridden_methods_begin(CXXMethod), overridden_methods_end(CXXMethod)); return; } - const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(D); + const auto *Method = dyn_cast<ObjCMethodDecl>(D); if (!Method) return; @@ -1447,7 +1478,7 @@ void ASTContext::addedLocalImportDecl(ImportDecl *Import) { /// getFloatTypeSemantics - Return the APFloat 'semantics' for the specified /// scalar floating point type. const llvm::fltSemantics &ASTContext::getFloatTypeSemantics(QualType T) const { - const BuiltinType *BT = T->getAs<BuiltinType>(); + const auto *BT = T->getAs<BuiltinType>(); assert(BT && "Not a floating point type!"); switch (BT->getKind()) { default: llvm_unreachable("Not a floating point type!"); @@ -1490,9 +1521,9 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool ForAlignof) const { // else about the declaration and its type. if (UseAlignAttrOnly) { // do nothing - } else if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) { + } else if (const auto *VD = dyn_cast<ValueDecl>(D)) { QualType T = VD->getType(); - if (const ReferenceType *RT = T->getAs<ReferenceType>()) { + if (const auto *RT = T->getAs<ReferenceType>()) { if (ForAlignof) T = RT->getPointeeType(); else @@ -1517,7 +1548,7 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool ForAlignof) const { Align = std::max(Align, getPreferredTypeAlign(T.getTypePtr())); if (BaseT.getQualifiers().hasUnaligned()) Align = Target->getCharWidth(); - if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { + if (const auto *VD = dyn_cast<VarDecl>(D)) { if (VD->hasGlobalStorage() && !ForAlignof) Align = std::max(Align, getTargetInfo().getMinGlobalAlign()); } @@ -1528,7 +1559,7 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool ForAlignof) 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)) { + if (const auto *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()) { @@ -1567,7 +1598,7 @@ ASTContext::getTypeInfoDataSizeInChars(QualType T) const { // of a base-class subobject. We decide whether that's possible // during class layout, so here we can just trust the layout results. if (getLangOpts().CPlusPlus) { - if (const RecordType *RT = T->getAs<RecordType>()) { + if (const auto *RT = T->getAs<RecordType>()) { const ASTRecordLayout &layout = getASTRecordLayout(RT->getDecl()); sizeAndAlign.first = layout.getDataSize(); } @@ -1598,7 +1629,7 @@ static getConstantArrayInfoInChars(const ASTContext &Context, std::pair<CharUnits, CharUnits> ASTContext::getTypeInfoInChars(const Type *T) const { - if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(T)) + if (const auto *CAT = dyn_cast<ConstantArrayType>(T)) return getConstantArrayInfoInChars(*this, CAT); TypeInfo Info = getTypeInfo(T); return std::make_pair(toCharUnitsFromBits(Info.Width), @@ -1620,7 +1651,7 @@ bool ASTContext::isAlignmentRequired(QualType T) const { unsigned ASTContext::getTypeAlignIfKnown(QualType T) const { // An alignment on a typedef overrides anything else. - if (auto *TT = T->getAs<TypedefType>()) + if (const auto *TT = T->getAs<TypedefType>()) if (unsigned Align = TT->getDecl()->getMaxAlignment()) return Align; @@ -1631,12 +1662,12 @@ unsigned ASTContext::getTypeAlignIfKnown(QualType T) const { // If we had an array type, its element type might be a typedef // type with an alignment attribute. - if (auto *TT = T->getAs<TypedefType>()) + if (const auto *TT = T->getAs<TypedefType>()) if (unsigned Align = TT->getDecl()->getMaxAlignment()) return Align; // Otherwise, see if the declaration of the type had an attribute. - if (auto *TT = T->getAs<TagType>()) + if (const auto *TT = T->getAs<TagType>()) return TT->getDecl()->getMaxAlignment(); return 0; @@ -1690,7 +1721,7 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { break; case Type::ConstantArray: { - const ConstantArrayType *CAT = cast<ConstantArrayType>(T); + const auto *CAT = cast<ConstantArrayType>(T); TypeInfo EltInfo = getTypeInfo(CAT->getElementType()); uint64_t Size = CAT->getSize().getZExtValue(); @@ -1705,7 +1736,7 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { } case Type::ExtVector: case Type::Vector: { - const VectorType *VT = cast<VectorType>(T); + const auto *VT = cast<VectorType>(T); TypeInfo EltInfo = getTypeInfo(VT->getElementType()); Width = EltInfo.Width * VT->getNumElements(); Align = Width; @@ -1738,6 +1769,7 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { case BuiltinType::Char_U: case BuiltinType::UChar: case BuiltinType::SChar: + case BuiltinType::Char8: Width = Target->getCharWidth(); Align = Target->getCharAlign(); break; @@ -1779,6 +1811,48 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { Width = 128; Align = 128; // int128_t is 128-bit aligned on all targets. break; + case BuiltinType::ShortAccum: + case BuiltinType::UShortAccum: + case BuiltinType::SatShortAccum: + case BuiltinType::SatUShortAccum: + Width = Target->getShortAccumWidth(); + Align = Target->getShortAccumAlign(); + break; + case BuiltinType::Accum: + case BuiltinType::UAccum: + case BuiltinType::SatAccum: + case BuiltinType::SatUAccum: + Width = Target->getAccumWidth(); + Align = Target->getAccumAlign(); + break; + case BuiltinType::LongAccum: + case BuiltinType::ULongAccum: + case BuiltinType::SatLongAccum: + case BuiltinType::SatULongAccum: + Width = Target->getLongAccumWidth(); + Align = Target->getLongAccumAlign(); + break; + case BuiltinType::ShortFract: + case BuiltinType::UShortFract: + case BuiltinType::SatShortFract: + case BuiltinType::SatUShortFract: + Width = Target->getShortFractWidth(); + Align = Target->getShortFractAlign(); + break; + case BuiltinType::Fract: + case BuiltinType::UFract: + case BuiltinType::SatFract: + case BuiltinType::SatUFract: + Width = Target->getFractWidth(); + Align = Target->getFractAlign(); + break; + case BuiltinType::LongFract: + case BuiltinType::ULongFract: + case BuiltinType::SatLongFract: + case BuiltinType::SatULongFract: + Width = Target->getLongFractWidth(); + Align = Target->getLongFractAlign(); + break; case BuiltinType::Float16: case BuiltinType::Half: Width = Target->getHalfWidth(); @@ -1848,7 +1922,7 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { Align = Target->getPointerAlign(AS); break; case Type::MemberPointer: { - const MemberPointerType *MPT = cast<MemberPointerType>(T); + const auto *MPT = cast<MemberPointerType>(T); CXXABI::MemberPointerInfo MPI = ABI->getMemberPointerInfo(MPT); Width = MPI.Width; Align = MPI.Align; @@ -1868,7 +1942,7 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { case Type::Decayed: return getTypeInfo(cast<AdjustedType>(T)->getAdjustedType().getTypePtr()); case Type::ObjCInterface: { - const ObjCInterfaceType *ObjCI = cast<ObjCInterfaceType>(T); + const auto *ObjCI = cast<ObjCInterfaceType>(T); const ASTRecordLayout &Layout = getASTObjCInterfaceLayout(ObjCI->getDecl()); Width = toBits(Layout.getSize()); Align = toBits(Layout.getAlignment()); @@ -1876,7 +1950,7 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { } case Type::Record: case Type::Enum: { - const TagType *TT = cast<TagType>(T); + const auto *TT = cast<TagType>(T); if (TT->getDecl()->isInvalidDecl()) { Width = 8; @@ -1884,7 +1958,7 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { break; } - if (const EnumType *ET = dyn_cast<EnumType>(TT)) { + if (const auto *ET = dyn_cast<EnumType>(TT)) { const EnumDecl *ED = ET->getDecl(); TypeInfo Info = getTypeInfo(ED->getIntegerType()->getUnqualifiedDesugaredType()); @@ -1895,7 +1969,7 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { return Info; } - const RecordType *RT = cast<RecordType>(TT); + const auto *RT = cast<RecordType>(TT); const RecordDecl *RD = RT->getDecl(); const ASTRecordLayout &Layout = getASTRecordLayout(RD); Width = toBits(Layout.getSize()); @@ -1910,7 +1984,7 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { case Type::Auto: case Type::DeducedTemplateSpecialization: { - const DeducedType *A = cast<DeducedType>(T); + const auto *A = cast<DeducedType>(T); assert(!A->getDeducedType().isNull() && "cannot request the size of an undeduced or dependent auto type"); return getTypeInfo(A->getDeducedType().getTypePtr()); @@ -1952,10 +2026,16 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { Width = Info.Width; Align = Info.Align; - // If the size of the type doesn't exceed the platform's max - // atomic promotion width, make the size and alignment more - // favorable to atomic operations: - if (Width != 0 && Width <= Target->getMaxAtomicPromoteWidth()) { + if (!Width) { + // An otherwise zero-sized type should still generate an + // atomic operation. + Width = Target->getCharWidth(); + assert(Align); + } else if (Width <= Target->getMaxAtomicPromoteWidth()) { + // If the size of the type doesn't exceed the platform's max + // atomic promotion width, make the size and alignment more + // favorable to atomic operations: + // Round the size up to a power of 2. if (!llvm::isPowerOf2_64(Width)) Width = llvm::NextPowerOf2(Width); @@ -2033,9 +2113,9 @@ unsigned ASTContext::getPreferredTypeAlign(const Type *T) const { return ABIAlign; // Double and long long should be naturally aligned if possible. - if (const ComplexType *CT = T->getAs<ComplexType>()) + if (const auto *CT = T->getAs<ComplexType>()) T = CT->getElementType().getTypePtr(); - if (const EnumType *ET = T->getAs<EnumType>()) + if (const auto *ET = T->getAs<EnumType>()) T = ET->getDecl()->getIntegerType().getTypePtr(); if (T->isSpecificBuiltinType(BuiltinType::Double) || T->isSpecificBuiltinType(BuiltinType::LongLong) || @@ -2091,7 +2171,7 @@ void ASTContext::DeepCollectObjCIvars(const ObjCInterfaceDecl *OI, for (const auto *I : OI->ivars()) Ivars.push_back(I); } else { - ObjCInterfaceDecl *IDecl = const_cast<ObjCInterfaceDecl *>(OI); + auto *IDecl = const_cast<ObjCInterfaceDecl *>(OI); for (const ObjCIvarDecl *Iv = IDecl->all_declared_ivar_begin(); Iv; Iv= Iv->getNextIvar()) Ivars.push_back(Iv); @@ -2102,7 +2182,7 @@ void ASTContext::DeepCollectObjCIvars(const ObjCInterfaceDecl *OI, /// those inherited by it. void ASTContext::CollectInheritedProtocols(const Decl *CDecl, llvm::SmallPtrSet<ObjCProtocolDecl*, 8> &Protocols) { - if (const ObjCInterfaceDecl *OI = dyn_cast<ObjCInterfaceDecl>(CDecl)) { + if (const auto *OI = dyn_cast<ObjCInterfaceDecl>(CDecl)) { // We can use protocol_iterator here instead of // all_referenced_protocol_iterator since we are walking all categories. for (auto *Proto : OI->all_referenced_protocols()) { @@ -2118,11 +2198,11 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl, CollectInheritedProtocols(SD, Protocols); SD = SD->getSuperClass(); } - } else if (const ObjCCategoryDecl *OC = dyn_cast<ObjCCategoryDecl>(CDecl)) { + } else if (const auto *OC = dyn_cast<ObjCCategoryDecl>(CDecl)) { for (auto *Proto : OC->protocols()) { CollectInheritedProtocols(Proto, Protocols); } - } else if (const ObjCProtocolDecl *OP = dyn_cast<ObjCProtocolDecl>(CDecl)) { + } else if (const auto *OP = dyn_cast<ObjCProtocolDecl>(CDecl)) { // Insert the protocol. if (!Protocols.insert( const_cast<ObjCProtocolDecl *>(OP->getCanonicalDecl())).second) @@ -2145,7 +2225,7 @@ static bool unionHasUniqueObjectRepresentations(const ASTContext &Context, if (FieldSize != UnionSize) return false; } - return true; + return !RD->field_empty(); } static bool isStructEmpty(QualType Ty) { @@ -2184,7 +2264,7 @@ structHasUniqueObjectRepresentations(const ASTContext &Context, } } - std::sort( + llvm::sort( Bases.begin(), Bases.end(), [&](const std::pair<QualType, int64_t> &L, const std::pair<QualType, int64_t> &R) { return Layout.getBaseClassOffset(L.first->getAsCXXRecordDecl()) < @@ -2264,7 +2344,7 @@ bool ASTContext::hasUniqueObjectRepresentations(QualType Ty) const { return true; if (Ty->isMemberPointerType()) { - const MemberPointerType *MPT = Ty->getAs<MemberPointerType>(); + const auto *MPT = Ty->getAs<MemberPointerType>(); return !ABI->getMemberPointerInfo(MPT).HasPadding; } @@ -2330,7 +2410,7 @@ bool ASTContext::isSentinelNullExpr(const Expr *E) { return false; } -/// \brief Get the implementation of ObjCInterfaceDecl, or nullptr if none +/// Get the implementation of ObjCInterfaceDecl, or nullptr if none /// exists. ObjCImplementationDecl *ASTContext::getObjCImplementation(ObjCInterfaceDecl *D) { llvm::DenseMap<ObjCContainerDecl*, ObjCImplDecl*>::iterator @@ -2340,7 +2420,7 @@ ObjCImplementationDecl *ASTContext::getObjCImplementation(ObjCInterfaceDecl *D) return nullptr; } -/// \brief Get the implementation of ObjCCategoryDecl, or nullptr if none +/// Get the implementation of ObjCCategoryDecl, or nullptr if none /// exists. ObjCCategoryImplDecl *ASTContext::getObjCImplementation(ObjCCategoryDecl *D) { llvm::DenseMap<ObjCContainerDecl*, ObjCImplDecl*>::iterator @@ -2350,14 +2430,14 @@ ObjCCategoryImplDecl *ASTContext::getObjCImplementation(ObjCCategoryDecl *D) { return nullptr; } -/// \brief Set the implementation of ObjCInterfaceDecl. +/// Set the implementation of ObjCInterfaceDecl. void ASTContext::setObjCImplementation(ObjCInterfaceDecl *IFaceD, ObjCImplementationDecl *ImplD) { assert(IFaceD && ImplD && "Passed null params"); ObjCImpls[IFaceD] = ImplD; } -/// \brief Set the implementation of ObjCCategoryDecl. +/// Set the implementation of ObjCCategoryDecl. void ASTContext::setObjCImplementation(ObjCCategoryDecl *CatD, ObjCCategoryImplDecl *ImplD) { assert(CatD && ImplD && "Passed null params"); @@ -2377,20 +2457,17 @@ void ASTContext::setObjCMethodRedeclaration(const ObjCMethodDecl *MD, const ObjCInterfaceDecl *ASTContext::getObjContainingInterface( const NamedDecl *ND) const { - if (const ObjCInterfaceDecl *ID = - dyn_cast<ObjCInterfaceDecl>(ND->getDeclContext())) + if (const auto *ID = dyn_cast<ObjCInterfaceDecl>(ND->getDeclContext())) return ID; - if (const ObjCCategoryDecl *CD = - dyn_cast<ObjCCategoryDecl>(ND->getDeclContext())) + if (const auto *CD = dyn_cast<ObjCCategoryDecl>(ND->getDeclContext())) return CD->getClassInterface(); - if (const ObjCImplDecl *IMD = - dyn_cast<ObjCImplDecl>(ND->getDeclContext())) + if (const auto *IMD = dyn_cast<ObjCImplDecl>(ND->getDeclContext())) return IMD->getClassInterface(); return nullptr; } -/// \brief Get the copy initialization expression of VarDecl, or nullptr if +/// Get the copy initialization expression of VarDecl, or nullptr if /// none exists. Expr *ASTContext::getBlockVarCopyInits(const VarDecl*VD) { assert(VD && "Passed null params"); @@ -2398,10 +2475,10 @@ Expr *ASTContext::getBlockVarCopyInits(const VarDecl*VD) { "getBlockVarCopyInits - not __block var"); llvm::DenseMap<const VarDecl*, Expr*>::iterator I = BlockVarCopyInits.find(VD); - return (I != BlockVarCopyInits.end()) ? cast<Expr>(I->second) : nullptr; + return (I != BlockVarCopyInits.end()) ? I->second : nullptr; } -/// \brief Set the copy inialization expression of a block var decl. +/// Set the copy inialization expression of a block var decl. void ASTContext::setBlockVarCopyInits(VarDecl*VD, Expr* Init) { assert(VD && Init && "Passed null params"); assert(VD->hasAttr<BlocksAttr>() && @@ -2417,7 +2494,7 @@ TypeSourceInfo *ASTContext::CreateTypeSourceInfo(QualType T, assert(DataSize == TypeLoc::getFullDataSizeForType(T) && "incorrect data size provided to CreateTypeSourceInfo!"); - TypeSourceInfo *TInfo = + auto *TInfo = (TypeSourceInfo*)BumpAlloc.Allocate(sizeof(TypeSourceInfo) + DataSize, 8); new (TInfo) TypeSourceInfo(T); return TInfo; @@ -2470,7 +2547,7 @@ ASTContext::getExtQualType(const Type *baseType, Qualifiers quals) const { (void) ExtQualNodes.FindNodeOrInsertPos(ID, insertPos); } - ExtQuals *eq = new (*this, TypeAlignment) ExtQuals(baseType, canon, quals); + auto *eq = new (*this, TypeAlignment) ExtQuals(baseType, canon, quals); ExtQualNodes.InsertNode(eq, insertPos); return QualType(eq, fastQuals); } @@ -2522,7 +2599,7 @@ QualType ASTContext::getObjCGCQualType(QualType T, if (CanT.getObjCGCAttr() == GCAttr) return T; - if (const PointerType *ptr = T->getAs<PointerType>()) { + if (const auto *ptr = T->getAs<PointerType>()) { QualType Pointee = ptr->getPointeeType(); if (Pointee->isAnyPointerType()) { QualType ResultType = getObjCGCQualType(Pointee, GCAttr); @@ -2550,10 +2627,10 @@ const FunctionType *ASTContext::adjustFunctionType(const FunctionType *T, return T; QualType Result; - if (const FunctionNoProtoType *FNPT = dyn_cast<FunctionNoProtoType>(T)) { + if (const auto *FNPT = dyn_cast<FunctionNoProtoType>(T)) { Result = getFunctionNoProtoType(FNPT->getReturnType(), Info); } else { - const FunctionProtoType *FPT = cast<FunctionProtoType>(T); + const auto *FPT = cast<FunctionProtoType>(T); FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); EPI.ExtInfo = Info; Result = getFunctionType(FPT->getReturnType(), FPT->getParamTypes(), EPI); @@ -2566,7 +2643,7 @@ void ASTContext::adjustDeducedFunctionResultType(FunctionDecl *FD, QualType ResultType) { FD = FD->getMostRecentDecl(); while (true) { - const FunctionProtoType *FPT = FD->getType()->castAs<FunctionProtoType>(); + const auto *FPT = FD->getType()->castAs<FunctionProtoType>(); FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); FD->setType(getFunctionType(ResultType, FPT->getParamTypes(), EPI)); if (FunctionDecl *Next = FD->getPreviousDecl()) @@ -2582,26 +2659,24 @@ void ASTContext::adjustDeducedFunctionResultType(FunctionDecl *FD, /// specified exception specification. Type sugar that can be present on a /// declaration of a function with an exception specification is permitted /// and preserved. Other type sugar (for instance, typedefs) is not. -static QualType getFunctionTypeWithExceptionSpec( - ASTContext &Context, QualType Orig, - const FunctionProtoType::ExceptionSpecInfo &ESI) { +QualType ASTContext::getFunctionTypeWithExceptionSpec( + QualType Orig, const FunctionProtoType::ExceptionSpecInfo &ESI) { // Might have some parens. - if (auto *PT = dyn_cast<ParenType>(Orig)) - return Context.getParenType( - getFunctionTypeWithExceptionSpec(Context, PT->getInnerType(), ESI)); + if (const auto *PT = dyn_cast<ParenType>(Orig)) + return getParenType( + getFunctionTypeWithExceptionSpec(PT->getInnerType(), ESI)); // Might have a calling-convention attribute. - if (auto *AT = dyn_cast<AttributedType>(Orig)) - return Context.getAttributedType( + if (const auto *AT = dyn_cast<AttributedType>(Orig)) + return getAttributedType( AT->getAttrKind(), - getFunctionTypeWithExceptionSpec(Context, AT->getModifiedType(), ESI), - getFunctionTypeWithExceptionSpec(Context, AT->getEquivalentType(), - ESI)); + getFunctionTypeWithExceptionSpec(AT->getModifiedType(), ESI), + getFunctionTypeWithExceptionSpec(AT->getEquivalentType(), ESI)); // Anything else must be a function type. Rebuild it with the new exception // specification. - const FunctionProtoType *Proto = cast<FunctionProtoType>(Orig); - return Context.getFunctionType( + const auto *Proto = cast<FunctionProtoType>(Orig); + return getFunctionType( Proto->getReturnType(), Proto->getParamTypes(), Proto->getExtProtoInfo().withExceptionSpec(ESI)); } @@ -2610,8 +2685,8 @@ bool ASTContext::hasSameFunctionTypeIgnoringExceptionSpec(QualType T, QualType U) { return hasSameType(T, U) || (getLangOpts().CPlusPlus17 && - hasSameType(getFunctionTypeWithExceptionSpec(*this, T, EST_None), - getFunctionTypeWithExceptionSpec(*this, U, EST_None))); + hasSameType(getFunctionTypeWithExceptionSpec(T, EST_None), + getFunctionTypeWithExceptionSpec(U, EST_None))); } void ASTContext::adjustExceptionSpec( @@ -2619,7 +2694,7 @@ void ASTContext::adjustExceptionSpec( bool AsWritten) { // Update the type. QualType Updated = - getFunctionTypeWithExceptionSpec(*this, FD->getType(), ESI); + getFunctionTypeWithExceptionSpec(FD->getType(), ESI); FD->setType(Updated); if (!AsWritten) @@ -2630,7 +2705,7 @@ void ASTContext::adjustExceptionSpec( // If the type and the type-as-written differ, we may need to update // the type-as-written too. if (TSInfo->getType() != FD->getType()) - Updated = getFunctionTypeWithExceptionSpec(*this, TSInfo->getType(), ESI); + Updated = getFunctionTypeWithExceptionSpec(TSInfo->getType(), ESI); // FIXME: When we get proper type location information for exceptions, // we'll also have to rebuild the TypeSourceInfo. For now, we just patch @@ -2664,7 +2739,7 @@ QualType ASTContext::getComplexType(QualType T) const { ComplexType *NewIP = ComplexTypes.FindNodeOrInsertPos(ID, InsertPos); assert(!NewIP && "Shouldn't be in the map!"); (void)NewIP; } - ComplexType *New = new (*this, TypeAlignment) ComplexType(T, Canonical); + auto *New = new (*this, TypeAlignment) ComplexType(T, Canonical); Types.push_back(New); ComplexTypes.InsertNode(New, InsertPos); return QualType(New, 0); @@ -2692,7 +2767,7 @@ QualType ASTContext::getPointerType(QualType T) const { PointerType *NewIP = PointerTypes.FindNodeOrInsertPos(ID, InsertPos); assert(!NewIP && "Shouldn't be in the map!"); (void)NewIP; } - PointerType *New = new (*this, TypeAlignment) PointerType(T, Canonical); + auto *New = new (*this, TypeAlignment) PointerType(T, Canonical); Types.push_back(New); PointerTypes.InsertNode(New, InsertPos); return QualType(New, 0); @@ -2783,8 +2858,7 @@ QualType ASTContext::getBlockPointerType(QualType T) const { BlockPointerTypes.FindNodeOrInsertPos(ID, InsertPos); assert(!NewIP && "Shouldn't be in the map!"); (void)NewIP; } - BlockPointerType *New - = new (*this, TypeAlignment) BlockPointerType(T, Canonical); + auto *New = new (*this, TypeAlignment) BlockPointerType(T, Canonical); Types.push_back(New); BlockPointerTypes.InsertNode(New, InsertPos); return QualType(New, 0); @@ -2807,7 +2881,7 @@ ASTContext::getLValueReferenceType(QualType T, bool SpelledAsLValue) const { LValueReferenceTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(RT, 0); - const ReferenceType *InnerRef = T->getAs<ReferenceType>(); + const auto *InnerRef = T->getAs<ReferenceType>(); // If the referencee type isn't canonical, this won't be a canonical type // either, so fill in the canonical type field. @@ -2822,9 +2896,8 @@ ASTContext::getLValueReferenceType(QualType T, bool SpelledAsLValue) const { assert(!NewIP && "Shouldn't be in the map!"); (void)NewIP; } - LValueReferenceType *New - = new (*this, TypeAlignment) LValueReferenceType(T, Canonical, - SpelledAsLValue); + auto *New = new (*this, TypeAlignment) LValueReferenceType(T, Canonical, + SpelledAsLValue); Types.push_back(New); LValueReferenceTypes.InsertNode(New, InsertPos); @@ -2844,7 +2917,7 @@ QualType ASTContext::getRValueReferenceType(QualType T) const { RValueReferenceTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(RT, 0); - const ReferenceType *InnerRef = T->getAs<ReferenceType>(); + const auto *InnerRef = T->getAs<ReferenceType>(); // If the referencee type isn't canonical, this won't be a canonical type // either, so fill in the canonical type field. @@ -2859,8 +2932,7 @@ QualType ASTContext::getRValueReferenceType(QualType T) const { assert(!NewIP && "Shouldn't be in the map!"); (void)NewIP; } - RValueReferenceType *New - = new (*this, TypeAlignment) RValueReferenceType(T, Canonical); + auto *New = new (*this, TypeAlignment) RValueReferenceType(T, Canonical); Types.push_back(New); RValueReferenceTypes.InsertNode(New, InsertPos); return QualType(New, 0); @@ -2890,8 +2962,7 @@ QualType ASTContext::getMemberPointerType(QualType T, const Type *Cls) const { MemberPointerTypes.FindNodeOrInsertPos(ID, InsertPos); assert(!NewIP && "Shouldn't be in the map!"); (void)NewIP; } - MemberPointerType *New - = new (*this, TypeAlignment) MemberPointerType(T, Cls, Canonical); + auto *New = new (*this, TypeAlignment) MemberPointerType(T, Cls, Canonical); Types.push_back(New); MemberPointerTypes.InsertNode(New, InsertPos); return QualType(New, 0); @@ -2935,7 +3006,7 @@ QualType ASTContext::getConstantArrayType(QualType EltTy, assert(!NewIP && "Shouldn't be in the map!"); (void)NewIP; } - ConstantArrayType *New = new(*this,TypeAlignment) + auto *New = new (*this,TypeAlignment) ConstantArrayType(EltTy, Canon, ArySize, ASM, IndexTypeQuals); ConstantArrayTypes.InsertNode(New, InsertPos); Types.push_back(New); @@ -2964,6 +3035,7 @@ QualType ASTContext::getVariableArrayDecayedType(QualType type) const { case Type::Builtin: case Type::Complex: case Type::Vector: + case Type::DependentVector: case Type::ExtVector: case Type::DependentSizedExtVector: case Type::DependentAddressSpace: @@ -3007,7 +3079,7 @@ QualType ASTContext::getVariableArrayDecayedType(QualType type) const { break; case Type::LValueReference: { - const LValueReferenceType *lv = cast<LValueReferenceType>(ty); + const auto *lv = cast<LValueReferenceType>(ty); result = getLValueReferenceType( getVariableArrayDecayedType(lv->getPointeeType()), lv->isSpelledAsLValue()); @@ -3015,20 +3087,20 @@ QualType ASTContext::getVariableArrayDecayedType(QualType type) const { } case Type::RValueReference: { - const RValueReferenceType *lv = cast<RValueReferenceType>(ty); + const auto *lv = cast<RValueReferenceType>(ty); result = getRValueReferenceType( getVariableArrayDecayedType(lv->getPointeeType())); break; } case Type::Atomic: { - const AtomicType *at = cast<AtomicType>(ty); + const auto *at = cast<AtomicType>(ty); result = getAtomicType(getVariableArrayDecayedType(at->getValueType())); break; } case Type::ConstantArray: { - const ConstantArrayType *cat = cast<ConstantArrayType>(ty); + const auto *cat = cast<ConstantArrayType>(ty); result = getConstantArrayType( getVariableArrayDecayedType(cat->getElementType()), cat->getSize(), @@ -3038,7 +3110,7 @@ QualType ASTContext::getVariableArrayDecayedType(QualType type) const { } case Type::DependentSizedArray: { - const DependentSizedArrayType *dat = cast<DependentSizedArrayType>(ty); + const auto *dat = cast<DependentSizedArrayType>(ty); result = getDependentSizedArrayType( getVariableArrayDecayedType(dat->getElementType()), dat->getSizeExpr(), @@ -3050,7 +3122,7 @@ QualType ASTContext::getVariableArrayDecayedType(QualType type) const { // Turn incomplete types into [*] types. case Type::IncompleteArray: { - const IncompleteArrayType *iat = cast<IncompleteArrayType>(ty); + const auto *iat = cast<IncompleteArrayType>(ty); result = getVariableArrayType( getVariableArrayDecayedType(iat->getElementType()), /*size*/ nullptr, @@ -3062,7 +3134,7 @@ QualType ASTContext::getVariableArrayDecayedType(QualType type) const { // Turn VLA types into [*] types. case Type::VariableArray: { - const VariableArrayType *vat = cast<VariableArrayType>(ty); + const auto *vat = cast<VariableArrayType>(ty); result = getVariableArrayType( getVariableArrayDecayedType(vat->getElementType()), /*size*/ nullptr, @@ -3096,7 +3168,7 @@ QualType ASTContext::getVariableArrayType(QualType EltTy, Canon = getQualifiedType(Canon, canonSplit.Quals); } - VariableArrayType *New = new(*this, TypeAlignment) + auto *New = new (*this, TypeAlignment) VariableArrayType(EltTy, Canon, NumElts, ASM, IndexTypeQuals, Brackets); VariableArrayTypes.push_back(New); @@ -3121,7 +3193,7 @@ QualType ASTContext::getDependentSizedArrayType(QualType elementType, // initializer. We do no canonicalization here at all, which is okay // because they can't be used in most locations. if (!numElements) { - DependentSizedArrayType *newType + auto *newType = new (*this, TypeAlignment) DependentSizedArrayType(*this, elementType, QualType(), numElements, ASM, elementTypeQuals, @@ -3167,7 +3239,7 @@ QualType ASTContext::getDependentSizedArrayType(QualType elementType, // Otherwise, we need to build a type which follows the spelling // of the element type. - DependentSizedArrayType *sugaredType + auto *sugaredType = new (*this, TypeAlignment) DependentSizedArrayType(*this, elementType, canon, numElements, ASM, elementTypeQuals, brackets); @@ -3203,7 +3275,7 @@ QualType ASTContext::getIncompleteArrayType(QualType elementType, assert(!existing && "Shouldn't be in the map!"); (void) existing; } - IncompleteArrayType *newType = new (*this, TypeAlignment) + auto *newType = new (*this, TypeAlignment) IncompleteArrayType(elementType, canon, ASM, elementTypeQuals); IncompleteArrayTypes.InsertNode(newType, insertPos); @@ -3235,13 +3307,52 @@ QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts, VectorType *NewIP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos); assert(!NewIP && "Shouldn't be in the map!"); (void)NewIP; } - VectorType *New = new (*this, TypeAlignment) + auto *New = new (*this, TypeAlignment) VectorType(vecType, NumElts, Canonical, VecKind); VectorTypes.InsertNode(New, InsertPos); Types.push_back(New); return QualType(New, 0); } +QualType +ASTContext::getDependentVectorType(QualType VecType, Expr *SizeExpr, + SourceLocation AttrLoc, + VectorType::VectorKind VecKind) const { + llvm::FoldingSetNodeID ID; + DependentVectorType::Profile(ID, *this, getCanonicalType(VecType), SizeExpr, + VecKind); + void *InsertPos = nullptr; + DependentVectorType *Canon = + DependentVectorTypes.FindNodeOrInsertPos(ID, InsertPos); + DependentVectorType *New; + + if (Canon) { + New = new (*this, TypeAlignment) DependentVectorType( + *this, VecType, QualType(Canon, 0), SizeExpr, AttrLoc, VecKind); + } else { + QualType CanonVecTy = getCanonicalType(VecType); + if (CanonVecTy == VecType) { + New = new (*this, TypeAlignment) DependentVectorType( + *this, VecType, QualType(), SizeExpr, AttrLoc, VecKind); + + DependentVectorType *CanonCheck = + DependentVectorTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(!CanonCheck && + "Dependent-sized vector_size canonical type broken"); + (void)CanonCheck; + DependentVectorTypes.InsertNode(New, InsertPos); + } else { + QualType Canon = getDependentSizedExtVectorType(CanonVecTy, SizeExpr, + SourceLocation()); + New = new (*this, TypeAlignment) DependentVectorType( + *this, VecType, Canon, SizeExpr, AttrLoc, VecKind); + } + } + + Types.push_back(New); + return QualType(New, 0); +} + /// getExtVectorType - Return the unique reference to an extended vector type of /// the specified element type and size. VectorType must be a built-in type. QualType @@ -3266,7 +3377,7 @@ ASTContext::getExtVectorType(QualType vecType, unsigned NumElts) const { VectorType *NewIP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos); assert(!NewIP && "Shouldn't be in the map!"); (void)NewIP; } - ExtVectorType *New = new (*this, TypeAlignment) + auto *New = new (*this, TypeAlignment) ExtVectorType(vecType, NumElts, Canonical); VectorTypes.InsertNode(New, InsertPos); Types.push_back(New); @@ -3342,7 +3453,7 @@ QualType ASTContext::getDependentAddressSpaceType(QualType PointeeType, canonTy->getAddrSpaceExpr() == AddrSpaceExpr) return QualType(canonTy, 0); - DependentAddressSpaceType *sugaredType + auto *sugaredType = new (*this, TypeAlignment) DependentAddressSpaceType(*this, PointeeType, QualType(canonTy, 0), AddrSpaceExpr, AttrLoc); @@ -3350,7 +3461,7 @@ QualType ASTContext::getDependentAddressSpaceType(QualType PointeeType, return QualType(sugaredType, 0); } -/// \brief Determine whether \p T is canonical as the result type of a function. +/// Determine whether \p T is canonical as the result type of a function. static bool isCanonicalResultType(QualType T) { return T.isCanonical() && (T.getObjCLifetime() == Qualifiers::OCL_None || @@ -3382,7 +3493,7 @@ ASTContext::getFunctionNoProtoType(QualType ResultTy, assert(!NewIP && "Shouldn't be in the map!"); (void)NewIP; } - FunctionNoProtoType *New = new (*this, TypeAlignment) + auto *New = new (*this, TypeAlignment) FunctionNoProtoType(ResultTy, Canonical, Info); Types.push_back(New); FunctionNoProtoTypes.InsertNode(New, InsertPos); @@ -3416,6 +3527,11 @@ static bool isCanonicalExceptionSpecification( if (ESI.Type == EST_BasicNoexcept) return true; + // A noexcept(expr) specification is (possibly) canonical if expr is + // value-dependent. + if (ESI.Type == EST_DependentNoexcept) + return true; + // A dynamic exception specification is canonical if it only contains pack // expansions (so we can't tell whether it's non-throwing) and all its // contained types are canonical. @@ -3430,11 +3546,6 @@ static bool isCanonicalExceptionSpecification( return AnyPackExpansions; } - // A noexcept(expr) specification is (possibly) canonical if expr is - // value-dependent. - if (ESI.Type == EST_ComputedNoexcept) - return ESI.NoexceptExpr && ESI.NoexceptExpr->isValueDependent(); - return false; } @@ -3462,7 +3573,7 @@ QualType ASTContext::getFunctionTypeInternal( // noexcept expression, or we're just looking for a canonical type. // Otherwise, we're going to need to create a type // sugar node to hold the concrete expression. - if (OnlyWantCanonical || EPI.ExceptionSpec.Type != EST_ComputedNoexcept || + if (OnlyWantCanonical || !isComputedNoexcept(EPI.ExceptionSpec.Type) || EPI.ExceptionSpec.NoexceptExpr == FPT->getNoexceptExpr()) return Existing; @@ -3509,7 +3620,7 @@ QualType ASTContext::getFunctionTypeInternal( // We don't know yet. It shouldn't matter what we pick here; no-one // should ever look at this. LLVM_FALLTHROUGH; - case EST_None: case EST_MSAny: + case EST_None: case EST_MSAny: case EST_NoexceptFalse: CanonicalEPI.ExceptionSpec.Type = EST_None; break; @@ -3531,24 +3642,12 @@ QualType ASTContext::getFunctionTypeInternal( break; } - case EST_DynamicNone: case EST_BasicNoexcept: + case EST_DynamicNone: case EST_BasicNoexcept: case EST_NoexceptTrue: CanonicalEPI.ExceptionSpec.Type = EST_BasicNoexcept; break; - case EST_ComputedNoexcept: - llvm::APSInt Value(1); - auto *E = CanonicalEPI.ExceptionSpec.NoexceptExpr; - if (!E || !E->isIntegerConstantExpr(Value, *this, nullptr, - /*IsEvaluated*/false)) { - // This noexcept specification is invalid. - // FIXME: Should this be able to happen? - CanonicalEPI.ExceptionSpec.Type = EST_None; - break; - } - - CanonicalEPI.ExceptionSpec.Type = - Value.getBoolValue() ? EST_BasicNoexcept : EST_None; - break; + case EST_DependentNoexcept: + llvm_unreachable("dependent noexcept is already canonical"); } } else { CanonicalEPI.ExceptionSpec = FunctionProtoType::ExceptionSpecInfo(); @@ -3573,18 +3672,10 @@ QualType ASTContext::getFunctionTypeInternal( // Instead of the exception types, there could be a noexcept // expression, or information used to resolve the exception // specification. - size_t Size = sizeof(FunctionProtoType) + - NumArgs * sizeof(QualType); - - if (EPI.ExceptionSpec.Type == EST_Dynamic) { - Size += EPI.ExceptionSpec.Exceptions.size() * sizeof(QualType); - } else if (EPI.ExceptionSpec.Type == EST_ComputedNoexcept) { - Size += sizeof(Expr*); - } else if (EPI.ExceptionSpec.Type == EST_Uninstantiated) { - Size += 2 * sizeof(FunctionDecl*); - } else if (EPI.ExceptionSpec.Type == EST_Unevaluated) { - Size += sizeof(FunctionDecl*); - } + size_t Size = + sizeof(FunctionProtoType) + NumArgs * sizeof(QualType) + + FunctionProtoType::getExceptionSpecSize( + EPI.ExceptionSpec.Type, EPI.ExceptionSpec.Exceptions.size()); // Put the ExtParameterInfos last. If all were equal, it would make // more sense to put these before the exception specification, because @@ -3596,7 +3687,7 @@ QualType ASTContext::getFunctionTypeInternal( Size += NumArgs * sizeof(FunctionProtoType::ExtParameterInfo); } - FunctionProtoType *FTP = (FunctionProtoType*) Allocate(Size, TypeAlignment); + auto *FTP = (FunctionProtoType *) Allocate(Size, TypeAlignment); FunctionProtoType::ExtProtoInfo newEPI = EPI; new (FTP) FunctionProtoType(ResultTy, ArgArray, Canonical, newEPI); Types.push_back(FTP); @@ -3624,12 +3715,18 @@ QualType ASTContext::getPipeType(QualType T, bool ReadOnly) const { assert(!NewIP && "Shouldn't be in the map!"); (void)NewIP; } - PipeType *New = new (*this, TypeAlignment) PipeType(T, Canonical, ReadOnly); + auto *New = new (*this, TypeAlignment) PipeType(T, Canonical, ReadOnly); Types.push_back(New); PipeTypes.InsertNode(New, InsertPos); return QualType(New, 0); } +QualType ASTContext::adjustStringLiteralBaseType(QualType Ty) const { + // OpenCL v1.1 s6.5.3: a string literal is in the constant address space. + return LangOpts.OpenCL ? getAddrSpaceQualType(Ty, LangAS::opencl_constant) + : Ty; +} + QualType ASTContext::getReadPipeType(QualType T) const { return getPipeType(T, true); } @@ -3641,7 +3738,7 @@ QualType ASTContext::getWritePipeType(QualType T) const { #ifndef NDEBUG static bool NeedsInjectedClassNameType(const RecordDecl *D) { if (!isa<CXXRecordDecl>(D)) return false; - const CXXRecordDecl *RD = cast<CXXRecordDecl>(D); + const auto *RD = cast<CXXRecordDecl>(D); if (isa<ClassTemplatePartialSpecializationDecl>(RD)) return true; if (RD->getDescribedClassTemplate() && @@ -3677,21 +3774,20 @@ QualType ASTContext::getTypeDeclTypeSlow(const TypeDecl *Decl) const { assert(Decl && "Passed null for Decl param"); assert(!Decl->TypeForDecl && "TypeForDecl present in slow case"); - if (const TypedefNameDecl *Typedef = dyn_cast<TypedefNameDecl>(Decl)) + if (const auto *Typedef = dyn_cast<TypedefNameDecl>(Decl)) return getTypedefType(Typedef); assert(!isa<TemplateTypeParmDecl>(Decl) && "Template type parameter types are always available."); - if (const RecordDecl *Record = dyn_cast<RecordDecl>(Decl)) { + if (const auto *Record = dyn_cast<RecordDecl>(Decl)) { assert(Record->isFirstDecl() && "struct/union has previous declaration"); assert(!NeedsInjectedClassNameType(Record)); return getRecordType(Record); - } else if (const EnumDecl *Enum = dyn_cast<EnumDecl>(Decl)) { + } else if (const auto *Enum = dyn_cast<EnumDecl>(Decl)) { assert(Enum->isFirstDecl() && "enum has previous declaration"); return getEnumType(Enum); - } else if (const UnresolvedUsingTypenameDecl *Using = - dyn_cast<UnresolvedUsingTypenameDecl>(Decl)) { + } else if (const auto *Using = dyn_cast<UnresolvedUsingTypenameDecl>(Decl)) { Type *newType = new (*this, TypeAlignment) UnresolvedUsingType(Using); Decl->TypeForDecl = newType; Types.push_back(newType); @@ -3710,7 +3806,7 @@ ASTContext::getTypedefType(const TypedefNameDecl *Decl, if (Canonical.isNull()) Canonical = getCanonicalType(Decl->getUnderlyingType()); - TypedefType *newType = new(*this, TypeAlignment) + auto *newType = new (*this, TypeAlignment) TypedefType(Type::Typedef, Decl, Canonical); Decl->TypeForDecl = newType; Types.push_back(newType); @@ -3724,7 +3820,7 @@ QualType ASTContext::getRecordType(const RecordDecl *Decl) const { if (PrevDecl->TypeForDecl) return QualType(Decl->TypeForDecl = PrevDecl->TypeForDecl, 0); - RecordType *newType = new (*this, TypeAlignment) RecordType(Decl); + auto *newType = new (*this, TypeAlignment) RecordType(Decl); Decl->TypeForDecl = newType; Types.push_back(newType); return QualType(newType, 0); @@ -3737,7 +3833,7 @@ QualType ASTContext::getEnumType(const EnumDecl *Decl) const { if (PrevDecl->TypeForDecl) return QualType(Decl->TypeForDecl = PrevDecl->TypeForDecl, 0); - EnumType *newType = new (*this, TypeAlignment) EnumType(Decl); + auto *newType = new (*this, TypeAlignment) EnumType(Decl); Decl->TypeForDecl = newType; Types.push_back(newType); return QualType(newType, 0); @@ -3763,7 +3859,7 @@ QualType ASTContext::getAttributedType(AttributedType::Kind attrKind, return QualType(type, 0); } -/// \brief Retrieve a substitution-result type. +/// Retrieve a substitution-result type. QualType ASTContext::getSubstTemplateTypeParmType(const TemplateTypeParmType *Parm, QualType Replacement) const { @@ -3786,7 +3882,7 @@ ASTContext::getSubstTemplateTypeParmType(const TemplateTypeParmType *Parm, return QualType(SubstParm, 0); } -/// \brief Retrieve a +/// Retrieve a QualType ASTContext::getSubstTemplateTypeParmPackType( const TemplateTypeParmType *Parm, const TemplateArgument &ArgPack) { @@ -3812,7 +3908,7 @@ QualType ASTContext::getSubstTemplateTypeParmPackType( SubstTemplateTypeParmPackTypes.FindNodeOrInsertPos(ID, InsertPos); } - SubstTemplateTypeParmPackType *SubstParm + auto *SubstParm = new (*this, TypeAlignment) SubstTemplateTypeParmPackType(Parm, Canon, ArgPack); Types.push_back(SubstParm); @@ -3820,7 +3916,7 @@ QualType ASTContext::getSubstTemplateTypeParmPackType( return QualType(SubstParm, 0); } -/// \brief Retrieve the template type parameter type for a template +/// Retrieve the template type parameter type for a template /// parameter or parameter pack with the given depth, index, and (optionally) /// name. QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index, @@ -3931,7 +4027,7 @@ ASTContext::getTemplateSpecializationType(TemplateName Template, sizeof(TemplateArgument) * Args.size() + (IsTypeAlias? sizeof(QualType) : 0), TypeAlignment); - TemplateSpecializationType *Spec + auto *Spec = new (Mem) TemplateSpecializationType(Template, Args, CanonType, IsTypeAlias ? Underlying : QualType()); @@ -3983,12 +4079,12 @@ QualType ASTContext::getCanonicalTemplateSpecializationType( return QualType(Spec, 0); } -QualType -ASTContext::getElaboratedType(ElaboratedTypeKeyword Keyword, - NestedNameSpecifier *NNS, - QualType NamedType) const { +QualType ASTContext::getElaboratedType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier *NNS, + QualType NamedType, + TagDecl *OwnedTagDecl) const { llvm::FoldingSetNodeID ID; - ElaboratedType::Profile(ID, Keyword, NNS, NamedType); + ElaboratedType::Profile(ID, Keyword, NNS, NamedType, OwnedTagDecl); void *InsertPos = nullptr; ElaboratedType *T = ElaboratedTypes.FindNodeOrInsertPos(ID, InsertPos); @@ -4003,7 +4099,8 @@ ASTContext::getElaboratedType(ElaboratedTypeKeyword Keyword, (void)CheckT; } - T = new (*this, TypeAlignment) ElaboratedType(Keyword, NNS, NamedType, Canon); + T = new (*this, TypeAlignment) + ElaboratedType(Keyword, NNS, NamedType, Canon, OwnedTagDecl); Types.push_back(T); ElaboratedTypes.InsertNode(T, InsertPos); return QualType(T, 0); @@ -4126,7 +4223,7 @@ ASTContext::getDependentTemplateSpecializationType( TemplateArgument ASTContext::getInjectedTemplateArg(NamedDecl *Param) { TemplateArgument Arg; - if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) { + if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) { QualType ArgType = getTypeDeclType(TTP); if (TTP->isParameterPack()) ArgType = getPackExpansionType(ArgType, None); @@ -4265,7 +4362,7 @@ QualType ASTContext::getObjCObjectType( // type. ArrayRef<QualType> effectiveTypeArgs = typeArgs; if (effectiveTypeArgs.empty()) { - if (auto baseObject = baseType->getAs<ObjCObjectType>()) + if (const auto *baseObject = baseType->getAs<ObjCObjectType>()) effectiveTypeArgs = baseObject->getTypeArgs(); } @@ -4313,7 +4410,7 @@ QualType ASTContext::getObjCObjectType( size += typeArgs.size() * sizeof(QualType); size += protocols.size() * sizeof(ObjCProtocolDecl *); void *mem = Allocate(size, TypeAlignment); - ObjCObjectTypeImpl *T = + auto *T = new (mem) ObjCObjectTypeImpl(canonical, baseType, typeArgs, protocols, isKindOf); @@ -4331,15 +4428,14 @@ ASTContext::applyObjCProtocolQualifiers(QualType type, bool allowOnPointerType) const { hasError = false; - if (const ObjCTypeParamType *objT = - dyn_cast<ObjCTypeParamType>(type.getTypePtr())) { + if (const auto *objT = dyn_cast<ObjCTypeParamType>(type.getTypePtr())) { return getObjCTypeParamType(objT->getDecl(), protocols); } // Apply protocol qualifiers to ObjCObjectPointerType. if (allowOnPointerType) { - if (const ObjCObjectPointerType *objPtr = - dyn_cast<ObjCObjectPointerType>(type.getTypePtr())) { + if (const auto *objPtr = + dyn_cast<ObjCObjectPointerType>(type.getTypePtr())) { const ObjCObjectType *objT = objPtr->getObjectType(); // Merge protocol lists and construct ObjCObjectType. SmallVector<ObjCProtocolDecl*, 8> protocolsVec; @@ -4357,7 +4453,7 @@ ASTContext::applyObjCProtocolQualifiers(QualType type, } // Apply protocol qualifiers to ObjCObjectType. - if (const ObjCObjectType *objT = dyn_cast<ObjCObjectType>(type.getTypePtr())){ + if (const auto *objT = dyn_cast<ObjCObjectType>(type.getTypePtr())){ // FIXME: Check for protocols to which the class type is already // known to conform. @@ -4379,7 +4475,7 @@ ASTContext::applyObjCProtocolQualifiers(QualType type, // id<protocol-list> if (type->isObjCIdType()) { - const ObjCObjectPointerType *objPtr = type->castAs<ObjCObjectPointerType>(); + const auto *objPtr = type->castAs<ObjCObjectPointerType>(); type = getObjCObjectType(ObjCBuiltinIdTy, {}, protocols, objPtr->isKindOfType()); return getObjCObjectPointerType(type); @@ -4387,7 +4483,7 @@ ASTContext::applyObjCProtocolQualifiers(QualType type, // Class<protocol-list> if (type->isObjCClassType()) { - const ObjCObjectPointerType *objPtr = type->castAs<ObjCObjectPointerType>(); + const auto *objPtr = type->castAs<ObjCObjectPointerType>(); type = getObjCObjectType(ObjCBuiltinClassTy, {}, protocols, objPtr->isKindOfType()); return getObjCObjectPointerType(type); @@ -4424,8 +4520,7 @@ ASTContext::getObjCTypeParamType(const ObjCTypeParamDecl *Decl, unsigned size = sizeof(ObjCTypeParamType); size += protocols.size() * sizeof(ObjCProtocolDecl *); void *mem = Allocate(size, TypeAlignment); - ObjCTypeParamType *newType = new (mem) - ObjCTypeParamType(Decl, Canonical, protocols); + auto *newType = new (mem) ObjCTypeParamType(Decl, Canonical, protocols); Types.push_back(newType); ObjCTypeParamTypes.InsertNode(newType, InsertPos); @@ -4440,7 +4535,7 @@ bool ASTContext::ObjCObjectAdoptsQTypeProtocols(QualType QT, if (!QT->isObjCQualifiedIdType()) return false; - if (const ObjCObjectPointerType *OPT = QT->getAs<ObjCObjectPointerType>()) { + if (const auto *OPT = QT->getAs<ObjCObjectPointerType>()) { // If both the right and left sides have qualifiers. for (auto *Proto : OPT->quals()) { if (!IC->ClassImplementsProtocol(Proto, false)) @@ -4458,7 +4553,7 @@ bool ASTContext::QIdProtocolsAdoptObjCObjectProtocols(QualType QT, ObjCInterfaceDecl *IDecl) { if (!QT->isObjCQualifiedIdType()) return false; - const ObjCObjectPointerType *OPT = QT->getAs<ObjCObjectPointerType>(); + const auto *OPT = QT->getAs<ObjCObjectPointerType>(); if (!OPT) return false; if (!IDecl->hasDefinition()) @@ -4467,7 +4562,7 @@ bool ASTContext::QIdProtocolsAdoptObjCObjectProtocols(QualType QT, CollectInheritedProtocols(IDecl, InheritedProtocols); if (InheritedProtocols.empty()) return false; - // Check that if every protocol in list of id<plist> conforms to a protcol + // Check that if every protocol in list of id<plist> conforms to a protocol // of IDecl's, then bridge casting is ok. bool Conforms = false; for (auto *Proto : OPT->quals()) { @@ -4520,7 +4615,7 @@ QualType ASTContext::getObjCObjectPointerType(QualType ObjectT) const { // No match. void *Mem = Allocate(sizeof(ObjCObjectPointerType), TypeAlignment); - ObjCObjectPointerType *QType = + auto *QType = new (Mem) ObjCObjectPointerType(Canonical, ObjectT); Types.push_back(QType); @@ -4546,7 +4641,7 @@ QualType ASTContext::getObjCInterfaceType(const ObjCInterfaceDecl *Decl, Decl = Def; void *Mem = Allocate(sizeof(ObjCInterfaceType), TypeAlignment); - ObjCInterfaceType *T = new (Mem) ObjCInterfaceType(Decl); + auto *T = new (Mem) ObjCInterfaceType(Decl); Decl->TypeForDecl = T; Types.push_back(T); return QualType(T, 0); @@ -4593,12 +4688,12 @@ QualType ASTContext::getTypeOfExprType(Expr *tofExpr) const { /// on canonical types (which are always unique). QualType ASTContext::getTypeOfType(QualType tofType) const { QualType Canonical = getCanonicalType(tofType); - TypeOfType *tot = new (*this, TypeAlignment) TypeOfType(tofType, Canonical); + auto *tot = new (*this, TypeAlignment) TypeOfType(tofType, Canonical); Types.push_back(tot); return QualType(tot, 0); } -/// \brief Unlike many "get<Type>" functions, we don't unique DecltypeType +/// Unlike many "get<Type>" functions, we don't unique DecltypeType /// nodes. This would never be helpful, since each such type has its own /// expression, and would not give a significant memory saving, since there /// is an Expr tree under each such type. @@ -4683,9 +4778,8 @@ QualType ASTContext::getAutoType(QualType DeducedType, AutoTypeKeyword Keyword, if (AutoType *AT = AutoTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(AT, 0); - AutoType *AT = new (*this, TypeAlignment) AutoType(DeducedType, - Keyword, - IsDependent); + auto *AT = new (*this, TypeAlignment) + AutoType(DeducedType, Keyword, IsDependent); Types.push_back(AT); if (InsertPos) AutoTypes.InsertNode(AT, InsertPos); @@ -4706,7 +4800,7 @@ QualType ASTContext::getDeducedTemplateSpecializationType( DeducedTemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(DTST, 0); - DeducedTemplateSpecializationType *DTST = new (*this, TypeAlignment) + auto *DTST = new (*this, TypeAlignment) DeducedTemplateSpecializationType(Template, DeducedType, IsDependent); Types.push_back(DTST); if (InsertPos) @@ -4736,7 +4830,7 @@ QualType ASTContext::getAtomicType(QualType T) const { AtomicType *NewIP = AtomicTypes.FindNodeOrInsertPos(ID, InsertPos); assert(!NewIP && "Shouldn't be in the map!"); (void)NewIP; } - AtomicType *New = new (*this, TypeAlignment) AtomicType(T, Canonical); + auto *New = new (*this, TypeAlignment) AtomicType(T, Canonical); Types.push_back(New); AtomicTypes.InsertNode(New, InsertPos); return QualType(New, 0); @@ -4820,14 +4914,14 @@ QualType ASTContext::getPointerDiffType() const { return getFromTargetType(Target->getPtrDiffType(0)); } -/// \brief Return the unique unsigned counterpart of "ptrdiff_t" +/// Return the unique unsigned counterpart of "ptrdiff_t" /// integer type. The standard (C11 7.21.6.1p7) refers to this type /// in the definition of %tu format specifier. QualType ASTContext::getUnsignedPointerDiffType() const { return getFromTargetType(Target->getUnsignedPtrDiffType(0)); } -/// \brief Return the unique type for "pid_t" defined in +/// Return the unique type for "pid_t" defined in /// <sys/types.h>. We need this to compute the correct type for vfork(). QualType ASTContext::getProcessIDType() const { return getFromTargetType(Target->getProcessIDType()); @@ -4863,8 +4957,8 @@ QualType ASTContext::getUnqualifiedArrayType(QualType type, // the unqualified desugared type and then drops it on the floor. // We then have to strip that sugar back off with // getUnqualifiedDesugaredType(), which is silly. - const ArrayType *AT = - dyn_cast<ArrayType>(splitType.Ty->getUnqualifiedDesugaredType()); + const auto *AT = + dyn_cast<ArrayType>(splitType.Ty->getUnqualifiedDesugaredType()); // If we don't have an array, just use the results in splitType. if (!AT) { @@ -4888,16 +4982,16 @@ QualType ASTContext::getUnqualifiedArrayType(QualType type, // build the type back up. quals.addConsistentQualifiers(splitType.Quals); - if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT)) { + if (const auto *CAT = dyn_cast<ConstantArrayType>(AT)) { return getConstantArrayType(unqualElementType, CAT->getSize(), CAT->getSizeModifier(), 0); } - if (const IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(AT)) { + if (const auto *IAT = dyn_cast<IncompleteArrayType>(AT)) { return getIncompleteArrayType(unqualElementType, IAT->getSizeModifier(), 0); } - if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(AT)) { + if (const auto *VAT = dyn_cast<VariableArrayType>(AT)) { return getVariableArrayType(unqualElementType, VAT->getSizeExpr(), VAT->getSizeModifier(), @@ -4905,31 +4999,66 @@ QualType ASTContext::getUnqualifiedArrayType(QualType type, VAT->getBracketsRange()); } - const DependentSizedArrayType *DSAT = cast<DependentSizedArrayType>(AT); + const auto *DSAT = cast<DependentSizedArrayType>(AT); return getDependentSizedArrayType(unqualElementType, DSAT->getSizeExpr(), DSAT->getSizeModifier(), 0, SourceRange()); } -/// UnwrapSimilarPointerTypes - If T1 and T2 are pointer types that -/// may be similar (C++ 4.4), replaces T1 and T2 with the type that -/// they point to and return true. If T1 and T2 aren't pointer types -/// or pointer-to-member types, or if they are not similar at this -/// level, returns false and leaves T1 and T2 unchanged. Top-level -/// qualifiers on T1 and T2 are ignored. This function will typically -/// be called in a loop that successively "unwraps" pointer and -/// pointer-to-member types to compare them at each level. -bool ASTContext::UnwrapSimilarPointerTypes(QualType &T1, QualType &T2) { - const PointerType *T1PtrType = T1->getAs<PointerType>(), - *T2PtrType = T2->getAs<PointerType>(); +/// Attempt to unwrap two types that may both be array types with the same bound +/// (or both be array types of unknown bound) for the purpose of comparing the +/// cv-decomposition of two types per C++ [conv.qual]. +bool ASTContext::UnwrapSimilarArrayTypes(QualType &T1, QualType &T2) { + bool UnwrappedAny = false; + while (true) { + auto *AT1 = getAsArrayType(T1); + if (!AT1) return UnwrappedAny; + + auto *AT2 = getAsArrayType(T2); + if (!AT2) return UnwrappedAny; + + // If we don't have two array types with the same constant bound nor two + // incomplete array types, we've unwrapped everything we can. + if (auto *CAT1 = dyn_cast<ConstantArrayType>(AT1)) { + auto *CAT2 = dyn_cast<ConstantArrayType>(AT2); + if (!CAT2 || CAT1->getSize() != CAT2->getSize()) + return UnwrappedAny; + } else if (!isa<IncompleteArrayType>(AT1) || + !isa<IncompleteArrayType>(AT2)) { + return UnwrappedAny; + } + + T1 = AT1->getElementType(); + T2 = AT2->getElementType(); + UnwrappedAny = true; + } +} + +/// Attempt to unwrap two types that may be similar (C++ [conv.qual]). +/// +/// If T1 and T2 are both pointer types of the same kind, or both array types +/// with the same bound, unwraps layers from T1 and T2 until a pointer type is +/// unwrapped. Top-level qualifiers on T1 and T2 are ignored. +/// +/// This function will typically be called in a loop that successively +/// "unwraps" pointer and pointer-to-member types to compare them at each +/// level. +/// +/// \return \c true if a pointer type was unwrapped, \c false if we reached a +/// pair of types that can't be unwrapped further. +bool ASTContext::UnwrapSimilarTypes(QualType &T1, QualType &T2) { + UnwrapSimilarArrayTypes(T1, T2); + + const auto *T1PtrType = T1->getAs<PointerType>(); + const auto *T2PtrType = T2->getAs<PointerType>(); if (T1PtrType && T2PtrType) { T1 = T1PtrType->getPointeeType(); T2 = T2PtrType->getPointeeType(); return true; } - - const MemberPointerType *T1MPType = T1->getAs<MemberPointerType>(), - *T2MPType = T2->getAs<MemberPointerType>(); + + const auto *T1MPType = T1->getAs<MemberPointerType>(); + const auto *T2MPType = T2->getAs<MemberPointerType>(); if (T1MPType && T2MPType && hasSameUnqualifiedType(QualType(T1MPType->getClass(), 0), QualType(T2MPType->getClass(), 0))) { @@ -4939,8 +5068,8 @@ bool ASTContext::UnwrapSimilarPointerTypes(QualType &T1, QualType &T2) { } if (getLangOpts().ObjC1) { - const ObjCObjectPointerType *T1OPType = T1->getAs<ObjCObjectPointerType>(), - *T2OPType = T2->getAs<ObjCObjectPointerType>(); + const auto *T1OPType = T1->getAs<ObjCObjectPointerType>(); + const auto *T2OPType = T2->getAs<ObjCObjectPointerType>(); if (T1OPType && T2OPType) { T1 = T1OPType->getPointeeType(); T2 = T2OPType->getPointeeType(); @@ -4953,6 +5082,37 @@ bool ASTContext::UnwrapSimilarPointerTypes(QualType &T1, QualType &T2) { return false; } +bool ASTContext::hasSimilarType(QualType T1, QualType T2) { + while (true) { + Qualifiers Quals; + T1 = getUnqualifiedArrayType(T1, Quals); + T2 = getUnqualifiedArrayType(T2, Quals); + if (hasSameType(T1, T2)) + return true; + if (!UnwrapSimilarTypes(T1, T2)) + return false; + } +} + +bool ASTContext::hasCvrSimilarType(QualType T1, QualType T2) { + while (true) { + Qualifiers Quals1, Quals2; + T1 = getUnqualifiedArrayType(T1, Quals1); + T2 = getUnqualifiedArrayType(T2, Quals2); + + Quals1.removeCVRQualifiers(); + Quals2.removeCVRQualifiers(); + if (Quals1 != Quals2) + return false; + + if (hasSameType(T1, T2)) + return true; + + if (!UnwrapSimilarTypes(T1, T2)) + return false; + } +} + DeclarationNameInfo ASTContext::getNameForTemplate(TemplateName Name, SourceLocation NameLoc) const { @@ -5008,8 +5168,7 @@ TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name) const { case TemplateName::QualifiedTemplate: case TemplateName::Template: { TemplateDecl *Template = Name.getAsTemplateDecl(); - if (TemplateTemplateParmDecl *TTP - = dyn_cast<TemplateTemplateParmDecl>(Template)) + if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(Template)) Template = getCanonicalTemplateTemplateParmDecl(TTP); // The canonical template name is the canonical template declaration. @@ -5061,7 +5220,7 @@ ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) const { return Arg; case TemplateArgument::Declaration: { - ValueDecl *D = cast<ValueDecl>(Arg.getAsDecl()->getCanonicalDecl()); + auto *D = cast<ValueDecl>(Arg.getAsDecl()->getCanonicalDecl()); return TemplateArgument(D, Arg.getParamTypeForDecl()); } @@ -5087,8 +5246,7 @@ ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) const { if (Arg.pack_size() == 0) return Arg; - TemplateArgument *CanonArgs - = new (*this) TemplateArgument[Arg.pack_size()]; + auto *CanonArgs = new (*this) TemplateArgument[Arg.pack_size()]; unsigned Idx = 0; for (TemplateArgument::pack_iterator A = Arg.pack_begin(), AEnd = Arg.pack_end(); @@ -5139,7 +5297,7 @@ ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const { // types, e.g., // typedef typename T::type T1; // typedef typename T1::type T2; - if (const DependentNameType *DNT = T->getAs<DependentNameType>()) + if (const auto *DNT = T->getAs<DependentNameType>()) return NestedNameSpecifier::Create(*this, DNT->getQualifier(), const_cast<IdentifierInfo *>(DNT->getIdentifier())); @@ -5163,7 +5321,7 @@ const ArrayType *ASTContext::getAsArrayType(QualType T) const { // Handle the non-qualified case efficiently. if (!T.hasLocalQualifiers()) { // Handle the common positive case fast. - if (const ArrayType *AT = dyn_cast<ArrayType>(T)) + if (const auto *AT = dyn_cast<ArrayType>(T)) return AT; } @@ -5183,7 +5341,7 @@ const ArrayType *ASTContext::getAsArrayType(QualType T) const { Qualifiers qs = split.Quals; // If we have a simple case, just return now. - const ArrayType *ATy = dyn_cast<ArrayType>(split.Ty); + const auto *ATy = dyn_cast<ArrayType>(split.Ty); if (!ATy || qs.empty()) return ATy; @@ -5191,17 +5349,16 @@ const ArrayType *ASTContext::getAsArrayType(QualType T) const { // qualifiers into the array element type and return a new array type. QualType NewEltTy = getQualifiedType(ATy->getElementType(), qs); - if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(ATy)) + if (const auto *CAT = dyn_cast<ConstantArrayType>(ATy)) return cast<ArrayType>(getConstantArrayType(NewEltTy, CAT->getSize(), CAT->getSizeModifier(), CAT->getIndexTypeCVRQualifiers())); - if (const IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(ATy)) + if (const auto *IAT = dyn_cast<IncompleteArrayType>(ATy)) return cast<ArrayType>(getIncompleteArrayType(NewEltTy, IAT->getSizeModifier(), IAT->getIndexTypeCVRQualifiers())); - if (const DependentSizedArrayType *DSAT - = dyn_cast<DependentSizedArrayType>(ATy)) + if (const auto *DSAT = dyn_cast<DependentSizedArrayType>(ATy)) return cast<ArrayType>( getDependentSizedArrayType(NewEltTy, DSAT->getSizeExpr(), @@ -5209,7 +5366,7 @@ const ArrayType *ASTContext::getAsArrayType(QualType T) const { DSAT->getIndexTypeCVRQualifiers(), DSAT->getBracketsRange())); - const VariableArrayType *VAT = cast<VariableArrayType>(ATy); + const auto *VAT = cast<VariableArrayType>(ATy); return cast<ArrayType>(getVariableArrayType(NewEltTy, VAT->getSizeExpr(), VAT->getSizeModifier(), @@ -5303,7 +5460,7 @@ ASTContext::getConstantArrayElementCount(const ConstantArrayType *CA) const { /// getFloatingRank - Return a relative rank for floating point types. /// This routine will assert if passed a built-in type that isn't a float. static FloatingRank getFloatingRank(QualType T) { - if (const ComplexType *CT = T->getAs<ComplexType>()) + if (const auto *CT = T->getAs<ComplexType>()) return getFloatingRank(CT->getElementType()); assert(T->getAs<BuiltinType>() && "getFloatingRank(): not a floating type"); @@ -5396,14 +5553,20 @@ unsigned ASTContext::getIntegerRank(const Type *T) const { } } -/// \brief Whether this is a promotable bitfield reference according +/// Whether this is a promotable bitfield reference according /// to C99 6.3.1.1p2, bullet 2 (and GCC extensions). /// /// \returns the type this bit-field will promote to, or NULL if no /// promotion occurs. QualType ASTContext::isPromotableBitField(Expr *E) const { if (E->isTypeDependent() || E->isValueDependent()) - return QualType(); + return {}; + + // C++ [conv.prom]p5: + // If the bit-field has an enumerated type, it is treated as any other + // value of that type for promotion purposes. + if (getLangOpts().CPlusPlus && E->getType()->isEnumeralType()) + return {}; // FIXME: We should not do this unless E->refersToBitField() is true. This // matters in C where getSourceBitField() will find bit-fields for various @@ -5411,7 +5574,7 @@ QualType ASTContext::isPromotableBitField(Expr *E) const { FieldDecl *Field = E->getSourceBitField(); // FIXME: conditional bit-fields? if (!Field) - return QualType(); + return {}; QualType FT = Field->getType(); @@ -5431,18 +5594,20 @@ QualType ASTContext::isPromotableBitField(Expr *E) const { // // FIXME: C does not permit promotion of a 'long : 3' bitfield to int. // We perform that promotion here to match GCC and C++. + // FIXME: C does not permit promotion of an enum bit-field whose rank is + // greater than that of 'int'. We perform that promotion to match GCC. if (BitWidth < IntSize) return IntTy; if (BitWidth == IntSize) return FT->isSignedIntegerType() ? IntTy : UnsignedIntTy; - // Types bigger than int are not subject to promotions, and therefore act + // Bit-fields wider than int are not subject to promotions, and therefore act // like the base type. GCC has some weird bugs in this area that we // deliberately do not follow (GCC follows a pre-standard resolution to // C's DR315 which treats bit-width as being part of the type, and this leaks // into their semantics in some cases). - return QualType(); + return {}; } /// getPromotedIntegerType - Returns the type that Promotable will @@ -5451,10 +5616,10 @@ QualType ASTContext::isPromotableBitField(Expr *E) const { QualType ASTContext::getPromotedIntegerType(QualType Promotable) const { assert(!Promotable.isNull()); assert(Promotable->isPromotableIntegerType()); - if (const EnumType *ET = Promotable->getAs<EnumType>()) + if (const auto *ET = Promotable->getAs<EnumType>()) return ET->getDecl()->getPromotionType(); - if (const BuiltinType *BT = Promotable->getAs<BuiltinType>()) { + if (const auto *BT = Promotable->getAs<BuiltinType>()) { // C++ [conv.prom]: A prvalue of type char16_t, char32_t, or wchar_t // (3.9.1) can be converted to a prvalue of the first of the following // types that can represent all the values of its underlying type: @@ -5463,6 +5628,7 @@ QualType ASTContext::getPromotedIntegerType(QualType Promotable) const { // FIXME: Is there some better way to compute this? if (BT->getKind() == BuiltinType::WChar_S || BT->getKind() == BuiltinType::WChar_U || + BT->getKind() == BuiltinType::Char8 || BT->getKind() == BuiltinType::Char16 || BT->getKind() == BuiltinType::Char32) { bool FromIsSigned = BT->getKind() == BuiltinType::WChar_S; @@ -5489,7 +5655,7 @@ QualType ASTContext::getPromotedIntegerType(QualType Promotable) const { return (PromotableSize != IntSize) ? IntTy : UnsignedIntTy; } -/// \brief Recurses in pointer/array types until it finds an objc retainable +/// Recurses in pointer/array types until it finds an objc retainable /// type and returns its ownership. Qualifiers::ObjCLifetime ASTContext::getInnerObjCOwnership(QualType T) const { while (!T.isNull()) { @@ -5497,9 +5663,9 @@ Qualifiers::ObjCLifetime ASTContext::getInnerObjCOwnership(QualType T) const { return T.getObjCLifetime(); if (T->isArrayType()) T = getBaseElementType(T); - else if (const PointerType *PT = T->getAs<PointerType>()) + else if (const auto *PT = T->getAs<PointerType>()) T = PT->getPointeeType(); - else if (const ReferenceType *RT = T->getAs<ReferenceType>()) + else if (const auto *RT = T->getAs<ReferenceType>()) T = RT->getPointeeType(); else break; @@ -5524,9 +5690,9 @@ int ASTContext::getIntegerTypeOrder(QualType LHS, QualType RHS) const { const Type *RHSC = getCanonicalType(RHS).getTypePtr(); // Unwrap enums to their underlying type. - if (const EnumType *ET = dyn_cast<EnumType>(LHSC)) + if (const auto *ET = dyn_cast<EnumType>(LHSC)) LHSC = getIntegerTypeForEnum(ET); - if (const EnumType *ET = dyn_cast<EnumType>(RHSC)) + if (const auto *ET = dyn_cast<EnumType>(RHSC)) RHSC = getIntegerTypeForEnum(ET); if (LHSC == RHSC) return 0; @@ -5633,10 +5799,10 @@ QualType ASTContext::getObjCSuperType() const { } void ASTContext::setCFConstantStringType(QualType T) { - const TypedefType *TD = T->getAs<TypedefType>(); + const auto *TD = T->getAs<TypedefType>(); assert(TD && "Invalid CFConstantStringType"); CFConstantStringTypeDecl = cast<TypedefDecl>(TD->getDecl()); - auto TagType = + const auto *TagType = CFConstantStringTypeDecl->getUnderlyingType()->getAs<RecordType>(); assert(TagType && "Invalid CFConstantStringType"); CFConstantStringTagDecl = TagType->getDecl(); @@ -5717,7 +5883,7 @@ QualType ASTContext::getBlockDescriptorExtendedType() const { } TargetInfo::OpenCLTypeKind ASTContext::getOpenCLTypeKind(const Type *T) const { - auto BT = dyn_cast<BuiltinType>(T); + const auto *BT = dyn_cast<BuiltinType>(T); if (!BT) { if (isa<PipeType>(T)) @@ -5768,6 +5934,11 @@ bool ASTContext::BlockRequiresCopying(QualType Ty, return true; } + // The block needs copy/destroy helpers if Ty is non-trivial to destructively + // move or destroy. + if (Ty.isNonTrivialToPrimitiveDestructiveMove() || Ty.isDestructedType()) + return true; + if (!Ty->isObjCRetainableType()) return false; Qualifiers qs = Ty.getQualifiers(); @@ -5781,13 +5952,12 @@ bool ASTContext::BlockRequiresCopying(QualType Ty, case Qualifiers::OCL_ExplicitNone: case Qualifiers::OCL_Autoreleasing: return false; - - // Tell the runtime that this is ARC __weak, called by the - // byref routines. + + // These cases should have been taken care of when checking the type's + // non-triviality. case Qualifiers::OCL_Weak: - // ARC __strong __block variables need to be retained. case Qualifiers::OCL_Strong: - return true; + llvm_unreachable("impossible"); } llvm_unreachable("fell out of lifetime switch!"); } @@ -5827,7 +5997,7 @@ TypedefDecl *ASTContext::getObjCInstanceTypeDecl() { // This returns true if a type has been typedefed to BOOL: // typedef <type> BOOL; static bool isTypeTypedefedAsBOOL(QualType T) { - if (const TypedefType *TT = dyn_cast<TypedefType>(T)) + if (const auto *TT = dyn_cast<TypedefType>(T)) if (IdentifierInfo *II = TT->getDecl()->getIdentifier()) return II->isStr("BOOL"); @@ -5879,8 +6049,7 @@ ASTContext::getInlineVariableDefinitionKind(const VarDecl *VD) const { return InlineVariableDefinitionKind::WeakUnknown; } -static inline -std::string charUnitsToString(const CharUnits &CU) { +static std::string charUnitsToString(const CharUnits &CU) { return llvm::itostr(CU.getQuantity()); } @@ -5921,8 +6090,8 @@ std::string ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr) const { ParmOffset = PtrSize; for (auto PVDecl : Decl->parameters()) { QualType PType = PVDecl->getOriginalType(); - if (const ArrayType *AT = - dyn_cast<ArrayType>(PType->getCanonicalTypeInternal())) { + if (const auto *AT = + dyn_cast<ArrayType>(PType->getCanonicalTypeInternal())) { // Use array's original type only if it has known number of // elements. if (!isa<ConstantArrayType>(AT)) @@ -5964,8 +6133,8 @@ ASTContext::getObjCEncodingForFunctionDecl(const FunctionDecl *Decl) const { // Argument types. for (auto PVDecl : Decl->parameters()) { QualType PType = PVDecl->getOriginalType(); - if (const ArrayType *AT = - dyn_cast<ArrayType>(PType->getCanonicalTypeInternal())) { + if (const auto *AT = + dyn_cast<ArrayType>(PType->getCanonicalTypeInternal())) { // Use array's original type only if it has known number of // elements. if (!isa<ConstantArrayType>(AT)) @@ -6034,8 +6203,8 @@ std::string ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, E = Decl->sel_param_end(); PI != E; ++PI) { const ParmVarDecl *PVDecl = *PI; QualType PType = PVDecl->getOriginalType(); - if (const ArrayType *AT = - dyn_cast<ArrayType>(PType->getCanonicalTypeInternal())) { + if (const auto *AT = + dyn_cast<ArrayType>(PType->getCanonicalTypeInternal())) { // Use array's original type only if it has known number of // elements. if (!isa<ConstantArrayType>(AT)) @@ -6057,13 +6226,12 @@ ASTContext::getObjCPropertyImplDeclForPropertyDecl( const Decl *Container) const { if (!Container) return nullptr; - if (const ObjCCategoryImplDecl *CID = - dyn_cast<ObjCCategoryImplDecl>(Container)) { + if (const auto *CID = dyn_cast<ObjCCategoryImplDecl>(Container)) { for (auto *PID : CID->property_impls()) if (PID->getPropertyDecl() == PD) return PID; } else { - const ObjCImplementationDecl *OID=cast<ObjCImplementationDecl>(Container); + const auto *OID = cast<ObjCImplementationDecl>(Container); for (auto *PID : OID->property_impls()) if (PID->getPropertyDecl() == PD) return PID; @@ -6170,7 +6338,7 @@ ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD, /// 'i' or 'I' instead if encoding a struct field, or a pointer! void ASTContext::getLegacyIntegralTypeEncoding (QualType &PointeeTy) const { if (isa<TypedefType>(PointeeTy.getTypePtr())) { - if (const BuiltinType *BT = PointeeTy->getAs<BuiltinType>()) { + if (const auto *BT = PointeeTy->getAs<BuiltinType>()) { if (BT->getKind() == BuiltinType::ULong && getIntWidth(PointeeTy) == 32) PointeeTy = UnsignedIntTy; else @@ -6207,6 +6375,7 @@ static char getObjCEncodingForPrimitiveKind(const ASTContext *C, switch (kind) { case BuiltinType::Void: return 'v'; case BuiltinType::Bool: return 'B'; + case BuiltinType::Char8: case BuiltinType::Char_U: case BuiltinType::UChar: return 'C'; case BuiltinType::Char16: @@ -6235,6 +6404,30 @@ static char getObjCEncodingForPrimitiveKind(const ASTContext *C, case BuiltinType::Float16: case BuiltinType::Float128: case BuiltinType::Half: + case BuiltinType::ShortAccum: + case BuiltinType::Accum: + case BuiltinType::LongAccum: + case BuiltinType::UShortAccum: + case BuiltinType::UAccum: + case BuiltinType::ULongAccum: + case BuiltinType::ShortFract: + case BuiltinType::Fract: + case BuiltinType::LongFract: + case BuiltinType::UShortFract: + case BuiltinType::UFract: + case BuiltinType::ULongFract: + case BuiltinType::SatShortAccum: + case BuiltinType::SatAccum: + case BuiltinType::SatLongAccum: + case BuiltinType::SatUShortAccum: + case BuiltinType::SatUAccum: + case BuiltinType::SatULongAccum: + case BuiltinType::SatShortFract: + case BuiltinType::SatFract: + case BuiltinType::SatLongFract: + case BuiltinType::SatUShortFract: + case BuiltinType::SatUFract: + case BuiltinType::SatULongFract: // FIXME: potentially need @encodes for these! return ' '; @@ -6270,7 +6463,7 @@ static char ObjCEncodingForEnumType(const ASTContext *C, const EnumType *ET) { return 'i'; // The encoding of a fixed enum type matches its fixed underlying type. - const BuiltinType *BT = Enum->getIntegerType()->castAs<BuiltinType>(); + const auto *BT = Enum->getIntegerType()->castAs<BuiltinType>(); return getObjCEncodingForPrimitiveKind(C, BT->getKind()); } @@ -6307,10 +6500,10 @@ static void EncodeBitField(const ASTContext *Ctx, std::string& S, S += llvm::utostr(Offset); - if (const EnumType *ET = T->getAs<EnumType>()) + if (const auto *ET = T->getAs<EnumType>()) S += ObjCEncodingForEnumType(Ctx, ET); else { - const BuiltinType *BT = T->castAs<BuiltinType>(); + const auto *BT = T->castAs<BuiltinType>(); S += getObjCEncodingForPrimitiveKind(Ctx, BT->getKind()); } } @@ -6335,21 +6528,21 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, case Type::Enum: if (FD && FD->isBitField()) return EncodeBitField(this, S, T, FD); - if (const BuiltinType *BT = dyn_cast<BuiltinType>(CT)) + if (const auto *BT = dyn_cast<BuiltinType>(CT)) S += getObjCEncodingForPrimitiveKind(this, BT->getKind()); else S += ObjCEncodingForEnumType(this, cast<EnumType>(CT)); return; case Type::Complex: { - const ComplexType *CT = T->castAs<ComplexType>(); + const auto *CT = T->castAs<ComplexType>(); S += 'j'; getObjCEncodingForTypeImpl(CT->getElementType(), S, false, false, nullptr); return; } case Type::Atomic: { - const AtomicType *AT = T->castAs<AtomicType>(); + const auto *AT = T->castAs<AtomicType>(); S += 'A'; getObjCEncodingForTypeImpl(AT->getValueType(), S, false, false, nullptr); return; @@ -6361,7 +6554,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, case Type::RValueReference: { QualType PointeeTy; if (isa<PointerType>(CT)) { - const PointerType *PT = T->castAs<PointerType>(); + const auto *PT = T->castAs<PointerType>(); if (PT->isObjCSelType()) { S += ':'; return; @@ -6405,7 +6598,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, S += '*'; return; } - } else if (const RecordType *RTy = PointeeTy->getAs<RecordType>()) { + } else if (const auto *RTy = PointeeTy->getAs<RecordType>()) { // GCC binary compat: Need to convert "struct objc_class *" to "#". if (RTy->getDecl()->getIdentifier() == &Idents.get("objc_class")) { S += '#'; @@ -6430,7 +6623,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, case Type::ConstantArray: case Type::IncompleteArray: case Type::VariableArray: { - const ArrayType *AT = cast<ArrayType>(CT); + const auto *AT = cast<ArrayType>(CT); if (isa<IncompleteArrayType>(AT) && !StructField) { // Incomplete arrays are encoded as a pointer to the array element. @@ -6441,7 +6634,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, } else { S += '['; - if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT)) + if (const auto *CAT = dyn_cast<ConstantArrayType>(AT)) S += llvm::utostr(CAT->getSize().getZExtValue()); else { //Variable length arrays are encoded as a regular array with 0 elements. @@ -6470,8 +6663,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, // Anonymous structures print as '?' if (const IdentifierInfo *II = RDecl->getIdentifier()) { S += II->getName(); - if (ClassTemplateSpecializationDecl *Spec - = dyn_cast<ClassTemplateSpecializationDecl>(RDecl)) { + if (const auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(RDecl)) { const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); llvm::raw_string_ostream OS(S); printTemplateArgumentList(OS, TemplateArgs.asArray(), @@ -6513,10 +6705,10 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, } case Type::BlockPointer: { - const BlockPointerType *BT = T->castAs<BlockPointerType>(); + const auto *BT = T->castAs<BlockPointerType>(); S += "@?"; // Unlike a pointer-to-function, which is "^?". if (EncodeBlockParameters) { - const FunctionType *FT = BT->getPointeeType()->castAs<FunctionType>(); + const auto *FT = BT->getPointeeType()->castAs<FunctionType>(); S += '<'; // Block return type @@ -6528,7 +6720,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, // Block self S += "@?"; // Block parameters - if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FT)) { + if (const auto *FPT = dyn_cast<FunctionProtoType>(FT)) { for (const auto &I : FPT->param_types()) getObjCEncodingForTypeImpl( I, S, ExpandPointedToStructures, ExpandStructures, FD, @@ -6552,7 +6744,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, S += "{objc_class=}"; return; } - // TODO: Double check to make sure this intentially falls through. + // TODO: Double check to make sure this intentionally falls through. LLVM_FALLTHROUGH; } @@ -6567,7 +6759,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, SmallVector<const ObjCIvarDecl*, 32> Ivars; DeepCollectObjCIvars(OI, true, Ivars); for (unsigned i = 0, e = Ivars.size(); i != e; ++i) { - const FieldDecl *Field = cast<FieldDecl>(Ivars[i]); + const FieldDecl *Field = Ivars[i]; if (Field->isBitField()) getObjCEncodingForTypeImpl(Field->getType(), S, false, true, Field); else @@ -6582,7 +6774,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, } case Type::ObjCObjectPointer: { - const ObjCObjectPointerType *OPT = T->castAs<ObjCObjectPointerType>(); + const auto *OPT = T->castAs<ObjCObjectPointerType>(); if (OPT->isObjCIdType()) { S += '@'; return; @@ -6591,7 +6783,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, if (OPT->isObjCClassType() || OPT->isObjCQualifiedClassType()) { // FIXME: Consider if we need to output qualifiers for 'Class<p>'. // Since this is a binary compatibility issue, need to consult with runtime - // folks. Fortunately, this is a *very* obsure construct. + // folks. Fortunately, this is a *very* obscure construct. S += '#'; return; } @@ -6628,7 +6820,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, 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) { + if (Ivars[i] == FD) { S += '{'; S += OI->getObjCRuntimeNameAsString(); S += '}'; @@ -6702,7 +6894,7 @@ void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl, if (!RDecl->getDefinition() || RDecl->getDefinition()->isInvalidDecl()) return; - CXXRecordDecl *CXXRec = dyn_cast<CXXRecordDecl>(RDecl); + const auto *CXXRec = dyn_cast<CXXRecordDecl>(RDecl); std::multimap<uint64_t, NamedDecl *> FieldOrBaseOffsets; const ASTRecordLayout &layout = getASTRecordLayout(RDecl); @@ -6795,7 +6987,7 @@ void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl, if (!dcl) break; // reached end of structure. - if (CXXRecordDecl *base = dyn_cast<CXXRecordDecl>(dcl)) { + if (auto *base = dyn_cast<CXXRecordDecl>(dcl)) { // We expand the bases without their virtual bases since those are going // in the initial structure. Note that this differs from gcc which // expands virtual bases each time one is encountered in the hierarchy, @@ -6807,7 +6999,7 @@ void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl, CurOffs += toBits(getASTRecordLayout(base).getNonVirtualSize()); #endif } else { - FieldDecl *field = cast<FieldDecl>(dcl); + const auto *field = cast<FieldDecl>(dcl); if (FD) { S += '"'; S += field->getNameAsString(); @@ -7250,6 +7442,10 @@ TypedefDecl *ASTContext::getBuiltinMSVaListDecl() const { return BuiltinMSVaListDecl; } +bool ASTContext::canBuiltinBeRedeclared(const FunctionDecl *FD) const { + return BuiltinInfo.canBeRedeclared(FD->getBuiltinID()); +} + void ASTContext::setObjCConstantStringInterface(ObjCInterfaceDecl *Decl) { assert(ObjCConstantStringType.isNull() && "'NSConstantString' type already set!"); @@ -7257,7 +7453,7 @@ void ASTContext::setObjCConstantStringInterface(ObjCInterfaceDecl *Decl) { ObjCConstantStringType = getObjCInterfaceType(Decl); } -/// \brief Retrieve the template name that corresponds to a non-empty +/// Retrieve the template name that corresponds to a non-empty /// lookup. TemplateName ASTContext::getOverloadedTemplateName(UnresolvedSetIterator Begin, @@ -7267,12 +7463,13 @@ ASTContext::getOverloadedTemplateName(UnresolvedSetIterator Begin, void *memory = Allocate(sizeof(OverloadedTemplateStorage) + size * sizeof(FunctionTemplateDecl*)); - OverloadedTemplateStorage *OT = new(memory) OverloadedTemplateStorage(size); + auto *OT = new (memory) OverloadedTemplateStorage(size); NamedDecl **Storage = OT->getStorage(); for (UnresolvedSetIterator I = Begin; I != End; ++I) { NamedDecl *D = *I; assert(isa<FunctionTemplateDecl>(D) || + isa<UnresolvedUsingValueDecl>(D) || (isa<UsingShadowDecl>(D) && isa<FunctionTemplateDecl>(D->getUnderlyingDecl()))); *Storage++ = D; @@ -7281,7 +7478,7 @@ ASTContext::getOverloadedTemplateName(UnresolvedSetIterator Begin, return TemplateName(OT); } -/// \brief Retrieve the template name that represents a qualified +/// Retrieve the template name that represents a qualified /// template name such as \c std::vector. TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS, @@ -7305,7 +7502,7 @@ ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS, return TemplateName(QTN); } -/// \brief Retrieve the template name that represents a dependent +/// Retrieve the template name that represents a dependent /// template name such as \c MetaFun::template apply. TemplateName ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS, @@ -7341,7 +7538,7 @@ ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS, return TemplateName(QTN); } -/// \brief Retrieve the template name that represents a dependent +/// Retrieve the template name that represents a dependent /// template name such as \c MetaFun::template operator+. TemplateName ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS, @@ -7399,7 +7596,7 @@ ASTContext::getSubstTemplateTemplateParm(TemplateTemplateParmDecl *param, TemplateName ASTContext::getSubstTemplateTemplateParmPack(TemplateTemplateParmDecl *Param, const TemplateArgument &ArgPack) const { - ASTContext &Self = const_cast<ASTContext &>(*this); + auto &Self = const_cast<ASTContext &>(*this); llvm::FoldingSetNodeID ID; SubstTemplateTemplateParmPackStorage::Profile(ID, Self, Param, ArgPack); @@ -7422,7 +7619,7 @@ ASTContext::getSubstTemplateTemplateParmPack(TemplateTemplateParmDecl *Param, /// is actually a value of type @c TargetInfo::IntType. CanQualType ASTContext::getFromTargetType(unsigned Type) const { switch (Type) { - case TargetInfo::NoInt: return CanQualType(); + case TargetInfo::NoInt: return {}; case TargetInfo::SignedChar: return SignedCharTy; case TargetInfo::UnsignedChar: return UnsignedCharTy; case TargetInfo::SignedShort: return ShortTy; @@ -7465,7 +7662,7 @@ Qualifiers::GC ASTContext::getObjCGCAttrKind(QualType Ty) const { // pointer. #ifndef NDEBUG QualType CT = Ty->getCanonicalTypeInternal(); - while (const ArrayType *AT = dyn_cast<ArrayType>(CT)) + while (const auto *AT = dyn_cast<ArrayType>(CT)) CT = AT->getElementType(); assert(CT->isAnyPointerType() || CT->isBlockPointerType()); #endif @@ -7496,8 +7693,8 @@ bool ASTContext::areCompatibleVectorTypes(QualType FirstVec, // Treat Neon vector types and most AltiVec vector types as if they are the // equivalent GCC vector types. - const VectorType *First = FirstVec->getAs<VectorType>(); - const VectorType *Second = SecondVec->getAs<VectorType>(); + const auto *First = FirstVec->getAs<VectorType>(); + const auto *Second = SecondVec->getAs<VectorType>(); if (First->getNumElements() == Second->getNumElements() && hasSameType(First->getElementType(), Second->getElementType()) && First->getVectorKind() != VectorType::AltiVecPixel && @@ -7530,8 +7727,8 @@ ASTContext::ProtocolCompatibleWithProtocol(ObjCProtocolDecl *lProto, /// Class<pr1, ...>. bool ASTContext::ObjCQualifiedClassTypesAreCompatible(QualType lhs, QualType rhs) { - const ObjCObjectPointerType *lhsQID = lhs->getAs<ObjCObjectPointerType>(); - const ObjCObjectPointerType *rhsOPT = rhs->getAs<ObjCObjectPointerType>(); + const auto *lhsQID = lhs->getAs<ObjCObjectPointerType>(); + const auto *rhsOPT = rhs->getAs<ObjCObjectPointerType>(); assert((lhsQID && rhsOPT) && "ObjCQualifiedClassTypesAreCompatible"); for (auto *lhsProto : lhsQID->quals()) { @@ -7561,7 +7758,7 @@ bool ASTContext::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs, return true; if (const ObjCObjectPointerType *lhsQID = lhs->getAsObjCQualifiedIdType()) { - const ObjCObjectPointerType *rhsOPT = rhs->getAs<ObjCObjectPointerType>(); + const auto *rhsOPT = rhs->getAs<ObjCObjectPointerType>(); if (!rhsOPT) return false; @@ -7847,14 +8044,14 @@ void getIntersectionOfProtocols(ASTContext &Context, static bool canAssignObjCObjectTypes(ASTContext &ctx, QualType lhs, QualType rhs) { // Common case: two object pointers. - const ObjCObjectPointerType *lhsOPT = lhs->getAs<ObjCObjectPointerType>(); - const ObjCObjectPointerType *rhsOPT = rhs->getAs<ObjCObjectPointerType>(); + const auto *lhsOPT = lhs->getAs<ObjCObjectPointerType>(); + const auto *rhsOPT = rhs->getAs<ObjCObjectPointerType>(); if (lhsOPT && rhsOPT) return ctx.canAssignObjCInterfaces(lhsOPT, rhsOPT); // Two block pointers. - const BlockPointerType *lhsBlock = lhs->getAs<BlockPointerType>(); - const BlockPointerType *rhsBlock = rhs->getAs<BlockPointerType>(); + const auto *lhsBlock = lhs->getAs<BlockPointerType>(); + const auto *rhsBlock = rhs->getAs<BlockPointerType>(); if (lhsBlock && rhsBlock) return ctx.typesAreBlockPointerCompatible(lhs, rhs); @@ -7914,7 +8111,7 @@ QualType ASTContext::areCommonBaseCompatible( const ObjCInterfaceDecl* RDecl = RHS->getInterface(); if (!LDecl || !RDecl) - return QualType(); + return {}; // When either LHS or RHS is a kindof type, we should return a kindof type. // For example, for common base of kindof(ASub1) and kindof(ASub2), we return @@ -7939,7 +8136,7 @@ QualType ASTContext::areCommonBaseCompatible( if (!sameObjCTypeArgs(*this, LHS->getInterface(), LHS->getTypeArgs(), RHS->getTypeArgs(), /*stripKindOf=*/true)) - return QualType(); + return {}; } else if (LHS->isSpecialized() != RHS->isSpecialized()) { // If only one has type arguments, the result will not have type // arguments. @@ -7990,7 +8187,7 @@ QualType ASTContext::areCommonBaseCompatible( if (!sameObjCTypeArgs(*this, LHS->getInterface(), LHS->getTypeArgs(), RHS->getTypeArgs(), /*stripKindOf=*/true)) - return QualType(); + return {}; } else if (LHS->isSpecialized() != RHS->isSpecialized()) { // If only one has type arguments, the result will not have type // arguments. @@ -8025,7 +8222,7 @@ QualType ASTContext::areCommonBaseCompatible( RHS = RHSSuperType->castAs<ObjCObjectType>(); } - return QualType(); + return {}; } bool ASTContext::canAssignObjCInterfaces(const ObjCObjectType *LHS, @@ -8092,8 +8289,8 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectType *LHS, bool ASTContext::areComparableObjCPointerTypes(QualType LHS, QualType RHS) { // get the "pointed to" types - const ObjCObjectPointerType *LHSOPT = LHS->getAs<ObjCObjectPointerType>(); - const ObjCObjectPointerType *RHSOPT = RHS->getAs<ObjCObjectPointerType>(); + const auto *LHSOPT = LHS->getAs<ObjCObjectPointerType>(); + const auto *RHSOPT = RHS->getAs<ObjCObjectPointerType>(); if (!LHSOPT || !RHSOPT) return false; @@ -8146,7 +8343,7 @@ QualType ASTContext::mergeTransparentUnionType(QualType T, QualType SubType, } } - return QualType(); + return {}; } /// mergeFunctionParameterTypes - merge two types which appear as function @@ -8173,10 +8370,10 @@ QualType ASTContext::mergeFunctionParameterTypes(QualType lhs, QualType rhs, QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, bool OfBlockPointer, bool Unqualified) { - const FunctionType *lbase = lhs->getAs<FunctionType>(); - const FunctionType *rbase = rhs->getAs<FunctionType>(); - const FunctionProtoType *lproto = dyn_cast<FunctionProtoType>(lbase); - const FunctionProtoType *rproto = dyn_cast<FunctionProtoType>(rbase); + const auto *lbase = lhs->getAs<FunctionType>(); + const auto *rbase = rhs->getAs<FunctionType>(); + const auto *lproto = dyn_cast<FunctionProtoType>(lbase); + const auto *rproto = dyn_cast<FunctionProtoType>(rbase); bool allLTypes = true; bool allRTypes = true; @@ -8193,7 +8390,8 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, else retType = mergeTypes(lbase->getReturnType(), rbase->getReturnType(), false, Unqualified); - if (retType.isNull()) return QualType(); + if (retType.isNull()) + return {}; if (Unqualified) retType = retType.getUnqualifiedType(); @@ -8219,18 +8417,20 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, // Compatible functions must have compatible calling conventions if (lbaseInfo.getCC() != rbaseInfo.getCC()) - return QualType(); + return {}; // Regparm is part of the calling convention. if (lbaseInfo.getHasRegParm() != rbaseInfo.getHasRegParm()) - return QualType(); + return {}; if (lbaseInfo.getRegParm() != rbaseInfo.getRegParm()) - return QualType(); + return {}; if (lbaseInfo.getProducesResult() != rbaseInfo.getProducesResult()) - return QualType(); + return {}; if (lbaseInfo.getNoCallerSavedRegs() != rbaseInfo.getNoCallerSavedRegs()) - return QualType(); + return {}; + if (lbaseInfo.getNoCfCheck() != rbaseInfo.getNoCfCheck()) + return {}; // FIXME: some uses, e.g. conditional exprs, really want this to be 'both'. bool NoReturn = lbaseInfo.getNoReturn() || rbaseInfo.getNoReturn(); @@ -8247,20 +8447,20 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, "C++ shouldn't be here"); // Compatible functions must have the same number of parameters if (lproto->getNumParams() != rproto->getNumParams()) - return QualType(); + return {}; // Variadic and non-variadic functions aren't compatible if (lproto->isVariadic() != rproto->isVariadic()) - return QualType(); + return {}; if (lproto->getTypeQuals() != rproto->getTypeQuals()) - return QualType(); + return {}; SmallVector<FunctionProtoType::ExtParameterInfo, 4> newParamInfos; bool canUseLeft, canUseRight; if (!mergeExtParameterInfo(lproto, rproto, canUseLeft, canUseRight, newParamInfos)) - return QualType(); + return {}; if (!canUseLeft) allLTypes = false; @@ -8275,7 +8475,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, QualType paramType = mergeFunctionParameterTypes( lParamType, rParamType, OfBlockPointer, Unqualified); if (paramType.isNull()) - return QualType(); + return {}; if (Unqualified) paramType = paramType.getUnqualifiedType(); @@ -8308,7 +8508,8 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, const FunctionProtoType *proto = lproto ? lproto : rproto; if (proto) { assert(!proto->hasExceptionSpec() && "C++ shouldn't be here"); - if (proto->isVariadic()) return QualType(); + if (proto->isVariadic()) + return {}; // Check that the types are compatible with the types that // would result from default argument promotions (C99 6.7.5.3p15). // The only types actually affected are promotable integer @@ -8319,15 +8520,15 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, // Look at the converted type of enum types, since that is the type used // to pass enum values. - if (const EnumType *Enum = paramTy->getAs<EnumType>()) { + if (const auto *Enum = paramTy->getAs<EnumType>()) { paramTy = Enum->getDecl()->getIntegerType(); if (paramTy.isNull()) - return QualType(); + return {}; } if (paramTy->isPromotableIntegerType() || getCanonicalType(paramTy).getUnqualifiedType() == FloatTy) - return QualType(); + return {}; } if (allLTypes) return lhs; @@ -8351,7 +8552,8 @@ static QualType mergeEnumWithInteger(ASTContext &Context, const EnumType *ET, // Compatibility is based on the underlying type, not the promotion // type. QualType underlyingType = ET->getDecl()->getIntegerType(); - if (underlyingType.isNull()) return QualType(); + if (underlyingType.isNull()) + return {}; if (Context.hasSameType(underlyingType, other)) return other; @@ -8361,7 +8563,7 @@ static QualType mergeEnumWithInteger(ASTContext &Context, const EnumType *ET, Context.getTypeSize(underlyingType) == Context.getTypeSize(other)) return other; - return QualType(); + return {}; } QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, @@ -8397,7 +8599,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, LQuals.getAddressSpace() != RQuals.getAddressSpace() || LQuals.getObjCLifetime() != RQuals.getObjCLifetime() || LQuals.hasUnaligned() != RQuals.hasUnaligned()) - return QualType(); + return {}; // Exactly one GC qualifier difference is allowed: __strong is // okay if the other type has no GC qualifier but is an Objective @@ -8409,7 +8611,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, assert((GC_L != GC_R) && "unequal qualifier sets had only equal elements"); if (GC_L == Qualifiers::Weak || GC_R == Qualifiers::Weak) - return QualType(); + return {}; if (GC_L == Qualifiers::Strong && RHSCan->isObjCObjectPointerType()) { return mergeTypes(LHS, getObjCGCQualType(RHS, Qualifiers::Strong)); @@ -8417,7 +8619,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, if (GC_R == Qualifiers::Strong && LHSCan->isObjCObjectPointerType()) { return mergeTypes(getObjCGCQualType(LHS, Qualifiers::Strong), RHS); } - return QualType(); + return {}; } // Okay, qualifiers are equal. @@ -8448,7 +8650,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, if (LHSClass != RHSClass) { // Note that we only have special rules for turning block enum // returns into block int returns, not vice-versa. - if (const EnumType* ETy = LHS->getAs<EnumType>()) { + if (const auto *ETy = LHS->getAs<EnumType>()) { return mergeEnumWithInteger(*this, ETy, RHS, false); } if (const EnumType* ETy = RHS->getAs<EnumType>()) { @@ -8462,7 +8664,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, return RHS; } - return QualType(); + return {}; } // The canonical type classes match. @@ -8500,7 +8702,8 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, } QualType ResultType = mergeTypes(LHSPointee, RHSPointee, false, Unqualified); - if (ResultType.isNull()) return QualType(); + if (ResultType.isNull()) + return {}; if (getCanonicalType(LHSPointee) == getCanonicalType(ResultType)) return LHS; if (getCanonicalType(RHSPointee) == getCanonicalType(ResultType)) @@ -8522,7 +8725,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, // Blocks can't be an expression in a ternary operator (OpenCL v2.0 // 6.12.5) thus the following check is asymmetric. if (!LHSPteeQual.isAddressSpaceSupersetOf(RHSPteeQual)) - return QualType(); + return {}; LHSPteeQual.removeAddressSpace(); RHSPteeQual.removeAddressSpace(); LHSPointee = @@ -8532,7 +8735,8 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, } QualType ResultType = mergeTypes(LHSPointee, RHSPointee, OfBlockPointer, Unqualified); - if (ResultType.isNull()) return QualType(); + if (ResultType.isNull()) + return {}; if (getCanonicalType(LHSPointee) == getCanonicalType(ResultType)) return LHS; if (getCanonicalType(RHSPointee) == getCanonicalType(ResultType)) @@ -8550,7 +8754,8 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, } QualType ResultType = mergeTypes(LHSValue, RHSValue, false, Unqualified); - if (ResultType.isNull()) return QualType(); + if (ResultType.isNull()) + return {}; if (getCanonicalType(LHSValue) == getCanonicalType(ResultType)) return LHS; if (getCanonicalType(RHSValue) == getCanonicalType(ResultType)) @@ -8562,7 +8767,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, const ConstantArrayType* LCAT = getAsConstantArrayType(LHS); const ConstantArrayType* RCAT = getAsConstantArrayType(RHS); if (LCAT && RCAT && RCAT->getSize() != LCAT->getSize()) - return QualType(); + return {}; QualType LHSElem = getAsArrayType(LHS)->getElementType(); QualType RHSElem = getAsArrayType(RHS)->getElementType(); @@ -8572,7 +8777,40 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, } QualType ResultType = mergeTypes(LHSElem, RHSElem, false, Unqualified); - if (ResultType.isNull()) return QualType(); + if (ResultType.isNull()) + return {}; + + const VariableArrayType* LVAT = getAsVariableArrayType(LHS); + const VariableArrayType* RVAT = getAsVariableArrayType(RHS); + + // If either side is a variable array, and both are complete, check whether + // the current dimension is definite. + if (LVAT || RVAT) { + auto SizeFetch = [this](const VariableArrayType* VAT, + const ConstantArrayType* CAT) + -> std::pair<bool,llvm::APInt> { + if (VAT) { + llvm::APSInt TheInt; + Expr *E = VAT->getSizeExpr(); + if (E && E->isIntegerConstantExpr(TheInt, *this)) + return std::make_pair(true, TheInt); + else + return std::make_pair(false, TheInt); + } else if (CAT) { + return std::make_pair(true, CAT->getSize()); + } else { + return std::make_pair(false, llvm::APInt()); + } + }; + + bool HaveLSize, HaveRSize; + llvm::APInt LSize, RSize; + std::tie(HaveLSize, LSize) = SizeFetch(LVAT, LCAT); + std::tie(HaveRSize, RSize) = SizeFetch(RVAT, RCAT); + if (HaveLSize && HaveRSize && !llvm::APInt::isSameValue(LSize, RSize)) + return {}; // Definite, but unequal, array dimension + } + if (LCAT && getCanonicalType(LHSElem) == getCanonicalType(ResultType)) return LHS; if (RCAT && getCanonicalType(RHSElem) == getCanonicalType(ResultType)) @@ -8581,8 +8819,6 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, ArrayType::ArraySizeModifier(), 0); if (RCAT) return getConstantArrayType(ResultType, RCAT->getSize(), ArrayType::ArraySizeModifier(), 0); - const VariableArrayType* LVAT = getAsVariableArrayType(LHS); - const VariableArrayType* RVAT = getAsVariableArrayType(RHS); if (LVAT && getCanonicalType(LHSElem) == getCanonicalType(ResultType)) return LHS; if (RVAT && getCanonicalType(RHSElem) == getCanonicalType(ResultType)) @@ -8608,29 +8844,29 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, return mergeFunctionTypes(LHS, RHS, OfBlockPointer, Unqualified); case Type::Record: case Type::Enum: - return QualType(); + return {}; case Type::Builtin: // Only exactly equal builtin types are compatible, which is tested above. - return QualType(); + return {}; case Type::Complex: // Distinct complex types are incompatible. - return QualType(); + return {}; case Type::Vector: // FIXME: The merged type should be an ExtVector! if (areCompatVectorTypes(LHSCan->getAs<VectorType>(), RHSCan->getAs<VectorType>())) return LHS; - return QualType(); + return {}; case Type::ObjCObject: { // Check if the types are assignment compatible. // FIXME: This should be type compatibility, e.g. whether // "LHS x; RHS x;" at global scope is legal. - const ObjCObjectType* LHSIface = LHS->getAs<ObjCObjectType>(); - const ObjCObjectType* RHSIface = RHS->getAs<ObjCObjectType>(); + const auto *LHSIface = LHS->getAs<ObjCObjectType>(); + const auto *RHSIface = RHS->getAs<ObjCObjectType>(); if (canAssignObjCInterfaces(LHSIface, RHSIface)) return LHS; - return QualType(); + return {}; } case Type::ObjCObjectPointer: if (OfBlockPointer) { @@ -8639,17 +8875,17 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, RHS->getAs<ObjCObjectPointerType>(), BlockReturnType)) return LHS; - return QualType(); + return {}; } if (canAssignObjCInterfaces(LHS->getAs<ObjCObjectPointerType>(), RHS->getAs<ObjCObjectPointerType>())) return LHS; - return QualType(); + return {}; case Type::Pipe: assert(LHS != RHS && "Equivalent pipe types should have already been handled!"); - return QualType(); + return {}; } llvm_unreachable("Invalid Type::Class!"); @@ -8717,7 +8953,7 @@ QualType ASTContext::mergeObjCGCQualifiers(QualType LHS, QualType RHS) { return LHS; if (RHSCan->isFunctionType()) { if (!LHSCan->isFunctionType()) - return QualType(); + return {}; QualType OldReturnType = cast<FunctionType>(RHSCan.getTypePtr())->getReturnType(); QualType NewReturnType = @@ -8725,12 +8961,12 @@ QualType ASTContext::mergeObjCGCQualifiers(QualType LHS, QualType RHS) { QualType ResReturnType = mergeObjCGCQualifiers(NewReturnType, OldReturnType); if (ResReturnType.isNull()) - return QualType(); + return {}; if (ResReturnType == NewReturnType || ResReturnType == OldReturnType) { // id foo(); ... __strong id foo(); or: __strong id foo(); ... id foo(); // In either case, use OldReturnType to build the new function type. - const FunctionType *F = LHS->getAs<FunctionType>(); - if (const FunctionProtoType *FPT = cast<FunctionProtoType>(F)) { + const auto *F = LHS->getAs<FunctionType>(); + if (const auto *FPT = cast<FunctionProtoType>(F)) { FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); EPI.ExtInfo = getFunctionExtInfo(LHS); QualType ResultType = @@ -8738,7 +8974,7 @@ QualType ASTContext::mergeObjCGCQualifiers(QualType LHS, QualType RHS) { return ResultType; } } - return QualType(); + return {}; } // If the qualifiers are different, the types can still be merged. @@ -8748,7 +8984,7 @@ QualType ASTContext::mergeObjCGCQualifiers(QualType LHS, QualType RHS) { // If any of these qualifiers are different, we have a type mismatch. if (LQuals.getCVRQualifiers() != RQuals.getCVRQualifiers() || LQuals.getAddressSpace() != RQuals.getAddressSpace()) - return QualType(); + return {}; // Exactly one GC qualifier difference is allowed: __strong is // okay if the other type has no GC qualifier but is an Objective @@ -8760,13 +8996,13 @@ QualType ASTContext::mergeObjCGCQualifiers(QualType LHS, QualType RHS) { assert((GC_L != GC_R) && "unequal qualifier sets had only equal elements"); if (GC_L == Qualifiers::Weak || GC_R == Qualifiers::Weak) - return QualType(); + return {}; if (GC_L == Qualifiers::Strong) return LHS; if (GC_R == Qualifiers::Strong) return RHS; - return QualType(); + return {}; } if (LHSCan->isObjCObjectPointerType() && RHSCan->isObjCObjectPointerType()) { @@ -8778,7 +9014,7 @@ QualType ASTContext::mergeObjCGCQualifiers(QualType LHS, QualType RHS) { if (ResQT == RHSBaseQT) return RHS; } - return QualType(); + return {}; } //===----------------------------------------------------------------------===// @@ -8786,7 +9022,7 @@ QualType ASTContext::mergeObjCGCQualifiers(QualType LHS, QualType RHS) { //===----------------------------------------------------------------------===// unsigned ASTContext::getIntWidth(QualType T) const { - if (const EnumType *ET = T->getAs<EnumType>()) + if (const auto *ET = T->getAs<EnumType>()) T = ET->getDecl()->getIntegerType(); if (T->isBooleanType()) return 1; @@ -8795,19 +9031,20 @@ unsigned ASTContext::getIntWidth(QualType T) const { } QualType ASTContext::getCorrespondingUnsignedType(QualType T) const { - assert(T->hasSignedIntegerRepresentation() && "Unexpected type"); + assert((T->hasSignedIntegerRepresentation() || T->isSignedFixedPointType()) && + "Unexpected type"); // Turn <4 x signed int> -> <4 x unsigned int> - if (const VectorType *VTy = T->getAs<VectorType>()) + if (const auto *VTy = T->getAs<VectorType>()) return getVectorType(getCorrespondingUnsignedType(VTy->getElementType()), VTy->getNumElements(), VTy->getVectorKind()); // For enums, we return the unsigned version of the base type. - if (const EnumType *ETy = T->getAs<EnumType>()) + if (const auto *ETy = T->getAs<EnumType>()) T = ETy->getDecl()->getIntegerType(); - const BuiltinType *BTy = T->getAs<BuiltinType>(); - assert(BTy && "Unexpected signed integer type"); + const auto *BTy = T->getAs<BuiltinType>(); + assert(BTy && "Unexpected signed integer or fixed point type"); switch (BTy->getKind()) { case BuiltinType::Char_S: case BuiltinType::SChar: @@ -8822,8 +9059,33 @@ QualType ASTContext::getCorrespondingUnsignedType(QualType T) const { return UnsignedLongLongTy; case BuiltinType::Int128: return UnsignedInt128Ty; + + case BuiltinType::ShortAccum: + return UnsignedShortAccumTy; + case BuiltinType::Accum: + return UnsignedAccumTy; + case BuiltinType::LongAccum: + return UnsignedLongAccumTy; + case BuiltinType::SatShortAccum: + return SatUnsignedShortAccumTy; + case BuiltinType::SatAccum: + return SatUnsignedAccumTy; + case BuiltinType::SatLongAccum: + return SatUnsignedLongAccumTy; + case BuiltinType::ShortFract: + return UnsignedShortFractTy; + case BuiltinType::Fract: + return UnsignedFractTy; + case BuiltinType::LongFract: + return UnsignedLongFractTy; + case BuiltinType::SatShortFract: + return SatUnsignedShortFractTy; + case BuiltinType::SatFract: + return SatUnsignedFractTy; + case BuiltinType::SatLongFract: + return SatUnsignedLongFractTy; default: - llvm_unreachable("Unexpected signed integer type"); + llvm_unreachable("Unexpected signed integer or fixed point type"); } } @@ -8931,10 +9193,12 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context, Type = Context.FloatTy; break; case 'd': - assert(HowLong < 2 && !Signed && !Unsigned && + assert(HowLong < 3 && !Signed && !Unsigned && "Bad modifiers used with 'd'!"); - if (HowLong) + if (HowLong == 1) Type = Context.LongDoubleTy; + else if (HowLong == 2) + Type = Context.Float128Ty; else Type = Context.DoubleTy; break; @@ -9050,7 +9314,7 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context, Type = Context.getFILEType(); if (Type.isNull()) { Error = ASTContext::GE_Missing_stdio; - return QualType(); + return {}; } break; case 'J': @@ -9061,7 +9325,7 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context, if (Type.isNull()) { Error = ASTContext::GE_Missing_setjmp; - return QualType(); + return {}; } break; case 'K': @@ -9070,7 +9334,7 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context, if (Type.isNull()) { Error = ASTContext::GE_Missing_ucontext; - return QualType(); + return {}; } break; case 'p': @@ -9132,14 +9396,14 @@ QualType ASTContext::GetBuiltinType(unsigned Id, QualType ResType = DecodeTypeFromStr(TypeStr, *this, Error, RequiresICE, true); if (Error != GE_None) - return QualType(); + return {}; assert(!RequiresICE && "Result of intrinsic cannot be required to be an ICE"); while (TypeStr[0] && TypeStr[0] != '.') { QualType Ty = DecodeTypeFromStr(TypeStr, *this, Error, RequiresICE, true); if (Error != GE_None) - return QualType(); + return {}; // If this argument is required to be an IntegerConstantExpression and the // caller cares, fill in the bitmask we return. @@ -9154,7 +9418,7 @@ QualType ASTContext::GetBuiltinType(unsigned Id, } if (Id == Builtin::BI__GetExceptionInfo) - return QualType(); + return {}; assert((TypeStr[0] != '.' || TypeStr[1] == 0) && "'.' should only occur at end of builtin type list!"); @@ -9185,7 +9449,7 @@ static GVALinkage basicGVALinkageForFunction(const ASTContext &Context, // Non-user-provided functions get emitted as weak definitions with every // use, no matter whether they've been explicitly instantiated etc. - if (auto *MD = dyn_cast<CXXMethodDecl>(FD)) + if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) if (!MD->isUserProvided()) return GVA_DiscardableODR; @@ -9240,6 +9504,21 @@ static GVALinkage basicGVALinkageForFunction(const ASTContext &Context, return GVA_DiscardableODR; } +static bool isDeclareTargetToDeclaration(const Decl *VD) { + for (const Decl *D : VD->redecls()) { + if (!D->hasAttrs()) + continue; + if (const auto *Attr = D->getAttr<OMPDeclareTargetDeclAttr>()) + return Attr->getMapType() == OMPDeclareTargetDeclAttr::MT_To; + } + if (const auto *V = dyn_cast<VarDecl>(VD)) { + if (const VarDecl *TD = V->getTemplateInstantiationPattern()) + return isDeclareTargetToDeclaration(TD); + } + + return false; +} + static GVALinkage adjustGVALinkageForAttributes(const ASTContext &Context, const Decl *D, GVALinkage L) { // See http://msdn.microsoft.com/en-us/library/xa0d9ste.aspx @@ -9256,6 +9535,12 @@ static GVALinkage adjustGVALinkageForAttributes(const ASTContext &Context, // visible externally so they can be launched from host. if (L == GVA_DiscardableODR || L == GVA_Internal) return GVA_StrongODR; + } else if (Context.getLangOpts().OpenMP && Context.getLangOpts().OpenMPIsDevice && + isDeclareTargetToDeclaration(D)) { + // Static variables must be visible externally so they can be mapped from + // host. + if (L == GVA_Internal) + return GVA_StrongODR; } return L; } @@ -9375,7 +9660,7 @@ GVALinkage ASTContext::GetGVALinkageForVariable(const VarDecl *VD) { } bool ASTContext::DeclMustBeEmitted(const Decl *D) { - if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { + if (const auto *VD = dyn_cast<VarDecl>(D)) { if (!VD->isFileVarDecl()) return false; // Global named register variables (GNU extension) are never emitted. @@ -9384,14 +9669,13 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) { if (VD->getDescribedVarTemplate() || isa<VarTemplatePartialSpecializationDecl>(VD)) return false; - } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + } else if (const auto *FD = dyn_cast<FunctionDecl>(D)) { // We never need to emit an uninstantiated function template. if (FD->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate) return false; } else if (isa<PragmaCommentDecl>(D)) return true; - else if (isa<OMPThreadPrivateDecl>(D) || - D->hasAttr<OMPDeclareTargetDeclAttr>()) + else if (isa<OMPThreadPrivateDecl>(D)) return true; else if (isa<PragmaDetectMismatchDecl>(D)) return true; @@ -9404,6 +9688,29 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) { else return false; + if (D->isFromASTFile() && !LangOpts.BuildingPCHWithObjectFile) { + assert(getExternalSource() && "It's from an AST file; must have a source."); + // On Windows, PCH files are built together with an object file. If this + // declaration comes from such a PCH and DeclMustBeEmitted would return + // true, it would have returned true and the decl would have been emitted + // into that object file, so it doesn't need to be emitted here. + // Note that decls are still emitted if they're referenced, as usual; + // DeclMustBeEmitted is used to decide whether a decl must be emitted even + // if it's not referenced. + // + // Explicit template instantiation definitions are tricky. If there was an + // explicit template instantiation decl in the PCH before, it will look like + // the definition comes from there, even if that was just the declaration. + // (Explicit instantiation defs of variable templates always get emitted.) + bool IsExpInstDef = + isa<FunctionDecl>(D) && + cast<FunctionDecl>(D)->getTemplateSpecializationKind() == + TSK_ExplicitInstantiationDefinition; + + if (getExternalSource()->DeclIsFromPCHWithObjectFile(D) && !IsExpInstDef) + return false; + } + // If this is a member of a class template, we do not need to emit it. if (D->getDeclContext()->isDependentContext()) return false; @@ -9416,7 +9723,7 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) { if (D->hasAttr<AliasAttr>() || D->hasAttr<UsedAttr>()) return true; - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + if (const auto *FD = dyn_cast<FunctionDecl>(D)) { // Forward declarations aren't required. if (!FD->doesThisDeclarationHaveABody()) return FD->doesDeclarationForceExternallyVisibleDefinition(); @@ -9424,11 +9731,11 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) { // Constructors and destructors are required. if (FD->hasAttr<ConstructorAttr>() || FD->hasAttr<DestructorAttr>()) return true; - + // The key function for a class is required. This rule only comes // into play when inline functions can be key functions, though. if (getTargetInfo().getCXXABI().canKeyFunctionBeInline()) { - if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) { + if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) { const CXXRecordDecl *RD = MD->getParent(); if (MD->isOutOfLine() && RD->isDynamicClass()) { const CXXMethodDecl *KeyFunc = getCurrentKeyFunction(RD); @@ -9445,8 +9752,8 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) { // Implicit template instantiations can also be deferred in C++. return !isDiscardableGVALinkage(Linkage); } - - const VarDecl *VD = cast<VarDecl>(D); + + const auto *VD = cast<VarDecl>(D); assert(VD->isFileVarDecl() && "Expected file scoped var"); if (VD->isThisDeclarationADefinition() == VarDecl::DeclarationOnly && @@ -9474,15 +9781,41 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) { // Likewise, variables with tuple-like bindings are required if their // bindings have side-effects. - if (auto *DD = dyn_cast<DecompositionDecl>(VD)) - for (auto *BD : DD->bindings()) - if (auto *BindingVD = BD->getHoldingVar()) + if (const auto *DD = dyn_cast<DecompositionDecl>(VD)) + for (const auto *BD : DD->bindings()) + if (const auto *BindingVD = BD->getHoldingVar()) if (DeclMustBeEmitted(BindingVD)) return true; + // If the decl is marked as `declare target`, it should be emitted. + for (const auto *Decl : D->redecls()) { + if (!Decl->hasAttrs()) + continue; + if (const auto *Attr = Decl->getAttr<OMPDeclareTargetDeclAttr>()) + if (Attr->getMapType() != OMPDeclareTargetDeclAttr::MT_Link) + return true; + } + return false; } +void ASTContext::forEachMultiversionedFunctionVersion( + const FunctionDecl *FD, + llvm::function_ref<void(const FunctionDecl *)> Pred) const { + assert(FD->isMultiVersion() && "Only valid for multiversioned functions"); + llvm::SmallDenseSet<const FunctionDecl*, 4> SeenDecls; + FD = FD->getCanonicalDecl(); + for (auto *CurDecl : + FD->getDeclContext()->getRedeclContext()->lookup(FD->getDeclName())) { + FunctionDecl *CurFD = CurDecl->getAsFunction()->getCanonicalDecl(); + if (CurFD && hasSameType(CurFD->getType(), FD->getType()) && + std::end(SeenDecls) == llvm::find(SeenDecls, CurFD)) { + SeenDecls.insert(CurFD); + Pred(CurFD); + } + } +} + CallingConv ASTContext::getDefaultCallingConvention(bool IsVariadic, bool IsCXXMethod) const { // Pass through to the C++ ABI object @@ -9595,7 +9928,7 @@ QualType ASTContext::getRealTypeForBitwidth(unsigned DestWidth) const { case TargetInfo::Float128: return Float128Ty; case TargetInfo::NoFloat: - return QualType(); + return {}; } llvm_unreachable("Unhandled TargetInfo::RealType value"); @@ -9739,7 +10072,7 @@ createDynTypedNode(const NestedNameSpecifierLoc &Node) { } /// @} - /// \brief A \c RecursiveASTVisitor that builds a map from nodes to their + /// 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 @@ -9749,7 +10082,7 @@ createDynTypedNode(const NestedNameSpecifierLoc &Node) { /// 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. + /// Builds and returns the translation unit's parent map. /// /// The caller takes ownership of the returned \c ParentMap. static std::pair<ASTContext::ParentMapPointers *, @@ -9874,7 +10207,8 @@ static ASTContext::DynTypedNodeList getDynNodeFromMap(const NodeTy &Node, if (I == Map.end()) { return llvm::ArrayRef<ast_type_traits::DynTypedNode>(); } - if (auto *V = I->second.template dyn_cast<ASTContext::ParentVector *>()) { + if (const auto *V = + I->second.template dyn_cast<ASTContext::ParentVector *>()) { return llvm::makeArrayRef(*V); } return getSingleDynTypedNodeFromParentMap(I->second); @@ -9942,6 +10276,42 @@ unsigned ASTContext::getTargetAddressSpace(LangAS AS) const { return (*AddrSpaceMap)[(unsigned)AS]; } +QualType ASTContext::getCorrespondingSaturatedType(QualType Ty) const { + assert(Ty->isFixedPointType()); + + if (Ty->isSaturatedFixedPointType()) return Ty; + + const auto &BT = Ty->getAs<BuiltinType>(); + switch (BT->getKind()) { + default: + llvm_unreachable("Not a fixed point type!"); + case BuiltinType::ShortAccum: + return SatShortAccumTy; + case BuiltinType::Accum: + return SatAccumTy; + case BuiltinType::LongAccum: + return SatLongAccumTy; + case BuiltinType::UShortAccum: + return SatUnsignedShortAccumTy; + case BuiltinType::UAccum: + return SatUnsignedAccumTy; + case BuiltinType::ULongAccum: + return SatUnsignedLongAccumTy; + case BuiltinType::ShortFract: + return SatShortFractTy; + case BuiltinType::Fract: + return SatFractTy; + case BuiltinType::LongFract: + return SatLongFractTy; + case BuiltinType::UShortFract: + return SatUnsignedShortFractTy; + case BuiltinType::UFract: + return SatUnsignedFractTy; + case BuiltinType::ULongFract: + return SatUnsignedLongFractTy; + } +} + // Explicitly instantiate this in case a Redeclarable<T> is used from a TU that // doesn't include ASTContext.h template @@ -9950,3 +10320,92 @@ clang::LazyGenerationalUpdatePtr< clang::LazyGenerationalUpdatePtr< const Decl *, Decl *, &ExternalASTSource::CompleteRedeclChain>::makeValue( const clang::ASTContext &Ctx, Decl *Value); + +unsigned char ASTContext::getFixedPointScale(QualType Ty) const { + assert(Ty->isFixedPointType()); + + const auto *BT = Ty->getAs<BuiltinType>(); + const TargetInfo &Target = getTargetInfo(); + switch (BT->getKind()) { + default: + llvm_unreachable("Not a fixed point type!"); + case BuiltinType::ShortAccum: + case BuiltinType::SatShortAccum: + return Target.getShortAccumScale(); + case BuiltinType::Accum: + case BuiltinType::SatAccum: + return Target.getAccumScale(); + case BuiltinType::LongAccum: + case BuiltinType::SatLongAccum: + return Target.getLongAccumScale(); + case BuiltinType::UShortAccum: + case BuiltinType::SatUShortAccum: + return Target.getUnsignedShortAccumScale(); + case BuiltinType::UAccum: + case BuiltinType::SatUAccum: + return Target.getUnsignedAccumScale(); + case BuiltinType::ULongAccum: + case BuiltinType::SatULongAccum: + return Target.getUnsignedLongAccumScale(); + case BuiltinType::ShortFract: + case BuiltinType::SatShortFract: + return Target.getShortFractScale(); + case BuiltinType::Fract: + case BuiltinType::SatFract: + return Target.getFractScale(); + case BuiltinType::LongFract: + case BuiltinType::SatLongFract: + return Target.getLongFractScale(); + case BuiltinType::UShortFract: + case BuiltinType::SatUShortFract: + return Target.getUnsignedShortFractScale(); + case BuiltinType::UFract: + case BuiltinType::SatUFract: + return Target.getUnsignedFractScale(); + case BuiltinType::ULongFract: + case BuiltinType::SatULongFract: + return Target.getUnsignedLongFractScale(); + } +} + +unsigned char ASTContext::getFixedPointIBits(QualType Ty) const { + assert(Ty->isFixedPointType()); + + const auto *BT = Ty->getAs<BuiltinType>(); + const TargetInfo &Target = getTargetInfo(); + switch (BT->getKind()) { + default: + llvm_unreachable("Not a fixed point type!"); + case BuiltinType::ShortAccum: + case BuiltinType::SatShortAccum: + return Target.getShortAccumIBits(); + case BuiltinType::Accum: + case BuiltinType::SatAccum: + return Target.getAccumIBits(); + case BuiltinType::LongAccum: + case BuiltinType::SatLongAccum: + return Target.getLongAccumIBits(); + case BuiltinType::UShortAccum: + case BuiltinType::SatUShortAccum: + return Target.getUnsignedShortAccumIBits(); + case BuiltinType::UAccum: + case BuiltinType::SatUAccum: + return Target.getUnsignedAccumIBits(); + case BuiltinType::ULongAccum: + case BuiltinType::SatULongAccum: + return Target.getUnsignedLongAccumIBits(); + case BuiltinType::ShortFract: + case BuiltinType::SatShortFract: + case BuiltinType::Fract: + case BuiltinType::SatFract: + case BuiltinType::LongFract: + case BuiltinType::SatLongFract: + case BuiltinType::UShortFract: + case BuiltinType::SatUShortFract: + case BuiltinType::UFract: + case BuiltinType::SatUFract: + case BuiltinType::ULongFract: + case BuiltinType::SatULongFract: + return 0; + } +} diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp index b43c28deb362..c4c0f6e5ebe3 100644 --- a/lib/AST/ASTDiagnostic.cpp +++ b/lib/AST/ASTDiagnostic.cpp @@ -200,7 +200,7 @@ break; \ return QC.apply(Context, QT); } -/// \brief Convert the given type to a string suitable for printing as part of +/// Convert the given type to a string suitable for printing as part of /// a diagnostic. /// /// There are four main criteria when determining whether we should have an diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 92be6d95e898..f46ae58d192d 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -521,10 +521,12 @@ namespace { // Exprs void VisitExpr(const Expr *Node); void VisitCastExpr(const CastExpr *Node); + void VisitImplicitCastExpr(const ImplicitCastExpr *Node); void VisitDeclRefExpr(const DeclRefExpr *Node); void VisitPredefinedExpr(const PredefinedExpr *Node); void VisitCharacterLiteral(const CharacterLiteral *Node); void VisitIntegerLiteral(const IntegerLiteral *Node); + void VisitFixedPointLiteral(const FixedPointLiteral *Node); void VisitFloatingLiteral(const FloatingLiteral *Node); void VisitStringLiteral(const StringLiteral *Str); void VisitInitListExpr(const InitListExpr *ILE); @@ -539,6 +541,7 @@ namespace { void VisitAddrLabelExpr(const AddrLabelExpr *Node); void VisitBlockExpr(const BlockExpr *Node); void VisitOpaqueValueExpr(const OpaqueValueExpr *Node); + void VisitGenericSelectionExpr(const GenericSelectionExpr *E); // C++ void VisitCXXNamedCastExpr(const CXXNamedCastExpr *Node); @@ -808,11 +811,10 @@ void ASTDumper::dumpLookups(const DeclContext *DC, bool DumpDecls) { bool HasUndeserializedLookups = Primary->hasExternalVisibleStorage(); - for (auto I = Deserialize ? Primary->lookups_begin() - : Primary->noload_lookups_begin(), - E = Deserialize ? Primary->lookups_end() - : Primary->noload_lookups_end(); - I != E; ++I) { + auto Range = Deserialize + ? Primary->lookups() + : Primary->noload_lookups(/*PreserveInternalState=*/true); + for (auto I = Range.begin(), E = Range.end(); I != E; ++I) { DeclarationName Name = I.getLookupName(); DeclContextLookupResult R = *I; @@ -1602,7 +1604,7 @@ void ASTDumper::VisitClassTemplatePartialSpecializationDecl( void ASTDumper::VisitClassScopeFunctionSpecializationDecl( const ClassScopeFunctionSpecializationDecl *D) { - dumpDeclRef(D->getSpecialization()); + dumpDecl(D->getSpecialization()); if (D->hasExplicitTemplateArgs()) dumpTemplateArgumentListInfo(D->templateArgs()); } @@ -1946,10 +1948,15 @@ void ASTDumper::dumpStmt(const Stmt *S) { return; } + // Some statements have custom mechanisms for dumping their children. if (const DeclStmt *DS = dyn_cast<DeclStmt>(S)) { VisitDeclStmt(DS); return; } + if (const GenericSelectionExpr *GSE = dyn_cast<GenericSelectionExpr>(S)) { + VisitGenericSelectionExpr(GSE); + return; + } ConstStmtVisitor<ASTDumper>::Visit(S); @@ -2113,6 +2120,12 @@ void ASTDumper::VisitCastExpr(const CastExpr *Node) { OS << ">"; } +void ASTDumper::VisitImplicitCastExpr(const ImplicitCastExpr *Node) { + VisitCastExpr(Node); + if (Node->isPartOfExplicitCast()) + OS << " part_of_explicit_cast"; +} + void ASTDumper::VisitDeclRefExpr(const DeclRefExpr *Node) { VisitExpr(Node); @@ -2172,6 +2185,13 @@ void ASTDumper::VisitIntegerLiteral(const IntegerLiteral *Node) { OS << " " << Node->getValue().toString(10, isSigned); } +void ASTDumper::VisitFixedPointLiteral(const FixedPointLiteral *Node) { + VisitExpr(Node); + + ColorScope Color(*this, ValueColor); + OS << " " << Node->getValueAsString(/*Radix=*/10); +} + void ASTDumper::VisitFloatingLiteral(const FloatingLiteral *Node) { VisitExpr(Node); ColorScope Color(*this, ValueColor); @@ -2211,6 +2231,8 @@ void ASTDumper::VisitUnaryOperator(const UnaryOperator *Node) { VisitExpr(Node); OS << " " << (Node->isPostfix() ? "postfix" : "prefix") << " '" << UnaryOperator::getOpcodeStr(Node->getOpcode()) << "'"; + if (!Node->canOverflow()) + OS << " cannot overflow"; } void ASTDumper::VisitUnaryExprOrTypeTraitExpr( @@ -2272,6 +2294,32 @@ void ASTDumper::VisitOpaqueValueExpr(const OpaqueValueExpr *Node) { dumpStmt(Source); } +void ASTDumper::VisitGenericSelectionExpr(const GenericSelectionExpr *E) { + VisitExpr(E); + if (E->isResultDependent()) + OS << " result_dependent"; + dumpStmt(E->getControllingExpr()); + dumpTypeAsChild(E->getControllingExpr()->getType()); // FIXME: remove + + for (unsigned I = 0, N = E->getNumAssocs(); I != N; ++I) { + dumpChild([=] { + if (const TypeSourceInfo *TSI = E->getAssocTypeSourceInfo(I)) { + OS << "case "; + dumpType(TSI->getType()); + } else { + OS << "default"; + } + + if (!E->isResultDependent() && E->getResultIndex() == I) + OS << " selected"; + + if (const TypeSourceInfo *TSI = E->getAssocTypeSourceInfo(I)) + dumpTypeAsChild(TSI->getType()); + dumpStmt(E->getAssocExpr(I)); + }); + } +} + // GNU extensions. void ASTDumper::VisitAddrLabelExpr(const AddrLabelExpr *Node) { diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index 0d1d9807549f..6668067233e4 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -1,4 +1,4 @@ -//===--- ASTImporter.cpp - Importing ASTs from other Contexts ---*- C++ -*-===// +//===- ASTImporter.cpp - Importing ASTs from other Contexts ---------------===// // // The LLVM Compiler Infrastructure // @@ -11,29 +11,165 @@ // context into another context. // //===----------------------------------------------------------------------===// + #include "clang/AST/ASTImporter.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTDiagnostic.h" #include "clang/AST/ASTStructuralEquivalence.h" +#include "clang/AST/Attr.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclAccessPair.h" +#include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclFriend.h" +#include "clang/AST/DeclGroup.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/DeclVisitor.h" +#include "clang/AST/DeclarationName.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" +#include "clang/AST/ExternalASTSource.h" +#include "clang/AST/LambdaCapture.h" +#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/OperationKinds.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/TypeVisitor.h" +#include "clang/AST/UnresolvedSet.h" +#include "clang/Basic/ExceptionSpecificationType.h" #include "clang/Basic/FileManager.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" +#include "clang/Basic/Specifiers.h" +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MemoryBuffer.h" -#include <deque> +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <memory> +#include <type_traits> +#include <utility> namespace clang { + + template <class T> + SmallVector<Decl*, 2> + getCanonicalForwardRedeclChain(Redeclarable<T>* D) { + SmallVector<Decl*, 2> Redecls; + for (auto *R : D->getFirstDecl()->redecls()) { + if (R != D->getFirstDecl()) + Redecls.push_back(R); + } + Redecls.push_back(D->getFirstDecl()); + std::reverse(Redecls.begin(), Redecls.end()); + return Redecls; + } + + SmallVector<Decl*, 2> getCanonicalForwardRedeclChain(Decl* D) { + // Currently only FunctionDecl is supported + auto FD = cast<FunctionDecl>(D); + return getCanonicalForwardRedeclChain<FunctionDecl>(FD); + } + + void updateFlags(const Decl *From, Decl *To) { + // Check if some flags or attrs are new in 'From' and copy into 'To'. + // FIXME: Other flags or attrs? + if (From->isUsed(false) && !To->isUsed(false)) + To->setIsUsed(); + } + class ASTNodeImporter : public TypeVisitor<ASTNodeImporter, QualType>, public DeclVisitor<ASTNodeImporter, Decl *>, public StmtVisitor<ASTNodeImporter, Stmt *> { ASTImporter &Importer; + // Wrapper for an overload set. + template <typename ToDeclT> struct CallOverloadedCreateFun { + template <typename... Args> + auto operator()(Args &&... args) + -> decltype(ToDeclT::Create(std::forward<Args>(args)...)) { + return ToDeclT::Create(std::forward<Args>(args)...); + } + }; + + // Always use these functions to create a Decl during import. There are + // certain tasks which must be done after the Decl was created, e.g. we + // must immediately register that as an imported Decl. The parameter `ToD` + // will be set to the newly created Decl or if had been imported before + // then to the already imported Decl. Returns a bool value set to true if + // the `FromD` had been imported before. + template <typename ToDeclT, typename FromDeclT, typename... Args> + LLVM_NODISCARD bool GetImportedOrCreateDecl(ToDeclT *&ToD, FromDeclT *FromD, + Args &&... args) { + // There may be several overloads of ToDeclT::Create. We must make sure + // to call the one which would be chosen by the arguments, thus we use a + // wrapper for the overload set. + CallOverloadedCreateFun<ToDeclT> OC; + return GetImportedOrCreateSpecialDecl(ToD, OC, FromD, + std::forward<Args>(args)...); + } + // Use this overload if a special Type is needed to be created. E.g if we + // want to create a `TypeAliasDecl` and assign that to a `TypedefNameDecl` + // then: + // TypedefNameDecl *ToTypedef; + // GetImportedOrCreateDecl<TypeAliasDecl>(ToTypedef, FromD, ...); + template <typename NewDeclT, typename ToDeclT, typename FromDeclT, + typename... Args> + LLVM_NODISCARD bool GetImportedOrCreateDecl(ToDeclT *&ToD, FromDeclT *FromD, + Args &&... args) { + CallOverloadedCreateFun<NewDeclT> OC; + return GetImportedOrCreateSpecialDecl(ToD, OC, FromD, + std::forward<Args>(args)...); + } + // Use this version if a special create function must be + // used, e.g. CXXRecordDecl::CreateLambda . + template <typename ToDeclT, typename CreateFunT, typename FromDeclT, + typename... Args> + LLVM_NODISCARD bool + GetImportedOrCreateSpecialDecl(ToDeclT *&ToD, CreateFunT CreateFun, + FromDeclT *FromD, Args &&... args) { + ToD = cast_or_null<ToDeclT>(Importer.GetAlreadyImportedOrNull(FromD)); + if (ToD) + return true; // Already imported. + ToD = CreateFun(std::forward<Args>(args)...); + InitializeImportedDecl(FromD, ToD); + return false; // A new Decl is created. + } + + void InitializeImportedDecl(Decl *FromD, Decl *ToD) { + Importer.MapImported(FromD, ToD); + ToD->IdentifierNamespace = FromD->IdentifierNamespace; + if (FromD->hasAttrs()) + for (const Attr *FromAttr : FromD->getAttrs()) + ToD->addAttr(Importer.Import(FromAttr)); + if (FromD->isUsed()) + ToD->setIsUsed(); + if (FromD->isImplicit()) + ToD->setImplicit(); + } + public: - explicit ASTNodeImporter(ASTImporter &Importer) : Importer(Importer) { } - + explicit ASTNodeImporter(ASTImporter &Importer) : Importer(Importer) {} + using TypeVisitor<ASTNodeImporter, QualType>::Visit; using DeclVisitor<ASTNodeImporter, Decl *>::Visit; using StmtVisitor<ASTNodeImporter, Stmt *>::Visit; @@ -52,7 +188,7 @@ namespace clang { QualType VisitConstantArrayType(const ConstantArrayType *T); QualType VisitIncompleteArrayType(const IncompleteArrayType *T); QualType VisitVariableArrayType(const VariableArrayType *T); - // FIXME: DependentSizedArrayType + QualType VisitDependentSizedArrayType(const DependentSizedArrayType *T); // FIXME: DependentSizedExtVectorType QualType VisitVectorType(const VectorType *T); QualType VisitExtVectorType(const ExtVectorType *T); @@ -76,14 +212,15 @@ namespace clang { QualType VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T); QualType VisitTemplateSpecializationType(const TemplateSpecializationType *T); QualType VisitElaboratedType(const ElaboratedType *T); - // FIXME: DependentNameType + QualType VisitDependentNameType(const DependentNameType *T); QualType VisitPackExpansionType(const PackExpansionType *T); - // FIXME: DependentTemplateSpecializationType + QualType VisitDependentTemplateSpecializationType( + const DependentTemplateSpecializationType *T); QualType VisitObjCInterfaceType(const ObjCInterfaceType *T); QualType VisitObjCObjectType(const ObjCObjectType *T); QualType VisitObjCObjectPointerType(const ObjCObjectPointerType *T); - - // Importing declarations + + // Importing declarations bool ImportDeclParts(NamedDecl *D, DeclContext *&DC, DeclContext *&LexicalDC, DeclarationName &Name, NamedDecl *&ToD, SourceLocation &Loc); @@ -91,22 +228,27 @@ namespace clang { void ImportDeclarationNameLoc(const DeclarationNameInfo &From, DeclarationNameInfo& To); void ImportDeclContext(DeclContext *FromDC, bool ForceImport = false); + void ImportImplicitMethods(const CXXRecordDecl *From, CXXRecordDecl *To); bool ImportCastPath(CastExpr *E, CXXCastPath &Path); - typedef DesignatedInitExpr::Designator Designator; + using Designator = DesignatedInitExpr::Designator; + Designator ImportDesignator(const Designator &D); + Optional<LambdaCapture> ImportLambdaCapture(const LambdaCapture &From); - /// \brief What we should import from the definition. + /// What we should import from the definition. enum ImportDefinitionKind { - /// \brief Import the default subset of the definition, which might be + /// Import the default subset of the definition, which might be /// nothing (if minimal import is set) or might be everything (if minimal /// import is not set). IDK_Default, - /// \brief Import everything. + + /// Import everything. IDK_Everything, - /// \brief Import only the bare bones needed to establish a valid + + /// Import only the bare bones needed to establish a valid /// DeclContext. IDK_Basic }; @@ -127,16 +269,33 @@ namespace clang { bool ImportDefinition(ObjCProtocolDecl *From, ObjCProtocolDecl *To, ImportDefinitionKind Kind = IDK_Default); TemplateParameterList *ImportTemplateParameterList( - TemplateParameterList *Params); + TemplateParameterList *Params); TemplateArgument ImportTemplateArgument(const TemplateArgument &From); Optional<TemplateArgumentLoc> ImportTemplateArgumentLoc( const TemplateArgumentLoc &TALoc); bool ImportTemplateArguments(const TemplateArgument *FromArgs, unsigned NumFromArgs, - SmallVectorImpl<TemplateArgument> &ToArgs); + SmallVectorImpl<TemplateArgument> &ToArgs); + template <typename InContainerTy> bool ImportTemplateArgumentListInfo(const InContainerTy &Container, TemplateArgumentListInfo &ToTAInfo); + + template<typename InContainerTy> + bool ImportTemplateArgumentListInfo(SourceLocation FromLAngleLoc, + SourceLocation FromRAngleLoc, + const InContainerTy &Container, + TemplateArgumentListInfo &Result); + + using TemplateArgsTy = SmallVector<TemplateArgument, 8>; + using OptionalTemplateArgsTy = Optional<TemplateArgsTy>; + std::tuple<FunctionTemplateDecl *, OptionalTemplateArgsTy> + ImportFunctionTemplateWithTemplateArgsFromSpecialization( + FunctionDecl *FromFD); + + bool ImportTemplateInformation(FunctionDecl *FromFD, FunctionDecl *ToFD); + + bool IsStructuralMatch(Decl *From, Decl *To, bool Complain); bool IsStructuralMatch(RecordDecl *FromRecord, RecordDecl *ToRecord, bool Complain = true); bool IsStructuralMatch(VarDecl *FromVar, VarDecl *ToVar, @@ -145,6 +304,7 @@ namespace clang { bool IsStructuralMatch(EnumConstantDecl *FromEC, EnumConstantDecl *ToEC); bool IsStructuralMatch(FunctionTemplateDecl *From, FunctionTemplateDecl *To); + bool IsStructuralMatch(FunctionDecl *From, FunctionDecl *To); bool IsStructuralMatch(ClassTemplateDecl *From, ClassTemplateDecl *To); bool IsStructuralMatch(VarTemplateDecl *From, VarTemplateDecl *To); Decl *VisitDecl(Decl *D); @@ -185,7 +345,6 @@ namespace clang { Decl *VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D); Decl *VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D); - ObjCTypeParamList *ImportObjCTypeParamList(ObjCTypeParamList *list); Decl *VisitObjCInterfaceDecl(ObjCInterfaceDecl *D); Decl *VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D); @@ -282,29 +441,38 @@ namespace clang { Expr *VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *CE); Expr *VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E); Expr *VisitPackExpansionExpr(PackExpansionExpr *E); + Expr *VisitSizeOfPackExpr(SizeOfPackExpr *E); Expr *VisitCXXNewExpr(CXXNewExpr *CE); Expr *VisitCXXDeleteExpr(CXXDeleteExpr *E); Expr *VisitCXXConstructExpr(CXXConstructExpr *E); Expr *VisitCXXMemberCallExpr(CXXMemberCallExpr *E); Expr *VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E); + Expr *VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E); + Expr *VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *CE); + Expr *VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E); + Expr *VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E); Expr *VisitExprWithCleanups(ExprWithCleanups *EWC); Expr *VisitCXXThisExpr(CXXThisExpr *E); Expr *VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E); Expr *VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E); Expr *VisitMemberExpr(MemberExpr *E); Expr *VisitCallExpr(CallExpr *E); + Expr *VisitLambdaExpr(LambdaExpr *LE); Expr *VisitInitListExpr(InitListExpr *E); + Expr *VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E); + Expr *VisitCXXInheritedCtorInitExpr(CXXInheritedCtorInitExpr *E); Expr *VisitArrayInitLoopExpr(ArrayInitLoopExpr *E); Expr *VisitArrayInitIndexExpr(ArrayInitIndexExpr *E); Expr *VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E); Expr *VisitCXXNamedCastExpr(CXXNamedCastExpr *E); Expr *VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *E); Expr *VisitTypeTraitExpr(TypeTraitExpr *E); - + Expr *VisitCXXTypeidExpr(CXXTypeidExpr *E); template<typename IIter, typename OIter> void ImportArray(IIter Ibegin, IIter Iend, OIter Obegin) { - typedef typename std::remove_reference<decltype(*Obegin)>::type ItemT; + using ItemT = typename std::remove_reference<decltype(*Obegin)>::type; + ASTImporter &ImporterRef = Importer; std::transform(Ibegin, Iend, Obegin, [&ImporterRef](ItemT From) -> ItemT { @@ -314,13 +482,13 @@ namespace clang { template<typename IIter, typename OIter> bool ImportArrayChecked(IIter Ibegin, IIter Iend, OIter Obegin) { - typedef typename std::remove_reference<decltype(**Obegin)>::type ItemT; + using ItemT = typename std::remove_reference<decltype(**Obegin)>::type; + ASTImporter &ImporterRef = Importer; bool Failed = false; std::transform(Ibegin, Iend, Obegin, [&ImporterRef, &Failed](ItemT *From) -> ItemT * { - ItemT *To = cast_or_null<ItemT>( - ImporterRef.Import(From)); + auto *To = cast_or_null<ItemT>(ImporterRef.Import(From)); if (!To && From) Failed = true; return To; @@ -342,9 +510,58 @@ namespace clang { // Importing overrides. void ImportOverrides(CXXMethodDecl *ToMethod, CXXMethodDecl *FromMethod); + + FunctionDecl *FindFunctionTemplateSpecialization(FunctionDecl *FromFD); }; + +template <typename InContainerTy> +bool ASTNodeImporter::ImportTemplateArgumentListInfo( + SourceLocation FromLAngleLoc, SourceLocation FromRAngleLoc, + const InContainerTy &Container, TemplateArgumentListInfo &Result) { + TemplateArgumentListInfo ToTAInfo(Importer.Import(FromLAngleLoc), + Importer.Import(FromRAngleLoc)); + if (ImportTemplateArgumentListInfo(Container, ToTAInfo)) + return true; + Result = ToTAInfo; + return false; +} + +template <> +bool ASTNodeImporter::ImportTemplateArgumentListInfo<TemplateArgumentListInfo>( + const TemplateArgumentListInfo &From, TemplateArgumentListInfo &Result) { + return ImportTemplateArgumentListInfo( + From.getLAngleLoc(), From.getRAngleLoc(), From.arguments(), Result); +} + +template <> +bool ASTNodeImporter::ImportTemplateArgumentListInfo< + ASTTemplateArgumentListInfo>(const ASTTemplateArgumentListInfo &From, + TemplateArgumentListInfo &Result) { + return ImportTemplateArgumentListInfo(From.LAngleLoc, From.RAngleLoc, + From.arguments(), Result); +} + +std::tuple<FunctionTemplateDecl *, ASTNodeImporter::OptionalTemplateArgsTy> +ASTNodeImporter::ImportFunctionTemplateWithTemplateArgsFromSpecialization( + FunctionDecl *FromFD) { + assert(FromFD->getTemplatedKind() == + FunctionDecl::TK_FunctionTemplateSpecialization); + auto *FTSInfo = FromFD->getTemplateSpecializationInfo(); + auto *Template = cast_or_null<FunctionTemplateDecl>( + Importer.Import(FTSInfo->getTemplate())); + + // Import template arguments. + auto TemplArgs = FTSInfo->TemplateArguments->asArray(); + TemplateArgsTy ToTemplArgs; + if (ImportTemplateArguments(TemplArgs.data(), TemplArgs.size(), + ToTemplArgs)) // Error during import. + return std::make_tuple(Template, OptionalTemplateArgsTy()); + + return std::make_tuple(Template, ToTemplArgs); } +} // namespace clang + //---------------------------------------------------------------------------- // Import Types //---------------------------------------------------------------------------- @@ -354,13 +571,13 @@ using namespace clang; QualType ASTNodeImporter::VisitType(const Type *T) { Importer.FromDiag(SourceLocation(), diag::err_unsupported_ast_node) << T->getTypeClassName(); - return QualType(); + return {}; } QualType ASTNodeImporter::VisitAtomicType(const AtomicType *T){ QualType UnderlyingType = Importer.Import(T->getValueType()); if(UnderlyingType.isNull()) - return QualType(); + return {}; return Importer.getToContext().getAtomicType(UnderlyingType); } @@ -413,7 +630,7 @@ QualType ASTNodeImporter::VisitBuiltinType(const BuiltinType *T) { QualType ASTNodeImporter::VisitDecayedType(const DecayedType *T) { QualType OrigT = Importer.Import(T->getOriginalType()); if (OrigT.isNull()) - return QualType(); + return {}; return Importer.getToContext().getDecayedType(OrigT); } @@ -421,7 +638,7 @@ QualType ASTNodeImporter::VisitDecayedType(const DecayedType *T) { QualType ASTNodeImporter::VisitComplexType(const ComplexType *T) { QualType ToElementType = Importer.Import(T->getElementType()); if (ToElementType.isNull()) - return QualType(); + return {}; return Importer.getToContext().getComplexType(ToElementType); } @@ -429,7 +646,7 @@ QualType ASTNodeImporter::VisitComplexType(const ComplexType *T) { QualType ASTNodeImporter::VisitPointerType(const PointerType *T) { QualType ToPointeeType = Importer.Import(T->getPointeeType()); if (ToPointeeType.isNull()) - return QualType(); + return {}; return Importer.getToContext().getPointerType(ToPointeeType); } @@ -438,7 +655,7 @@ QualType ASTNodeImporter::VisitBlockPointerType(const BlockPointerType *T) { // FIXME: Check for blocks support in "to" context. QualType ToPointeeType = Importer.Import(T->getPointeeType()); if (ToPointeeType.isNull()) - return QualType(); + return {}; return Importer.getToContext().getBlockPointerType(ToPointeeType); } @@ -448,7 +665,7 @@ ASTNodeImporter::VisitLValueReferenceType(const LValueReferenceType *T) { // FIXME: Check for C++ support in "to" context. QualType ToPointeeType = Importer.Import(T->getPointeeTypeAsWritten()); if (ToPointeeType.isNull()) - return QualType(); + return {}; return Importer.getToContext().getLValueReferenceType(ToPointeeType); } @@ -458,7 +675,7 @@ ASTNodeImporter::VisitRValueReferenceType(const RValueReferenceType *T) { // FIXME: Check for C++0x support in "to" context. QualType ToPointeeType = Importer.Import(T->getPointeeTypeAsWritten()); if (ToPointeeType.isNull()) - return QualType(); + return {}; return Importer.getToContext().getRValueReferenceType(ToPointeeType); } @@ -467,7 +684,7 @@ QualType ASTNodeImporter::VisitMemberPointerType(const MemberPointerType *T) { // FIXME: Check for C++ support in "to" context. QualType ToPointeeType = Importer.Import(T->getPointeeType()); if (ToPointeeType.isNull()) - return QualType(); + return {}; QualType ClassType = Importer.Import(QualType(T->getClass(), 0)); return Importer.getToContext().getMemberPointerType(ToPointeeType, @@ -477,7 +694,7 @@ QualType ASTNodeImporter::VisitMemberPointerType(const MemberPointerType *T) { QualType ASTNodeImporter::VisitConstantArrayType(const ConstantArrayType *T) { QualType ToElementType = Importer.Import(T->getElementType()); if (ToElementType.isNull()) - return QualType(); + return {}; return Importer.getToContext().getConstantArrayType(ToElementType, T->getSize(), @@ -489,7 +706,7 @@ QualType ASTNodeImporter::VisitIncompleteArrayType(const IncompleteArrayType *T) { QualType ToElementType = Importer.Import(T->getElementType()); if (ToElementType.isNull()) - return QualType(); + return {}; return Importer.getToContext().getIncompleteArrayType(ToElementType, T->getSizeModifier(), @@ -499,11 +716,11 @@ ASTNodeImporter::VisitIncompleteArrayType(const IncompleteArrayType *T) { QualType ASTNodeImporter::VisitVariableArrayType(const VariableArrayType *T) { QualType ToElementType = Importer.Import(T->getElementType()); if (ToElementType.isNull()) - return QualType(); + return {}; Expr *Size = Importer.Import(T->getSizeExpr()); if (!Size) - return QualType(); + return {}; SourceRange Brackets = Importer.Import(T->getBracketsRange()); return Importer.getToContext().getVariableArrayType(ToElementType, Size, @@ -512,10 +729,28 @@ QualType ASTNodeImporter::VisitVariableArrayType(const VariableArrayType *T) { Brackets); } +QualType ASTNodeImporter::VisitDependentSizedArrayType( + const DependentSizedArrayType *T) { + QualType ToElementType = Importer.Import(T->getElementType()); + if (ToElementType.isNull()) + return {}; + + // SizeExpr may be null if size is not specified directly. + // For example, 'int a[]'. + Expr *Size = Importer.Import(T->getSizeExpr()); + if (!Size && T->getSizeExpr()) + return {}; + + SourceRange Brackets = Importer.Import(T->getBracketsRange()); + return Importer.getToContext().getDependentSizedArrayType( + ToElementType, Size, T->getSizeModifier(), T->getIndexTypeCVRQualifiers(), + Brackets); +} + QualType ASTNodeImporter::VisitVectorType(const VectorType *T) { QualType ToElementType = Importer.Import(T->getElementType()); if (ToElementType.isNull()) - return QualType(); + return {}; return Importer.getToContext().getVectorType(ToElementType, T->getNumElements(), @@ -525,7 +760,7 @@ QualType ASTNodeImporter::VisitVectorType(const VectorType *T) { QualType ASTNodeImporter::VisitExtVectorType(const ExtVectorType *T) { QualType ToElementType = Importer.Import(T->getElementType()); if (ToElementType.isNull()) - return QualType(); + return {}; return Importer.getToContext().getExtVectorType(ToElementType, T->getNumElements()); @@ -537,7 +772,7 @@ ASTNodeImporter::VisitFunctionNoProtoType(const FunctionNoProtoType *T) { // into C++? Should we make it variadic? QualType ToResultType = Importer.Import(T->getReturnType()); if (ToResultType.isNull()) - return QualType(); + return {}; return Importer.getToContext().getFunctionNoProtoType(ToResultType, T->getExtInfo()); @@ -546,14 +781,14 @@ ASTNodeImporter::VisitFunctionNoProtoType(const FunctionNoProtoType *T) { QualType ASTNodeImporter::VisitFunctionProtoType(const FunctionProtoType *T) { QualType ToResultType = Importer.Import(T->getReturnType()); if (ToResultType.isNull()) - return QualType(); + return {}; // Import argument types SmallVector<QualType, 4> ArgTypes; for (const auto &A : T->param_types()) { QualType ArgType = Importer.Import(A); if (ArgType.isNull()) - return QualType(); + return {}; ArgTypes.push_back(ArgType); } @@ -562,7 +797,7 @@ QualType ASTNodeImporter::VisitFunctionProtoType(const FunctionProtoType *T) { for (const auto &E : T->exceptions()) { QualType ExceptionType = Importer.Import(E); if (ExceptionType.isNull()) - return QualType(); + return {}; ExceptionTypes.push_back(ExceptionType); } @@ -588,16 +823,16 @@ QualType ASTNodeImporter::VisitFunctionProtoType(const FunctionProtoType *T) { QualType ASTNodeImporter::VisitUnresolvedUsingType( const UnresolvedUsingType *T) { - UnresolvedUsingTypenameDecl *ToD = cast_or_null<UnresolvedUsingTypenameDecl>( - Importer.Import(T->getDecl())); + const auto *ToD = + cast_or_null<UnresolvedUsingTypenameDecl>(Importer.Import(T->getDecl())); if (!ToD) - return QualType(); + return {}; - UnresolvedUsingTypenameDecl *ToPrevD = + auto *ToPrevD = cast_or_null<UnresolvedUsingTypenameDecl>( Importer.Import(T->getDecl()->getPreviousDecl())); if (!ToPrevD && T->getDecl()->getPreviousDecl()) - return QualType(); + return {}; return Importer.getToContext().getTypeDeclType(ToD, ToPrevD); } @@ -605,16 +840,16 @@ QualType ASTNodeImporter::VisitUnresolvedUsingType( QualType ASTNodeImporter::VisitParenType(const ParenType *T) { QualType ToInnerType = Importer.Import(T->getInnerType()); if (ToInnerType.isNull()) - return QualType(); + return {}; return Importer.getToContext().getParenType(ToInnerType); } QualType ASTNodeImporter::VisitTypedefType(const TypedefType *T) { - TypedefNameDecl *ToDecl - = dyn_cast_or_null<TypedefNameDecl>(Importer.Import(T->getDecl())); + auto *ToDecl = + dyn_cast_or_null<TypedefNameDecl>(Importer.Import(T->getDecl())); if (!ToDecl) - return QualType(); + return {}; return Importer.getToContext().getTypeDeclType(ToDecl); } @@ -622,7 +857,7 @@ QualType ASTNodeImporter::VisitTypedefType(const TypedefType *T) { QualType ASTNodeImporter::VisitTypeOfExprType(const TypeOfExprType *T) { Expr *ToExpr = Importer.Import(T->getUnderlyingExpr()); if (!ToExpr) - return QualType(); + return {}; return Importer.getToContext().getTypeOfExprType(ToExpr); } @@ -630,7 +865,7 @@ QualType ASTNodeImporter::VisitTypeOfExprType(const TypeOfExprType *T) { QualType ASTNodeImporter::VisitTypeOfType(const TypeOfType *T) { QualType ToUnderlyingType = Importer.Import(T->getUnderlyingType()); if (ToUnderlyingType.isNull()) - return QualType(); + return {}; return Importer.getToContext().getTypeOfType(ToUnderlyingType); } @@ -639,11 +874,11 @@ QualType ASTNodeImporter::VisitDecltypeType(const DecltypeType *T) { // FIXME: Make sure that the "to" context supports C++0x! Expr *ToExpr = Importer.Import(T->getUnderlyingExpr()); if (!ToExpr) - return QualType(); + return {}; QualType UnderlyingType = Importer.Import(T->getUnderlyingType()); if (UnderlyingType.isNull()) - return QualType(); + return {}; return Importer.getToContext().getDecltypeType(ToExpr, UnderlyingType); } @@ -652,7 +887,7 @@ QualType ASTNodeImporter::VisitUnaryTransformType(const UnaryTransformType *T) { QualType ToBaseType = Importer.Import(T->getBaseType()); QualType ToUnderlyingType = Importer.Import(T->getUnderlyingType()); if (ToBaseType.isNull() || ToUnderlyingType.isNull()) - return QualType(); + return {}; return Importer.getToContext().getUnaryTransformType(ToBaseType, ToUnderlyingType, @@ -666,7 +901,7 @@ QualType ASTNodeImporter::VisitAutoType(const AutoType *T) { if (!FromDeduced.isNull()) { ToDeduced = Importer.Import(FromDeduced); if (ToDeduced.isNull()) - return QualType(); + return {}; } return Importer.getToContext().getAutoType(ToDeduced, T->getKeyword(), @@ -675,13 +910,13 @@ QualType ASTNodeImporter::VisitAutoType(const AutoType *T) { QualType ASTNodeImporter::VisitInjectedClassNameType( const InjectedClassNameType *T) { - CXXRecordDecl *D = cast_or_null<CXXRecordDecl>(Importer.Import(T->getDecl())); + auto *D = cast_or_null<CXXRecordDecl>(Importer.Import(T->getDecl())); if (!D) - return QualType(); + return {}; QualType InjType = Importer.Import(T->getInjectedSpecializationType()); if (InjType.isNull()) - return QualType(); + return {}; // FIXME: ASTContext::getInjectedClassNameType is not suitable for AST reading // See comments in InjectedClassNameType definition for details @@ -696,19 +931,17 @@ QualType ASTNodeImporter::VisitInjectedClassNameType( } QualType ASTNodeImporter::VisitRecordType(const RecordType *T) { - RecordDecl *ToDecl - = dyn_cast_or_null<RecordDecl>(Importer.Import(T->getDecl())); + auto *ToDecl = dyn_cast_or_null<RecordDecl>(Importer.Import(T->getDecl())); if (!ToDecl) - return QualType(); + return {}; return Importer.getToContext().getTagDeclType(ToDecl); } QualType ASTNodeImporter::VisitEnumType(const EnumType *T) { - EnumDecl *ToDecl - = dyn_cast_or_null<EnumDecl>(Importer.Import(T->getDecl())); + auto *ToDecl = dyn_cast_or_null<EnumDecl>(Importer.Import(T->getDecl())); if (!ToDecl) - return QualType(); + return {}; return Importer.getToContext().getTagDeclType(ToDecl); } @@ -722,25 +955,24 @@ QualType ASTNodeImporter::VisitAttributedType(const AttributedType *T) { if (!FromModifiedType.isNull()) { ToModifiedType = Importer.Import(FromModifiedType); if (ToModifiedType.isNull()) - return QualType(); + return {}; } if (!FromEquivalentType.isNull()) { ToEquivalentType = Importer.Import(FromEquivalentType); if (ToEquivalentType.isNull()) - return QualType(); + return {}; } return Importer.getToContext().getAttributedType(T->getAttrKind(), ToModifiedType, ToEquivalentType); } - QualType ASTNodeImporter::VisitTemplateTypeParmType( const TemplateTypeParmType *T) { - TemplateTypeParmDecl *ParmDecl = + auto *ParmDecl = cast_or_null<TemplateTypeParmDecl>(Importer.Import(T->getDecl())); if (!ParmDecl && T->getDecl()) - return QualType(); + return {}; return Importer.getToContext().getTemplateTypeParmType( T->getDepth(), T->getIndex(), T->isParameterPack(), ParmDecl); @@ -748,15 +980,15 @@ QualType ASTNodeImporter::VisitTemplateTypeParmType( QualType ASTNodeImporter::VisitSubstTemplateTypeParmType( const SubstTemplateTypeParmType *T) { - const TemplateTypeParmType *Replaced = + const auto *Replaced = cast_or_null<TemplateTypeParmType>(Importer.Import( QualType(T->getReplacedParameter(), 0)).getTypePtr()); if (!Replaced) - return QualType(); + return {}; QualType Replacement = Importer.Import(T->getReplacementType()); if (Replacement.isNull()) - return QualType(); + return {}; Replacement = Replacement.getCanonicalType(); return Importer.getToContext().getSubstTemplateTypeParmType( @@ -767,11 +999,11 @@ QualType ASTNodeImporter::VisitTemplateSpecializationType( const TemplateSpecializationType *T) { TemplateName ToTemplate = Importer.Import(T->getTemplateName()); if (ToTemplate.isNull()) - return QualType(); + return {}; SmallVector<TemplateArgument, 2> ToTemplateArgs; if (ImportTemplateArguments(T->getArgs(), T->getNumArgs(), ToTemplateArgs)) - return QualType(); + return {}; QualType ToCanonType; if (!QualType(T, 0).isCanonical()) { @@ -779,7 +1011,7 @@ QualType ASTNodeImporter::VisitTemplateSpecializationType( = Importer.getFromContext().getCanonicalType(QualType(T, 0)); ToCanonType =Importer.Import(FromCanonType); if (ToCanonType.isNull()) - return QualType(); + return {}; } return Importer.getToContext().getTemplateSpecializationType(ToTemplate, ToTemplateArgs, @@ -792,31 +1024,75 @@ QualType ASTNodeImporter::VisitElaboratedType(const ElaboratedType *T) { if (T->getQualifier()) { ToQualifier = Importer.Import(T->getQualifier()); if (!ToQualifier) - return QualType(); + return {}; } QualType ToNamedType = Importer.Import(T->getNamedType()); if (ToNamedType.isNull()) - return QualType(); + return {}; + + TagDecl *OwnedTagDecl = + cast_or_null<TagDecl>(Importer.Import(T->getOwnedTagDecl())); + if (!OwnedTagDecl && T->getOwnedTagDecl()) + return {}; return Importer.getToContext().getElaboratedType(T->getKeyword(), - ToQualifier, ToNamedType); + ToQualifier, ToNamedType, + OwnedTagDecl); } QualType ASTNodeImporter::VisitPackExpansionType(const PackExpansionType *T) { QualType Pattern = Importer.Import(T->getPattern()); if (Pattern.isNull()) - return QualType(); + return {}; return Importer.getToContext().getPackExpansionType(Pattern, T->getNumExpansions()); } +QualType ASTNodeImporter::VisitDependentTemplateSpecializationType( + const DependentTemplateSpecializationType *T) { + NestedNameSpecifier *Qualifier = Importer.Import(T->getQualifier()); + if (!Qualifier && T->getQualifier()) + return {}; + + IdentifierInfo *Name = Importer.Import(T->getIdentifier()); + if (!Name && T->getIdentifier()) + return {}; + + SmallVector<TemplateArgument, 2> ToPack; + ToPack.reserve(T->getNumArgs()); + if (ImportTemplateArguments(T->getArgs(), T->getNumArgs(), ToPack)) + return {}; + + return Importer.getToContext().getDependentTemplateSpecializationType( + T->getKeyword(), Qualifier, Name, ToPack); +} + +QualType ASTNodeImporter::VisitDependentNameType(const DependentNameType *T) { + NestedNameSpecifier *NNS = Importer.Import(T->getQualifier()); + if (!NNS && T->getQualifier()) + return QualType(); + + IdentifierInfo *Name = Importer.Import(T->getIdentifier()); + if (!Name && T->getIdentifier()) + return QualType(); + + QualType Canon = (T == T->getCanonicalTypeInternal().getTypePtr()) + ? QualType() + : Importer.Import(T->getCanonicalTypeInternal()); + if (!Canon.isNull()) + Canon = Canon.getCanonicalType(); + + return Importer.getToContext().getDependentNameType(T->getKeyword(), NNS, + Name, Canon); +} + QualType ASTNodeImporter::VisitObjCInterfaceType(const ObjCInterfaceType *T) { - ObjCInterfaceDecl *Class - = dyn_cast_or_null<ObjCInterfaceDecl>(Importer.Import(T->getDecl())); + auto *Class = + dyn_cast_or_null<ObjCInterfaceDecl>(Importer.Import(T->getDecl())); if (!Class) - return QualType(); + return {}; return Importer.getToContext().getObjCInterfaceType(Class); } @@ -824,23 +1100,22 @@ QualType ASTNodeImporter::VisitObjCInterfaceType(const ObjCInterfaceType *T) { QualType ASTNodeImporter::VisitObjCObjectType(const ObjCObjectType *T) { QualType ToBaseType = Importer.Import(T->getBaseType()); if (ToBaseType.isNull()) - return QualType(); + return {}; SmallVector<QualType, 4> TypeArgs; for (auto TypeArg : T->getTypeArgsAsWritten()) { QualType ImportedTypeArg = Importer.Import(TypeArg); if (ImportedTypeArg.isNull()) - return QualType(); + return {}; TypeArgs.push_back(ImportedTypeArg); } SmallVector<ObjCProtocolDecl *, 4> Protocols; for (auto *P : T->quals()) { - ObjCProtocolDecl *Protocol - = dyn_cast_or_null<ObjCProtocolDecl>(Importer.Import(P)); + auto *Protocol = dyn_cast_or_null<ObjCProtocolDecl>(Importer.Import(P)); if (!Protocol) - return QualType(); + return {}; Protocols.push_back(Protocol); } @@ -853,7 +1128,7 @@ QualType ASTNodeImporter::VisitObjCObjectPointerType(const ObjCObjectPointerType *T) { QualType ToPointeeType = Importer.Import(T->getPointeeType()); if (ToPointeeType.isNull()) - return QualType(); + return {}; return Importer.getToContext().getObjCObjectPointerType(ToPointeeType); } @@ -866,8 +1141,26 @@ bool ASTNodeImporter::ImportDeclParts(NamedDecl *D, DeclContext *&DC, DeclarationName &Name, NamedDecl *&ToD, SourceLocation &Loc) { + // Check if RecordDecl is in FunctionDecl parameters to avoid infinite loop. + // example: int struct_in_proto(struct data_t{int a;int b;} *d); + DeclContext *OrigDC = D->getDeclContext(); + FunctionDecl *FunDecl; + if (isa<RecordDecl>(D) && (FunDecl = dyn_cast<FunctionDecl>(OrigDC)) && + FunDecl->hasBody()) { + SourceRange RecR = D->getSourceRange(); + SourceRange BodyR = FunDecl->getBody()->getSourceRange(); + // If RecordDecl is not in Body (it is a param), we bail out. + if (RecR.isValid() && BodyR.isValid() && + (RecR.getBegin() < BodyR.getBegin() || + BodyR.getEnd() < RecR.getEnd())) { + Importer.FromDiag(D->getLocation(), diag::err_unsupported_ast_node) + << D->getDeclKindName(); + return true; + } + } + // Import the context of this declaration. - DC = Importer.ImportContext(D->getDeclContext()); + DC = Importer.ImportContext(OrigDC); if (!DC) return true; @@ -899,8 +1192,8 @@ void ASTNodeImporter::ImportDefinitionIfNeeded(Decl *FromD, Decl *ToD) { return; } - if (RecordDecl *FromRecord = dyn_cast<RecordDecl>(FromD)) { - if (RecordDecl *ToRecord = cast_or_null<RecordDecl>(ToD)) { + if (auto *FromRecord = dyn_cast<RecordDecl>(FromD)) { + if (auto *ToRecord = cast_or_null<RecordDecl>(ToD)) { if (FromRecord->getDefinition() && FromRecord->isCompleteDefinition() && !ToRecord->getDefinition()) { ImportDefinition(FromRecord, ToRecord); } @@ -908,8 +1201,8 @@ void ASTNodeImporter::ImportDefinitionIfNeeded(Decl *FromD, Decl *ToD) { return; } - if (EnumDecl *FromEnum = dyn_cast<EnumDecl>(FromD)) { - if (EnumDecl *ToEnum = cast_or_null<EnumDecl>(ToD)) { + if (auto *FromEnum = dyn_cast<EnumDecl>(FromD)) { + if (auto *ToEnum = cast_or_null<EnumDecl>(ToD)) { if (FromEnum->getDefinition() && !ToEnum->getDefinition()) { ImportDefinition(FromEnum, ToEnum); } @@ -963,6 +1256,27 @@ void ASTNodeImporter::ImportDeclContext(DeclContext *FromDC, bool ForceImport) { Importer.Import(From); } +void ASTNodeImporter::ImportImplicitMethods( + const CXXRecordDecl *From, CXXRecordDecl *To) { + assert(From->isCompleteDefinition() && To->getDefinition() == To && + "Import implicit methods to or from non-definition"); + + for (CXXMethodDecl *FromM : From->methods()) + if (FromM->isImplicit()) + Importer.Import(FromM); +} + +static void setTypedefNameForAnonDecl(TagDecl *From, TagDecl *To, + ASTImporter &Importer) { + if (TypedefNameDecl *FromTypedef = From->getTypedefNameForAnonDecl()) { + auto *ToTypedef = + cast_or_null<TypedefNameDecl>(Importer.Import(FromTypedef)); + assert (ToTypedef && "Failed to import typedef of an anonymous structure"); + + To->setTypedefNameForAnonDecl(ToTypedef); + } +} + bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To, ImportDefinitionKind Kind) { if (To->getDefinition() || To->isBeingDefined()) { @@ -973,10 +1287,12 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To, } To->startDefinition(); + + setTypedefNameForAnonDecl(From, To, Importer); // Add base classes. - if (CXXRecordDecl *ToCXX = dyn_cast<CXXRecordDecl>(To)) { - CXXRecordDecl *FromCXX = cast<CXXRecordDecl>(From); + if (auto *ToCXX = dyn_cast<CXXRecordDecl>(To)) { + auto *FromCXX = cast<CXXRecordDecl>(From); struct CXXRecordDecl::DefinitionData &ToData = ToCXX->data(); struct CXXRecordDecl::DefinitionData &FromData = FromCXX->data(); @@ -988,7 +1304,10 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To, ToData.Polymorphic = FromData.Polymorphic; ToData.Abstract = FromData.Abstract; ToData.IsStandardLayout = FromData.IsStandardLayout; - ToData.HasNoNonEmptyBases = FromData.HasNoNonEmptyBases; + ToData.IsCXX11StandardLayout = FromData.IsCXX11StandardLayout; + ToData.HasBasesWithFields = FromData.HasBasesWithFields; + ToData.HasBasesWithNonStaticDataMembers = + FromData.HasBasesWithNonStaticDataMembers; ToData.HasPrivateFields = FromData.HasPrivateFields; ToData.HasProtectedFields = FromData.HasProtectedFields; ToData.HasPublicFields = FromData.HasPublicFields; @@ -1022,7 +1341,6 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To, = FromData.HasConstexprNonCopyMoveConstructor; ToData.HasDefaultedDefaultConstructor = FromData.HasDefaultedDefaultConstructor; - ToData.CanPassInRegisters = FromData.CanPassInRegisters; ToData.DefaultedDefaultConstructorIsConstexpr = FromData.DefaultedDefaultConstructorIsConstexpr; ToData.HasConstexprDefaultConstructor @@ -1043,7 +1361,6 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To, = FromData.HasDeclaredCopyConstructorWithConstParam; ToData.HasDeclaredCopyAssignmentWithConstParam = FromData.HasDeclaredCopyAssignmentWithConstParam; - ToData.IsLambda = FromData.IsLambda; SmallVector<CXXBaseSpecifier *, 4> Bases; for (const auto &Base1 : FromCXX->bases()) { @@ -1103,6 +1420,8 @@ bool ASTNodeImporter::ImportDefinition(EnumDecl *From, EnumDecl *To, To->startDefinition(); + setTypedefNameForAnonDecl(From, To, Importer); + QualType T = Importer.Import(Importer.getFromContext().getTypeDeclType(From)); if (T.isNull()) return true; @@ -1154,36 +1473,36 @@ ASTNodeImporter::ImportTemplateArgument(const TemplateArgument &From) { case TemplateArgument::Type: { QualType ToType = Importer.Import(From.getAsType()); if (ToType.isNull()) - return TemplateArgument(); + return {}; return TemplateArgument(ToType); } case TemplateArgument::Integral: { QualType ToType = Importer.Import(From.getIntegralType()); if (ToType.isNull()) - return TemplateArgument(); + return {}; return TemplateArgument(From, ToType); } case TemplateArgument::Declaration: { - ValueDecl *To = cast_or_null<ValueDecl>(Importer.Import(From.getAsDecl())); + auto *To = cast_or_null<ValueDecl>(Importer.Import(From.getAsDecl())); QualType ToType = Importer.Import(From.getParamTypeForDecl()); if (!To || ToType.isNull()) - return TemplateArgument(); + return {}; return TemplateArgument(To, ToType); } case TemplateArgument::NullPtr: { QualType ToType = Importer.Import(From.getNullPtrType()); if (ToType.isNull()) - return TemplateArgument(); + return {}; return TemplateArgument(ToType, /*isNullPtr*/true); } case TemplateArgument::Template: { TemplateName ToTemplate = Importer.Import(From.getAsTemplate()); if (ToTemplate.isNull()) - return TemplateArgument(); + return {}; return TemplateArgument(ToTemplate); } @@ -1192,7 +1511,7 @@ ASTNodeImporter::ImportTemplateArgument(const TemplateArgument &From) { TemplateName ToTemplate = Importer.Import(From.getAsTemplateOrTemplatePattern()); if (ToTemplate.isNull()) - return TemplateArgument(); + return {}; return TemplateArgument(ToTemplate, From.getNumTemplateExpansions()); } @@ -1206,7 +1525,7 @@ ASTNodeImporter::ImportTemplateArgument(const TemplateArgument &From) { SmallVector<TemplateArgument, 2> ToPack; ToPack.reserve(From.pack_size()); if (ImportTemplateArguments(From.pack_begin(), From.pack_size(), ToPack)) - return TemplateArgument(); + return {}; return TemplateArgument( llvm::makeArrayRef(ToPack).copy(Importer.getToContext())); @@ -1254,6 +1573,9 @@ bool ASTNodeImporter::ImportTemplateArguments(const TemplateArgument *FromArgs, return false; } +// We cannot use Optional<> pattern here and below because +// TemplateArgumentListInfo's operator new is declared as deleted so it cannot +// be stored in Optional. template <typename InContainerTy> bool ASTNodeImporter::ImportTemplateArgumentListInfo( const InContainerTy &Container, TemplateArgumentListInfo &ToTAInfo) { @@ -1266,13 +1588,27 @@ bool ASTNodeImporter::ImportTemplateArgumentListInfo( return false; } -bool ASTNodeImporter::IsStructuralMatch(RecordDecl *FromRecord, +static StructuralEquivalenceKind +getStructuralEquivalenceKind(const ASTImporter &Importer) { + return Importer.isMinimalImport() ? StructuralEquivalenceKind::Minimal + : StructuralEquivalenceKind::Default; +} + +bool ASTNodeImporter::IsStructuralMatch(Decl *From, Decl *To, bool Complain) { + StructuralEquivalenceContext Ctx( + Importer.getFromContext(), Importer.getToContext(), + Importer.getNonEquivalentDecls(), getStructuralEquivalenceKind(Importer), + false, Complain); + return Ctx.IsEquivalent(From, To); +} + +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); + auto *ToOriginRecord = dyn_cast<RecordDecl>(ToOrigin); if (ToOriginRecord) ToRecord = ToOriginRecord; } @@ -1280,36 +1616,46 @@ bool ASTNodeImporter::IsStructuralMatch(RecordDecl *FromRecord, StructuralEquivalenceContext Ctx(Importer.getFromContext(), ToRecord->getASTContext(), Importer.getNonEquivalentDecls(), + getStructuralEquivalenceKind(Importer), false, Complain); - return Ctx.IsStructurallyEquivalent(FromRecord, ToRecord); + return Ctx.IsEquivalent(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); + Importer.getNonEquivalentDecls(), getStructuralEquivalenceKind(Importer), + false, Complain); + return Ctx.IsEquivalent(FromVar, ToVar); } bool ASTNodeImporter::IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToEnum) { - StructuralEquivalenceContext Ctx(Importer.getFromContext(), - Importer.getToContext(), - Importer.getNonEquivalentDecls()); - return Ctx.IsStructurallyEquivalent(FromEnum, ToEnum); + StructuralEquivalenceContext Ctx( + Importer.getFromContext(), Importer.getToContext(), + Importer.getNonEquivalentDecls(), getStructuralEquivalenceKind(Importer)); + return Ctx.IsEquivalent(FromEnum, ToEnum); } bool ASTNodeImporter::IsStructuralMatch(FunctionTemplateDecl *From, FunctionTemplateDecl *To) { StructuralEquivalenceContext Ctx( Importer.getFromContext(), Importer.getToContext(), - Importer.getNonEquivalentDecls(), false, false); - return Ctx.IsStructurallyEquivalent(From, To); + Importer.getNonEquivalentDecls(), getStructuralEquivalenceKind(Importer), + false, false); + return Ctx.IsEquivalent(From, To); +} + +bool ASTNodeImporter::IsStructuralMatch(FunctionDecl *From, FunctionDecl *To) { + StructuralEquivalenceContext Ctx( + Importer.getFromContext(), Importer.getToContext(), + Importer.getNonEquivalentDecls(), getStructuralEquivalenceKind(Importer), + false, false); + return Ctx.IsEquivalent(From, To); } bool ASTNodeImporter::IsStructuralMatch(EnumConstantDecl *FromEC, - EnumConstantDecl *ToEC) -{ + EnumConstantDecl *ToEC) { const llvm::APSInt &FromVal = FromEC->getInitVal(); const llvm::APSInt &ToVal = ToEC->getInitVal(); @@ -1322,16 +1668,18 @@ bool ASTNodeImporter::IsStructuralMatch(ClassTemplateDecl *From, ClassTemplateDecl *To) { StructuralEquivalenceContext Ctx(Importer.getFromContext(), Importer.getToContext(), - Importer.getNonEquivalentDecls()); - return Ctx.IsStructurallyEquivalent(From, To); + Importer.getNonEquivalentDecls(), + getStructuralEquivalenceKind(Importer)); + return Ctx.IsEquivalent(From, To); } bool ASTNodeImporter::IsStructuralMatch(VarTemplateDecl *From, VarTemplateDecl *To) { StructuralEquivalenceContext Ctx(Importer.getFromContext(), Importer.getToContext(), - Importer.getNonEquivalentDecls()); - return Ctx.IsStructurallyEquivalent(From, To); + Importer.getNonEquivalentDecls(), + getStructuralEquivalenceKind(Importer)); + return Ctx.IsEquivalent(From, To); } Decl *ASTNodeImporter::VisitDecl(Decl *D) { @@ -1356,9 +1704,11 @@ Decl *ASTNodeImporter::VisitEmptyDecl(EmptyDecl *D) { // Import the location of this declaration. SourceLocation Loc = Importer.Import(D->getLocation()); - EmptyDecl *ToD = EmptyDecl::Create(Importer.getToContext(), DC, Loc); + EmptyDecl *ToD; + if (GetImportedOrCreateDecl(ToD, D, Importer.getToContext(), DC, Loc)) + return ToD; + ToD->setLexicalDeclContext(LexicalDC); - Importer.Imported(D, ToD); LexicalDC->addDeclInternal(ToD); return ToD; } @@ -1367,13 +1717,12 @@ Decl *ASTNodeImporter::VisitTranslationUnitDecl(TranslationUnitDecl *D) { TranslationUnitDecl *ToD = Importer.getToContext().getTranslationUnitDecl(); - Importer.Imported(D, ToD); + Importer.MapImported(D, ToD); return ToD; } Decl *ASTNodeImporter::VisitAccessSpecDecl(AccessSpecDecl *D) { - SourceLocation Loc = Importer.Import(D->getLocation()); SourceLocation ColonLoc = Importer.Import(D->getColonLoc()); @@ -1382,19 +1731,17 @@ Decl *ASTNodeImporter::VisitAccessSpecDecl(AccessSpecDecl *D) { if (!DC) return nullptr; - AccessSpecDecl *accessSpecDecl - = AccessSpecDecl::Create(Importer.getToContext(), D->getAccess(), - DC, Loc, ColonLoc); - - if (!accessSpecDecl) - return nullptr; + AccessSpecDecl *ToD; + if (GetImportedOrCreateDecl(ToD, D, Importer.getToContext(), D->getAccess(), + DC, Loc, ColonLoc)) + return ToD; // Lexical DeclContext and Semantic DeclContext // is always the same for the accessSpec. - accessSpecDecl->setLexicalDeclContext(DC); - DC->addDeclInternal(accessSpecDecl); + ToD->setLexicalDeclContext(DC); + DC->addDeclInternal(ToD); - return accessSpecDecl; + return ToD; } Decl *ASTNodeImporter::VisitStaticAssertDecl(StaticAssertDecl *D) { @@ -1412,17 +1759,18 @@ Decl *ASTNodeImporter::VisitStaticAssertDecl(StaticAssertDecl *D) { return nullptr; StringLiteral *FromMsg = D->getMessage(); - StringLiteral *ToMsg = cast_or_null<StringLiteral>(Importer.Import(FromMsg)); + auto *ToMsg = cast_or_null<StringLiteral>(Importer.Import(FromMsg)); if (!ToMsg && FromMsg) return nullptr; - StaticAssertDecl *ToD = StaticAssertDecl::Create( - Importer.getToContext(), DC, Loc, AssertExpr, ToMsg, - Importer.Import(D->getRParenLoc()), D->isFailed()); + StaticAssertDecl *ToD; + if (GetImportedOrCreateDecl( + ToD, D, Importer.getToContext(), DC, Loc, AssertExpr, ToMsg, + Importer.Import(D->getRParenLoc()), D->isFailed())) + return ToD; ToD->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToD); - Importer.Imported(D, ToD); return ToD; } @@ -1442,7 +1790,7 @@ Decl *ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) { // This is an anonymous namespace. Adopt an existing anonymous // namespace if we can. // FIXME: Not testable. - if (TranslationUnitDecl *TU = dyn_cast<TranslationUnitDecl>(DC)) + if (auto *TU = dyn_cast<TranslationUnitDecl>(DC)) MergeWithNamespace = TU->getAnonymousNamespace(); else MergeWithNamespace = cast<NamespaceDecl>(DC)->getAnonymousNamespace(); @@ -1450,17 +1798,17 @@ Decl *ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) { SmallVector<NamedDecl *, 4> ConflictingDecls; SmallVector<NamedDecl *, 2> FoundDecls; DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls); - for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { - if (!FoundDecls[I]->isInIdentifierNamespace(Decl::IDNS_Namespace)) + for (auto *FoundDecl : FoundDecls) { + if (!FoundDecl->isInIdentifierNamespace(Decl::IDNS_Namespace)) continue; - if (NamespaceDecl *FoundNS = dyn_cast<NamespaceDecl>(FoundDecls[I])) { + if (auto *FoundNS = dyn_cast<NamespaceDecl>(FoundDecl)) { MergeWithNamespace = FoundNS; ConflictingDecls.clear(); break; } - ConflictingDecls.push_back(FoundDecls[I]); + ConflictingDecls.push_back(FoundDecl); } if (!ConflictingDecls.empty()) { @@ -1473,24 +1821,24 @@ Decl *ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) { // Create the "to" namespace, if needed. NamespaceDecl *ToNamespace = MergeWithNamespace; if (!ToNamespace) { - ToNamespace = NamespaceDecl::Create(Importer.getToContext(), DC, - D->isInline(), - Importer.Import(D->getLocStart()), - Loc, Name.getAsIdentifierInfo(), - /*PrevDecl=*/nullptr); + if (GetImportedOrCreateDecl( + ToNamespace, D, Importer.getToContext(), DC, D->isInline(), + Importer.Import(D->getLocStart()), Loc, Name.getAsIdentifierInfo(), + /*PrevDecl=*/nullptr)) + return ToNamespace; ToNamespace->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToNamespace); // If this is an anonymous namespace, register it as the anonymous // namespace within its context. if (!Name) { - if (TranslationUnitDecl *TU = dyn_cast<TranslationUnitDecl>(DC)) + if (auto *TU = dyn_cast<TranslationUnitDecl>(DC)) TU->setAnonymousNamespace(ToNamespace); else cast<NamespaceDecl>(DC)->setAnonymousNamespace(ToNamespace); } } - Importer.Imported(D, ToNamespace); + Importer.MapImported(D, ToNamespace); ImportDeclContext(D); @@ -1510,8 +1858,8 @@ Decl *ASTNodeImporter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { // NOTE: No conflict resolution is done for namespace aliases now. - NamespaceDecl *TargetDecl = cast_or_null<NamespaceDecl>( - Importer.Import(D->getNamespace())); + auto *TargetDecl = cast_or_null<NamespaceDecl>( + Importer.Import(D->getNamespace())); if (!TargetDecl) return nullptr; @@ -1523,13 +1871,15 @@ Decl *ASTNodeImporter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { if (D->getQualifierLoc() && !ToQLoc) return nullptr; - NamespaceAliasDecl *ToD = NamespaceAliasDecl::Create( - Importer.getToContext(), DC, Importer.Import(D->getNamespaceLoc()), - Importer.Import(D->getAliasLoc()), ToII, ToQLoc, - Importer.Import(D->getTargetNameLoc()), TargetDecl); + NamespaceAliasDecl *ToD; + if (GetImportedOrCreateDecl(ToD, D, Importer.getToContext(), DC, + Importer.Import(D->getNamespaceLoc()), + Importer.Import(D->getAliasLoc()), ToII, ToQLoc, + Importer.Import(D->getTargetNameLoc()), + TargetDecl)) + return ToD; ToD->setLexicalDeclContext(LexicalDC); - Importer.Imported(D, ToD); LexicalDC->addDeclInternal(ToD); return ToD; @@ -1554,17 +1904,16 @@ Decl *ASTNodeImporter::VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias) { unsigned IDNS = Decl::IDNS_Ordinary; SmallVector<NamedDecl *, 2> FoundDecls; DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls); - for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { - if (!FoundDecls[I]->isInIdentifierNamespace(IDNS)) + for (auto *FoundDecl : FoundDecls) { + if (!FoundDecl->isInIdentifierNamespace(IDNS)) continue; - if (TypedefNameDecl *FoundTypedef = - dyn_cast<TypedefNameDecl>(FoundDecls[I])) { + if (auto *FoundTypedef = dyn_cast<TypedefNameDecl>(FoundDecl)) { if (Importer.IsStructurallyEquivalent(D->getUnderlyingType(), FoundTypedef->getUnderlyingType())) - return Importer.Imported(D, FoundTypedef); + return Importer.MapImported(D, FoundTypedef); } - ConflictingDecls.push_back(FoundDecls[I]); + ConflictingDecls.push_back(FoundDecl); } if (!ConflictingDecls.empty()) { @@ -1584,22 +1933,25 @@ Decl *ASTNodeImporter::VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias) { // Create the new typedef node. TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo()); SourceLocation StartL = Importer.Import(D->getLocStart()); + TypedefNameDecl *ToTypedef; - if (IsAlias) - ToTypedef = TypeAliasDecl::Create(Importer.getToContext(), DC, - StartL, Loc, - Name.getAsIdentifierInfo(), - TInfo); - else - ToTypedef = TypedefDecl::Create(Importer.getToContext(), DC, - StartL, Loc, - Name.getAsIdentifierInfo(), - TInfo); + if (IsAlias) { + if (GetImportedOrCreateDecl<TypeAliasDecl>( + ToTypedef, D, Importer.getToContext(), DC, StartL, Loc, + Name.getAsIdentifierInfo(), TInfo)) + return ToTypedef; + } else if (GetImportedOrCreateDecl<TypedefDecl>( + ToTypedef, D, Importer.getToContext(), DC, StartL, Loc, + Name.getAsIdentifierInfo(), TInfo)) + return ToTypedef; ToTypedef->setAccess(D->getAccess()); ToTypedef->setLexicalDeclContext(LexicalDC); - Importer.Imported(D, ToTypedef); - LexicalDC->addDeclInternal(ToTypedef); + + // Templated declarations should not appear in DeclContext. + TypeAliasDecl *FromAlias = IsAlias ? cast<TypeAliasDecl>(D) : nullptr; + if (!FromAlias || !FromAlias->getDescribedAliasTemplate()) + LexicalDC->addDeclInternal(ToTypedef); return ToTypedef; } @@ -1617,11 +1969,11 @@ Decl *ASTNodeImporter::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) { DeclContext *DC, *LexicalDC; DeclarationName Name; SourceLocation Loc; - NamedDecl *ToD; - if (ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) + NamedDecl *FoundD; + if (ImportDeclParts(D, DC, LexicalDC, Name, FoundD, Loc)) return nullptr; - if (ToD) - return ToD; + if (FoundD) + return FoundD; // If this typedef is not in block scope, determine whether we've // seen a typedef with the same name (that we can merge with) or any @@ -1631,13 +1983,12 @@ Decl *ASTNodeImporter::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) { unsigned IDNS = Decl::IDNS_Ordinary; SmallVector<NamedDecl *, 2> FoundDecls; DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls); - for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { - if (!FoundDecls[I]->isInIdentifierNamespace(IDNS)) + for (auto *FoundDecl : FoundDecls) { + if (!FoundDecl->isInIdentifierNamespace(IDNS)) continue; - if (auto *FoundAlias = - dyn_cast<TypeAliasTemplateDecl>(FoundDecls[I])) - return Importer.Imported(D, FoundAlias); - ConflictingDecls.push_back(FoundDecls[I]); + if (auto *FoundAlias = dyn_cast<TypeAliasTemplateDecl>(FoundDecl)) + return Importer.MapImported(D, FoundAlias); + ConflictingDecls.push_back(FoundDecl); } if (!ConflictingDecls.empty()) { @@ -1654,19 +2005,22 @@ Decl *ASTNodeImporter::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) { if (!Params) return nullptr; - NamedDecl *TemplDecl = cast_or_null<NamedDecl>( + auto *TemplDecl = cast_or_null<TypeAliasDecl>( Importer.Import(D->getTemplatedDecl())); if (!TemplDecl) return nullptr; - TypeAliasTemplateDecl *ToAlias = TypeAliasTemplateDecl::Create( - Importer.getToContext(), DC, Loc, Name, Params, TemplDecl); + TypeAliasTemplateDecl *ToAlias; + if (GetImportedOrCreateDecl(ToAlias, D, Importer.getToContext(), DC, Loc, + Name, Params, TemplDecl)) + return ToAlias; + + TemplDecl->setDescribedAliasTemplate(ToAlias); ToAlias->setAccess(D->getAccess()); ToAlias->setLexicalDeclContext(LexicalDC); - Importer.Imported(D, ToAlias); LexicalDC->addDeclInternal(ToAlias); - return ToD; + return ToAlias; } Decl *ASTNodeImporter::VisitLabelDecl(LabelDecl *D) { @@ -1682,17 +2036,18 @@ Decl *ASTNodeImporter::VisitLabelDecl(LabelDecl *D) { assert(LexicalDC->isFunctionOrMethod()); - LabelDecl *ToLabel = D->isGnuLocal() - ? LabelDecl::Create(Importer.getToContext(), - DC, Importer.Import(D->getLocation()), - Name.getAsIdentifierInfo(), - Importer.Import(D->getLocStart())) - : LabelDecl::Create(Importer.getToContext(), - DC, Importer.Import(D->getLocation()), - Name.getAsIdentifierInfo()); - Importer.Imported(D, ToLabel); - - LabelStmt *Label = cast_or_null<LabelStmt>(Importer.Import(D->getStmt())); + LabelDecl *ToLabel; + if (D->isGnuLocal() + ? GetImportedOrCreateDecl(ToLabel, D, Importer.getToContext(), DC, + Importer.Import(D->getLocation()), + Name.getAsIdentifierInfo(), + Importer.Import(D->getLocStart())) + : GetImportedOrCreateDecl(ToLabel, D, Importer.getToContext(), DC, + Importer.Import(D->getLocation()), + Name.getAsIdentifierInfo())) + return ToLabel; + + auto *Label = cast_or_null<LabelStmt>(Importer.Import(D->getStmt())); if (!Label) return nullptr; @@ -1727,22 +2082,22 @@ Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) { SmallVector<NamedDecl *, 4> ConflictingDecls; SmallVector<NamedDecl *, 2> FoundDecls; DC->getRedeclContext()->localUncachedLookup(SearchName, FoundDecls); - for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { - if (!FoundDecls[I]->isInIdentifierNamespace(IDNS)) + for (auto *FoundDecl : FoundDecls) { + if (!FoundDecl->isInIdentifierNamespace(IDNS)) continue; - Decl *Found = FoundDecls[I]; - if (TypedefNameDecl *Typedef = dyn_cast<TypedefNameDecl>(Found)) { - if (const TagType *Tag = Typedef->getUnderlyingType()->getAs<TagType>()) + Decl *Found = FoundDecl; + if (auto *Typedef = dyn_cast<TypedefNameDecl>(Found)) { + if (const auto *Tag = Typedef->getUnderlyingType()->getAs<TagType>()) Found = Tag->getDecl(); } - if (EnumDecl *FoundEnum = dyn_cast<EnumDecl>(Found)) { + if (auto *FoundEnum = dyn_cast<EnumDecl>(Found)) { if (IsStructuralMatch(D, FoundEnum)) - return Importer.Imported(D, FoundEnum); + return Importer.MapImported(D, FoundEnum); } - ConflictingDecls.push_back(FoundDecls[I]); + ConflictingDecls.push_back(FoundDecl); } if (!ConflictingDecls.empty()) { @@ -1751,18 +2106,19 @@ Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) { ConflictingDecls.size()); } } - + // Create the enum declaration. - EnumDecl *D2 = EnumDecl::Create(Importer.getToContext(), DC, - Importer.Import(D->getLocStart()), - Loc, Name.getAsIdentifierInfo(), nullptr, - D->isScoped(), D->isScopedUsingClassTag(), - D->isFixed()); + EnumDecl *D2; + if (GetImportedOrCreateDecl( + D2, D, Importer.getToContext(), DC, Importer.Import(D->getLocStart()), + Loc, Name.getAsIdentifierInfo(), nullptr, D->isScoped(), + D->isScopedUsingClassTag(), D->isFixed())) + return D2; + // Import the qualifier, if any. D2->setQualifierInfo(Importer.Import(D->getQualifierLoc())); D2->setAccess(D->getAccess()); D2->setLexicalDeclContext(LexicalDC); - Importer.Imported(D, D2); LexicalDC->addDeclInternal(D2); // Import the integer type. @@ -1783,14 +2139,20 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { // but this particular declaration is not that definition, import the // definition and map to that. TagDecl *Definition = D->getDefinition(); - if (Definition && Definition != D) { + if (Definition && Definition != D && + // In contrast to a normal CXXRecordDecl, the implicit + // CXXRecordDecl of ClassTemplateSpecializationDecl is its redeclaration. + // The definition of the implicit CXXRecordDecl in this case is the + // ClassTemplateSpecializationDecl itself. Thus, we start with an extra + // condition in order to be able to import the implict Decl. + !D->isImplicit()) { Decl *ImportedDef = Importer.Import(Definition); if (!ImportedDef) return nullptr; - return Importer.Imported(D, ImportedDef); + return Importer.MapImported(D, ImportedDef); } - + // Import the major distinguishing characteristics of this record. DeclContext *DC, *LexicalDC; DeclarationName Name; @@ -1824,30 +2186,27 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { D->getASTContext().getExternalSource()->CompleteType(D); } - for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { - if (!FoundDecls[I]->isInIdentifierNamespace(IDNS)) + for (auto *FoundDecl : FoundDecls) { + if (!FoundDecl->isInIdentifierNamespace(IDNS)) continue; - Decl *Found = FoundDecls[I]; - if (TypedefNameDecl *Typedef = dyn_cast<TypedefNameDecl>(Found)) { - if (const TagType *Tag = Typedef->getUnderlyingType()->getAs<TagType>()) + Decl *Found = FoundDecl; + if (auto *Typedef = dyn_cast<TypedefNameDecl>(Found)) { + if (const auto *Tag = Typedef->getUnderlyingType()->getAs<TagType>()) Found = Tag->getDecl(); } - - if (RecordDecl *FoundRecord = dyn_cast<RecordDecl>(Found)) { - if (D->isAnonymousStructOrUnion() && - FoundRecord->isAnonymousStructOrUnion()) { - // If both anonymous structs/unions are in a record context, make sure - // they occur in the same location in the context records. - if (Optional<unsigned> Index1 = - StructuralEquivalenceContext::findUntaggedStructOrUnionIndex( - D)) { - if (Optional<unsigned> Index2 = StructuralEquivalenceContext:: - findUntaggedStructOrUnionIndex(FoundRecord)) { - if (*Index1 != *Index2) - continue; - } - } + + if (D->getDescribedTemplate()) { + if (auto *Template = dyn_cast<ClassTemplateDecl>(Found)) + Found = Template->getTemplatedDecl(); + else + continue; + } + + if (auto *FoundRecord = dyn_cast<RecordDecl>(Found)) { + if (!SearchName) { + if (!IsStructuralMatch(D, FoundRecord, false)) + continue; } PrevDecl = FoundRecord; @@ -1861,8 +2220,19 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { // The record types structurally match, or the "from" translation // unit only had a forward declaration anyway; call it the same // function. - // FIXME: For C++, we should also merge methods here. - return Importer.Imported(D, FoundDef); + // FIXME: Structural equivalence check should check for same + // user-defined methods. + Importer.MapImported(D, FoundDef); + if (const auto *DCXX = dyn_cast<CXXRecordDecl>(D)) { + auto *FoundCXX = dyn_cast<CXXRecordDecl>(FoundDef); + assert(FoundCXX && "Record type mismatch"); + + if (D->isCompleteDefinition() && !Importer.isMinimalImport()) + // FoundDef may not have every implicit method that D has + // because implicit methods are created only if they are used. + ImportImplicitMethods(DCXX, FoundCXX); + } + return FoundDef; } } else if (!D->isCompleteDefinition()) { // We have a forward declaration of this type, so adopt that forward @@ -1889,7 +2259,7 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { } } - ConflictingDecls.push_back(FoundDecls[I]); + ConflictingDecls.push_back(FoundDecl); } if (!ConflictingDecls.empty() && SearchName) { @@ -1904,53 +2274,80 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { SourceLocation StartLoc = Importer.Import(D->getLocStart()); if (!D2) { CXXRecordDecl *D2CXX = nullptr; - if (CXXRecordDecl *DCXX = llvm::dyn_cast<CXXRecordDecl>(D)) { + if (auto *DCXX = dyn_cast<CXXRecordDecl>(D)) { if (DCXX->isLambda()) { TypeSourceInfo *TInfo = Importer.Import(DCXX->getLambdaTypeInfo()); - D2CXX = CXXRecordDecl::CreateLambda(Importer.getToContext(), - DC, TInfo, Loc, - DCXX->isDependentLambda(), - DCXX->isGenericLambda(), - DCXX->getLambdaCaptureDefault()); + if (GetImportedOrCreateSpecialDecl( + D2CXX, CXXRecordDecl::CreateLambda, D, Importer.getToContext(), + DC, TInfo, Loc, DCXX->isDependentLambda(), + DCXX->isGenericLambda(), DCXX->getLambdaCaptureDefault())) + return D2CXX; Decl *CDecl = Importer.Import(DCXX->getLambdaContextDecl()); if (DCXX->getLambdaContextDecl() && !CDecl) return nullptr; D2CXX->setLambdaMangling(DCXX->getLambdaManglingNumber(), CDecl); - } else if (DCXX->isInjectedClassName()) { - // We have to be careful to do a similar dance to the one in - // Sema::ActOnStartCXXMemberDeclarations - CXXRecordDecl *const PrevDecl = nullptr; - const bool DelayTypeCreation = true; - D2CXX = CXXRecordDecl::Create( - Importer.getToContext(), D->getTagKind(), DC, StartLoc, Loc, - Name.getAsIdentifierInfo(), PrevDecl, DelayTypeCreation); - Importer.getToContext().getTypeDeclType( - D2CXX, llvm::dyn_cast<CXXRecordDecl>(DC)); + } else if (DCXX->isInjectedClassName()) { + // We have to be careful to do a similar dance to the one in + // Sema::ActOnStartCXXMemberDeclarations + CXXRecordDecl *const PrevDecl = nullptr; + const bool DelayTypeCreation = true; + if (GetImportedOrCreateDecl(D2CXX, D, Importer.getToContext(), + D->getTagKind(), DC, StartLoc, Loc, + Name.getAsIdentifierInfo(), PrevDecl, + DelayTypeCreation)) + return D2CXX; + Importer.getToContext().getTypeDeclType( + D2CXX, dyn_cast<CXXRecordDecl>(DC)); } else { - D2CXX = CXXRecordDecl::Create(Importer.getToContext(), - D->getTagKind(), - DC, StartLoc, Loc, - Name.getAsIdentifierInfo()); + if (GetImportedOrCreateDecl(D2CXX, D, Importer.getToContext(), + D->getTagKind(), DC, StartLoc, Loc, + Name.getAsIdentifierInfo(), + cast_or_null<CXXRecordDecl>(PrevDecl))) + return D2CXX; } + D2 = D2CXX; D2->setAccess(D->getAccess()); - - Importer.Imported(D, D2); + D2->setLexicalDeclContext(LexicalDC); + if (!DCXX->getDescribedClassTemplate() || DCXX->isImplicit()) + LexicalDC->addDeclInternal(D2); if (ClassTemplateDecl *FromDescribed = DCXX->getDescribedClassTemplate()) { - ClassTemplateDecl *ToDescribed = cast_or_null<ClassTemplateDecl>( - Importer.Import(FromDescribed)); + auto *ToDescribed = cast_or_null<ClassTemplateDecl>( + Importer.Import(FromDescribed)); if (!ToDescribed) return nullptr; D2CXX->setDescribedClassTemplate(ToDescribed); - + if (!DCXX->isInjectedClassName()) { + // In a record describing a template the type should be an + // InjectedClassNameType (see Sema::CheckClassTemplate). Update the + // previously set type to the correct value here (ToDescribed is not + // available at record create). + // FIXME: The previous type is cleared but not removed from + // ASTContext's internal storage. + CXXRecordDecl *Injected = nullptr; + for (NamedDecl *Found : D2CXX->noload_lookup(Name)) { + auto *Record = dyn_cast<CXXRecordDecl>(Found); + if (Record && Record->isInjectedClassName()) { + Injected = Record; + break; + } + } + D2CXX->setTypeForDecl(nullptr); + Importer.getToContext().getInjectedClassNameType(D2CXX, + ToDescribed->getInjectedClassNameSpecialization()); + if (Injected) { + Injected->setTypeForDecl(nullptr); + Importer.getToContext().getTypeDeclType(Injected, D2CXX); + } + } } else if (MemberSpecializationInfo *MemberInfo = DCXX->getMemberSpecializationInfo()) { TemplateSpecializationKind SK = MemberInfo->getTemplateSpecializationKind(); CXXRecordDecl *FromInst = DCXX->getInstantiatedFromMemberClass(); - CXXRecordDecl *ToInst = + auto *ToInst = cast_or_null<CXXRecordDecl>(Importer.Import(FromInst)); if (FromInst && !ToInst) return nullptr; @@ -1958,24 +2355,21 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { D2CXX->getMemberSpecializationInfo()->setPointOfInstantiation( Importer.Import(MemberInfo->getPointOfInstantiation())); } - } else { - D2 = RecordDecl::Create(Importer.getToContext(), D->getTagKind(), - DC, StartLoc, Loc, Name.getAsIdentifierInfo()); + if (GetImportedOrCreateDecl(D2, D, Importer.getToContext(), + D->getTagKind(), DC, StartLoc, Loc, + Name.getAsIdentifierInfo(), PrevDecl)) + return D2; + D2->setLexicalDeclContext(LexicalDC); + LexicalDC->addDeclInternal(D2); } - + D2->setQualifierInfo(Importer.Import(D->getQualifierLoc())); - D2->setLexicalDeclContext(LexicalDC); - LexicalDC->addDeclInternal(D2); if (D->isAnonymousStructOrUnion()) D2->setAnonymousStructOrUnion(true); - if (PrevDecl) { - // FIXME: do this for all Redeclarables, not just RecordDecls. - D2->setPreviousDecl(PrevDecl); - } } - - Importer.Imported(D, D2); + + Importer.MapImported(D, D2); if (D->isCompleteDefinition() && ImportDefinition(D, D2, IDK_Default)) return nullptr; @@ -2005,17 +2399,16 @@ Decl *ASTNodeImporter::VisitEnumConstantDecl(EnumConstantDecl *D) { unsigned IDNS = Decl::IDNS_Ordinary; SmallVector<NamedDecl *, 2> FoundDecls; DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls); - for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { - if (!FoundDecls[I]->isInIdentifierNamespace(IDNS)) + for (auto *FoundDecl : FoundDecls) { + if (!FoundDecl->isInIdentifierNamespace(IDNS)) continue; - if (EnumConstantDecl *FoundEnumConstant - = dyn_cast<EnumConstantDecl>(FoundDecls[I])) { + if (auto *FoundEnumConstant = dyn_cast<EnumConstantDecl>(FoundDecl)) { if (IsStructuralMatch(D, FoundEnumConstant)) - return Importer.Imported(D, FoundEnumConstant); + return Importer.MapImported(D, FoundEnumConstant); } - ConflictingDecls.push_back(FoundDecls[I]); + ConflictingDecls.push_back(FoundDecl); } if (!ConflictingDecls.empty()) { @@ -2031,18 +2424,120 @@ Decl *ASTNodeImporter::VisitEnumConstantDecl(EnumConstantDecl *D) { if (D->getInitExpr() && !Init) return nullptr; - EnumConstantDecl *ToEnumerator - = EnumConstantDecl::Create(Importer.getToContext(), cast<EnumDecl>(DC), Loc, - Name.getAsIdentifierInfo(), T, - Init, D->getInitVal()); + EnumConstantDecl *ToEnumerator; + if (GetImportedOrCreateDecl( + ToEnumerator, D, Importer.getToContext(), cast<EnumDecl>(DC), Loc, + Name.getAsIdentifierInfo(), T, Init, D->getInitVal())) + return ToEnumerator; + ToEnumerator->setAccess(D->getAccess()); ToEnumerator->setLexicalDeclContext(LexicalDC); - Importer.Imported(D, ToEnumerator); LexicalDC->addDeclInternal(ToEnumerator); return ToEnumerator; } +bool ASTNodeImporter::ImportTemplateInformation(FunctionDecl *FromFD, + FunctionDecl *ToFD) { + switch (FromFD->getTemplatedKind()) { + case FunctionDecl::TK_NonTemplate: + case FunctionDecl::TK_FunctionTemplate: + return false; + + case FunctionDecl::TK_MemberSpecialization: { + auto *InstFD = cast_or_null<FunctionDecl>( + Importer.Import(FromFD->getInstantiatedFromMemberFunction())); + if (!InstFD) + return true; + + TemplateSpecializationKind TSK = FromFD->getTemplateSpecializationKind(); + SourceLocation POI = Importer.Import( + FromFD->getMemberSpecializationInfo()->getPointOfInstantiation()); + ToFD->setInstantiationOfMemberFunction(InstFD, TSK); + ToFD->getMemberSpecializationInfo()->setPointOfInstantiation(POI); + return false; + } + + case FunctionDecl::TK_FunctionTemplateSpecialization: { + FunctionTemplateDecl* Template; + OptionalTemplateArgsTy ToTemplArgs; + std::tie(Template, ToTemplArgs) = + ImportFunctionTemplateWithTemplateArgsFromSpecialization(FromFD); + if (!Template || !ToTemplArgs) + return true; + + TemplateArgumentList *ToTAList = TemplateArgumentList::CreateCopy( + Importer.getToContext(), *ToTemplArgs); + + auto *FTSInfo = FromFD->getTemplateSpecializationInfo(); + TemplateArgumentListInfo ToTAInfo; + const auto *FromTAArgsAsWritten = FTSInfo->TemplateArgumentsAsWritten; + if (FromTAArgsAsWritten) + if (ImportTemplateArgumentListInfo(*FromTAArgsAsWritten, ToTAInfo)) + return true; + + SourceLocation POI = Importer.Import(FTSInfo->getPointOfInstantiation()); + + TemplateSpecializationKind TSK = FTSInfo->getTemplateSpecializationKind(); + ToFD->setFunctionTemplateSpecialization( + Template, ToTAList, /* InsertPos= */ nullptr, + TSK, FromTAArgsAsWritten ? &ToTAInfo : nullptr, POI); + return false; + } + + case FunctionDecl::TK_DependentFunctionTemplateSpecialization: { + auto *FromInfo = FromFD->getDependentSpecializationInfo(); + UnresolvedSet<8> TemplDecls; + unsigned NumTemplates = FromInfo->getNumTemplates(); + for (unsigned I = 0; I < NumTemplates; I++) { + if (auto *ToFTD = cast_or_null<FunctionTemplateDecl>( + Importer.Import(FromInfo->getTemplate(I)))) + TemplDecls.addDecl(ToFTD); + else + return true; + } + + // Import TemplateArgumentListInfo. + TemplateArgumentListInfo ToTAInfo; + if (ImportTemplateArgumentListInfo( + FromInfo->getLAngleLoc(), FromInfo->getRAngleLoc(), + llvm::makeArrayRef(FromInfo->getTemplateArgs(), + FromInfo->getNumTemplateArgs()), + ToTAInfo)) + return true; + + ToFD->setDependentTemplateSpecialization(Importer.getToContext(), + TemplDecls, ToTAInfo); + return false; + } + } + llvm_unreachable("All cases should be covered!"); +} + +FunctionDecl * +ASTNodeImporter::FindFunctionTemplateSpecialization(FunctionDecl *FromFD) { + FunctionTemplateDecl* Template; + OptionalTemplateArgsTy ToTemplArgs; + std::tie(Template, ToTemplArgs) = + ImportFunctionTemplateWithTemplateArgsFromSpecialization(FromFD); + if (!Template || !ToTemplArgs) + return nullptr; + + void *InsertPos = nullptr; + auto *FoundSpec = Template->findSpecialization(*ToTemplArgs, InsertPos); + return FoundSpec; +} + Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { + + SmallVector<Decl*, 2> Redecls = getCanonicalForwardRedeclChain(D); + auto RedeclIt = Redecls.begin(); + // Import the first part of the decl chain. I.e. import all previous + // declarations starting from the canonical decl. + for (; RedeclIt != Redecls.end() && *RedeclIt != D; ++RedeclIt) + if (!Importer.Import(*RedeclIt)) + return nullptr; + assert(*RedeclIt == D); + // Import the major distinguishing characteristics of this function. DeclContext *DC, *LexicalDC; DeclarationName Name; @@ -2053,33 +2548,54 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { if (ToD) return ToD; - const FunctionDecl *FoundWithoutBody = nullptr; - + const FunctionDecl *FoundByLookup = nullptr; + FunctionTemplateDecl *FromFT = D->getDescribedFunctionTemplate(); + + // If this is a function template specialization, then try to find the same + // existing specialization in the "to" context. The localUncachedLookup + // below will not find any specialization, but would find the primary + // template; thus, we have to skip normal lookup in case of specializations. + // FIXME handle member function templates (TK_MemberSpecialization) similarly? + if (D->getTemplatedKind() == + FunctionDecl::TK_FunctionTemplateSpecialization) { + if (FunctionDecl *FoundFunction = FindFunctionTemplateSpecialization(D)) { + if (D->doesThisDeclarationHaveABody() && + FoundFunction->hasBody()) + return Importer.Imported(D, FoundFunction); + FoundByLookup = FoundFunction; + } + } // Try to find a function in our own ("to") context with the same name, same // type, and in the same context as the function we're importing. - if (!LexicalDC->isFunctionOrMethod()) { + else if (!LexicalDC->isFunctionOrMethod()) { SmallVector<NamedDecl *, 4> ConflictingDecls; - unsigned IDNS = Decl::IDNS_Ordinary; + unsigned IDNS = Decl::IDNS_Ordinary | Decl::IDNS_OrdinaryFriend; SmallVector<NamedDecl *, 2> FoundDecls; DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls); - for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { - if (!FoundDecls[I]->isInIdentifierNamespace(IDNS)) + for (auto *FoundDecl : FoundDecls) { + if (!FoundDecl->isInIdentifierNamespace(IDNS)) continue; - if (FunctionDecl *FoundFunction = dyn_cast<FunctionDecl>(FoundDecls[I])) { + // If template was found, look at the templated function. + if (FromFT) { + if (auto *Template = dyn_cast<FunctionTemplateDecl>(FoundDecl)) + FoundDecl = Template->getTemplatedDecl(); + else + continue; + } + + if (auto *FoundFunction = dyn_cast<FunctionDecl>(FoundDecl)) { if (FoundFunction->hasExternalFormalLinkage() && D->hasExternalFormalLinkage()) { - if (Importer.IsStructurallyEquivalent(D->getType(), - FoundFunction->getType())) { - // FIXME: Actually try to merge the body and other attributes. - const FunctionDecl *FromBodyDecl = nullptr; - D->hasBody(FromBodyDecl); - if (D == FromBodyDecl && !FoundFunction->hasBody()) { - // This function is needed to merge completely. - FoundWithoutBody = FoundFunction; - break; + if (IsStructuralMatch(D, FoundFunction)) { + const FunctionDecl *Definition = nullptr; + if (D->doesThisDeclarationHaveABody() && + FoundFunction->hasBody(Definition)) { + return Importer.MapImported( + D, const_cast<FunctionDecl *>(Definition)); } - return Importer.Imported(D, FoundFunction); + FoundByLookup = FoundFunction; + break; } // FIXME: Check for overloading more carefully, e.g., by boosting @@ -2098,7 +2614,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { } } - ConflictingDecls.push_back(FoundDecls[I]); + ConflictingDecls.push_back(FoundDecl); } if (!ConflictingDecls.empty()) { @@ -2117,8 +2633,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { QualType FromTy = D->getType(); bool usedDifferentExceptionSpec = false; - if (const FunctionProtoType * - FromFPT = D->getType()->getAs<FunctionProtoType>()) { + if (const auto *FromFPT = D->getType()->getAs<FunctionProtoType>()) { FunctionProtoType::ExtProtoInfo FromEPI = FromFPT->getExtProtoInfo(); // FunctionProtoType::ExtProtoInfo's ExceptionSpecDecl can point to the // FunctionDecl that we are importing the FunctionProtoType for. @@ -2142,75 +2657,66 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { // Import the function parameters. SmallVector<ParmVarDecl *, 8> Parameters; for (auto P : D->parameters()) { - ParmVarDecl *ToP = cast_or_null<ParmVarDecl>(Importer.Import(P)); + auto *ToP = cast_or_null<ParmVarDecl>(Importer.Import(P)); if (!ToP) return nullptr; Parameters.push_back(ToP); } - // Create the imported function. TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo()); + if (D->getTypeSourceInfo() && !TInfo) + return nullptr; + + // Create the imported function. FunctionDecl *ToFunction = nullptr; SourceLocation InnerLocStart = Importer.Import(D->getInnerLocStart()); - if (CXXConstructorDecl *FromConstructor = dyn_cast<CXXConstructorDecl>(D)) { - ToFunction = CXXConstructorDecl::Create(Importer.getToContext(), - cast<CXXRecordDecl>(DC), - InnerLocStart, - NameInfo, T, TInfo, - FromConstructor->isExplicit(), - D->isInlineSpecified(), - D->isImplicit(), - D->isConstexpr()); + if (auto *FromConstructor = dyn_cast<CXXConstructorDecl>(D)) { + if (GetImportedOrCreateDecl<CXXConstructorDecl>( + ToFunction, D, Importer.getToContext(), cast<CXXRecordDecl>(DC), + InnerLocStart, NameInfo, T, TInfo, FromConstructor->isExplicit(), + D->isInlineSpecified(), D->isImplicit(), D->isConstexpr())) + return ToFunction; if (unsigned NumInitializers = FromConstructor->getNumCtorInitializers()) { SmallVector<CXXCtorInitializer *, 4> CtorInitializers; - for (CXXCtorInitializer *I : FromConstructor->inits()) { - CXXCtorInitializer *ToI = - cast_or_null<CXXCtorInitializer>(Importer.Import(I)); + for (auto *I : FromConstructor->inits()) { + auto *ToI = cast_or_null<CXXCtorInitializer>(Importer.Import(I)); if (!ToI && I) return nullptr; CtorInitializers.push_back(ToI); } - CXXCtorInitializer **Memory = + auto **Memory = new (Importer.getToContext()) CXXCtorInitializer *[NumInitializers]; std::copy(CtorInitializers.begin(), CtorInitializers.end(), Memory); - CXXConstructorDecl *ToCtor = llvm::cast<CXXConstructorDecl>(ToFunction); + auto *ToCtor = cast<CXXConstructorDecl>(ToFunction); ToCtor->setCtorInitializers(Memory); ToCtor->setNumCtorInitializers(NumInitializers); } } else if (isa<CXXDestructorDecl>(D)) { - ToFunction = CXXDestructorDecl::Create(Importer.getToContext(), - cast<CXXRecordDecl>(DC), - InnerLocStart, - NameInfo, T, TInfo, - D->isInlineSpecified(), - D->isImplicit()); - } else if (CXXConversionDecl *FromConversion - = dyn_cast<CXXConversionDecl>(D)) { - ToFunction = CXXConversionDecl::Create(Importer.getToContext(), - cast<CXXRecordDecl>(DC), - InnerLocStart, - NameInfo, T, TInfo, - D->isInlineSpecified(), - FromConversion->isExplicit(), - D->isConstexpr(), - Importer.Import(D->getLocEnd())); - } else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) { - ToFunction = CXXMethodDecl::Create(Importer.getToContext(), - cast<CXXRecordDecl>(DC), - InnerLocStart, - NameInfo, T, TInfo, - Method->getStorageClass(), - Method->isInlineSpecified(), - D->isConstexpr(), - Importer.Import(D->getLocEnd())); + if (GetImportedOrCreateDecl<CXXDestructorDecl>( + ToFunction, D, Importer.getToContext(), cast<CXXRecordDecl>(DC), + InnerLocStart, NameInfo, T, TInfo, D->isInlineSpecified(), + D->isImplicit())) + return ToFunction; + } else if (CXXConversionDecl *FromConversion = + dyn_cast<CXXConversionDecl>(D)) { + if (GetImportedOrCreateDecl<CXXConversionDecl>( + ToFunction, D, Importer.getToContext(), cast<CXXRecordDecl>(DC), + InnerLocStart, NameInfo, T, TInfo, D->isInlineSpecified(), + FromConversion->isExplicit(), D->isConstexpr(), SourceLocation())) + return ToFunction; + } else if (auto *Method = dyn_cast<CXXMethodDecl>(D)) { + if (GetImportedOrCreateDecl<CXXMethodDecl>( + ToFunction, D, Importer.getToContext(), cast<CXXRecordDecl>(DC), + InnerLocStart, NameInfo, T, TInfo, Method->getStorageClass(), + Method->isInlineSpecified(), D->isConstexpr(), SourceLocation())) + return ToFunction; } else { - ToFunction = FunctionDecl::Create(Importer.getToContext(), DC, - InnerLocStart, - NameInfo, T, TInfo, D->getStorageClass(), - D->isInlineSpecified(), - D->hasWrittenPrototype(), - D->isConstexpr()); + if (GetImportedOrCreateDecl(ToFunction, D, Importer.getToContext(), DC, + InnerLocStart, NameInfo, T, TInfo, + D->getStorageClass(), D->isInlineSpecified(), + D->hasWrittenPrototype(), D->isConstexpr())) + return ToFunction; } // Import the qualifier, if any. @@ -2220,21 +2726,31 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { ToFunction->setVirtualAsWritten(D->isVirtualAsWritten()); ToFunction->setTrivial(D->isTrivial()); ToFunction->setPure(D->isPure()); - Importer.Imported(D, ToFunction); + ToFunction->setRangeEnd(Importer.Import(D->getLocEnd())); // Set the parameters. - for (unsigned I = 0, N = Parameters.size(); I != N; ++I) { - Parameters[I]->setOwningFunction(ToFunction); - ToFunction->addDeclInternal(Parameters[I]); + for (auto *Param : Parameters) { + Param->setOwningFunction(ToFunction); + ToFunction->addDeclInternal(Param); } ToFunction->setParams(Parameters); - if (FoundWithoutBody) { + if (FoundByLookup) { auto *Recent = const_cast<FunctionDecl *>( - FoundWithoutBody->getMostRecentDecl()); + FoundByLookup->getMostRecentDecl()); ToFunction->setPreviousDecl(Recent); } + // We need to complete creation of FunctionProtoTypeLoc manually with setting + // params it refers to. + if (TInfo) { + if (auto ProtoLoc = + TInfo->getTypeLoc().IgnoreParens().getAs<FunctionProtoTypeLoc>()) { + for (unsigned I = 0, N = Parameters.size(); I != N; ++I) + ProtoLoc.setParam(I, Parameters[I]); + } + } + if (usedDifferentExceptionSpec) { // Update FunctionProtoType::ExtProtoInfo. QualType T = Importer.Import(D->getType()); @@ -2243,17 +2759,47 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { ToFunction->setType(T); } - // Import the body, if any. - if (Stmt *FromBody = D->getBody()) { - if (Stmt *ToBody = Importer.Import(FromBody)) { - ToFunction->setBody(ToBody); + // Import the describing template function, if any. + if (FromFT) + if (!Importer.Import(FromFT)) + return nullptr; + + if (D->doesThisDeclarationHaveABody()) { + if (Stmt *FromBody = D->getBody()) { + if (Stmt *ToBody = Importer.Import(FromBody)) { + ToFunction->setBody(ToBody); + } } } // FIXME: Other bits to merge? - // Add this function to the lexical context. - LexicalDC->addDeclInternal(ToFunction); + // If it is a template, import all related things. + if (ImportTemplateInformation(D, ToFunction)) + return nullptr; + + bool IsFriend = D->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend); + + // TODO Can we generalize this approach to other AST nodes as well? + if (D->getDeclContext()->containsDeclAndLoad(D)) + DC->addDeclInternal(ToFunction); + if (DC != LexicalDC && D->getLexicalDeclContext()->containsDeclAndLoad(D)) + LexicalDC->addDeclInternal(ToFunction); + + // Friend declaration's lexical context is the befriending class, but the + // semantic context is the enclosing scope of the befriending class. + // We want the friend functions to be found in the semantic context by lookup. + // FIXME should we handle this generically in VisitFriendDecl? + // In Other cases when LexicalDC != DC we don't want it to be added, + // e.g out-of-class definitions like void B::f() {} . + if (LexicalDC != DC && IsFriend) { + DC->makeDeclVisibleInContext(ToFunction); + } + + // Import the rest of the chain. I.e. import all subsequent declarations. + for (++RedeclIt; RedeclIt != Redecls.end(); ++RedeclIt) + if (!Importer.Import(*RedeclIt)) + return nullptr; if (auto *FromCXXMethod = dyn_cast<CXXMethodDecl>(D)) ImportOverrides(cast<CXXMethodDecl>(ToFunction), FromCXXMethod); @@ -2278,7 +2824,7 @@ Decl *ASTNodeImporter::VisitCXXConversionDecl(CXXConversionDecl *D) { } static unsigned getFieldIndex(Decl *F) { - RecordDecl *Owner = dyn_cast<RecordDecl>(F->getDeclContext()); + auto *Owner = dyn_cast<RecordDecl>(F->getDeclContext()); if (!Owner) return 0; @@ -2308,15 +2854,15 @@ Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) { // Determine whether we've already imported this field. SmallVector<NamedDecl *, 2> FoundDecls; DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls); - for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { - if (FieldDecl *FoundField = dyn_cast<FieldDecl>(FoundDecls[I])) { + for (auto *FoundDecl : FoundDecls) { + if (auto *FoundField = dyn_cast<FieldDecl>(FoundDecl)) { // For anonymous fields, match up by index. if (!Name && getFieldIndex(D) != getFieldIndex(FoundField)) continue; if (Importer.IsStructurallyEquivalent(D->getType(), FoundField->getType())) { - Importer.Imported(D, FoundField); + Importer.MapImported(D, FoundField); return FoundField; } @@ -2338,11 +2884,13 @@ Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) { if (!BitWidth && D->getBitWidth()) return nullptr; - FieldDecl *ToField = FieldDecl::Create(Importer.getToContext(), DC, - Importer.Import(D->getInnerLocStart()), - Loc, Name.getAsIdentifierInfo(), - T, TInfo, BitWidth, D->isMutable(), - D->getInClassInitStyle()); + FieldDecl *ToField; + if (GetImportedOrCreateDecl(ToField, D, Importer.getToContext(), DC, + Importer.Import(D->getInnerLocStart()), Loc, + Name.getAsIdentifierInfo(), T, TInfo, BitWidth, + D->isMutable(), D->getInClassInitStyle())) + return ToField; + ToField->setAccess(D->getAccess()); ToField->setLexicalDeclContext(LexicalDC); if (Expr *FromInitializer = D->getInClassInitializer()) { @@ -2353,7 +2901,6 @@ Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) { return nullptr; } ToField->setImplicit(D->isImplicit()); - Importer.Imported(D, ToField); LexicalDC->addDeclInternal(ToField); return ToField; } @@ -2373,8 +2920,7 @@ Decl *ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *D) { SmallVector<NamedDecl *, 2> FoundDecls; DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls); for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { - if (IndirectFieldDecl *FoundField - = dyn_cast<IndirectFieldDecl>(FoundDecls[I])) { + if (auto *FoundField = dyn_cast<IndirectFieldDecl>(FoundDecls[I])) { // For anonymous indirect fields, match up by index. if (!Name && getFieldIndex(D) != getFieldIndex(FoundField)) continue; @@ -2382,7 +2928,7 @@ Decl *ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *D) { if (Importer.IsStructurallyEquivalent(D->getType(), FoundField->getType(), !Name.isEmpty())) { - Importer.Imported(D, FoundField); + Importer.MapImported(D, FoundField); return FoundField; } @@ -2403,8 +2949,8 @@ Decl *ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *D) { if (T.isNull()) return nullptr; - NamedDecl **NamedChain = - new (Importer.getToContext())NamedDecl*[D->getChainingSize()]; + auto **NamedChain = + new (Importer.getToContext()) NamedDecl*[D->getChainingSize()]; unsigned i = 0; for (auto *PI : D->chain()) { @@ -2414,16 +2960,18 @@ Decl *ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *D) { NamedChain[i++] = cast<NamedDecl>(D); } - IndirectFieldDecl *ToIndirectField = IndirectFieldDecl::Create( - Importer.getToContext(), DC, Loc, Name.getAsIdentifierInfo(), T, - {NamedChain, D->getChainingSize()}); + llvm::MutableArrayRef<NamedDecl *> CH = {NamedChain, D->getChainingSize()}; + IndirectFieldDecl *ToIndirectField; + if (GetImportedOrCreateDecl(ToIndirectField, D, Importer.getToContext(), DC, + Loc, Name.getAsIdentifierInfo(), T, CH)) + // FIXME here we leak `NamedChain` which is allocated before + return ToIndirectField; - for (const auto *Attr : D->attrs()) - ToIndirectField->addAttr(Attr->clone(Importer.getToContext())); + for (const auto *A : D->attrs()) + ToIndirectField->addAttr(Importer.Import(A)); ToIndirectField->setAccess(D->getAccess()); ToIndirectField->setLexicalDeclContext(LexicalDC); - Importer.Imported(D, ToIndirectField); LexicalDC->addDeclInternal(ToIndirectField); return ToIndirectField; } @@ -2440,37 +2988,38 @@ Decl *ASTNodeImporter::VisitFriendDecl(FriendDecl *D) { // FriendDecl is not a NamedDecl so we cannot use localUncachedLookup. auto *RD = cast<CXXRecordDecl>(DC); FriendDecl *ImportedFriend = RD->getFirstFriend(); - StructuralEquivalenceContext Context( - Importer.getFromContext(), Importer.getToContext(), - Importer.getNonEquivalentDecls(), false, false); while (ImportedFriend) { if (D->getFriendDecl() && ImportedFriend->getFriendDecl()) { - if (Context.IsStructurallyEquivalent(D->getFriendDecl(), - ImportedFriend->getFriendDecl())) - return Importer.Imported(D, ImportedFriend); + if (IsStructuralMatch(D->getFriendDecl(), ImportedFriend->getFriendDecl(), + /*Complain=*/false)) + return Importer.MapImported(D, ImportedFriend); } else if (D->getFriendType() && ImportedFriend->getFriendType()) { if (Importer.IsStructurallyEquivalent( D->getFriendType()->getType(), ImportedFriend->getFriendType()->getType(), true)) - return Importer.Imported(D, ImportedFriend); + return Importer.MapImported(D, ImportedFriend); } ImportedFriend = ImportedFriend->getNextFriend(); } // Not found. Create it. FriendDecl::FriendUnion ToFU; - if (NamedDecl *FriendD = D->getFriendDecl()) - ToFU = cast_or_null<NamedDecl>(Importer.Import(FriendD)); - else + if (NamedDecl *FriendD = D->getFriendDecl()) { + auto *ToFriendD = cast_or_null<NamedDecl>(Importer.Import(FriendD)); + if (ToFriendD && FriendD->getFriendObjectKind() != Decl::FOK_None && + !(FriendD->isInIdentifierNamespace(Decl::IDNS_NonMemberOperator))) + ToFriendD->setObjectOfFriendDecl(false); + + ToFU = ToFriendD; + } else // The friend is a type, not a decl. ToFU = Importer.Import(D->getFriendType()); if (!ToFU) return nullptr; SmallVector<TemplateParameterList *, 1> ToTPLists(D->NumTPLists); - TemplateParameterList **FromTPLists = - D->getTrailingObjects<TemplateParameterList *>(); + auto **FromTPLists = D->getTrailingObjects<TemplateParameterList *>(); for (unsigned I = 0; I < D->NumTPLists; I++) { TemplateParameterList *List = ImportTemplateParameterList(FromTPLists[I]); if (!List) @@ -2478,13 +3027,11 @@ Decl *ASTNodeImporter::VisitFriendDecl(FriendDecl *D) { ToTPLists[I] = List; } - FriendDecl *FrD = FriendDecl::Create(Importer.getToContext(), DC, - Importer.Import(D->getLocation()), - ToFU, Importer.Import(D->getFriendLoc()), - ToTPLists); - - Importer.Imported(D, FrD); - RD->pushFriendDecl(FrD); + FriendDecl *FrD; + if (GetImportedOrCreateDecl(FrD, D, Importer.getToContext(), DC, + Importer.Import(D->getLocation()), ToFU, + Importer.Import(D->getFriendLoc()), ToTPLists)) + return FrD; FrD->setAccess(D->getAccess()); FrD->setLexicalDeclContext(LexicalDC); @@ -2506,11 +3053,11 @@ Decl *ASTNodeImporter::VisitObjCIvarDecl(ObjCIvarDecl *D) { // Determine whether we've already imported this ivar SmallVector<NamedDecl *, 2> FoundDecls; DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls); - for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { - if (ObjCIvarDecl *FoundIvar = dyn_cast<ObjCIvarDecl>(FoundDecls[I])) { + for (auto *FoundDecl : FoundDecls) { + if (auto *FoundIvar = dyn_cast<ObjCIvarDecl>(FoundDecl)) { if (Importer.IsStructurallyEquivalent(D->getType(), FoundIvar->getType())) { - Importer.Imported(D, FoundIvar); + Importer.MapImported(D, FoundIvar); return FoundIvar; } @@ -2532,17 +3079,17 @@ Decl *ASTNodeImporter::VisitObjCIvarDecl(ObjCIvarDecl *D) { if (!BitWidth && D->getBitWidth()) return nullptr; - ObjCIvarDecl *ToIvar = ObjCIvarDecl::Create(Importer.getToContext(), - cast<ObjCContainerDecl>(DC), - Importer.Import(D->getInnerLocStart()), - Loc, Name.getAsIdentifierInfo(), - T, TInfo, D->getAccessControl(), - BitWidth, D->getSynthesize()); + ObjCIvarDecl *ToIvar; + if (GetImportedOrCreateDecl( + ToIvar, D, Importer.getToContext(), cast<ObjCContainerDecl>(DC), + Importer.Import(D->getInnerLocStart()), Loc, + Name.getAsIdentifierInfo(), T, TInfo, D->getAccessControl(), BitWidth, + D->getSynthesize())) + return ToIvar; + ToIvar->setLexicalDeclContext(LexicalDC); - Importer.Imported(D, ToIvar); LexicalDC->addDeclInternal(ToIvar); return ToIvar; - } Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) { @@ -2564,11 +3111,11 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) { unsigned IDNS = Decl::IDNS_Ordinary; SmallVector<NamedDecl *, 2> FoundDecls; DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls); - for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { - if (!FoundDecls[I]->isInIdentifierNamespace(IDNS)) + for (auto *FoundDecl : FoundDecls) { + if (!FoundDecl->isInIdentifierNamespace(IDNS)) continue; - if (VarDecl *FoundVar = dyn_cast<VarDecl>(FoundDecls[I])) { + if (auto *FoundVar = dyn_cast<VarDecl>(FoundDecl)) { // We have found a variable that we may need to merge with. Check it. if (FoundVar->hasExternalFormalLinkage() && D->hasExternalFormalLinkage()) { @@ -2607,14 +3154,15 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) { } } - ConflictingDecls.push_back(FoundDecls[I]); + ConflictingDecls.push_back(FoundDecl); } if (MergeWithVar) { - // An equivalent variable with external linkage has been found. Link + // An equivalent variable with external linkage has been found. Link // the two declarations, then merge them. - Importer.Imported(D, MergeWithVar); - + Importer.MapImported(D, MergeWithVar); + updateFlags(D, MergeWithVar); + if (VarDecl *DDef = D->getDefinition()) { if (VarDecl *ExistingDef = MergeWithVar->getDefinition()) { Importer.ToDiag(ExistingDef->getLocation(), @@ -2651,20 +3199,20 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) { // Create the imported variable. TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo()); - VarDecl *ToVar = VarDecl::Create(Importer.getToContext(), DC, - Importer.Import(D->getInnerLocStart()), - Loc, Name.getAsIdentifierInfo(), - T, TInfo, - D->getStorageClass()); + VarDecl *ToVar; + if (GetImportedOrCreateDecl(ToVar, D, Importer.getToContext(), DC, + Importer.Import(D->getInnerLocStart()), Loc, + Name.getAsIdentifierInfo(), T, TInfo, + D->getStorageClass())) + return ToVar; + ToVar->setQualifierInfo(Importer.Import(D->getQualifierLoc())); ToVar->setAccess(D->getAccess()); ToVar->setLexicalDeclContext(LexicalDC); - Importer.Imported(D, ToVar); - LexicalDC->addDeclInternal(ToVar); - if (!D->isFileVarDecl() && - D->isUsed()) - ToVar->setIsUsed(); + // Templated declarations should never appear in the enclosing DeclContext. + if (!D->getDescribedVarTemplate()) + LexicalDC->addDeclInternal(ToVar); // Merge the initializer. if (ImportDefinition(D, ToVar)) @@ -2695,10 +3243,12 @@ Decl *ASTNodeImporter::VisitImplicitParamDecl(ImplicitParamDecl *D) { return nullptr; // Create the imported parameter. - auto *ToParm = ImplicitParamDecl::Create(Importer.getToContext(), DC, Loc, - Name.getAsIdentifierInfo(), T, - D->getParameterKind()); - return Importer.Imported(D, ToParm); + ImplicitParamDecl *ToParm = nullptr; + if (GetImportedOrCreateDecl(ToParm, D, Importer.getToContext(), DC, Loc, + Name.getAsIdentifierInfo(), T, + D->getParameterKind())) + return ToParm; + return ToParm; } Decl *ASTNodeImporter::VisitParmVarDecl(ParmVarDecl *D) { @@ -2721,11 +3271,13 @@ Decl *ASTNodeImporter::VisitParmVarDecl(ParmVarDecl *D) { // Create the imported parameter. TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo()); - ParmVarDecl *ToParm = ParmVarDecl::Create(Importer.getToContext(), DC, - Importer.Import(D->getInnerLocStart()), - Loc, Name.getAsIdentifierInfo(), - T, TInfo, D->getStorageClass(), - /*DefaultArg*/ nullptr); + ParmVarDecl *ToParm; + if (GetImportedOrCreateDecl(ToParm, D, Importer.getToContext(), DC, + Importer.Import(D->getInnerLocStart()), Loc, + Name.getAsIdentifierInfo(), T, TInfo, + D->getStorageClass(), + /*DefaultArg*/ nullptr)) + return ToParm; // Set the default argument. ToParm->setHasInheritedDefaultArg(D->hasInheritedDefaultArg()); @@ -2747,10 +3299,15 @@ Decl *ASTNodeImporter::VisitParmVarDecl(ParmVarDecl *D) { if (FromDefArg && !ToDefArg) return nullptr; - if (D->isUsed()) - ToParm->setIsUsed(); + if (D->isObjCMethodParameter()) { + ToParm->setObjCMethodScopeInfo(D->getFunctionScopeIndex()); + ToParm->setObjCDeclQualifier(D->getObjCDeclQualifier()); + } else { + ToParm->setScopeInfo(D->getFunctionScopeDepth(), + D->getFunctionScopeIndex()); + } - return Importer.Imported(D, ToParm); + return ToParm; } Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) { @@ -2766,8 +3323,8 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) { SmallVector<NamedDecl *, 2> FoundDecls; DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls); - for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { - if (ObjCMethodDecl *FoundMethod = dyn_cast<ObjCMethodDecl>(FoundDecls[I])) { + for (auto *FoundDecl : FoundDecls) { + if (auto *FoundMethod = dyn_cast<ObjCMethodDecl>(FoundDecl)) { if (FoundMethod->isInstanceMethod() != D->isInstanceMethod()) continue; @@ -2822,7 +3379,7 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) { } // FIXME: Any other bits we need to merge? - return Importer.Imported(D, FoundMethod); + return Importer.MapImported(D, FoundMethod); } } @@ -2833,11 +3390,14 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) { TypeSourceInfo *ReturnTInfo = Importer.Import(D->getReturnTypeSourceInfo()); - ObjCMethodDecl *ToMethod = ObjCMethodDecl::Create( - Importer.getToContext(), Loc, Importer.Import(D->getLocEnd()), - Name.getObjCSelector(), ResultTy, ReturnTInfo, DC, D->isInstanceMethod(), - D->isVariadic(), D->isPropertyAccessor(), D->isImplicit(), D->isDefined(), - D->getImplementationControl(), D->hasRelatedResultType()); + ObjCMethodDecl *ToMethod; + if (GetImportedOrCreateDecl( + ToMethod, D, Importer.getToContext(), Loc, + Importer.Import(D->getLocEnd()), Name.getObjCSelector(), ResultTy, + ReturnTInfo, DC, D->isInstanceMethod(), D->isVariadic(), + D->isPropertyAccessor(), D->isImplicit(), D->isDefined(), + D->getImplementationControl(), D->hasRelatedResultType())) + return ToMethod; // FIXME: When we decide to merge method definitions, we'll need to // deal with implicit parameters. @@ -2845,7 +3405,7 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) { // Import the parameters SmallVector<ParmVarDecl *, 5> ToParams; for (auto *FromP : D->parameters()) { - ParmVarDecl *ToP = cast_or_null<ParmVarDecl>(Importer.Import(FromP)); + auto *ToP = cast_or_null<ParmVarDecl>(Importer.Import(FromP)); if (!ToP) return nullptr; @@ -2853,16 +3413,19 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) { } // Set the parameters. - for (unsigned I = 0, N = ToParams.size(); I != N; ++I) { - ToParams[I]->setOwningFunction(ToMethod); - ToMethod->addDeclInternal(ToParams[I]); + for (auto *ToParam : ToParams) { + ToParam->setOwningFunction(ToMethod); + ToMethod->addDeclInternal(ToParam); } + SmallVector<SourceLocation, 12> SelLocs; D->getSelectorLocs(SelLocs); - ToMethod->setMethodParams(Importer.getToContext(), ToParams, SelLocs); + for (auto &Loc : SelLocs) + Loc = Importer.Import(Loc); + + ToMethod->setMethodParams(Importer.getToContext(), ToParams, SelLocs); ToMethod->setLexicalDeclContext(LexicalDC); - Importer.Imported(D, ToMethod); LexicalDC->addDeclInternal(ToMethod); return ToMethod; } @@ -2882,16 +3445,14 @@ Decl *ASTNodeImporter::VisitObjCTypeParamDecl(ObjCTypeParamDecl *D) { if (!BoundInfo) return nullptr; - ObjCTypeParamDecl *Result = ObjCTypeParamDecl::Create( - Importer.getToContext(), DC, - D->getVariance(), - Importer.Import(D->getVarianceLoc()), - D->getIndex(), - Importer.Import(D->getLocation()), - Name.getAsIdentifierInfo(), - Importer.Import(D->getColonLoc()), - BoundInfo); - Importer.Imported(D, Result); + ObjCTypeParamDecl *Result; + if (GetImportedOrCreateDecl( + Result, D, Importer.getToContext(), DC, D->getVariance(), + Importer.Import(D->getVarianceLoc()), D->getIndex(), + Importer.Import(D->getLocation()), Name.getAsIdentifierInfo(), + Importer.Import(D->getColonLoc()), BoundInfo)) + return Result; + Result->setLexicalDeclContext(LexicalDC); return Result; } @@ -2907,8 +3468,8 @@ Decl *ASTNodeImporter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) { if (ToD) return ToD; - ObjCInterfaceDecl *ToInterface - = cast_or_null<ObjCInterfaceDecl>(Importer.Import(D->getClassInterface())); + auto *ToInterface = + cast_or_null<ObjCInterfaceDecl>(Importer.Import(D->getClassInterface())); if (!ToInterface) return nullptr; @@ -2917,18 +3478,18 @@ Decl *ASTNodeImporter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) { = ToInterface->FindCategoryDeclaration(Name.getAsIdentifierInfo()); ObjCCategoryDecl *ToCategory = MergeWithCategory; if (!ToCategory) { - ToCategory = ObjCCategoryDecl::Create(Importer.getToContext(), DC, - Importer.Import(D->getAtStartLoc()), - Loc, - Importer.Import(D->getCategoryNameLoc()), - Name.getAsIdentifierInfo(), - ToInterface, - /*TypeParamList=*/nullptr, - Importer.Import(D->getIvarLBraceLoc()), - Importer.Import(D->getIvarRBraceLoc())); + + if (GetImportedOrCreateDecl(ToCategory, D, Importer.getToContext(), DC, + Importer.Import(D->getAtStartLoc()), Loc, + Importer.Import(D->getCategoryNameLoc()), + Name.getAsIdentifierInfo(), ToInterface, + /*TypeParamList=*/nullptr, + Importer.Import(D->getIvarLBraceLoc()), + Importer.Import(D->getIvarRBraceLoc()))) + return ToCategory; + ToCategory->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToCategory); - Importer.Imported(D, ToCategory); // Import the type parameter list after calling Imported, to avoid // loops when bringing in their DeclContext. ToCategory->setTypeParamList(ImportObjCTypeParamList( @@ -2943,8 +3504,8 @@ Decl *ASTNodeImporter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) { FromProtoEnd = D->protocol_end(); FromProto != FromProtoEnd; ++FromProto, ++FromProtoLoc) { - ObjCProtocolDecl *ToProto - = cast_or_null<ObjCProtocolDecl>(Importer.Import(*FromProto)); + auto *ToProto = + cast_or_null<ObjCProtocolDecl>(Importer.Import(*FromProto)); if (!ToProto) return nullptr; Protocols.push_back(ToProto); @@ -2954,9 +3515,8 @@ Decl *ASTNodeImporter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) { // FIXME: If we're merging, make sure that the protocol list is the same. ToCategory->setProtocolList(Protocols.data(), Protocols.size(), ProtocolLocs.data(), Importer.getToContext()); - } else { - Importer.Imported(D, ToCategory); + Importer.MapImported(D, ToCategory); } // Import all of the members of this category. @@ -2964,8 +3524,8 @@ Decl *ASTNodeImporter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) { // If we have an implementation, import it as well. if (D->getImplementation()) { - ObjCCategoryImplDecl *Impl - = cast_or_null<ObjCCategoryImplDecl>( + auto *Impl = + cast_or_null<ObjCCategoryImplDecl>( Importer.Import(D->getImplementation())); if (!Impl) return nullptr; @@ -2997,8 +3557,7 @@ bool ASTNodeImporter::ImportDefinition(ObjCProtocolDecl *From, FromProtoEnd = From->protocol_end(); FromProto != FromProtoEnd; ++FromProto, ++FromProtoLoc) { - ObjCProtocolDecl *ToProto - = cast_or_null<ObjCProtocolDecl>(Importer.Import(*FromProto)); + auto *ToProto = cast_or_null<ObjCProtocolDecl>(Importer.Import(*FromProto)); if (!ToProto) return true; Protocols.push_back(ToProto); @@ -3026,7 +3585,7 @@ Decl *ASTNodeImporter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) { if (!ImportedDef) return nullptr; - return Importer.Imported(D, ImportedDef); + return Importer.MapImported(D, ImportedDef); } // Import the major distinguishing characteristics of a protocol. @@ -3042,25 +3601,26 @@ Decl *ASTNodeImporter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) { ObjCProtocolDecl *MergeWithProtocol = nullptr; SmallVector<NamedDecl *, 2> FoundDecls; DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls); - for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { - if (!FoundDecls[I]->isInIdentifierNamespace(Decl::IDNS_ObjCProtocol)) + for (auto *FoundDecl : FoundDecls) { + if (!FoundDecl->isInIdentifierNamespace(Decl::IDNS_ObjCProtocol)) continue; - if ((MergeWithProtocol = dyn_cast<ObjCProtocolDecl>(FoundDecls[I]))) + if ((MergeWithProtocol = dyn_cast<ObjCProtocolDecl>(FoundDecl))) break; } ObjCProtocolDecl *ToProto = MergeWithProtocol; if (!ToProto) { - ToProto = ObjCProtocolDecl::Create(Importer.getToContext(), DC, - Name.getAsIdentifierInfo(), Loc, - Importer.Import(D->getAtStartLoc()), - /*PrevDecl=*/nullptr); + if (GetImportedOrCreateDecl(ToProto, D, Importer.getToContext(), DC, + Name.getAsIdentifierInfo(), Loc, + Importer.Import(D->getAtStartLoc()), + /*PrevDecl=*/nullptr)) + return ToProto; ToProto->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToProto); } - - Importer.Imported(D, ToProto); + + Importer.MapImported(D, ToProto); if (D->isThisDeclarationADefinition() && ImportDefinition(D, ToProto)) return nullptr; @@ -3076,14 +3636,11 @@ Decl *ASTNodeImporter::VisitLinkageSpecDecl(LinkageSpecDecl *D) { SourceLocation LangLoc = Importer.Import(D->getLocation()); bool HasBraces = D->hasBraces(); - - LinkageSpecDecl *ToLinkageSpec = - LinkageSpecDecl::Create(Importer.getToContext(), - DC, - ExternLoc, - LangLoc, - D->getLanguage(), - HasBraces); + + LinkageSpecDecl *ToLinkageSpec; + if (GetImportedOrCreateDecl(ToLinkageSpec, D, Importer.getToContext(), DC, + ExternLoc, LangLoc, D->getLanguage(), HasBraces)) + return ToLinkageSpec; if (HasBraces) { SourceLocation RBraceLoc = Importer.Import(D->getRBraceLoc()); @@ -3093,8 +3650,6 @@ Decl *ASTNodeImporter::VisitLinkageSpecDecl(LinkageSpecDecl *D) { ToLinkageSpec->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToLinkageSpec); - Importer.Imported(D, ToLinkageSpec); - return ToLinkageSpec; } @@ -3112,26 +3667,28 @@ Decl *ASTNodeImporter::VisitUsingDecl(UsingDecl *D) { Importer.Import(D->getNameInfo().getLoc())); ImportDeclarationNameLoc(D->getNameInfo(), NameInfo); - UsingDecl *ToUsing = UsingDecl::Create(Importer.getToContext(), DC, - Importer.Import(D->getUsingLoc()), - Importer.Import(D->getQualifierLoc()), - NameInfo, D->hasTypename()); + UsingDecl *ToUsing; + if (GetImportedOrCreateDecl(ToUsing, D, Importer.getToContext(), DC, + Importer.Import(D->getUsingLoc()), + Importer.Import(D->getQualifierLoc()), NameInfo, + D->hasTypename())) + return ToUsing; + ToUsing->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToUsing); - Importer.Imported(D, ToUsing); if (NamedDecl *FromPattern = Importer.getFromContext().getInstantiatedFromUsingDecl(D)) { - if (NamedDecl *ToPattern = - dyn_cast_or_null<NamedDecl>(Importer.Import(FromPattern))) + if (auto *ToPattern = + dyn_cast_or_null<NamedDecl>(Importer.Import(FromPattern))) Importer.getToContext().setInstantiatedFromUsingDecl(ToUsing, ToPattern); else return nullptr; } - for (UsingShadowDecl *FromShadow : D->shadows()) { - if (UsingShadowDecl *ToShadow = - dyn_cast_or_null<UsingShadowDecl>(Importer.Import(FromShadow))) + for (auto *FromShadow : D->shadows()) { + if (auto *ToShadow = + dyn_cast_or_null<UsingShadowDecl>(Importer.Import(FromShadow))) ToUsing->addShadowDecl(ToShadow); else // FIXME: We return a nullptr here but the definition is already created @@ -3151,27 +3708,28 @@ Decl *ASTNodeImporter::VisitUsingShadowDecl(UsingShadowDecl *D) { if (ToD) return ToD; - UsingDecl *ToUsing = dyn_cast_or_null<UsingDecl>( - Importer.Import(D->getUsingDecl())); + auto *ToUsing = dyn_cast_or_null<UsingDecl>( + Importer.Import(D->getUsingDecl())); if (!ToUsing) return nullptr; - NamedDecl *ToTarget = dyn_cast_or_null<NamedDecl>( - Importer.Import(D->getTargetDecl())); + auto *ToTarget = dyn_cast_or_null<NamedDecl>( + Importer.Import(D->getTargetDecl())); if (!ToTarget) return nullptr; - UsingShadowDecl *ToShadow = UsingShadowDecl::Create( - Importer.getToContext(), DC, Loc, ToUsing, ToTarget); + UsingShadowDecl *ToShadow; + if (GetImportedOrCreateDecl(ToShadow, D, Importer.getToContext(), DC, Loc, + ToUsing, ToTarget)) + return ToShadow; ToShadow->setLexicalDeclContext(LexicalDC); ToShadow->setAccess(D->getAccess()); - Importer.Imported(D, ToShadow); if (UsingShadowDecl *FromPattern = Importer.getFromContext().getInstantiatedFromUsingShadowDecl(D)) { - if (UsingShadowDecl *ToPattern = - dyn_cast_or_null<UsingShadowDecl>(Importer.Import(FromPattern))) + if (auto *ToPattern = + dyn_cast_or_null<UsingShadowDecl>(Importer.Import(FromPattern))) Importer.getToContext().setInstantiatedFromUsingShadowDecl(ToShadow, ToPattern); else @@ -3185,7 +3743,6 @@ Decl *ASTNodeImporter::VisitUsingShadowDecl(UsingShadowDecl *D) { return ToShadow; } - Decl *ASTNodeImporter::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { DeclContext *DC, *LexicalDC; DeclarationName Name; @@ -3200,19 +3757,22 @@ Decl *ASTNodeImporter::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { if (!ToComAncestor) return nullptr; - NamespaceDecl *ToNominated = cast_or_null<NamespaceDecl>( - Importer.Import(D->getNominatedNamespace())); + auto *ToNominated = cast_or_null<NamespaceDecl>( + Importer.Import(D->getNominatedNamespace())); if (!ToNominated) return nullptr; - UsingDirectiveDecl *ToUsingDir = UsingDirectiveDecl::Create( - Importer.getToContext(), DC, Importer.Import(D->getUsingLoc()), - Importer.Import(D->getNamespaceKeyLocation()), - Importer.Import(D->getQualifierLoc()), - Importer.Import(D->getIdentLocation()), ToNominated, ToComAncestor); + UsingDirectiveDecl *ToUsingDir; + if (GetImportedOrCreateDecl(ToUsingDir, D, Importer.getToContext(), DC, + Importer.Import(D->getUsingLoc()), + Importer.Import(D->getNamespaceKeyLocation()), + Importer.Import(D->getQualifierLoc()), + Importer.Import(D->getIdentLocation()), + ToNominated, ToComAncestor)) + return ToUsingDir; + ToUsingDir->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToUsingDir); - Importer.Imported(D, ToUsingDir); return ToUsingDir; } @@ -3231,12 +3791,13 @@ Decl *ASTNodeImporter::VisitUnresolvedUsingValueDecl( DeclarationNameInfo NameInfo(Name, Importer.Import(D->getNameInfo().getLoc())); ImportDeclarationNameLoc(D->getNameInfo(), NameInfo); - UnresolvedUsingValueDecl *ToUsingValue = UnresolvedUsingValueDecl::Create( - Importer.getToContext(), DC, Importer.Import(D->getUsingLoc()), - Importer.Import(D->getQualifierLoc()), NameInfo, - Importer.Import(D->getEllipsisLoc())); + UnresolvedUsingValueDecl *ToUsingValue; + if (GetImportedOrCreateDecl(ToUsingValue, D, Importer.getToContext(), DC, + Importer.Import(D->getUsingLoc()), + Importer.Import(D->getQualifierLoc()), NameInfo, + Importer.Import(D->getEllipsisLoc()))) + return ToUsingValue; - Importer.Imported(D, ToUsingValue); ToUsingValue->setAccess(D->getAccess()); ToUsingValue->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToUsingValue); @@ -3255,13 +3816,14 @@ Decl *ASTNodeImporter::VisitUnresolvedUsingTypenameDecl( if (ToD) return ToD; - UnresolvedUsingTypenameDecl *ToUsing = UnresolvedUsingTypenameDecl::Create( - Importer.getToContext(), DC, Importer.Import(D->getUsingLoc()), - Importer.Import(D->getTypenameLoc()), - Importer.Import(D->getQualifierLoc()), Loc, Name, - Importer.Import(D->getEllipsisLoc())); + UnresolvedUsingTypenameDecl *ToUsing; + if (GetImportedOrCreateDecl(ToUsing, D, Importer.getToContext(), DC, + Importer.Import(D->getUsingLoc()), + Importer.Import(D->getTypenameLoc()), + Importer.Import(D->getQualifierLoc()), Loc, Name, + Importer.Import(D->getEllipsisLoc()))) + return ToUsing; - Importer.Imported(D, ToUsing); ToUsing->setAccess(D->getAccess()); ToUsing->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToUsing); @@ -3269,7 +3831,6 @@ Decl *ASTNodeImporter::VisitUnresolvedUsingTypenameDecl( return ToUsing; } - bool ASTNodeImporter::ImportDefinition(ObjCInterfaceDecl *From, ObjCInterfaceDecl *To, ImportDefinitionKind Kind) { @@ -3330,8 +3891,7 @@ bool ASTNodeImporter::ImportDefinition(ObjCInterfaceDecl *From, FromProtoEnd = From->protocol_end(); FromProto != FromProtoEnd; ++FromProto, ++FromProtoLoc) { - ObjCProtocolDecl *ToProto - = cast_or_null<ObjCProtocolDecl>(Importer.Import(*FromProto)); + auto *ToProto = cast_or_null<ObjCProtocolDecl>(Importer.Import(*FromProto)); if (!ToProto) return true; Protocols.push_back(ToProto); @@ -3349,8 +3909,8 @@ bool ASTNodeImporter::ImportDefinition(ObjCInterfaceDecl *From, // If we have an @implementation, import it as well. if (From->getImplementation()) { - ObjCImplementationDecl *Impl = cast_or_null<ObjCImplementationDecl>( - Importer.Import(From->getImplementation())); + auto *Impl = cast_or_null<ObjCImplementationDecl>( + Importer.Import(From->getImplementation())); if (!Impl) return true; @@ -3371,8 +3931,8 @@ ASTNodeImporter::ImportObjCTypeParamList(ObjCTypeParamList *list) { SmallVector<ObjCTypeParamDecl *, 4> toTypeParams; for (auto fromTypeParam : *list) { - auto toTypeParam = cast_or_null<ObjCTypeParamDecl>( - Importer.Import(fromTypeParam)); + auto *toTypeParam = cast_or_null<ObjCTypeParamDecl>( + Importer.Import(fromTypeParam)); if (!toTypeParam) return nullptr; @@ -3395,7 +3955,7 @@ Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { if (!ImportedDef) return nullptr; - return Importer.Imported(D, ImportedDef); + return Importer.MapImported(D, ImportedDef); } // Import the major distinguishing characteristics of an @interface. @@ -3412,27 +3972,27 @@ Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { ObjCInterfaceDecl *MergeWithIface = nullptr; SmallVector<NamedDecl *, 2> FoundDecls; DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls); - for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { - if (!FoundDecls[I]->isInIdentifierNamespace(Decl::IDNS_Ordinary)) + for (auto *FoundDecl : FoundDecls) { + if (!FoundDecl->isInIdentifierNamespace(Decl::IDNS_Ordinary)) continue; - if ((MergeWithIface = dyn_cast<ObjCInterfaceDecl>(FoundDecls[I]))) + if ((MergeWithIface = dyn_cast<ObjCInterfaceDecl>(FoundDecl))) break; } // Create an interface declaration, if one does not already exist. ObjCInterfaceDecl *ToIface = MergeWithIface; if (!ToIface) { - ToIface = ObjCInterfaceDecl::Create(Importer.getToContext(), DC, - Importer.Import(D->getAtStartLoc()), - Name.getAsIdentifierInfo(), - /*TypeParamList=*/nullptr, - /*PrevDecl=*/nullptr, Loc, - D->isImplicitInterfaceDecl()); + if (GetImportedOrCreateDecl( + ToIface, D, Importer.getToContext(), DC, + Importer.Import(D->getAtStartLoc()), Name.getAsIdentifierInfo(), + /*TypeParamList=*/nullptr, + /*PrevDecl=*/nullptr, Loc, D->isImplicitInterfaceDecl())) + return ToIface; ToIface->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToIface); } - Importer.Imported(D, ToIface); + Importer.MapImported(D, ToIface); // Import the type parameter list after calling Imported, to avoid // loops when bringing in their DeclContext. ToIface->setTypeParamList(ImportObjCTypeParamList( @@ -3445,8 +4005,8 @@ Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { } Decl *ASTNodeImporter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) { - ObjCCategoryDecl *Category = cast_or_null<ObjCCategoryDecl>( - Importer.Import(D->getCategoryDecl())); + auto *Category = cast_or_null<ObjCCategoryDecl>( + Importer.Import(D->getCategoryDecl())); if (!Category) return nullptr; @@ -3457,13 +4017,13 @@ Decl *ASTNodeImporter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) { return nullptr; SourceLocation CategoryNameLoc = Importer.Import(D->getCategoryNameLoc()); - ToImpl = ObjCCategoryImplDecl::Create(Importer.getToContext(), DC, - Importer.Import(D->getIdentifier()), - Category->getClassInterface(), - Importer.Import(D->getLocation()), - Importer.Import(D->getAtStartLoc()), - CategoryNameLoc); - + if (GetImportedOrCreateDecl( + ToImpl, D, Importer.getToContext(), DC, + Importer.Import(D->getIdentifier()), Category->getClassInterface(), + Importer.Import(D->getLocation()), + Importer.Import(D->getAtStartLoc()), CategoryNameLoc)) + return ToImpl; + DeclContext *LexicalDC = DC; if (D->getDeclContext() != D->getLexicalDeclContext()) { LexicalDC = Importer.ImportContext(D->getLexicalDeclContext()); @@ -3477,15 +4037,15 @@ Decl *ASTNodeImporter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) { Category->setImplementation(ToImpl); } - Importer.Imported(D, ToImpl); + Importer.MapImported(D, ToImpl); ImportDeclContext(D); return ToImpl; } Decl *ASTNodeImporter::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { // Find the corresponding interface. - ObjCInterfaceDecl *Iface = cast_or_null<ObjCInterfaceDecl>( - Importer.Import(D->getClassInterface())); + auto *Iface = cast_or_null<ObjCInterfaceDecl>( + Importer.Import(D->getClassInterface())); if (!Iface) return nullptr; @@ -3502,15 +4062,15 @@ Decl *ASTNodeImporter::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { if (!Impl) { // We haven't imported an implementation yet. Create a new @implementation // now. - Impl = ObjCImplementationDecl::Create(Importer.getToContext(), - Importer.ImportContext(D->getDeclContext()), - Iface, Super, - Importer.Import(D->getLocation()), - Importer.Import(D->getAtStartLoc()), - Importer.Import(D->getSuperClassLoc()), - Importer.Import(D->getIvarLBraceLoc()), - Importer.Import(D->getIvarRBraceLoc())); - + if (GetImportedOrCreateDecl(Impl, D, Importer.getToContext(), + Importer.ImportContext(D->getDeclContext()), + Iface, Super, Importer.Import(D->getLocation()), + Importer.Import(D->getAtStartLoc()), + Importer.Import(D->getSuperClassLoc()), + Importer.Import(D->getIvarLBraceLoc()), + Importer.Import(D->getIvarRBraceLoc()))) + return Impl; + if (D->getDeclContext() != D->getLexicalDeclContext()) { DeclContext *LexicalDC = Importer.ImportContext(D->getLexicalDeclContext()); @@ -3518,12 +4078,12 @@ Decl *ASTNodeImporter::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { return nullptr; Impl->setLexicalDeclContext(LexicalDC); } - + // Associate the implementation with the class it implements. Iface->setImplementation(Impl); - Importer.Imported(D, Iface->getImplementation()); + Importer.MapImported(D, Iface->getImplementation()); } else { - Importer.Imported(D, Iface->getImplementation()); + Importer.MapImported(D, Iface->getImplementation()); // Verify that the existing @implementation has the same superclass. if ((Super && !Impl->getSuperClass()) || @@ -3574,9 +4134,8 @@ Decl *ASTNodeImporter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { // Check whether we have already imported this property. SmallVector<NamedDecl *, 2> FoundDecls; DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls); - for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { - if (ObjCPropertyDecl *FoundProp - = dyn_cast<ObjCPropertyDecl>(FoundDecls[I])) { + for (auto *FoundDecl : FoundDecls) { + if (auto *FoundProp = dyn_cast<ObjCPropertyDecl>(FoundDecl)) { // Check property types. if (!Importer.IsStructurallyEquivalent(D->getType(), FoundProp->getType())) { @@ -3590,7 +4149,7 @@ Decl *ASTNodeImporter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { // FIXME: Check property attributes, getters, setters, etc.? // Consider these properties to be equivalent. - Importer.Imported(D, FoundProp); + Importer.MapImported(D, FoundProp); return FoundProp; } } @@ -3601,15 +4160,14 @@ Decl *ASTNodeImporter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { return nullptr; // Create the new property. - ObjCPropertyDecl *ToProperty - = ObjCPropertyDecl::Create(Importer.getToContext(), DC, Loc, - Name.getAsIdentifierInfo(), - Importer.Import(D->getAtLoc()), - Importer.Import(D->getLParenLoc()), - Importer.Import(D->getType()), - TSI, - D->getPropertyImplementation()); - Importer.Imported(D, ToProperty); + ObjCPropertyDecl *ToProperty; + if (GetImportedOrCreateDecl( + ToProperty, D, Importer.getToContext(), DC, Loc, + Name.getAsIdentifierInfo(), Importer.Import(D->getAtLoc()), + Importer.Import(D->getLParenLoc()), Importer.Import(D->getType()), + TSI, D->getPropertyImplementation())) + return ToProperty; + ToProperty->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToProperty); @@ -3630,8 +4188,8 @@ Decl *ASTNodeImporter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { } Decl *ASTNodeImporter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { - ObjCPropertyDecl *Property = cast_or_null<ObjCPropertyDecl>( - Importer.Import(D->getPropertyDecl())); + auto *Property = cast_or_null<ObjCPropertyDecl>( + Importer.Import(D->getPropertyDecl())); if (!Property) return nullptr; @@ -3647,7 +4205,7 @@ Decl *ASTNodeImporter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { return nullptr; } - ObjCImplDecl *InImpl = dyn_cast<ObjCImplDecl>(LexicalDC); + auto *InImpl = dyn_cast<ObjCImplDecl>(LexicalDC); if (!InImpl) return nullptr; @@ -3663,16 +4221,15 @@ Decl *ASTNodeImporter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { ObjCPropertyImplDecl *ToImpl = InImpl->FindPropertyImplDecl(Property->getIdentifier(), Property->getQueryKind()); - if (!ToImpl) { - ToImpl = ObjCPropertyImplDecl::Create(Importer.getToContext(), DC, - Importer.Import(D->getLocStart()), - Importer.Import(D->getLocation()), - Property, - D->getPropertyImplementation(), - Ivar, - Importer.Import(D->getPropertyIvarDeclLoc())); + if (!ToImpl) { + if (GetImportedOrCreateDecl(ToImpl, D, Importer.getToContext(), DC, + Importer.Import(D->getLocStart()), + Importer.Import(D->getLocation()), Property, + D->getPropertyImplementation(), Ivar, + Importer.Import(D->getPropertyIvarDeclLoc()))) + return ToImpl; + ToImpl->setLexicalDeclContext(LexicalDC); - Importer.Imported(D, ToImpl); LexicalDC->addDeclInternal(ToImpl); } else { // Check that we have the same kind of property implementation (@synthesize @@ -3705,7 +4262,7 @@ Decl *ASTNodeImporter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { } // Merge the existing implementation with the new implementation. - Importer.Imported(D, ToImpl); + Importer.MapImported(D, ToImpl); } return ToImpl; @@ -3717,15 +4274,14 @@ Decl *ASTNodeImporter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { // is created. // FIXME: Import default argument. - return TemplateTypeParmDecl::Create(Importer.getToContext(), - Importer.getToContext().getTranslationUnitDecl(), - Importer.Import(D->getLocStart()), - Importer.Import(D->getLocation()), - D->getDepth(), - D->getIndex(), - Importer.Import(D->getIdentifier()), - D->wasDeclaredWithTypename(), - D->isParameterPack()); + TemplateTypeParmDecl *ToD = nullptr; + (void)GetImportedOrCreateDecl( + ToD, D, Importer.getToContext(), + Importer.getToContext().getTranslationUnitDecl(), + Importer.Import(D->getLocStart()), Importer.Import(D->getLocation()), + D->getDepth(), D->getIndex(), Importer.Import(D->getIdentifier()), + D->wasDeclaredWithTypename(), D->isParameterPack()); + return ToD; } Decl * @@ -3749,13 +4305,15 @@ ASTNodeImporter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { return nullptr; // FIXME: Import default argument. - - return NonTypeTemplateParmDecl::Create(Importer.getToContext(), - Importer.getToContext().getTranslationUnitDecl(), - Importer.Import(D->getInnerLocStart()), - Loc, D->getDepth(), D->getPosition(), - Name.getAsIdentifierInfo(), - T, D->isParameterPack(), TInfo); + + NonTypeTemplateParmDecl *ToD = nullptr; + (void)GetImportedOrCreateDecl( + ToD, D, Importer.getToContext(), + Importer.getToContext().getTranslationUnitDecl(), + Importer.Import(D->getInnerLocStart()), Loc, D->getDepth(), + D->getPosition(), Name.getAsIdentifierInfo(), T, D->isParameterPack(), + TInfo); + return ToD; } Decl * @@ -3767,7 +4325,7 @@ ASTNodeImporter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { // Import the location of this declaration. SourceLocation Loc = Importer.Import(D->getLocation()); - + // Import template parameters. TemplateParameterList *TemplateParams = ImportTemplateParameterList(D->getTemplateParameters()); @@ -3775,30 +4333,42 @@ ASTNodeImporter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { return nullptr; // FIXME: Import default argument. - - return TemplateTemplateParmDecl::Create(Importer.getToContext(), - Importer.getToContext().getTranslationUnitDecl(), - Loc, D->getDepth(), D->getPosition(), - D->isParameterPack(), - Name.getAsIdentifierInfo(), - TemplateParams); + + TemplateTemplateParmDecl *ToD = nullptr; + (void)GetImportedOrCreateDecl( + ToD, D, Importer.getToContext(), + Importer.getToContext().getTranslationUnitDecl(), Loc, D->getDepth(), + D->getPosition(), D->isParameterPack(), Name.getAsIdentifierInfo(), + TemplateParams); + return ToD; +} + +// Returns the definition for a (forward) declaration of a ClassTemplateDecl, if +// it has any definition in the redecl chain. +static ClassTemplateDecl *getDefinition(ClassTemplateDecl *D) { + CXXRecordDecl *ToTemplatedDef = D->getTemplatedDecl()->getDefinition(); + if (!ToTemplatedDef) + return nullptr; + ClassTemplateDecl *TemplateWithDef = + ToTemplatedDef->getDescribedClassTemplate(); + return TemplateWithDef; } Decl *ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) { // If this record has a definition in the translation unit we're coming from, // but this particular declaration is not that definition, import the // definition and map to that. - CXXRecordDecl *Definition - = cast_or_null<CXXRecordDecl>(D->getTemplatedDecl()->getDefinition()); + auto *Definition = + cast_or_null<CXXRecordDecl>(D->getTemplatedDecl()->getDefinition()); if (Definition && Definition != D->getTemplatedDecl()) { Decl *ImportedDef = Importer.Import(Definition->getDescribedClassTemplate()); if (!ImportedDef) return nullptr; - return Importer.Imported(D, ImportedDef); + return Importer.MapImported(D, ImportedDef); } - + // Import the major distinguishing characteristics of this class template. DeclContext *DC, *LexicalDC; DeclarationName Name; @@ -3814,69 +4384,73 @@ Decl *ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) { SmallVector<NamedDecl *, 4> ConflictingDecls; SmallVector<NamedDecl *, 2> FoundDecls; DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls); - for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { - if (!FoundDecls[I]->isInIdentifierNamespace(Decl::IDNS_Ordinary)) + for (auto *FoundDecl : FoundDecls) { + if (!FoundDecl->isInIdentifierNamespace(Decl::IDNS_Ordinary)) continue; - - Decl *Found = FoundDecls[I]; - if (ClassTemplateDecl *FoundTemplate - = dyn_cast<ClassTemplateDecl>(Found)) { + + Decl *Found = FoundDecl; + if (auto *FoundTemplate = dyn_cast<ClassTemplateDecl>(Found)) { + + // The class to be imported is a definition. + if (D->isThisDeclarationADefinition()) { + // Lookup will find the fwd decl only if that is more recent than the + // definition. So, try to get the definition if that is available in + // the redecl chain. + ClassTemplateDecl *TemplateWithDef = getDefinition(FoundTemplate); + if (!TemplateWithDef) + continue; + FoundTemplate = TemplateWithDef; // Continue with the definition. + } + if (IsStructuralMatch(D, FoundTemplate)) { // The class templates structurally match; call it the same template. - // FIXME: We may be filling in a forward declaration here. Handle - // this case! - Importer.Imported(D->getTemplatedDecl(), - FoundTemplate->getTemplatedDecl()); - return Importer.Imported(D, FoundTemplate); - } + + Importer.MapImported(D->getTemplatedDecl(), + FoundTemplate->getTemplatedDecl()); + return Importer.MapImported(D, FoundTemplate); + } } - - ConflictingDecls.push_back(FoundDecls[I]); + + ConflictingDecls.push_back(FoundDecl); } - + if (!ConflictingDecls.empty()) { Name = Importer.HandleNameConflict(Name, DC, Decl::IDNS_Ordinary, - ConflictingDecls.data(), + ConflictingDecls.data(), ConflictingDecls.size()); } - + if (!Name) return nullptr; } - CXXRecordDecl *DTemplated = D->getTemplatedDecl(); - + CXXRecordDecl *FromTemplated = D->getTemplatedDecl(); + // Create the declaration that is being templated. - CXXRecordDecl *D2Templated = cast_or_null<CXXRecordDecl>( - Importer.Import(DTemplated)); - if (!D2Templated) + auto *ToTemplated = cast_or_null<CXXRecordDecl>( + Importer.Import(FromTemplated)); + if (!ToTemplated) return nullptr; - // Resolve possible cyclic import. - if (Decl *AlreadyImported = Importer.GetAlreadyImportedOrNull(D)) - return AlreadyImported; - // Create the class template declaration itself. - TemplateParameterList *TemplateParams - = ImportTemplateParameterList(D->getTemplateParameters()); + TemplateParameterList *TemplateParams = + ImportTemplateParameterList(D->getTemplateParameters()); if (!TemplateParams) return nullptr; - ClassTemplateDecl *D2 = ClassTemplateDecl::Create(Importer.getToContext(), DC, - Loc, Name, TemplateParams, - D2Templated); - D2Templated->setDescribedClassTemplate(D2); + ClassTemplateDecl *D2; + if (GetImportedOrCreateDecl(D2, D, Importer.getToContext(), DC, Loc, Name, + TemplateParams, ToTemplated)) + return D2; + + ToTemplated->setDescribedClassTemplate(D2); D2->setAccess(D->getAccess()); D2->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(D2); - // Note the relationship between the class templates. - Importer.Imported(D, D2); - Importer.Imported(DTemplated, D2Templated); - - if (DTemplated->isCompleteDefinition() && - !D2Templated->isCompleteDefinition()) { + if (FromTemplated->isCompleteDefinition() && + !ToTemplated->isCompleteDefinition()) { // FIXME: Import definition! } @@ -3894,11 +4468,11 @@ Decl *ASTNodeImporter::VisitClassTemplateSpecializationDecl( if (!ImportedDef) return nullptr; - return Importer.Imported(D, ImportedDef); + return Importer.MapImported(D, ImportedDef); } - ClassTemplateDecl *ClassTemplate - = cast_or_null<ClassTemplateDecl>(Importer.Import( + auto *ClassTemplate = + cast_or_null<ClassTemplateDecl>(Importer.Import( D->getSpecializedTemplate())); if (!ClassTemplate) return nullptr; @@ -3941,23 +4515,18 @@ Decl *ASTNodeImporter::VisitClassTemplateSpecializationDecl( // The record types structurally match, or the "from" translation // unit only had a forward declaration anyway; call it the same // function. - return Importer.Imported(D, FoundDef); + return Importer.MapImported(D, FoundDef); } } } else { // Create a new specialization. - if (ClassTemplatePartialSpecializationDecl *PartialSpec = - dyn_cast<ClassTemplatePartialSpecializationDecl>(D)) { - + if (auto *PartialSpec = + dyn_cast<ClassTemplatePartialSpecializationDecl>(D)) { // Import TemplateArgumentListInfo TemplateArgumentListInfo ToTAInfo; - auto &ASTTemplateArgs = *PartialSpec->getTemplateArgsAsWritten(); - for (unsigned I = 0, E = ASTTemplateArgs.NumTemplateArgs; I < E; ++I) { - if (auto ToLoc = ImportTemplateArgumentLoc(ASTTemplateArgs[I])) - ToTAInfo.addArgument(*ToLoc); - else - return nullptr; - } + const auto &ASTTemplateArgs = *PartialSpec->getTemplateArgsAsWritten(); + if (ImportTemplateArgumentListInfo(ASTTemplateArgs, ToTAInfo)) + return nullptr; QualType CanonInjType = Importer.Import( PartialSpec->getInjectedSpecializationType()); @@ -3970,19 +4539,18 @@ Decl *ASTNodeImporter::VisitClassTemplateSpecializationDecl( if (!ToTPList && PartialSpec->getTemplateParameters()) return nullptr; - D2 = ClassTemplatePartialSpecializationDecl::Create( - Importer.getToContext(), D->getTagKind(), DC, StartLoc, IdLoc, - ToTPList, ClassTemplate, - llvm::makeArrayRef(TemplateArgs.data(), TemplateArgs.size()), - ToTAInfo, CanonInjType, nullptr); + if (GetImportedOrCreateDecl<ClassTemplatePartialSpecializationDecl>( + D2, D, Importer.getToContext(), D->getTagKind(), DC, StartLoc, + IdLoc, ToTPList, ClassTemplate, + llvm::makeArrayRef(TemplateArgs.data(), TemplateArgs.size()), + ToTAInfo, CanonInjType, nullptr)) + return D2; } else { - D2 = ClassTemplateSpecializationDecl::Create(Importer.getToContext(), - D->getTagKind(), DC, - StartLoc, IdLoc, - ClassTemplate, - TemplateArgs, - /*PrevDecl=*/nullptr); + if (GetImportedOrCreateDecl( + D2, D, Importer.getToContext(), D->getTagKind(), DC, StartLoc, + IdLoc, ClassTemplate, TemplateArgs, /*PrevDecl=*/nullptr)) + return D2; } D2->setSpecializationKind(D->getSpecializationKind()); @@ -3993,8 +4561,6 @@ Decl *ASTNodeImporter::VisitClassTemplateSpecializationDecl( // Import the qualifier, if any. D2->setQualifierInfo(Importer.Import(D->getQualifierLoc())); - Importer.Imported(D, D2); - if (auto *TSI = D->getTypeAsWritten()) { TypeSourceInfo *TInfo = Importer.Import(TSI); if (!TInfo) @@ -4012,11 +4578,14 @@ Decl *ASTNodeImporter::VisitClassTemplateSpecializationDecl( D2->setTemplateSpecializationKind(D->getTemplateSpecializationKind()); - // Add the specialization to this context. + // Set the context of this specialization/instantiation. D2->setLexicalDeclContext(LexicalDC); - LexicalDC->addDeclInternal(D2); + + // Add to the DC only if it was an explicit specialization/instantiation. + if (D2->isExplicitInstantiationOrSpecialization()) { + LexicalDC->addDeclInternal(D2); + } } - Importer.Imported(D, D2); if (D->isCompleteDefinition() && ImportDefinition(D, D2)) return nullptr; @@ -4028,14 +4597,14 @@ Decl *ASTNodeImporter::VisitVarTemplateDecl(VarTemplateDecl *D) { // from, // but this particular declaration is not that definition, import the // definition and map to that. - VarDecl *Definition = + auto *Definition = cast_or_null<VarDecl>(D->getTemplatedDecl()->getDefinition()); if (Definition && Definition != D->getTemplatedDecl()) { Decl *ImportedDef = Importer.Import(Definition->getDescribedVarTemplate()); if (!ImportedDef) return nullptr; - return Importer.Imported(D, ImportedDef); + return Importer.MapImported(D, ImportedDef); } // Import the major distinguishing characteristics of this variable template. @@ -4054,21 +4623,21 @@ Decl *ASTNodeImporter::VisitVarTemplateDecl(VarTemplateDecl *D) { SmallVector<NamedDecl *, 4> ConflictingDecls; SmallVector<NamedDecl *, 2> FoundDecls; DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls); - for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { - if (!FoundDecls[I]->isInIdentifierNamespace(Decl::IDNS_Ordinary)) + for (auto *FoundDecl : FoundDecls) { + if (!FoundDecl->isInIdentifierNamespace(Decl::IDNS_Ordinary)) continue; - Decl *Found = FoundDecls[I]; - if (VarTemplateDecl *FoundTemplate = dyn_cast<VarTemplateDecl>(Found)) { + Decl *Found = FoundDecl; + if (auto *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); + Importer.MapImported(D->getTemplatedDecl(), + FoundTemplate->getTemplatedDecl()); + return Importer.MapImported(D, FoundTemplate); } } - ConflictingDecls.push_back(FoundDecls[I]); + ConflictingDecls.push_back(FoundDecl); } if (!ConflictingDecls.empty()) { @@ -4088,21 +4657,8 @@ Decl *ASTNodeImporter::VisitVarTemplateDecl(VarTemplateDecl *D) { return nullptr; // 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)) + auto *ToTemplated = dyn_cast_or_null<VarDecl>(Importer.Import(DTemplated)); + if (!ToTemplated) return nullptr; // Create the variable template declaration itself. @@ -4111,24 +4667,23 @@ Decl *ASTNodeImporter::VisitVarTemplateDecl(VarTemplateDecl *D) { if (!TemplateParams) return nullptr; - VarTemplateDecl *D2 = VarTemplateDecl::Create( - Importer.getToContext(), DC, Loc, Name, TemplateParams, D2Templated); - D2Templated->setDescribedVarTemplate(D2); + VarTemplateDecl *ToVarTD; + if (GetImportedOrCreateDecl(ToVarTD, D, Importer.getToContext(), DC, Loc, + Name, TemplateParams, ToTemplated)) + return ToVarTD; - D2->setAccess(D->getAccess()); - D2->setLexicalDeclContext(LexicalDC); - LexicalDC->addDeclInternal(D2); + ToTemplated->setDescribedVarTemplate(ToVarTD); - // Note the relationship between the variable templates. - Importer.Imported(D, D2); - Importer.Imported(DTemplated, D2Templated); + ToVarTD->setAccess(D->getAccess()); + ToVarTD->setLexicalDeclContext(LexicalDC); + LexicalDC->addDeclInternal(ToVarTD); if (DTemplated->isThisDeclarationADefinition() && - !D2Templated->isThisDeclarationADefinition()) { + !ToTemplated->isThisDeclarationADefinition()) { // FIXME: Import definition! } - return D2; + return ToVarTD; } Decl *ASTNodeImporter::VisitVarTemplateSpecializationDecl( @@ -4142,10 +4697,10 @@ Decl *ASTNodeImporter::VisitVarTemplateSpecializationDecl( if (!ImportedDef) return nullptr; - return Importer.Imported(D, ImportedDef); + return Importer.MapImported(D, ImportedDef); } - VarTemplateDecl *VarTemplate = cast_or_null<VarTemplateDecl>( + auto *VarTemplate = cast_or_null<VarTemplateDecl>( Importer.Import(D->getSpecializedTemplate())); if (!VarTemplate) return nullptr; @@ -4188,23 +4743,68 @@ Decl *ASTNodeImporter::VisitVarTemplateSpecializationDecl( // 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); + return Importer.MapImported(D, FoundDef); } } } else { - // Import the type. QualType T = Importer.Import(D->getType()); if (T.isNull()) return nullptr; + TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo()); + if (D->getTypeSourceInfo() && !TInfo) + return nullptr; + + TemplateArgumentListInfo ToTAInfo; + if (ImportTemplateArgumentListInfo(D->getTemplateArgsInfo(), ToTAInfo)) + return nullptr; + using PartVarSpecDecl = VarTemplatePartialSpecializationDecl; // Create a new specialization. - D2 = VarTemplateSpecializationDecl::Create( - Importer.getToContext(), DC, StartLoc, IdLoc, VarTemplate, T, TInfo, - D->getStorageClass(), TemplateArgs); + if (auto *FromPartial = dyn_cast<PartVarSpecDecl>(D)) { + // Import TemplateArgumentListInfo + TemplateArgumentListInfo ArgInfos; + const auto *FromTAArgsAsWritten = FromPartial->getTemplateArgsAsWritten(); + // NOTE: FromTAArgsAsWritten and template parameter list are non-null. + if (ImportTemplateArgumentListInfo(*FromTAArgsAsWritten, ArgInfos)) + return nullptr; + + TemplateParameterList *ToTPList = ImportTemplateParameterList( + FromPartial->getTemplateParameters()); + if (!ToTPList) + return nullptr; + + PartVarSpecDecl *ToPartial; + if (GetImportedOrCreateDecl(ToPartial, D, Importer.getToContext(), DC, + StartLoc, IdLoc, ToTPList, VarTemplate, T, + TInfo, D->getStorageClass(), TemplateArgs, + ArgInfos)) + return ToPartial; + + auto *FromInst = FromPartial->getInstantiatedFromMember(); + auto *ToInst = cast_or_null<PartVarSpecDecl>(Importer.Import(FromInst)); + if (FromInst && !ToInst) + return nullptr; + + ToPartial->setInstantiatedFromMember(ToInst); + if (FromPartial->isMemberSpecialization()) + ToPartial->setMemberSpecialization(); + + D2 = ToPartial; + } else { // Full specialization + if (GetImportedOrCreateDecl(D2, D, Importer.getToContext(), DC, StartLoc, + IdLoc, VarTemplate, T, TInfo, + D->getStorageClass(), TemplateArgs)) + return D2; + } + + SourceLocation POI = D->getPointOfInstantiation(); + if (POI.isValid()) + D2->setPointOfInstantiation(Importer.Import(POI)); + D2->setSpecializationKind(D->getSpecializationKind()); - D2->setTemplateArgsInfo(D->getTemplateArgsInfo()); + D2->setTemplateArgsInfo(ToTAInfo); // Add this specialization to the class template. VarTemplate->AddSpecialization(D2, InsertPos); @@ -4212,13 +4812,22 @@ Decl *ASTNodeImporter::VisitVarTemplateSpecializationDecl( // Import the qualifier, if any. D2->setQualifierInfo(Importer.Import(D->getQualifierLoc())); + if (D->isConstexpr()) + D2->setConstexpr(true); + // Add the specialization to this context. D2->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(D2); + + D2->setAccess(D->getAccess()); } - Importer.Imported(D, D2); - if (D->isThisDeclarationADefinition() && ImportDefinition(D, D2)) + // NOTE: isThisDeclarationADefinition() can return DeclarationOnly even if + // declaration has initializer. Should this be fixed in the AST?.. Anyway, + // we have to check the declaration for initializer - otherwise, it won't be + // imported. + if ((D->isThisDeclarationADefinition() || D->hasInit()) && + ImportDefinition(D, D2)) return nullptr; return D2; @@ -4242,16 +4851,15 @@ Decl *ASTNodeImporter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { unsigned IDNS = Decl::IDNS_Ordinary; SmallVector<NamedDecl *, 2> FoundDecls; DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls); - for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { - if (!FoundDecls[I]->isInIdentifierNamespace(IDNS)) + for (auto *FoundDecl : FoundDecls) { + if (!FoundDecl->isInIdentifierNamespace(IDNS)) continue; - if (FunctionTemplateDecl *FoundFunction = - dyn_cast<FunctionTemplateDecl>(FoundDecls[I])) { + if (auto *FoundFunction = dyn_cast<FunctionTemplateDecl>(FoundDecl)) { if (FoundFunction->hasExternalFormalLinkage() && D->hasExternalFormalLinkage()) { if (IsStructuralMatch(D, FoundFunction)) { - Importer.Imported(D, FoundFunction); + Importer.MapImported(D, FoundFunction); // FIXME: Actually try to merge the body and other attributes. return FoundFunction; } @@ -4265,18 +4873,19 @@ Decl *ASTNodeImporter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { if (!Params) return nullptr; - FunctionDecl *TemplatedFD = + auto *TemplatedFD = cast_or_null<FunctionDecl>(Importer.Import(D->getTemplatedDecl())); if (!TemplatedFD) return nullptr; - FunctionTemplateDecl *ToFunc = FunctionTemplateDecl::Create( - Importer.getToContext(), DC, Loc, Name, Params, TemplatedFD); + FunctionTemplateDecl *ToFunc; + if (GetImportedOrCreateDecl(ToFunc, D, Importer.getToContext(), DC, Loc, Name, + Params, TemplatedFD)) + return ToFunc; TemplatedFD->setDescribedFunctionTemplate(ToFunc); ToFunc->setAccess(D->getAccess()); ToFunc->setLexicalDeclContext(LexicalDC); - Importer.Imported(D, ToFunc); LexicalDC->addDeclInternal(ToFunc); return ToFunc; @@ -4301,12 +4910,11 @@ DeclGroupRef ASTNodeImporter::ImportDeclGroup(DeclGroupRef DG) { NumDecls); } - Stmt *ASTNodeImporter::VisitStmt(Stmt *S) { - Importer.FromDiag(S->getLocStart(), diag::err_unsupported_ast_node) - << S->getStmtClassName(); - return nullptr; - } - +Stmt *ASTNodeImporter::VisitStmt(Stmt *S) { + Importer.FromDiag(S->getLocStart(), diag::err_unsupported_ast_node) + << S->getStmtClassName(); + return nullptr; +} Stmt *ASTNodeImporter::VisitGCCAsmStmt(GCCAsmStmt *S) { SmallVector<IdentifierInfo *, 4> Names; @@ -4329,8 +4937,8 @@ Stmt *ASTNodeImporter::VisitGCCAsmStmt(GCCAsmStmt *S) { SmallVector<StringLiteral *, 4> Clobbers; for (unsigned I = 0, E = S->getNumClobbers(); I != E; I++) { - StringLiteral *Clobber = cast_or_null<StringLiteral>( - Importer.Import(S->getClobberStringLiteral(I))); + auto *Clobber = cast_or_null<StringLiteral>( + Importer.Import(S->getClobberStringLiteral(I))); if (!Clobber) return nullptr; Clobbers.push_back(Clobber); @@ -4338,16 +4946,16 @@ Stmt *ASTNodeImporter::VisitGCCAsmStmt(GCCAsmStmt *S) { SmallVector<StringLiteral *, 4> Constraints; for (unsigned I = 0, E = S->getNumOutputs(); I != E; I++) { - StringLiteral *Output = cast_or_null<StringLiteral>( - Importer.Import(S->getOutputConstraintLiteral(I))); + auto *Output = cast_or_null<StringLiteral>( + Importer.Import(S->getOutputConstraintLiteral(I))); if (!Output) return nullptr; Constraints.push_back(Output); } for (unsigned I = 0, E = S->getNumInputs(); I != E; I++) { - StringLiteral *Input = cast_or_null<StringLiteral>( - Importer.Import(S->getInputConstraintLiteral(I))); + auto *Input = cast_or_null<StringLiteral>( + Importer.Import(S->getInputConstraintLiteral(I))); if (!Input) return nullptr; Constraints.push_back(Input); @@ -4360,8 +4968,8 @@ Stmt *ASTNodeImporter::VisitGCCAsmStmt(GCCAsmStmt *S) { if (ImportArrayChecked(S->inputs(), Exprs.begin() + S->getNumOutputs())) return nullptr; - StringLiteral *AsmStr = cast_or_null<StringLiteral>( - Importer.Import(S->getAsmString())); + auto *AsmStr = cast_or_null<StringLiteral>( + Importer.Import(S->getAsmString())); if (!AsmStr) return nullptr; @@ -4383,7 +4991,7 @@ Stmt *ASTNodeImporter::VisitGCCAsmStmt(GCCAsmStmt *S) { Stmt *ASTNodeImporter::VisitDeclStmt(DeclStmt *S) { DeclGroupRef ToDG = ImportDeclGroup(S->getDeclGroup()); - for (Decl *ToD : ToDG) { + for (auto *ToD : ToDG) { if (!ToD) return nullptr; } @@ -4399,7 +5007,7 @@ Stmt *ASTNodeImporter::VisitNullStmt(NullStmt *S) { } Stmt *ASTNodeImporter::VisitCompoundStmt(CompoundStmt *S) { - llvm::SmallVector<Stmt *, 8> ToStmts(S->size()); + SmallVector<Stmt *, 8> ToStmts(S->size()); if (ImportContainerChecked(S->body(), ToStmts)) return nullptr; @@ -4423,7 +5031,7 @@ Stmt *ASTNodeImporter::VisitCaseStmt(CaseStmt *S) { SourceLocation ToCaseLoc = Importer.Import(S->getCaseLoc()); SourceLocation ToEllipsisLoc = Importer.Import(S->getEllipsisLoc()); SourceLocation ToColonLoc = Importer.Import(S->getColonLoc()); - CaseStmt *ToStmt = new (Importer.getToContext()) + auto *ToStmt = new (Importer.getToContext()) CaseStmt(ToLHS, ToRHS, ToCaseLoc, ToEllipsisLoc, ToColonLoc); ToStmt->setSubStmt(ToSubStmt); return ToStmt; @@ -4441,8 +5049,7 @@ Stmt *ASTNodeImporter::VisitDefaultStmt(DefaultStmt *S) { Stmt *ASTNodeImporter::VisitLabelStmt(LabelStmt *S) { SourceLocation ToIdentLoc = Importer.Import(S->getIdentLoc()); - LabelDecl *ToLabelDecl = - cast_or_null<LabelDecl>(Importer.Import(S->getDecl())); + auto *ToLabelDecl = cast_or_null<LabelDecl>(Importer.Import(S->getDecl())); if (!ToLabelDecl && S->getDecl()) return nullptr; Stmt *ToSubStmt = Importer.Import(S->getSubStmt()); @@ -4456,15 +5063,8 @@ Stmt *ASTNodeImporter::VisitAttributedStmt(AttributedStmt *S) { SourceLocation ToAttrLoc = Importer.Import(S->getAttrLoc()); ArrayRef<const Attr*> FromAttrs(S->getAttrs()); SmallVector<const Attr *, 1> ToAttrs(FromAttrs.size()); - ASTContext &_ToContext = Importer.getToContext(); - std::transform(FromAttrs.begin(), FromAttrs.end(), ToAttrs.begin(), - [&_ToContext](const Attr *A) -> const Attr * { - return A->clone(_ToContext); - }); - for (const Attr *ToA : ToAttrs) { - if (!ToA) - return nullptr; - } + if (ImportContainerChecked(FromAttrs, ToAttrs)) + return nullptr; Stmt *ToSubStmt = Importer.Import(S->getSubStmt()); if (!ToSubStmt && S->getSubStmt()) return nullptr; @@ -4516,7 +5116,7 @@ Stmt *ASTNodeImporter::VisitSwitchStmt(SwitchStmt *S) { Expr *ToCondition = Importer.Import(S->getCond()); if (!ToCondition && S->getCond()) return nullptr; - SwitchStmt *ToStmt = new (Importer.getToContext()) SwitchStmt( + auto *ToStmt = new (Importer.getToContext()) SwitchStmt( Importer.getToContext(), ToInit, ToConditionVariable, ToCondition); Stmt *ToBody = Importer.Import(S->getBody()); @@ -4528,7 +5128,7 @@ Stmt *ASTNodeImporter::VisitSwitchStmt(SwitchStmt *S) { SwitchCase *LastChainedSwitchCase = nullptr; for (SwitchCase *SC = S->getSwitchCaseList(); SC != nullptr; SC = SC->getNextSwitchCase()) { - SwitchCase *ToSC = dyn_cast_or_null<SwitchCase>(Importer.Import(SC)); + auto *ToSC = dyn_cast_or_null<SwitchCase>(Importer.Import(SC)); if (!ToSC) return nullptr; if (LastChainedSwitchCase) @@ -4645,8 +5245,8 @@ Stmt *ASTNodeImporter::VisitReturnStmt(ReturnStmt *S) { Expr *ToRetExpr = Importer.Import(S->getRetValue()); if (!ToRetExpr && S->getRetValue()) return nullptr; - VarDecl *NRVOCandidate = const_cast<VarDecl*>(S->getNRVOCandidate()); - VarDecl *ToNRVOCandidate = cast_or_null<VarDecl>(Importer.Import(NRVOCandidate)); + auto *NRVOCandidate = const_cast<VarDecl *>(S->getNRVOCandidate()); + auto *ToNRVOCandidate = cast_or_null<VarDecl>(Importer.Import(NRVOCandidate)); if (!ToNRVOCandidate && NRVOCandidate) return nullptr; return new (Importer.getToContext()) ReturnStmt(ToRetLoc, ToRetExpr, @@ -4688,15 +5288,15 @@ Stmt *ASTNodeImporter::VisitCXXTryStmt(CXXTryStmt *S) { } Stmt *ASTNodeImporter::VisitCXXForRangeStmt(CXXForRangeStmt *S) { - DeclStmt *ToRange = + auto *ToRange = dyn_cast_or_null<DeclStmt>(Importer.Import(S->getRangeStmt())); if (!ToRange && S->getRangeStmt()) return nullptr; - DeclStmt *ToBegin = + auto *ToBegin = dyn_cast_or_null<DeclStmt>(Importer.Import(S->getBeginStmt())); if (!ToBegin && S->getBeginStmt()) return nullptr; - DeclStmt *ToEnd = + auto *ToEnd = dyn_cast_or_null<DeclStmt>(Importer.Import(S->getEndStmt())); if (!ToEnd && S->getEndStmt()) return nullptr; @@ -4706,7 +5306,7 @@ Stmt *ASTNodeImporter::VisitCXXForRangeStmt(CXXForRangeStmt *S) { Expr *ToInc = Importer.Import(S->getInc()); if (!ToInc && S->getInc()) return nullptr; - DeclStmt *ToLoopVar = + auto *ToLoopVar = dyn_cast_or_null<DeclStmt>(Importer.Import(S->getLoopVarStmt())); if (!ToLoopVar && S->getLoopVarStmt()) return nullptr; @@ -4851,7 +5451,6 @@ Expr *ASTNodeImporter::VisitVAArgExpr(VAArgExpr *E) { Importer.Import(E->getRParenLoc()), T, E->isMicrosoftABI()); } - Expr *ASTNodeImporter::VisitGNUNullExpr(GNUNullExpr *E) { QualType T = Importer.Import(E->getType()); if (T.isNull()) @@ -4866,8 +5465,7 @@ Expr *ASTNodeImporter::VisitPredefinedExpr(PredefinedExpr *E) { if (T.isNull()) return nullptr; - StringLiteral *SL = cast_or_null<StringLiteral>( - Importer.Import(E->getFunctionName())); + auto *SL = cast_or_null<StringLiteral>(Importer.Import(E->getFunctionName())); if (!SL && E->getFunctionName()) return nullptr; @@ -4876,7 +5474,7 @@ Expr *ASTNodeImporter::VisitPredefinedExpr(PredefinedExpr *E) { } Expr *ASTNodeImporter::VisitDeclRefExpr(DeclRefExpr *E) { - ValueDecl *ToD = cast_or_null<ValueDecl>(Importer.Import(E->getDecl())); + auto *ToD = cast_or_null<ValueDecl>(Importer.Import(E->getDecl())); if (!ToD) return nullptr; @@ -4891,16 +5489,11 @@ Expr *ASTNodeImporter::VisitDeclRefExpr(DeclRefExpr *E) { if (T.isNull()) return nullptr; - TemplateArgumentListInfo ToTAInfo; TemplateArgumentListInfo *ResInfo = nullptr; if (E->hasExplicitTemplateArgs()) { - for (const auto &FromLoc : E->template_arguments()) { - if (auto ToTALoc = ImportTemplateArgumentLoc(FromLoc)) - ToTAInfo.addArgument(*ToTALoc); - else - return nullptr; - } + if (ImportTemplateArgumentListInfo(E->template_arguments(), ToTAInfo)) + return nullptr; ResInfo = &ToTAInfo; } @@ -4947,14 +5540,14 @@ ASTNodeImporter::ImportDesignator(const Designator &D) { Expr *ASTNodeImporter::VisitDesignatedInitExpr(DesignatedInitExpr *DIE) { - Expr *Init = cast_or_null<Expr>(Importer.Import(DIE->getInit())); + auto *Init = cast_or_null<Expr>(Importer.Import(DIE->getInit())); if (!Init) return nullptr; SmallVector<Expr *, 4> IndexExprs(DIE->getNumSubExprs() - 1); // List elements from the second, the first is Init itself for (unsigned I = 1, E = DIE->getNumSubExprs(); I < E; I++) { - if (Expr *Arg = cast_or_null<Expr>(Importer.Import(DIE->getSubExpr(I)))) + if (auto *Arg = cast_or_null<Expr>(Importer.Import(DIE->getSubExpr(I)))) IndexExprs[I - 1] = Arg; else return nullptr; @@ -4966,7 +5559,7 @@ Expr *ASTNodeImporter::VisitDesignatedInitExpr(DesignatedInitExpr *DIE) { return ImportDesignator(D); }); - for (const Designator &D : DIE->designators()) + for (const auto &D : DIE->designators()) if (D.isFieldDesignator() && !D.getFieldName()) return nullptr; @@ -5067,7 +5660,7 @@ Expr *ASTNodeImporter::VisitAddrLabelExpr(AddrLabelExpr *E) { if (T.isNull()) return nullptr; - LabelDecl *ToLabel = cast_or_null<LabelDecl>(Importer.Import(E->getLabel())); + auto *ToLabel = cast_or_null<LabelDecl>(Importer.Import(E->getLabel())); if (!ToLabel) return nullptr; @@ -5102,8 +5695,8 @@ Expr *ASTNodeImporter::VisitStmtExpr(StmtExpr *E) { if (T.isNull()) return nullptr; - CompoundStmt *ToSubStmt = cast_or_null<CompoundStmt>( - Importer.Import(E->getSubStmt())); + auto *ToSubStmt = cast_or_null<CompoundStmt>( + Importer.Import(E->getSubStmt())); if (!ToSubStmt && E->getSubStmt()) return nullptr; @@ -5120,14 +5713,13 @@ Expr *ASTNodeImporter::VisitUnaryOperator(UnaryOperator *E) { if (!SubExpr) return nullptr; - return new (Importer.getToContext()) UnaryOperator(SubExpr, E->getOpcode(), - T, E->getValueKind(), - E->getObjectKind(), - Importer.Import(E->getOperatorLoc())); + return new (Importer.getToContext()) UnaryOperator( + SubExpr, E->getOpcode(), T, E->getValueKind(), E->getObjectKind(), + Importer.Import(E->getOperatorLoc()), E->canOverflow()); } -Expr *ASTNodeImporter::VisitUnaryExprOrTypeTraitExpr( - UnaryExprOrTypeTraitExpr *E) { +Expr * +ASTNodeImporter::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) { QualType ResultType = Importer.Import(E->getType()); if (E->isArgumentType()) { @@ -5208,8 +5800,8 @@ Expr *ASTNodeImporter::VisitBinaryConditionalOperator( if (!Cond) return nullptr; - OpaqueValueExpr *OpaqueValue = cast_or_null<OpaqueValueExpr>( - Importer.Import(E->getOpaqueValue())); + auto *OpaqueValue = cast_or_null<OpaqueValueExpr>( + Importer.Import(E->getOpaqueValue())); if (!OpaqueValue) return nullptr; @@ -5367,7 +5959,7 @@ Expr *ASTNodeImporter::VisitExplicitCastExpr(ExplicitCastExpr *E) { switch (E->getStmtClass()) { case Stmt::CStyleCastExprClass: { - CStyleCastExpr *CCE = cast<CStyleCastExpr>(E); + auto *CCE = cast<CStyleCastExpr>(E); return CStyleCastExpr::Create(Importer.getToContext(), T, E->getValueKind(), E->getCastKind(), SubExpr, &BasePath, TInfo, @@ -5376,7 +5968,7 @@ Expr *ASTNodeImporter::VisitExplicitCastExpr(ExplicitCastExpr *E) { } case Stmt::CXXFunctionalCastExprClass: { - CXXFunctionalCastExpr *FCE = cast<CXXFunctionalCastExpr>(E); + auto *FCE = cast<CXXFunctionalCastExpr>(E); return CXXFunctionalCastExpr::Create(Importer.getToContext(), T, E->getValueKind(), TInfo, E->getCastKind(), SubExpr, &BasePath, @@ -5385,7 +5977,7 @@ Expr *ASTNodeImporter::VisitExplicitCastExpr(ExplicitCastExpr *E) { } case Stmt::ObjCBridgedCastExprClass: { - ObjCBridgedCastExpr *OCE = cast<ObjCBridgedCastExpr>(E); + auto *OCE = cast<ObjCBridgedCastExpr>(E); return new (Importer.getToContext()) ObjCBridgedCastExpr( Importer.Import(OCE->getLParenLoc()), OCE->getBridgeKind(), E->getCastKind(), Importer.Import(OCE->getBridgeKeywordLoc()), @@ -5395,7 +5987,7 @@ Expr *ASTNodeImporter::VisitExplicitCastExpr(ExplicitCastExpr *E) { break; // just fall through } - CXXNamedCastExpr *Named = cast<CXXNamedCastExpr>(E); + auto *Named = cast<CXXNamedCastExpr>(E); SourceLocation ExprLoc = Importer.Import(Named->getOperatorLoc()), RParenLoc = Importer.Import(Named->getRParenLoc()); SourceRange Brackets = Importer.Import(Named->getAngleBrackets()); @@ -5453,7 +6045,7 @@ Expr *ASTNodeImporter::VisitOffsetOfExpr(OffsetOfExpr *OE) { break; } case OffsetOfNode::Field: { - FieldDecl *FD = cast_or_null<FieldDecl>(Importer.Import(Node.getField())); + auto *FD = cast_or_null<FieldDecl>(Importer.Import(Node.getField())); if (!FD) return nullptr; Nodes.push_back(OffsetOfNode(Importer.Import(Node.getLocStart()), FD, @@ -5524,8 +6116,7 @@ Expr *ASTNodeImporter::VisitCXXThrowExpr(CXXThrowExpr *E) { } Expr *ASTNodeImporter::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) { - ParmVarDecl *Param = cast_or_null<ParmVarDecl>( - Importer.Import(E->getParam())); + auto *Param = cast_or_null<ParmVarDecl>(Importer.Import(E->getParam())); if (!Param) return nullptr; @@ -5567,6 +6158,10 @@ Expr *ASTNodeImporter::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *CE) { if (T.isNull()) return nullptr; + TypeSourceInfo *TInfo = Importer.Import(CE->getTypeSourceInfo()); + if (!TInfo) + return nullptr; + SmallVector<Expr *, 8> Args(CE->getNumArgs()); if (ImportContainerChecked(CE->arguments(), Args)) return nullptr; @@ -5576,18 +6171,11 @@ Expr *ASTNodeImporter::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *CE) { if (!Ctor) return nullptr; - return CXXTemporaryObjectExpr::Create( - Importer.getToContext(), T, - Importer.Import(CE->getLocStart()), - Ctor, - CE->isElidable(), - Args, - CE->hadMultipleCandidates(), - CE->isListInitialization(), - CE->isStdInitListInitialization(), - CE->requiresZeroInitialization(), - CE->getConstructionKind(), - Importer.Import(CE->getParenOrBraceRange())); + return new (Importer.getToContext()) CXXTemporaryObjectExpr( + Importer.getToContext(), Ctor, T, TInfo, Args, + Importer.Import(CE->getParenOrBraceRange()), CE->hadMultipleCandidates(), + CE->isListInitialization(), CE->isStdInitListInitialization(), + CE->requiresZeroInitialization()); } Expr * @@ -5600,7 +6188,7 @@ ASTNodeImporter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) { if (!TempE) return nullptr; - ValueDecl *ExtendedBy = cast_or_null<ValueDecl>( + auto *ExtendedBy = cast_or_null<ValueDecl>( Importer.Import(const_cast<ValueDecl *>(E->getExtendingDecl()))); if (!ExtendedBy && E->getExtendingDecl()) return nullptr; @@ -5627,6 +6215,30 @@ Expr *ASTNodeImporter::VisitPackExpansionExpr(PackExpansionExpr *E) { E->getNumExpansions()); } +Expr *ASTNodeImporter::VisitSizeOfPackExpr(SizeOfPackExpr *E) { + auto *Pack = cast_or_null<NamedDecl>(Importer.Import(E->getPack())); + if (!Pack) + return nullptr; + + Optional<unsigned> Length; + + if (!E->isValueDependent()) + Length = E->getPackLength(); + + SmallVector<TemplateArgument, 8> PartialArguments; + if (E->isPartiallySubstituted()) { + if (ImportTemplateArguments(E->getPartialArguments().data(), + E->getPartialArguments().size(), + PartialArguments)) + return nullptr; + } + + return SizeOfPackExpr::Create( + Importer.getToContext(), Importer.Import(E->getOperatorLoc()), Pack, + Importer.Import(E->getPackLoc()), Importer.Import(E->getRParenLoc()), + Length, PartialArguments); +} + Expr *ASTNodeImporter::VisitCXXNewExpr(CXXNewExpr *CE) { QualType T = Importer.Import(CE->getType()); if (T.isNull()) @@ -5636,12 +6248,12 @@ Expr *ASTNodeImporter::VisitCXXNewExpr(CXXNewExpr *CE) { if (ImportContainerChecked(CE->placement_arguments(), PlacementArgs)) return nullptr; - FunctionDecl *OperatorNewDecl = cast_or_null<FunctionDecl>( + auto *OperatorNewDecl = cast_or_null<FunctionDecl>( Importer.Import(CE->getOperatorNew())); if (!OperatorNewDecl && CE->getOperatorNew()) return nullptr; - FunctionDecl *OperatorDeleteDecl = cast_or_null<FunctionDecl>( + auto *OperatorDeleteDecl = cast_or_null<FunctionDecl>( Importer.Import(CE->getOperatorDelete())); if (!OperatorDeleteDecl && CE->getOperatorDelete()) return nullptr; @@ -5676,7 +6288,7 @@ Expr *ASTNodeImporter::VisitCXXDeleteExpr(CXXDeleteExpr *E) { if (T.isNull()) return nullptr; - FunctionDecl *OperatorDeleteDecl = cast_or_null<FunctionDecl>( + auto *OperatorDeleteDecl = cast_or_null<FunctionDecl>( Importer.Import(E->getOperatorDelete())); if (!OperatorDeleteDecl && E->getOperatorDelete()) return nullptr; @@ -5700,7 +6312,7 @@ Expr *ASTNodeImporter::VisitCXXConstructExpr(CXXConstructExpr *E) { if (T.isNull()) return nullptr; - CXXConstructorDecl *ToCCD = + auto *ToCCD = dyn_cast_or_null<CXXConstructorDecl>(Importer.Import(E->getConstructor())); if (!ToCCD) return nullptr; @@ -5784,13 +6396,17 @@ Expr *ASTNodeImporter::VisitMemberExpr(MemberExpr *E) { if (!ToBase && E->getBase()) return nullptr; - ValueDecl *ToMember = dyn_cast<ValueDecl>(Importer.Import(E->getMemberDecl())); + auto *ToMember = dyn_cast<ValueDecl>(Importer.Import(E->getMemberDecl())); if (!ToMember && E->getMemberDecl()) return nullptr; - DeclAccessPair ToFoundDecl = DeclAccessPair::make( - dyn_cast<NamedDecl>(Importer.Import(E->getFoundDecl().getDecl())), - E->getFoundDecl().getAccess()); + auto *ToDecl = + dyn_cast_or_null<NamedDecl>(Importer.Import(E->getFoundDecl().getDecl())); + if (!ToDecl && E->getFoundDecl().getDecl()) + return nullptr; + + DeclAccessPair ToFoundDecl = + DeclAccessPair::make(ToDecl, E->getFoundDecl().getAccess()); DeclarationNameInfo ToMemberNameInfo( Importer.Import(E->getMemberNameInfo().getName()), @@ -5812,7 +6428,6 @@ Expr *ASTNodeImporter::VisitMemberExpr(MemberExpr *E) { Expr *ASTNodeImporter::VisitCXXPseudoDestructorExpr( CXXPseudoDestructorExpr *E) { - Expr *BaseE = Importer.Import(E->getBase()); if (!BaseE) return nullptr; @@ -5856,11 +6471,10 @@ Expr *ASTNodeImporter::VisitCXXDependentScopeMemberExpr( if (BaseType.isNull()) return nullptr; - TemplateArgumentListInfo ToTAInfo(Importer.Import(E->getLAngleLoc()), - Importer.Import(E->getRAngleLoc())); - TemplateArgumentListInfo *ResInfo = nullptr; + TemplateArgumentListInfo ToTAInfo, *ResInfo = nullptr; if (E->hasExplicitTemplateArgs()) { - if (ImportTemplateArgumentListInfo(E->template_arguments(), ToTAInfo)) + if (ImportTemplateArgumentListInfo(E->getLAngleLoc(), E->getRAngleLoc(), + E->template_arguments(), ToTAInfo)) return nullptr; ResInfo = &ToTAInfo; } @@ -5884,6 +6498,127 @@ Expr *ASTNodeImporter::VisitCXXDependentScopeMemberExpr( cast_or_null<NamedDecl>(ToFQ), MemberNameInfo, ResInfo); } +Expr * +ASTNodeImporter::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) { + DeclarationName Name = Importer.Import(E->getDeclName()); + if (!E->getDeclName().isEmpty() && Name.isEmpty()) + return nullptr; + + DeclarationNameInfo NameInfo(Name, Importer.Import(E->getExprLoc())); + ImportDeclarationNameLoc(E->getNameInfo(), NameInfo); + + TemplateArgumentListInfo ToTAInfo(Importer.Import(E->getLAngleLoc()), + Importer.Import(E->getRAngleLoc())); + TemplateArgumentListInfo *ResInfo = nullptr; + if (E->hasExplicitTemplateArgs()) { + if (ImportTemplateArgumentListInfo(E->template_arguments(), ToTAInfo)) + return nullptr; + ResInfo = &ToTAInfo; + } + + return DependentScopeDeclRefExpr::Create( + Importer.getToContext(), Importer.Import(E->getQualifierLoc()), + Importer.Import(E->getTemplateKeywordLoc()), NameInfo, ResInfo); +} + +Expr *ASTNodeImporter::VisitCXXUnresolvedConstructExpr( + CXXUnresolvedConstructExpr *CE) { + unsigned NumArgs = CE->arg_size(); + + SmallVector<Expr *, 8> ToArgs(NumArgs); + if (ImportArrayChecked(CE->arg_begin(), CE->arg_end(), ToArgs.begin())) + return nullptr; + + return CXXUnresolvedConstructExpr::Create( + Importer.getToContext(), Importer.Import(CE->getTypeSourceInfo()), + Importer.Import(CE->getLParenLoc()), llvm::makeArrayRef(ToArgs), + Importer.Import(CE->getRParenLoc())); +} + +Expr *ASTNodeImporter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) { + auto *NamingClass = + cast_or_null<CXXRecordDecl>(Importer.Import(E->getNamingClass())); + if (E->getNamingClass() && !NamingClass) + return nullptr; + + DeclarationName Name = Importer.Import(E->getName()); + if (E->getName() && !Name) + return nullptr; + + DeclarationNameInfo NameInfo(Name, Importer.Import(E->getNameLoc())); + // Import additional name location/type info. + ImportDeclarationNameLoc(E->getNameInfo(), NameInfo); + + UnresolvedSet<8> ToDecls; + for (auto *D : E->decls()) { + if (auto *To = cast_or_null<NamedDecl>(Importer.Import(D))) + ToDecls.addDecl(To); + else + return nullptr; + } + + TemplateArgumentListInfo ToTAInfo, *ResInfo = nullptr; + if (E->hasExplicitTemplateArgs()) { + if (ImportTemplateArgumentListInfo(E->getLAngleLoc(), E->getRAngleLoc(), + E->template_arguments(), ToTAInfo)) + return nullptr; + ResInfo = &ToTAInfo; + } + + if (ResInfo || E->getTemplateKeywordLoc().isValid()) + return UnresolvedLookupExpr::Create( + Importer.getToContext(), NamingClass, + Importer.Import(E->getQualifierLoc()), + Importer.Import(E->getTemplateKeywordLoc()), NameInfo, E->requiresADL(), + ResInfo, ToDecls.begin(), ToDecls.end()); + + return UnresolvedLookupExpr::Create( + Importer.getToContext(), NamingClass, + Importer.Import(E->getQualifierLoc()), NameInfo, E->requiresADL(), + E->isOverloaded(), ToDecls.begin(), ToDecls.end()); +} + +Expr *ASTNodeImporter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E) { + DeclarationName Name = Importer.Import(E->getName()); + if (!E->getName().isEmpty() && Name.isEmpty()) + return nullptr; + DeclarationNameInfo NameInfo(Name, Importer.Import(E->getNameLoc())); + // Import additional name location/type info. + ImportDeclarationNameLoc(E->getNameInfo(), NameInfo); + + QualType BaseType = Importer.Import(E->getType()); + if (!E->getType().isNull() && BaseType.isNull()) + return nullptr; + + UnresolvedSet<8> ToDecls; + for (Decl *D : E->decls()) { + if (NamedDecl *To = cast_or_null<NamedDecl>(Importer.Import(D))) + ToDecls.addDecl(To); + else + return nullptr; + } + + TemplateArgumentListInfo ToTAInfo; + TemplateArgumentListInfo *ResInfo = nullptr; + if (E->hasExplicitTemplateArgs()) { + if (ImportTemplateArgumentListInfo(E->template_arguments(), ToTAInfo)) + return nullptr; + ResInfo = &ToTAInfo; + } + + Expr *BaseE = E->isImplicitAccess() ? nullptr : Importer.Import(E->getBase()); + if (!BaseE && !E->isImplicitAccess() && E->getBase()) { + return nullptr; + } + + return UnresolvedMemberExpr::Create( + Importer.getToContext(), E->hasUnresolvedUsing(), BaseE, BaseType, + E->isArrow(), Importer.Import(E->getOperatorLoc()), + Importer.Import(E->getQualifierLoc()), + Importer.Import(E->getTemplateKeywordLoc()), NameInfo, ResInfo, + ToDecls.begin(), ToDecls.end()); +} + Expr *ASTNodeImporter::VisitCallExpr(CallExpr *E) { QualType T = Importer.Import(E->getType()); if (T.isNull()) @@ -5894,35 +6629,100 @@ Expr *ASTNodeImporter::VisitCallExpr(CallExpr *E) { return nullptr; unsigned NumArgs = E->getNumArgs(); + SmallVector<Expr *, 2> ToArgs(NumArgs); + if (ImportContainerChecked(E->arguments(), ToArgs)) + return nullptr; - llvm::SmallVector<Expr *, 2> ToArgs(NumArgs); - - for (unsigned ai = 0, ae = NumArgs; ai != ae; ++ai) { - Expr *FromArg = E->getArg(ai); - Expr *ToArg = Importer.Import(FromArg); - if (!ToArg) - return nullptr; - ToArgs[ai] = ToArg; - } - - Expr **ToArgs_Copied = new (Importer.getToContext()) - Expr*[NumArgs]; + auto **ToArgs_Copied = new (Importer.getToContext()) Expr*[NumArgs]; for (unsigned ai = 0, ae = NumArgs; ai != ae; ++ai) ToArgs_Copied[ai] = ToArgs[ai]; + if (const auto *OCE = dyn_cast<CXXOperatorCallExpr>(E)) { + return new (Importer.getToContext()) CXXOperatorCallExpr( + Importer.getToContext(), OCE->getOperator(), ToCallee, ToArgs, T, + OCE->getValueKind(), Importer.Import(OCE->getRParenLoc()), + OCE->getFPFeatures()); + } + return new (Importer.getToContext()) CallExpr(Importer.getToContext(), ToCallee, llvm::makeArrayRef(ToArgs_Copied, NumArgs), T, E->getValueKind(), Importer.Import(E->getRParenLoc())); } +Optional<LambdaCapture> +ASTNodeImporter::ImportLambdaCapture(const LambdaCapture &From) { + VarDecl *Var = nullptr; + if (From.capturesVariable()) { + Var = cast_or_null<VarDecl>(Importer.Import(From.getCapturedVar())); + if (!Var) + return None; + } + + return LambdaCapture(Importer.Import(From.getLocation()), From.isImplicit(), + From.getCaptureKind(), Var, + From.isPackExpansion() + ? Importer.Import(From.getEllipsisLoc()) + : SourceLocation()); +} + +Expr *ASTNodeImporter::VisitLambdaExpr(LambdaExpr *LE) { + CXXRecordDecl *FromClass = LE->getLambdaClass(); + auto *ToClass = dyn_cast_or_null<CXXRecordDecl>(Importer.Import(FromClass)); + if (!ToClass) + return nullptr; + + // NOTE: lambda classes are created with BeingDefined flag set up. + // It means that ImportDefinition doesn't work for them and we should fill it + // manually. + if (ToClass->isBeingDefined()) { + for (auto FromField : FromClass->fields()) { + auto *ToField = cast_or_null<FieldDecl>(Importer.Import(FromField)); + if (!ToField) + return nullptr; + } + } + + auto *ToCallOp = dyn_cast_or_null<CXXMethodDecl>( + Importer.Import(LE->getCallOperator())); + if (!ToCallOp) + return nullptr; + + ToClass->completeDefinition(); + + unsigned NumCaptures = LE->capture_size(); + SmallVector<LambdaCapture, 8> Captures; + Captures.reserve(NumCaptures); + for (const auto &FromCapture : LE->captures()) { + if (auto ToCapture = ImportLambdaCapture(FromCapture)) + Captures.push_back(*ToCapture); + else + return nullptr; + } + + SmallVector<Expr *, 8> InitCaptures(NumCaptures); + if (ImportContainerChecked(LE->capture_inits(), InitCaptures)) + return nullptr; + + return LambdaExpr::Create(Importer.getToContext(), ToClass, + Importer.Import(LE->getIntroducerRange()), + LE->getCaptureDefault(), + Importer.Import(LE->getCaptureDefaultLoc()), + Captures, + LE->hasExplicitParameters(), + LE->hasExplicitResultType(), + InitCaptures, + Importer.Import(LE->getLocEnd()), + LE->containsUnexpandedParameterPack()); +} + Expr *ASTNodeImporter::VisitInitListExpr(InitListExpr *ILE) { QualType T = Importer.Import(ILE->getType()); if (T.isNull()) return nullptr; - llvm::SmallVector<Expr *, 4> Exprs(ILE->getNumInits()); + SmallVector<Expr *, 4> Exprs(ILE->getNumInits()); if (ImportContainerChecked(ILE->inits(), Exprs)) return nullptr; @@ -5940,15 +6740,14 @@ Expr *ASTNodeImporter::VisitInitListExpr(InitListExpr *ILE) { } if (FieldDecl *FromFD = ILE->getInitializedFieldInUnion()) { - FieldDecl *ToFD = cast_or_null<FieldDecl>(Importer.Import(FromFD)); + auto *ToFD = cast_or_null<FieldDecl>(Importer.Import(FromFD)); if (!ToFD) return nullptr; To->setInitializedFieldInUnion(ToFD); } if (InitListExpr *SyntForm = ILE->getSyntacticForm()) { - InitListExpr *ToSyntForm = cast_or_null<InitListExpr>( - Importer.Import(SyntForm)); + auto *ToSyntForm = cast_or_null<InitListExpr>(Importer.Import(SyntForm)); if (!ToSyntForm) return nullptr; To->setSyntacticForm(ToSyntForm); @@ -5961,6 +6760,35 @@ Expr *ASTNodeImporter::VisitInitListExpr(InitListExpr *ILE) { return To; } +Expr *ASTNodeImporter::VisitCXXStdInitializerListExpr( + CXXStdInitializerListExpr *E) { + QualType T = Importer.Import(E->getType()); + if (T.isNull()) + return nullptr; + + Expr *SE = Importer.Import(E->getSubExpr()); + if (!SE) + return nullptr; + + return new (Importer.getToContext()) CXXStdInitializerListExpr(T, SE); +} + +Expr *ASTNodeImporter::VisitCXXInheritedCtorInitExpr( + CXXInheritedCtorInitExpr *E) { + QualType T = Importer.Import(E->getType()); + if (T.isNull()) + return nullptr; + + auto *Ctor = cast_or_null<CXXConstructorDecl>(Importer.Import( + E->getConstructor())); + if (!Ctor) + return nullptr; + + return new (Importer.getToContext()) CXXInheritedCtorInitExpr( + Importer.Import(E->getLocation()), T, Ctor, + E->constructsVBase(), E->inheritedFromVBase()); +} + Expr *ASTNodeImporter::VisitArrayInitLoopExpr(ArrayInitLoopExpr *E) { QualType ToType = Importer.Import(E->getType()); if (ToType.isNull()) @@ -5986,8 +6814,7 @@ Expr *ASTNodeImporter::VisitArrayInitIndexExpr(ArrayInitIndexExpr *E) { } Expr *ASTNodeImporter::VisitCXXDefaultInitExpr(CXXDefaultInitExpr *DIE) { - FieldDecl *ToField = llvm::dyn_cast_or_null<FieldDecl>( - Importer.Import(DIE->getField())); + auto *ToField = dyn_cast_or_null<FieldDecl>(Importer.Import(DIE->getField())); if (!ToField && DIE->getField()) return nullptr; @@ -6029,14 +6856,13 @@ Expr *ASTNodeImporter::VisitCXXNamedCastExpr(CXXNamedCastExpr *E) { } } - Expr *ASTNodeImporter::VisitSubstNonTypeTemplateParmExpr( SubstNonTypeTemplateParmExpr *E) { QualType T = Importer.Import(E->getType()); if (T.isNull()) return nullptr; - NonTypeTemplateParmDecl *Param = cast_or_null<NonTypeTemplateParmDecl>( + auto *Param = cast_or_null<NonTypeTemplateParmDecl>( Importer.Import(E->getParameter())); if (!Param) return nullptr; @@ -6070,6 +6896,28 @@ Expr *ASTNodeImporter::VisitTypeTraitExpr(TypeTraitExpr *E) { E->getTrait(), ToArgs, Importer.Import(E->getLocEnd()), ToValue); } +Expr *ASTNodeImporter::VisitCXXTypeidExpr(CXXTypeidExpr *E) { + QualType ToType = Importer.Import(E->getType()); + if (ToType.isNull()) + return nullptr; + + if (E->isTypeOperand()) { + TypeSourceInfo *TSI = Importer.Import(E->getTypeOperandSourceInfo()); + if (!TSI) + return nullptr; + + return new (Importer.getToContext()) + CXXTypeidExpr(ToType, TSI, Importer.Import(E->getSourceRange())); + } + + Expr *Op = Importer.Import(E->getExprOperand()); + if (!Op) + return nullptr; + + return new (Importer.getToContext()) + CXXTypeidExpr(ToType, Op, Importer.Import(E->getSourceRange())); +} + void ASTNodeImporter::ImportOverrides(CXXMethodDecl *ToMethod, CXXMethodDecl *FromMethod) { for (auto *FromOverriddenMethod : FromMethod->overridden_methods()) @@ -6081,19 +6929,18 @@ void ASTNodeImporter::ImportOverrides(CXXMethodDecl *ToMethod, ASTImporter::ASTImporter(ASTContext &ToContext, FileManager &ToFileManager, ASTContext &FromContext, FileManager &FromFileManager, bool MinimalImport) - : ToContext(ToContext), FromContext(FromContext), - ToFileManager(ToFileManager), FromFileManager(FromFileManager), - Minimal(MinimalImport), LastDiagFromFrom(false) -{ + : ToContext(ToContext), FromContext(FromContext), + ToFileManager(ToFileManager), FromFileManager(FromFileManager), + Minimal(MinimalImport) { ImportedDecls[FromContext.getTranslationUnitDecl()] = ToContext.getTranslationUnitDecl(); } -ASTImporter::~ASTImporter() { } +ASTImporter::~ASTImporter() = default; QualType ASTImporter::Import(QualType FromT) { if (FromT.isNull()) - return QualType(); + return {}; const Type *fromTy = FromT.getTypePtr(); @@ -6129,10 +6976,17 @@ TypeSourceInfo *ASTImporter::Import(TypeSourceInfo *FromTSI) { Import(FromTSI->getTypeLoc().getLocStart())); } +Attr *ASTImporter::Import(const Attr *FromAttr) { + Attr *ToAttr = FromAttr->clone(ToContext); + ToAttr->setRange(Import(FromAttr->getRange())); + return ToAttr; +} + Decl *ASTImporter::GetAlreadyImportedOrNull(Decl *FromD) { llvm::DenseMap<Decl *, Decl *>::iterator Pos = ImportedDecls.find(FromD); if (Pos != ImportedDecls.end()) { Decl *ToD = Pos->second; + // FIXME: move this call to ImportDeclParts(). ASTNodeImporter(*this).ImportDefinitionIfNeeded(FromD, ToD); return ToD; } else { @@ -6146,44 +7000,22 @@ Decl *ASTImporter::Import(Decl *FromD) { ASTNodeImporter Importer(*this); - // Check whether we've already imported this declaration. - llvm::DenseMap<Decl *, Decl *>::iterator Pos = ImportedDecls.find(FromD); - if (Pos != ImportedDecls.end()) { - Decl *ToD = Pos->second; - Importer.ImportDefinitionIfNeeded(FromD, ToD); + // Check whether we've already imported this declaration. + Decl *ToD = GetAlreadyImportedOrNull(FromD); + if (ToD) { + // If FromD has some updated flags after last import, apply it + updateFlags(FromD, ToD); return ToD; } - - // Import the type - Decl *ToD = Importer.Visit(FromD); + + // Import the type. + ToD = Importer.Visit(FromD); if (!ToD) return nullptr; - // Record the imported declaration. - ImportedDecls[FromD] = ToD; - - if (TagDecl *FromTag = dyn_cast<TagDecl>(FromD)) { - // Keep track of anonymous tags that have an associated typedef. - if (FromTag->getTypedefNameForAnonDecl()) - AnonTagsWithPendingTypedefs.push_back(FromTag); - } 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 (SmallVectorImpl<TagDecl *>::iterator - FromTag = AnonTagsWithPendingTypedefs.begin(), - FromTagEnd = AnonTagsWithPendingTypedefs.end(); - FromTag != FromTagEnd; ++FromTag) { - if ((*FromTag)->getTypedefNameForAnonDecl() == FromTypedef) { - if (TagDecl *ToTag = cast_or_null<TagDecl>(Import(*FromTag))) { - // We found the typedef for an anonymous tag; link them. - ToTag->setTypedefNameForAnonDecl(cast<TypedefNameDecl>(ToD)); - AnonTagsWithPendingTypedefs.erase(FromTag); - break; - } - } - } - } - + // Notify subclasses. + Imported(FromD, ToD); + return ToD; } @@ -6191,14 +7023,14 @@ DeclContext *ASTImporter::ImportContext(DeclContext *FromDC) { if (!FromDC) return FromDC; - DeclContext *ToDC = cast_or_null<DeclContext>(Import(cast<Decl>(FromDC))); + auto *ToDC = cast_or_null<DeclContext>(Import(cast<Decl>(FromDC))); if (!ToDC) return nullptr; // When we're using a record/enum/Objective-C class/protocol as a context, we // need it to have a definition. - if (RecordDecl *ToRecord = dyn_cast<RecordDecl>(ToDC)) { - RecordDecl *FromRecord = cast<RecordDecl>(FromDC); + if (auto *ToRecord = dyn_cast<RecordDecl>(ToDC)) { + auto *FromRecord = cast<RecordDecl>(FromDC); if (ToRecord->isCompleteDefinition()) { // Do nothing. } else if (FromRecord->isCompleteDefinition()) { @@ -6207,8 +7039,8 @@ DeclContext *ASTImporter::ImportContext(DeclContext *FromDC) { } else { CompleteDecl(ToRecord); } - } else if (EnumDecl *ToEnum = dyn_cast<EnumDecl>(ToDC)) { - EnumDecl *FromEnum = cast<EnumDecl>(FromDC); + } else if (auto *ToEnum = dyn_cast<EnumDecl>(ToDC)) { + auto *FromEnum = cast<EnumDecl>(FromDC); if (ToEnum->isCompleteDefinition()) { // Do nothing. } else if (FromEnum->isCompleteDefinition()) { @@ -6217,8 +7049,8 @@ DeclContext *ASTImporter::ImportContext(DeclContext *FromDC) { } else { CompleteDecl(ToEnum); } - } else if (ObjCInterfaceDecl *ToClass = dyn_cast<ObjCInterfaceDecl>(ToDC)) { - ObjCInterfaceDecl *FromClass = cast<ObjCInterfaceDecl>(FromDC); + } else if (auto *ToClass = dyn_cast<ObjCInterfaceDecl>(ToDC)) { + auto *FromClass = cast<ObjCInterfaceDecl>(FromDC); if (ToClass->getDefinition()) { // Do nothing. } else if (ObjCInterfaceDecl *FromDef = FromClass->getDefinition()) { @@ -6227,8 +7059,8 @@ DeclContext *ASTImporter::ImportContext(DeclContext *FromDC) { } else { CompleteDecl(ToClass); } - } else if (ObjCProtocolDecl *ToProto = dyn_cast<ObjCProtocolDecl>(ToDC)) { - ObjCProtocolDecl *FromProto = cast<ObjCProtocolDecl>(FromDC); + } else if (auto *ToProto = dyn_cast<ObjCProtocolDecl>(ToDC)) { + auto *FromProto = cast<ObjCProtocolDecl>(FromDC); if (ToProto->getDefinition()) { // Do nothing. } else if (ObjCProtocolDecl *FromDef = FromProto->getDefinition()) { @@ -6283,14 +7115,14 @@ NestedNameSpecifier *ASTImporter::Import(NestedNameSpecifier *FromNNS) { return nullptr; case NestedNameSpecifier::Namespace: - if (NamespaceDecl *NS = - cast_or_null<NamespaceDecl>(Import(FromNNS->getAsNamespace()))) { + if (auto *NS = + cast_or_null<NamespaceDecl>(Import(FromNNS->getAsNamespace()))) { return NestedNameSpecifier::Create(ToContext, prefix, NS); } return nullptr; case NestedNameSpecifier::NamespaceAlias: - if (NamespaceAliasDecl *NSAD = + if (auto *NSAD = cast_or_null<NamespaceAliasDecl>(Import(FromNNS->getAsNamespaceAlias()))) { return NestedNameSpecifier::Create(ToContext, prefix, NSAD); } @@ -6300,7 +7132,7 @@ NestedNameSpecifier *ASTImporter::Import(NestedNameSpecifier *FromNNS) { return NestedNameSpecifier::GlobalSpecifier(ToContext); case NestedNameSpecifier::Super: - if (CXXRecordDecl *RD = + if (auto *RD = cast_or_null<CXXRecordDecl>(Import(FromNNS->getAsRecordDecl()))) { return NestedNameSpecifier::SuperSpecifier(ToContext, RD); } @@ -6396,22 +7228,20 @@ NestedNameSpecifierLoc ASTImporter::Import(NestedNameSpecifierLoc FromNNS) { TemplateName ASTImporter::Import(TemplateName From) { switch (From.getKind()) { case TemplateName::Template: - if (TemplateDecl *ToTemplate - = cast_or_null<TemplateDecl>(Import(From.getAsTemplateDecl()))) + if (auto *ToTemplate = + cast_or_null<TemplateDecl>(Import(From.getAsTemplateDecl()))) return TemplateName(ToTemplate); - return TemplateName(); + return {}; case TemplateName::OverloadedTemplate: { OverloadedTemplateStorage *FromStorage = From.getAsOverloadedTemplate(); UnresolvedSet<2> ToTemplates; - for (OverloadedTemplateStorage::iterator I = FromStorage->begin(), - E = FromStorage->end(); - I != E; ++I) { - if (NamedDecl *To = cast_or_null<NamedDecl>(Import(*I))) + for (auto *I : *FromStorage) { + if (auto *To = cast_or_null<NamedDecl>(Import(I))) ToTemplates.addDecl(To); else - return TemplateName(); + return {}; } return ToContext.getOverloadedTemplateName(ToTemplates.begin(), ToTemplates.end()); @@ -6421,22 +7251,22 @@ TemplateName ASTImporter::Import(TemplateName From) { QualifiedTemplateName *QTN = From.getAsQualifiedTemplateName(); NestedNameSpecifier *Qualifier = Import(QTN->getQualifier()); if (!Qualifier) - return TemplateName(); + return {}; - if (TemplateDecl *ToTemplate - = cast_or_null<TemplateDecl>(Import(From.getAsTemplateDecl()))) + if (auto *ToTemplate = + cast_or_null<TemplateDecl>(Import(From.getAsTemplateDecl()))) return ToContext.getQualifiedTemplateName(Qualifier, QTN->hasTemplateKeyword(), ToTemplate); - - return TemplateName(); + + return {}; } case TemplateName::DependentTemplate: { DependentTemplateName *DTN = From.getAsDependentTemplateName(); NestedNameSpecifier *Qualifier = Import(DTN->getQualifier()); if (!Qualifier) - return TemplateName(); + return {}; if (DTN->isIdentifier()) { return ToContext.getDependentTemplateName(Qualifier, @@ -6449,13 +7279,14 @@ TemplateName ASTImporter::Import(TemplateName From) { case TemplateName::SubstTemplateTemplateParm: { SubstTemplateTemplateParmStorage *subst = From.getAsSubstTemplateTemplateParm(); - TemplateTemplateParmDecl *param - = cast_or_null<TemplateTemplateParmDecl>(Import(subst->getParameter())); + auto *param = + cast_or_null<TemplateTemplateParmDecl>(Import(subst->getParameter())); if (!param) - return TemplateName(); + return {}; TemplateName replacement = Import(subst->getReplacement()); - if (replacement.isNull()) return TemplateName(); + if (replacement.isNull()) + return {}; return ToContext.getSubstTemplateTemplateParm(param, replacement); } @@ -6463,17 +7294,17 @@ TemplateName ASTImporter::Import(TemplateName From) { case TemplateName::SubstTemplateTemplateParmPack: { SubstTemplateTemplateParmPackStorage *SubstPack = From.getAsSubstTemplateTemplateParmPack(); - TemplateTemplateParmDecl *Param - = cast_or_null<TemplateTemplateParmDecl>( - Import(SubstPack->getParameterPack())); + auto *Param = + cast_or_null<TemplateTemplateParmDecl>( + Import(SubstPack->getParameterPack())); if (!Param) - return TemplateName(); + return {}; ASTNodeImporter Importer(*this); TemplateArgument ArgPack = Importer.ImportTemplateArgument(SubstPack->getArgumentPack()); if (ArgPack.isNull()) - return TemplateName(); + return {}; return ToContext.getSubstTemplateTemplateParmPack(Param, ArgPack); } @@ -6484,22 +7315,16 @@ TemplateName ASTImporter::Import(TemplateName From) { SourceLocation ASTImporter::Import(SourceLocation FromLoc) { if (FromLoc.isInvalid()) - return SourceLocation(); + return {}; SourceManager &FromSM = FromContext.getSourceManager(); - - // For now, map everything down to its file location, so that we - // don't have to import macro expansions. - // FIXME: Import macro expansions! - FromLoc = FromSM.getFileLoc(FromLoc); + std::pair<FileID, unsigned> Decomposed = FromSM.getDecomposedLoc(FromLoc); - SourceManager &ToSM = ToContext.getSourceManager(); FileID ToFileID = Import(Decomposed.first); if (ToFileID.isInvalid()) - return SourceLocation(); - SourceLocation ret = ToSM.getLocForStartOfFile(ToFileID) - .getLocWithOffset(Decomposed.second); - return ret; + return {}; + SourceManager &ToSM = ToContext.getSourceManager(); + return ToSM.getComposedLoc(ToFileID, Decomposed.second); } SourceRange ASTImporter::Import(SourceRange FromRange) { @@ -6507,44 +7332,58 @@ SourceRange ASTImporter::Import(SourceRange FromRange) { } FileID ASTImporter::Import(FileID FromID) { - llvm::DenseMap<FileID, FileID>::iterator Pos - = ImportedFileIDs.find(FromID); + llvm::DenseMap<FileID, FileID>::iterator Pos = ImportedFileIDs.find(FromID); if (Pos != ImportedFileIDs.end()) return Pos->second; - + SourceManager &FromSM = FromContext.getSourceManager(); SourceManager &ToSM = ToContext.getSourceManager(); const SrcMgr::SLocEntry &FromSLoc = FromSM.getSLocEntry(FromID); - assert(FromSLoc.isFile() && "Cannot handle macro expansions yet"); - - // Include location of this file. - SourceLocation ToIncludeLoc = Import(FromSLoc.getFile().getIncludeLoc()); - - // Map the FileID for to the "to" source manager. + + // Map the FromID to the "to" source manager. FileID ToID; - const SrcMgr::ContentCache *Cache = FromSLoc.getFile().getContentCache(); - if (Cache->OrigEntry && Cache->OrigEntry->getDir()) { - // FIXME: We probably want to use getVirtualFile(), so we don't hit the - // disk again - // FIXME: We definitely want to re-use the existing MemoryBuffer, rather - // than mmap the files several times. - const FileEntry *Entry = ToFileManager.getFile(Cache->OrigEntry->getName()); - if (!Entry) - return FileID(); - ToID = ToSM.createFileID(Entry, ToIncludeLoc, - FromSLoc.getFile().getFileCharacteristic()); + if (FromSLoc.isExpansion()) { + const SrcMgr::ExpansionInfo &FromEx = FromSLoc.getExpansion(); + SourceLocation ToSpLoc = Import(FromEx.getSpellingLoc()); + SourceLocation ToExLocS = Import(FromEx.getExpansionLocStart()); + unsigned TokenLen = FromSM.getFileIDSize(FromID); + SourceLocation MLoc; + if (FromEx.isMacroArgExpansion()) { + MLoc = ToSM.createMacroArgExpansionLoc(ToSpLoc, ToExLocS, TokenLen); + } else { + SourceLocation ToExLocE = Import(FromEx.getExpansionLocEnd()); + MLoc = ToSM.createExpansionLoc(ToSpLoc, ToExLocS, ToExLocE, TokenLen, + FromEx.isExpansionTokenRange()); + } + ToID = ToSM.getFileID(MLoc); } else { - // FIXME: We want to re-use the existing MemoryBuffer! - const llvm::MemoryBuffer * - FromBuf = Cache->getBuffer(FromContext.getDiagnostics(), FromSM); - std::unique_ptr<llvm::MemoryBuffer> ToBuf - = llvm::MemoryBuffer::getMemBufferCopy(FromBuf->getBuffer(), - FromBuf->getBufferIdentifier()); - ToID = ToSM.createFileID(std::move(ToBuf), - FromSLoc.getFile().getFileCharacteristic()); + // Include location of this file. + SourceLocation ToIncludeLoc = Import(FromSLoc.getFile().getIncludeLoc()); + + const SrcMgr::ContentCache *Cache = FromSLoc.getFile().getContentCache(); + if (Cache->OrigEntry && Cache->OrigEntry->getDir()) { + // FIXME: We probably want to use getVirtualFile(), so we don't hit the + // disk again + // FIXME: We definitely want to re-use the existing MemoryBuffer, rather + // than mmap the files several times. + const FileEntry *Entry = + ToFileManager.getFile(Cache->OrigEntry->getName()); + if (!Entry) + return {}; + ToID = ToSM.createFileID(Entry, ToIncludeLoc, + FromSLoc.getFile().getFileCharacteristic()); + } else { + // FIXME: We want to re-use the existing MemoryBuffer! + const llvm::MemoryBuffer *FromBuf = + Cache->getBuffer(FromContext.getDiagnostics(), FromSM); + std::unique_ptr<llvm::MemoryBuffer> ToBuf = + llvm::MemoryBuffer::getMemBufferCopy(FromBuf->getBuffer(), + FromBuf->getBufferIdentifier()); + ToID = ToSM.createFileID(std::move(ToBuf), + FromSLoc.getFile().getFileCharacteristic()); + } } - - + ImportedFileIDs[FromID] = ToID; return ToID; } @@ -6565,8 +7404,7 @@ CXXCtorInitializer *ASTImporter::Import(CXXCtorInitializer *From) { From->isPackExpansion() ? Import(From->getEllipsisLoc()) : SourceLocation()); } else if (From->isMemberInitializer()) { - FieldDecl *ToField = - llvm::cast_or_null<FieldDecl>(Import(From->getMember())); + auto *ToField = cast_or_null<FieldDecl>(Import(From->getMember())); if (!ToField && From->getMember()) return nullptr; @@ -6574,7 +7412,7 @@ CXXCtorInitializer *ASTImporter::Import(CXXCtorInitializer *From) { ToContext, ToField, Import(From->getMemberLocation()), Import(From->getLParenLoc()), ToExpr, Import(From->getRParenLoc())); } else if (From->isIndirectMemberInitializer()) { - IndirectFieldDecl *ToIField = llvm::cast_or_null<IndirectFieldDecl>( + auto *ToIField = cast_or_null<IndirectFieldDecl>( Import(From->getIndirectMember())); if (!ToIField && From->getIndirectMember()) return nullptr; @@ -6595,7 +7433,6 @@ CXXCtorInitializer *ASTImporter::Import(CXXCtorInitializer *From) { } } - CXXBaseSpecifier *ASTImporter::Import(const CXXBaseSpecifier *BaseSpec) { auto Pos = ImportedCXXBaseSpecifiers.find(BaseSpec); if (Pos != ImportedCXXBaseSpecifiers.end()) @@ -6616,10 +7453,10 @@ void ASTImporter::ImportDefinition(Decl *From) { if (!To) return; - if (DeclContext *FromDC = cast<DeclContext>(From)) { + if (auto *FromDC = cast<DeclContext>(From)) { ASTNodeImporter Importer(*this); - if (RecordDecl *ToRecord = dyn_cast<RecordDecl>(To)) { + if (auto *ToRecord = dyn_cast<RecordDecl>(To)) { if (!ToRecord->getDefinition()) { Importer.ImportDefinition(cast<RecordDecl>(FromDC), ToRecord, ASTNodeImporter::IDK_Everything); @@ -6627,7 +7464,7 @@ void ASTImporter::ImportDefinition(Decl *From) { } } - if (EnumDecl *ToEnum = dyn_cast<EnumDecl>(To)) { + if (auto *ToEnum = dyn_cast<EnumDecl>(To)) { if (!ToEnum->getDefinition()) { Importer.ImportDefinition(cast<EnumDecl>(FromDC), ToEnum, ASTNodeImporter::IDK_Everything); @@ -6635,7 +7472,7 @@ void ASTImporter::ImportDefinition(Decl *From) { } } - if (ObjCInterfaceDecl *ToIFace = dyn_cast<ObjCInterfaceDecl>(To)) { + if (auto *ToIFace = dyn_cast<ObjCInterfaceDecl>(To)) { if (!ToIFace->getDefinition()) { Importer.ImportDefinition(cast<ObjCInterfaceDecl>(FromDC), ToIFace, ASTNodeImporter::IDK_Everything); @@ -6643,7 +7480,7 @@ void ASTImporter::ImportDefinition(Decl *From) { } } - if (ObjCProtocolDecl *ToProto = dyn_cast<ObjCProtocolDecl>(To)) { + if (auto *ToProto = dyn_cast<ObjCProtocolDecl>(To)) { if (!ToProto->getDefinition()) { Importer.ImportDefinition(cast<ObjCProtocolDecl>(FromDC), ToProto, ASTNodeImporter::IDK_Everything); @@ -6657,7 +7494,7 @@ void ASTImporter::ImportDefinition(Decl *From) { DeclarationName ASTImporter::Import(DeclarationName FromName) { if (!FromName) - return DeclarationName(); + return {}; switch (FromName.getNameKind()) { case DeclarationName::Identifier: @@ -6671,7 +7508,7 @@ DeclarationName ASTImporter::Import(DeclarationName FromName) { case DeclarationName::CXXConstructorName: { QualType T = Import(FromName.getCXXNameType()); if (T.isNull()) - return DeclarationName(); + return {}; return ToContext.DeclarationNames.getCXXConstructorName( ToContext.getCanonicalType(T)); @@ -6680,24 +7517,24 @@ DeclarationName ASTImporter::Import(DeclarationName FromName) { case DeclarationName::CXXDestructorName: { QualType T = Import(FromName.getCXXNameType()); if (T.isNull()) - return DeclarationName(); + return {}; return ToContext.DeclarationNames.getCXXDestructorName( ToContext.getCanonicalType(T)); } case DeclarationName::CXXDeductionGuideName: { - TemplateDecl *Template = cast_or_null<TemplateDecl>( + auto *Template = cast_or_null<TemplateDecl>( Import(FromName.getCXXDeductionGuideTemplate())); if (!Template) - return DeclarationName(); + return {}; return ToContext.DeclarationNames.getCXXDeductionGuideName(Template); } case DeclarationName::CXXConversionFunctionName: { QualType T = Import(FromName.getCXXNameType()); if (T.isNull()) - return DeclarationName(); + return {}; return ToContext.DeclarationNames.getCXXConversionFunctionName( ToContext.getCanonicalType(T)); @@ -6733,7 +7570,7 @@ IdentifierInfo *ASTImporter::Import(const IdentifierInfo *FromId) { Selector ASTImporter::Import(Selector FromSel) { if (FromSel.isNull()) - return Selector(); + return {}; SmallVector<IdentifierInfo *, 4> Idents; Idents.push_back(Import(FromSel.getIdentifierInfoForSlot(0))); @@ -6767,36 +7604,31 @@ DiagnosticBuilder ASTImporter::FromDiag(SourceLocation Loc, unsigned DiagID) { } void ASTImporter::CompleteDecl (Decl *D) { - if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) { + if (auto *ID = dyn_cast<ObjCInterfaceDecl>(D)) { if (!ID->getDefinition()) ID->startDefinition(); } - else if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D)) { + else if (auto *PD = dyn_cast<ObjCProtocolDecl>(D)) { if (!PD->getDefinition()) PD->startDefinition(); } - else if (TagDecl *TD = dyn_cast<TagDecl>(D)) { + else if (auto *TD = dyn_cast<TagDecl>(D)) { if (!TD->getDefinition() && !TD->isBeingDefined()) { TD->startDefinition(); TD->setCompleteDefinition(true); } } else { - assert (0 && "CompleteDecl called on a Decl that can't be completed"); + assert(0 && "CompleteDecl called on a Decl that can't be completed"); } } -Decl *ASTImporter::Imported(Decl *From, Decl *To) { - if (From->hasAttrs()) { - for (Attr *FromAttr : From->getAttrs()) - To->addAttr(FromAttr->clone(To->getASTContext())); - } - if (From->isUsed()) { - To->setIsUsed(); - } - if (From->isImplicit()) { - To->setImplicit(); - } +Decl *ASTImporter::MapImported(Decl *From, Decl *To) { + llvm::DenseMap<Decl *, Decl *>::iterator Pos = ImportedDecls.find(From); + assert((Pos == ImportedDecls.end() || Pos->second == To) && + "Try to import an already imported Decl"); + if (Pos != ImportedDecls.end()) + return Pos->second; ImportedDecls[From] = To; return To; } @@ -6809,6 +7641,7 @@ bool ASTImporter::IsStructurallyEquivalent(QualType From, QualType To, return true; StructuralEquivalenceContext Ctx(FromContext, ToContext, NonEquivalentDecls, - false, Complain); - return Ctx.IsStructurallyEquivalent(From, To); + getStructuralEquivalenceKind(*this), false, + Complain); + return Ctx.IsEquivalent(From, To); } diff --git a/lib/AST/ASTStructuralEquivalence.cpp b/lib/AST/ASTStructuralEquivalence.cpp index 0df8e5653f3b..7853ab28810b 100644 --- a/lib/AST/ASTStructuralEquivalence.cpp +++ b/lib/AST/ASTStructuralEquivalence.cpp @@ -1,4 +1,4 @@ -//===--- ASTStructuralEquivalence.cpp - -------------------------*- C++ -*-===// +//===- ASTStructuralEquivalence.cpp ---------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -10,20 +10,87 @@ // This file implement StructuralEquivalenceContext class and helper functions // for layout matching. // +// The structural equivalence check could have been implemented as a parallel +// BFS on a pair of graphs. That must have been the original approach at the +// beginning. +// Let's consider this simple BFS algorithm from the `s` source: +// ``` +// void bfs(Graph G, int s) +// { +// Queue<Integer> queue = new Queue<Integer>(); +// marked[s] = true; // Mark the source +// queue.enqueue(s); // and put it on the queue. +// while (!q.isEmpty()) { +// int v = queue.dequeue(); // Remove next vertex from the queue. +// for (int w : G.adj(v)) +// if (!marked[w]) // For every unmarked adjacent vertex, +// { +// marked[w] = true; +// queue.enqueue(w); +// } +// } +// } +// ``` +// Indeed, it has it's queue, which holds pairs of nodes, one from each graph, +// this is the `DeclsToCheck` and it's pair is in `TentativeEquivalences`. +// `TentativeEquivalences` also plays the role of the marking (`marked`) +// functionality above, we use it to check whether we've already seen a pair of +// nodes. +// +// We put in the elements into the queue only in the toplevel decl check +// function: +// ``` +// static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, +// Decl *D1, Decl *D2); +// ``` +// The `while` loop where we iterate over the children is implemented in +// `Finish()`. And `Finish` is called only from the two **member** functions +// which check the equivalency of two Decls or two Types. ASTImporter (and +// other clients) call only these functions. +// +// The `static` implementation functions are called from `Finish`, these push +// the children nodes to the queue via `static bool +// IsStructurallyEquivalent(StructuralEquivalenceContext &Context, Decl *D1, +// Decl *D2)`. So far so good, this is almost like the BFS. However, if we +// let a static implementation function to call `Finish` via another **member** +// function that means we end up with two nested while loops each of them +// working on the same queue. This is wrong and nobody can reason about it's +// doing. Thus, static implementation functions must not call the **member** +// functions. +// +// So, now `TentativeEquivalences` plays two roles. It is used to store the +// second half of the decls which we want to compare, plus it plays a role in +// closing the recursion. On a long term, we could refactor structural +// equivalency to be more alike to the traditional BFS. +// //===----------------------------------------------------------------------===// #include "clang/AST/ASTStructuralEquivalence.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTDiagnostic.h" -#include "clang/AST/ASTImporter.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclFriend.h" #include "clang/AST/DeclObjC.h" -#include "clang/AST/DeclVisitor.h" -#include "clang/AST/StmtVisitor.h" -#include "clang/AST/TypeVisitor.h" -#include "clang/Basic/SourceManager.h" - -namespace { +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/TemplateBase.h" +#include "clang/AST/TemplateName.h" +#include "clang/AST/Type.h" +#include "clang/Basic/ExceptionSpecificationType.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/Optional.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/ErrorHandling.h" +#include <cassert> +#include <utility> using namespace clang; @@ -37,7 +104,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, /// Determine structural equivalence of two expressions. static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, - Expr *E1, Expr *E2) { + const Expr *E1, const Expr *E2) { if (!E1 || !E2) return E1 == E2; @@ -144,6 +211,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, IsStructurallyEquivalent(Context, TS1->getReplacement(), TS2->getReplacement()); } + case TemplateName::SubstTemplateTemplateParmPack: { SubstTemplateTemplateParmPackStorage *P1 = N1.getAsSubstTemplateTemplateParmPack(), @@ -169,10 +237,10 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, return true; case TemplateArgument::Type: - return Context.IsStructurallyEquivalent(Arg1.getAsType(), Arg2.getAsType()); + return IsStructurallyEquivalent(Context, Arg1.getAsType(), Arg2.getAsType()); case TemplateArgument::Integral: - if (!Context.IsStructurallyEquivalent(Arg1.getIntegralType(), + if (!IsStructurallyEquivalent(Context, Arg1.getIntegralType(), Arg2.getIntegralType())) return false; @@ -180,7 +248,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, Arg2.getAsIntegral()); case TemplateArgument::Declaration: - return Context.IsStructurallyEquivalent(Arg1.getAsDecl(), Arg2.getAsDecl()); + return IsStructurallyEquivalent(Context, Arg1.getAsDecl(), Arg2.getAsDecl()); case TemplateArgument::NullPtr: return true; // FIXME: Is this correct? @@ -235,6 +303,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (T1.isNull() || T2.isNull()) return T1.isNull() && T2.isNull(); + QualType OrigT1 = T1; + QualType OrigT2 = T2; + if (!Context.StrictTypeSpelling) { // We aren't being strict about token-to-token equivalence of types, // so map down to the canonical type. @@ -298,8 +369,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, case Type::LValueReference: case Type::RValueReference: { - const ReferenceType *Ref1 = cast<ReferenceType>(T1); - const ReferenceType *Ref2 = cast<ReferenceType>(T2); + const auto *Ref1 = cast<ReferenceType>(T1); + const auto *Ref2 = cast<ReferenceType>(T2); if (Ref1->isSpelledAsLValue() != Ref2->isSpelledAsLValue()) return false; if (Ref1->isInnerRef() != Ref2->isInnerRef()) @@ -311,8 +382,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, } case Type::MemberPointer: { - const MemberPointerType *MemPtr1 = cast<MemberPointerType>(T1); - const MemberPointerType *MemPtr2 = cast<MemberPointerType>(T2); + const auto *MemPtr1 = cast<MemberPointerType>(T1); + const auto *MemPtr2 = cast<MemberPointerType>(T2); if (!IsStructurallyEquivalent(Context, MemPtr1->getPointeeType(), MemPtr2->getPointeeType())) return false; @@ -323,8 +394,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, } case Type::ConstantArray: { - const ConstantArrayType *Array1 = cast<ConstantArrayType>(T1); - const ConstantArrayType *Array2 = cast<ConstantArrayType>(T2); + const auto *Array1 = cast<ConstantArrayType>(T1); + const auto *Array2 = cast<ConstantArrayType>(T2); if (!llvm::APInt::isSameValue(Array1->getSize(), Array2->getSize())) return false; @@ -340,8 +411,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, break; case Type::VariableArray: { - const VariableArrayType *Array1 = cast<VariableArrayType>(T1); - const VariableArrayType *Array2 = cast<VariableArrayType>(T2); + const auto *Array1 = cast<VariableArrayType>(T1); + const auto *Array2 = cast<VariableArrayType>(T2); if (!IsStructurallyEquivalent(Context, Array1->getSizeExpr(), Array2->getSizeExpr())) return false; @@ -353,8 +424,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, } case Type::DependentSizedArray: { - const DependentSizedArrayType *Array1 = cast<DependentSizedArrayType>(T1); - const DependentSizedArrayType *Array2 = cast<DependentSizedArrayType>(T2); + const auto *Array1 = cast<DependentSizedArrayType>(T1); + const auto *Array2 = cast<DependentSizedArrayType>(T2); if (!IsStructurallyEquivalent(Context, Array1->getSizeExpr(), Array2->getSizeExpr())) return false; @@ -366,10 +437,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, } case Type::DependentAddressSpace: { - const DependentAddressSpaceType *DepAddressSpace1 = - cast<DependentAddressSpaceType>(T1); - const DependentAddressSpaceType *DepAddressSpace2 = - cast<DependentAddressSpaceType>(T2); + const auto *DepAddressSpace1 = cast<DependentAddressSpaceType>(T1); + const auto *DepAddressSpace2 = cast<DependentAddressSpaceType>(T2); if (!IsStructurallyEquivalent(Context, DepAddressSpace1->getAddrSpaceExpr(), DepAddressSpace2->getAddrSpaceExpr())) return false; @@ -381,10 +450,22 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, } case Type::DependentSizedExtVector: { - const DependentSizedExtVectorType *Vec1 = - cast<DependentSizedExtVectorType>(T1); - const DependentSizedExtVectorType *Vec2 = - cast<DependentSizedExtVectorType>(T2); + const auto *Vec1 = cast<DependentSizedExtVectorType>(T1); + const auto *Vec2 = cast<DependentSizedExtVectorType>(T2); + if (!IsStructurallyEquivalent(Context, Vec1->getSizeExpr(), + Vec2->getSizeExpr())) + return false; + if (!IsStructurallyEquivalent(Context, Vec1->getElementType(), + Vec2->getElementType())) + return false; + break; + } + + case Type::DependentVector: { + const auto *Vec1 = cast<DependentVectorType>(T1); + const auto *Vec2 = cast<DependentVectorType>(T2); + if (Vec1->getVectorKind() != Vec2->getVectorKind()) + return false; if (!IsStructurallyEquivalent(Context, Vec1->getSizeExpr(), Vec2->getSizeExpr())) return false; @@ -396,8 +477,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, case Type::Vector: case Type::ExtVector: { - const VectorType *Vec1 = cast<VectorType>(T1); - const VectorType *Vec2 = cast<VectorType>(T2); + const auto *Vec1 = cast<VectorType>(T1); + const auto *Vec2 = cast<VectorType>(T2); if (!IsStructurallyEquivalent(Context, Vec1->getElementType(), Vec2->getElementType())) return false; @@ -409,8 +490,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, } case Type::FunctionProto: { - const FunctionProtoType *Proto1 = cast<FunctionProtoType>(T1); - const FunctionProtoType *Proto2 = cast<FunctionProtoType>(T2); + const auto *Proto1 = cast<FunctionProtoType>(T1); + const auto *Proto2 = cast<FunctionProtoType>(T2); + if (Proto1->getNumParams() != Proto2->getNumParams()) return false; for (unsigned I = 0, N = Proto1->getNumParams(); I != N; ++I) { @@ -420,31 +502,41 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, } if (Proto1->isVariadic() != Proto2->isVariadic()) return false; - if (Proto1->getExceptionSpecType() != Proto2->getExceptionSpecType()) + + if (Proto1->getTypeQuals() != Proto2->getTypeQuals()) return false; - if (Proto1->getExceptionSpecType() == EST_Dynamic) { - if (Proto1->getNumExceptions() != Proto2->getNumExceptions()) + + // Check exceptions, this information is lost in canonical type. + const auto *OrigProto1 = + cast<FunctionProtoType>(OrigT1.getDesugaredType(Context.FromCtx)); + const auto *OrigProto2 = + cast<FunctionProtoType>(OrigT2.getDesugaredType(Context.ToCtx)); + auto Spec1 = OrigProto1->getExceptionSpecType(); + auto Spec2 = OrigProto2->getExceptionSpecType(); + + if (Spec1 != Spec2) + return false; + if (Spec1 == EST_Dynamic) { + if (OrigProto1->getNumExceptions() != OrigProto2->getNumExceptions()) return false; - for (unsigned I = 0, N = Proto1->getNumExceptions(); I != N; ++I) { - if (!IsStructurallyEquivalent(Context, Proto1->getExceptionType(I), - Proto2->getExceptionType(I))) + for (unsigned I = 0, N = OrigProto1->getNumExceptions(); I != N; ++I) { + if (!IsStructurallyEquivalent(Context, OrigProto1->getExceptionType(I), + OrigProto2->getExceptionType(I))) return false; } - } else if (Proto1->getExceptionSpecType() == EST_ComputedNoexcept) { - if (!IsStructurallyEquivalent(Context, Proto1->getNoexceptExpr(), - Proto2->getNoexceptExpr())) + } else if (isComputedNoexcept(Spec1)) { + if (!IsStructurallyEquivalent(Context, OrigProto1->getNoexceptExpr(), + OrigProto2->getNoexceptExpr())) return false; } - if (Proto1->getTypeQuals() != Proto2->getTypeQuals()) - return false; // Fall through to check the bits common with FunctionNoProtoType. LLVM_FALLTHROUGH; } case Type::FunctionNoProto: { - const FunctionType *Function1 = cast<FunctionType>(T1); - const FunctionType *Function2 = cast<FunctionType>(T2); + const auto *Function1 = cast<FunctionType>(T1); + const auto *Function2 = cast<FunctionType>(T2); if (!IsStructurallyEquivalent(Context, Function1->getReturnType(), Function2->getReturnType())) return false; @@ -458,7 +550,6 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, cast<UnresolvedUsingType>(T1)->getDecl(), cast<UnresolvedUsingType>(T2)->getDecl())) return false; - break; case Type::Attributed: @@ -501,7 +592,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, case Type::UnaryTransform: if (!IsStructurallyEquivalent( Context, cast<UnaryTransformType>(T1)->getUnderlyingType(), - cast<UnaryTransformType>(T1)->getUnderlyingType())) + cast<UnaryTransformType>(T2)->getUnderlyingType())) return false; break; @@ -519,8 +610,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, break; case Type::DeducedTemplateSpecialization: { - auto *DT1 = cast<DeducedTemplateSpecializationType>(T1); - auto *DT2 = cast<DeducedTemplateSpecializationType>(T2); + const auto *DT1 = cast<DeducedTemplateSpecializationType>(T1); + const auto *DT2 = cast<DeducedTemplateSpecializationType>(T2); if (!IsStructurallyEquivalent(Context, DT1->getTemplateName(), DT2->getTemplateName())) return false; @@ -538,8 +629,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, break; case Type::TemplateTypeParm: { - const TemplateTypeParmType *Parm1 = cast<TemplateTypeParmType>(T1); - const TemplateTypeParmType *Parm2 = cast<TemplateTypeParmType>(T2); + const auto *Parm1 = cast<TemplateTypeParmType>(T1); + const auto *Parm2 = cast<TemplateTypeParmType>(T2); if (Parm1->getDepth() != Parm2->getDepth()) return false; if (Parm1->getIndex() != Parm2->getIndex()) @@ -552,10 +643,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, } case Type::SubstTemplateTypeParm: { - const SubstTemplateTypeParmType *Subst1 = - cast<SubstTemplateTypeParmType>(T1); - const SubstTemplateTypeParmType *Subst2 = - cast<SubstTemplateTypeParmType>(T2); + const auto *Subst1 = cast<SubstTemplateTypeParmType>(T1); + const auto *Subst2 = cast<SubstTemplateTypeParmType>(T2); if (!IsStructurallyEquivalent(Context, QualType(Subst1->getReplacedParameter(), 0), QualType(Subst2->getReplacedParameter(), 0))) @@ -567,10 +656,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, } case Type::SubstTemplateTypeParmPack: { - const SubstTemplateTypeParmPackType *Subst1 = - cast<SubstTemplateTypeParmPackType>(T1); - const SubstTemplateTypeParmPackType *Subst2 = - cast<SubstTemplateTypeParmPackType>(T2); + const auto *Subst1 = cast<SubstTemplateTypeParmPackType>(T1); + const auto *Subst2 = cast<SubstTemplateTypeParmPackType>(T2); if (!IsStructurallyEquivalent(Context, QualType(Subst1->getReplacedParameter(), 0), QualType(Subst2->getReplacedParameter(), 0))) @@ -580,11 +667,10 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, return false; break; } + case Type::TemplateSpecialization: { - const TemplateSpecializationType *Spec1 = - cast<TemplateSpecializationType>(T1); - const TemplateSpecializationType *Spec2 = - cast<TemplateSpecializationType>(T2); + const auto *Spec1 = cast<TemplateSpecializationType>(T1); + const auto *Spec2 = cast<TemplateSpecializationType>(T2); if (!IsStructurallyEquivalent(Context, Spec1->getTemplateName(), Spec2->getTemplateName())) return false; @@ -599,8 +685,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, } case Type::Elaborated: { - const ElaboratedType *Elab1 = cast<ElaboratedType>(T1); - const ElaboratedType *Elab2 = cast<ElaboratedType>(T2); + const auto *Elab1 = cast<ElaboratedType>(T1); + const auto *Elab2 = cast<ElaboratedType>(T2); // CHECKME: what if a keyword is ETK_None or ETK_typename ? if (Elab1->getKeyword() != Elab2->getKeyword()) return false; @@ -614,8 +700,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, } case Type::InjectedClassName: { - const InjectedClassNameType *Inj1 = cast<InjectedClassNameType>(T1); - const InjectedClassNameType *Inj2 = cast<InjectedClassNameType>(T2); + const auto *Inj1 = cast<InjectedClassNameType>(T1); + const auto *Inj2 = cast<InjectedClassNameType>(T2); if (!IsStructurallyEquivalent(Context, Inj1->getInjectedSpecializationType(), Inj2->getInjectedSpecializationType())) @@ -624,8 +710,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, } case Type::DependentName: { - const DependentNameType *Typename1 = cast<DependentNameType>(T1); - const DependentNameType *Typename2 = cast<DependentNameType>(T2); + const auto *Typename1 = cast<DependentNameType>(T1); + const auto *Typename2 = cast<DependentNameType>(T2); if (!IsStructurallyEquivalent(Context, Typename1->getQualifier(), Typename2->getQualifier())) return false; @@ -637,10 +723,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, } case Type::DependentTemplateSpecialization: { - const DependentTemplateSpecializationType *Spec1 = - cast<DependentTemplateSpecializationType>(T1); - const DependentTemplateSpecializationType *Spec2 = - cast<DependentTemplateSpecializationType>(T2); + const auto *Spec1 = cast<DependentTemplateSpecializationType>(T1); + const auto *Spec2 = cast<DependentTemplateSpecializationType>(T2); if (!IsStructurallyEquivalent(Context, Spec1->getQualifier(), Spec2->getQualifier())) return false; @@ -665,8 +749,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, break; case Type::ObjCInterface: { - const ObjCInterfaceType *Iface1 = cast<ObjCInterfaceType>(T1); - const ObjCInterfaceType *Iface2 = cast<ObjCInterfaceType>(T2); + const auto *Iface1 = cast<ObjCInterfaceType>(T1); + const auto *Iface2 = cast<ObjCInterfaceType>(T2); if (!IsStructurallyEquivalent(Context, Iface1->getDecl(), Iface2->getDecl())) return false; @@ -674,8 +758,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, } case Type::ObjCTypeParam: { - const ObjCTypeParamType *Obj1 = cast<ObjCTypeParamType>(T1); - const ObjCTypeParamType *Obj2 = cast<ObjCTypeParamType>(T2); + const auto *Obj1 = cast<ObjCTypeParamType>(T1); + const auto *Obj2 = cast<ObjCTypeParamType>(T2); if (!IsStructurallyEquivalent(Context, Obj1->getDecl(), Obj2->getDecl())) return false; @@ -688,9 +772,10 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, } break; } + case Type::ObjCObject: { - const ObjCObjectType *Obj1 = cast<ObjCObjectType>(T1); - const ObjCObjectType *Obj2 = cast<ObjCObjectType>(T2); + const auto *Obj1 = cast<ObjCObjectType>(T1); + const auto *Obj2 = cast<ObjCObjectType>(T2); if (!IsStructurallyEquivalent(Context, Obj1->getBaseType(), Obj2->getBaseType())) return false; @@ -705,28 +790,25 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, } case Type::ObjCObjectPointer: { - const ObjCObjectPointerType *Ptr1 = cast<ObjCObjectPointerType>(T1); - const ObjCObjectPointerType *Ptr2 = cast<ObjCObjectPointerType>(T2); + const auto *Ptr1 = cast<ObjCObjectPointerType>(T1); + const auto *Ptr2 = cast<ObjCObjectPointerType>(T2); if (!IsStructurallyEquivalent(Context, Ptr1->getPointeeType(), Ptr2->getPointeeType())) return false; break; } - case Type::Atomic: { + case Type::Atomic: if (!IsStructurallyEquivalent(Context, cast<AtomicType>(T1)->getValueType(), cast<AtomicType>(T2)->getValueType())) return false; break; - } - case Type::Pipe: { + case Type::Pipe: if (!IsStructurallyEquivalent(Context, cast<PipeType>(T1)->getElementType(), cast<PipeType>(T2)->getElementType())) return false; break; - } - } // end switch return true; @@ -735,7 +817,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, /// Determine structural equivalence of two fields. static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, FieldDecl *Field1, FieldDecl *Field2) { - RecordDecl *Owner2 = cast<RecordDecl>(Field2->getDeclContext()); + const auto *Owner2 = cast<RecordDecl>(Field2->getDeclContext()); // For anonymous structs/unions, match up the anonymous struct/union type // declarations directly, so that we don't go off searching for anonymous @@ -829,6 +911,56 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, return true; } +/// Determine structural equivalence of two methodss. +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + CXXMethodDecl *Method1, + CXXMethodDecl *Method2) { + bool PropertiesEqual = + Method1->getDeclKind() == Method2->getDeclKind() && + Method1->getRefQualifier() == Method2->getRefQualifier() && + Method1->getAccess() == Method2->getAccess() && + Method1->getOverloadedOperator() == Method2->getOverloadedOperator() && + Method1->isStatic() == Method2->isStatic() && + Method1->isConst() == Method2->isConst() && + Method1->isVolatile() == Method2->isVolatile() && + Method1->isVirtual() == Method2->isVirtual() && + Method1->isPure() == Method2->isPure() && + Method1->isDefaulted() == Method2->isDefaulted() && + Method1->isDeleted() == Method2->isDeleted(); + if (!PropertiesEqual) + return false; + // FIXME: Check for 'final'. + + if (auto *Constructor1 = dyn_cast<CXXConstructorDecl>(Method1)) { + auto *Constructor2 = cast<CXXConstructorDecl>(Method2); + if (Constructor1->isExplicit() != Constructor2->isExplicit()) + return false; + } + + if (auto *Conversion1 = dyn_cast<CXXConversionDecl>(Method1)) { + auto *Conversion2 = cast<CXXConversionDecl>(Method2); + if (Conversion1->isExplicit() != Conversion2->isExplicit()) + return false; + if (!IsStructurallyEquivalent(Context, Conversion1->getConversionType(), + Conversion2->getConversionType())) + return false; + } + + const IdentifierInfo *Name1 = Method1->getIdentifier(); + const IdentifierInfo *Name2 = Method2->getIdentifier(); + if (!::IsStructurallyEquivalent(Name1, Name2)) { + return false; + // TODO: Names do not match, add warning like at check for FieldDecl. + } + + // Check the prototypes. + if (!::IsStructurallyEquivalent(Context, + Method1->getType(), Method2->getType())) + return false; + + return true; +} + /// Determine structural equivalence of two records. static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, RecordDecl *D1, RecordDecl *D2) { @@ -845,7 +977,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, return false; } - if (D1->isAnonymousStructOrUnion() && D2->isAnonymousStructOrUnion()) { + if (!D1->getDeclName() && !D2->getDeclName()) { // If both anonymous structs/unions are in a record context, make sure // they occur in the same location in the context records. if (Optional<unsigned> Index1 = @@ -861,10 +993,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, // If both declarations are class template specializations, we know // the ODR applies, so check the template and template arguments. - ClassTemplateSpecializationDecl *Spec1 = - dyn_cast<ClassTemplateSpecializationDecl>(D1); - ClassTemplateSpecializationDecl *Spec2 = - dyn_cast<ClassTemplateSpecializationDecl>(D2); + const auto *Spec1 = dyn_cast<ClassTemplateSpecializationDecl>(D1); + const auto *Spec2 = dyn_cast<ClassTemplateSpecializationDecl>(D2); if (Spec1 && Spec2) { // Check that the specialized templates are the same. if (!IsStructurallyEquivalent(Context, Spec1->getSpecializedTemplate(), @@ -892,8 +1022,17 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (!D1 || !D2) return true; - if (CXXRecordDecl *D1CXX = dyn_cast<CXXRecordDecl>(D1)) { - if (CXXRecordDecl *D2CXX = dyn_cast<CXXRecordDecl>(D2)) { + // If any of the records has external storage and we do a minimal check (or + // AST import) we assmue they are equivalent. (If we didn't have this + // assumption then `RecordDecl::LoadFieldsFromExternalStorage` could trigger + // another AST import which in turn would call the structural equivalency + // check again and finally we'd have an improper result.) + if (Context.EqKind == StructuralEquivalenceKind::Minimal) + if (D1->hasExternalLexicalStorage() || D2->hasExternalLexicalStorage()) + return true; + + if (auto *D1CXX = dyn_cast<CXXRecordDecl>(D1)) { + if (auto *D2CXX = dyn_cast<CXXRecordDecl>(D2)) { if (D1CXX->hasExternalLexicalStorage() && !D1CXX->isCompleteDefinition()) { D1CXX->getASTContext().getExternalSource()->CompleteType(D1CXX); @@ -944,6 +1083,44 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, return false; } } + + // Check the friends for consistency. + CXXRecordDecl::friend_iterator Friend2 = D2CXX->friend_begin(), + Friend2End = D2CXX->friend_end(); + for (CXXRecordDecl::friend_iterator Friend1 = D1CXX->friend_begin(), + Friend1End = D1CXX->friend_end(); + Friend1 != Friend1End; ++Friend1, ++Friend2) { + if (Friend2 == Friend2End) { + if (Context.Complain) { + Context.Diag2(D2->getLocation(), + diag::warn_odr_tag_type_inconsistent) + << Context.ToCtx.getTypeDeclType(D2CXX); + Context.Diag1((*Friend1)->getFriendLoc(), diag::note_odr_friend); + Context.Diag2(D2->getLocation(), diag::note_odr_missing_friend); + } + return false; + } + + if (!IsStructurallyEquivalent(Context, *Friend1, *Friend2)) { + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.ToCtx.getTypeDeclType(D2CXX); + Context.Diag1((*Friend1)->getFriendLoc(), diag::note_odr_friend); + Context.Diag2((*Friend2)->getFriendLoc(), diag::note_odr_friend); + } + return false; + } + } + + if (Friend2 != Friend2End) { + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.ToCtx.getTypeDeclType(D2); + Context.Diag2((*Friend2)->getFriendLoc(), diag::note_odr_friend); + Context.Diag1(D1->getLocation(), diag::note_odr_missing_friend); + } + return false; + } } else if (D1CXX->getNumBases() > 0) { if (Context.Complain) { Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) @@ -1081,11 +1258,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, return false; } - if (!Context.IsStructurallyEquivalent(Params1->getParam(I), - Params2->getParam(I))) { - + if (!IsStructurallyEquivalent(Context, Params1->getParam(I), + Params2->getParam(I))) return false; - } } return true; @@ -1121,7 +1296,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, } // Check types. - if (!Context.IsStructurallyEquivalent(D1->getType(), D2->getType())) { + if (!IsStructurallyEquivalent(Context, D1->getType(), D2->getType())) { if (Context.Complain) { Context.Diag2(D2->getLocation(), diag::err_odr_non_type_parameter_type_inconsistent) @@ -1153,17 +1328,64 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, D2->getTemplateParameters()); } +static bool IsTemplateDeclCommonStructurallyEquivalent( + StructuralEquivalenceContext &Ctx, TemplateDecl *D1, TemplateDecl *D2) { + if (!IsStructurallyEquivalent(D1->getIdentifier(), D2->getIdentifier())) + return false; + if (!D1->getIdentifier()) // Special name + if (D1->getNameAsString() != D2->getNameAsString()) + return false; + return IsStructurallyEquivalent(Ctx, D1->getTemplateParameters(), + D2->getTemplateParameters()); +} + static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, ClassTemplateDecl *D1, ClassTemplateDecl *D2) { // Check template parameters. - if (!IsStructurallyEquivalent(Context, D1->getTemplateParameters(), - D2->getTemplateParameters())) + if (!IsTemplateDeclCommonStructurallyEquivalent(Context, D1, D2)) + return false; + + // Check the templated declaration. + return IsStructurallyEquivalent(Context, D1->getTemplatedDecl(), + D2->getTemplatedDecl()); +} + +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + FunctionTemplateDecl *D1, + FunctionTemplateDecl *D2) { + // Check template parameters. + if (!IsTemplateDeclCommonStructurallyEquivalent(Context, D1, D2)) return false; // Check the templated declaration. - return Context.IsStructurallyEquivalent(D1->getTemplatedDecl(), - D2->getTemplatedDecl()); + return IsStructurallyEquivalent(Context, D1->getTemplatedDecl()->getType(), + D2->getTemplatedDecl()->getType()); +} + +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + FriendDecl *D1, FriendDecl *D2) { + if ((D1->getFriendType() && D2->getFriendDecl()) || + (D1->getFriendDecl() && D2->getFriendType())) { + return false; + } + if (D1->getFriendType() && D2->getFriendType()) + return IsStructurallyEquivalent(Context, + D1->getFriendType()->getType(), + D2->getFriendType()->getType()); + if (D1->getFriendDecl() && D2->getFriendDecl()) + return IsStructurallyEquivalent(Context, D1->getFriendDecl(), + D2->getFriendDecl()); + return false; +} + +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + FunctionDecl *D1, FunctionDecl *D2) { + // FIXME: Consider checking for function attributes as well. + if (!IsStructurallyEquivalent(Context, D1->getType(), D2->getType())) + return false; + + return true; } /// Determine structural equivalence of two declarations. @@ -1187,9 +1409,6 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, Context.DeclsToCheck.push_back(D1->getCanonicalDecl()); return true; } -} // namespace - -namespace clang { DiagnosticBuilder StructuralEquivalenceContext::Diag1(SourceLocation Loc, unsigned DiagID) { @@ -1214,7 +1433,7 @@ StructuralEquivalenceContext::findUntaggedStructOrUnionIndex(RecordDecl *Anon) { ASTContext &Context = Anon->getASTContext(); QualType AnonTy = Context.getRecordType(Anon); - RecordDecl *Owner = dyn_cast<RecordDecl>(Anon->getDeclContext()); + const auto *Owner = dyn_cast<RecordDecl>(Anon->getDeclContext()); if (!Owner) return None; @@ -1234,6 +1453,10 @@ StructuralEquivalenceContext::findUntaggedStructOrUnionIndex(RecordDecl *Anon) { // If the field looks like this: // struct { ... } A; QualType FieldType = F->getType(); + // In case of nested structs. + while (const auto *ElabType = dyn_cast<ElaboratedType>(FieldType)) + FieldType = ElabType->getNamedType(); + if (const auto *RecType = dyn_cast<RecordType>(FieldType)) { const RecordDecl *RecDecl = RecType->getDecl(); if (RecDecl->getDeclContext() == Owner && !RecDecl->getIdentifier()) { @@ -1248,16 +1471,26 @@ StructuralEquivalenceContext::findUntaggedStructOrUnionIndex(RecordDecl *Anon) { return Index; } -bool StructuralEquivalenceContext::IsStructurallyEquivalent(Decl *D1, - Decl *D2) { +bool StructuralEquivalenceContext::IsEquivalent(Decl *D1, Decl *D2) { + + // Ensure that the implementation functions (all static functions in this TU) + // never call the public ASTStructuralEquivalence::IsEquivalent() functions, + // because that will wreak havoc the internal state (DeclsToCheck and + // TentativeEquivalences members) and can cause faulty behaviour. For + // instance, some leaf declarations can be stated and cached as inequivalent + // as a side effect of one inequivalent element in the DeclsToCheck list. + assert(DeclsToCheck.empty()); + assert(TentativeEquivalences.empty()); + if (!::IsStructurallyEquivalent(*this, D1, D2)) return false; return !Finish(); } -bool StructuralEquivalenceContext::IsStructurallyEquivalent(QualType T1, - QualType T2) { +bool StructuralEquivalenceContext::IsEquivalent(QualType T1, QualType T2) { + assert(DeclsToCheck.empty()); + assert(TentativeEquivalences.empty()); if (!::IsStructurallyEquivalent(*this, T1, T2)) return false; @@ -1277,8 +1510,8 @@ bool StructuralEquivalenceContext::Finish() { // FIXME: Switch on all declaration kinds. For now, we're just going to // check the obvious ones. - if (RecordDecl *Record1 = dyn_cast<RecordDecl>(D1)) { - if (RecordDecl *Record2 = dyn_cast<RecordDecl>(D2)) { + if (auto *Record1 = dyn_cast<RecordDecl>(D1)) { + if (auto *Record2 = dyn_cast<RecordDecl>(D2)) { // Check for equivalent structure names. IdentifierInfo *Name1 = Record1->getIdentifier(); if (!Name1 && Record1->getTypedefNameForAnonDecl()) @@ -1293,8 +1526,8 @@ bool StructuralEquivalenceContext::Finish() { // Record/non-record mismatch. Equivalent = false; } - } else if (EnumDecl *Enum1 = dyn_cast<EnumDecl>(D1)) { - if (EnumDecl *Enum2 = dyn_cast<EnumDecl>(D2)) { + } else if (auto *Enum1 = dyn_cast<EnumDecl>(D1)) { + if (auto *Enum2 = dyn_cast<EnumDecl>(D2)) { // Check for equivalent enum names. IdentifierInfo *Name1 = Enum1->getIdentifier(); if (!Name1 && Enum1->getTypedefNameForAnonDecl()) @@ -1309,8 +1542,8 @@ bool StructuralEquivalenceContext::Finish() { // Enum/non-enum mismatch Equivalent = false; } - } else if (TypedefNameDecl *Typedef1 = dyn_cast<TypedefNameDecl>(D1)) { - if (TypedefNameDecl *Typedef2 = dyn_cast<TypedefNameDecl>(D2)) { + } else if (const auto *Typedef1 = dyn_cast<TypedefNameDecl>(D1)) { + if (const auto *Typedef2 = dyn_cast<TypedefNameDecl>(D2)) { if (!::IsStructurallyEquivalent(Typedef1->getIdentifier(), Typedef2->getIdentifier()) || !::IsStructurallyEquivalent(*this, Typedef1->getUnderlyingType(), @@ -1320,46 +1553,75 @@ bool StructuralEquivalenceContext::Finish() { // Typedef/non-typedef mismatch. Equivalent = false; } - } else if (ClassTemplateDecl *ClassTemplate1 = - dyn_cast<ClassTemplateDecl>(D1)) { - if (ClassTemplateDecl *ClassTemplate2 = dyn_cast<ClassTemplateDecl>(D2)) { - if (!::IsStructurallyEquivalent(ClassTemplate1->getIdentifier(), - ClassTemplate2->getIdentifier()) || - !::IsStructurallyEquivalent(*this, ClassTemplate1, ClassTemplate2)) + } else if (auto *ClassTemplate1 = dyn_cast<ClassTemplateDecl>(D1)) { + if (auto *ClassTemplate2 = dyn_cast<ClassTemplateDecl>(D2)) { + if (!::IsStructurallyEquivalent(*this, ClassTemplate1, + ClassTemplate2)) + Equivalent = false; + } else { + // Class template/non-class-template mismatch. + Equivalent = false; + } + } else if (auto *FunctionTemplate1 = dyn_cast<FunctionTemplateDecl>(D1)) { + if (auto *FunctionTemplate2 = dyn_cast<FunctionTemplateDecl>(D2)) { + if (!::IsStructurallyEquivalent(*this, FunctionTemplate1, + FunctionTemplate2)) Equivalent = false; } else { // Class template/non-class-template mismatch. Equivalent = false; } - } else if (TemplateTypeParmDecl *TTP1 = - dyn_cast<TemplateTypeParmDecl>(D1)) { - if (TemplateTypeParmDecl *TTP2 = dyn_cast<TemplateTypeParmDecl>(D2)) { + } else if (auto *TTP1 = dyn_cast<TemplateTypeParmDecl>(D1)) { + if (auto *TTP2 = dyn_cast<TemplateTypeParmDecl>(D2)) { if (!::IsStructurallyEquivalent(*this, TTP1, TTP2)) Equivalent = false; } else { // Kind mismatch. Equivalent = false; } - } else if (NonTypeTemplateParmDecl *NTTP1 = - dyn_cast<NonTypeTemplateParmDecl>(D1)) { - if (NonTypeTemplateParmDecl *NTTP2 = - dyn_cast<NonTypeTemplateParmDecl>(D2)) { + } else if (auto *NTTP1 = dyn_cast<NonTypeTemplateParmDecl>(D1)) { + if (auto *NTTP2 = dyn_cast<NonTypeTemplateParmDecl>(D2)) { if (!::IsStructurallyEquivalent(*this, NTTP1, NTTP2)) Equivalent = false; } else { // Kind mismatch. Equivalent = false; } - } else if (TemplateTemplateParmDecl *TTP1 = - dyn_cast<TemplateTemplateParmDecl>(D1)) { - if (TemplateTemplateParmDecl *TTP2 = - dyn_cast<TemplateTemplateParmDecl>(D2)) { + } else if (auto *TTP1 = dyn_cast<TemplateTemplateParmDecl>(D1)) { + if (auto *TTP2 = dyn_cast<TemplateTemplateParmDecl>(D2)) { if (!::IsStructurallyEquivalent(*this, TTP1, TTP2)) Equivalent = false; } else { // Kind mismatch. Equivalent = false; } + } else if (auto *MD1 = dyn_cast<CXXMethodDecl>(D1)) { + if (auto *MD2 = dyn_cast<CXXMethodDecl>(D2)) { + if (!::IsStructurallyEquivalent(*this, MD1, MD2)) + Equivalent = false; + } else { + // Kind mismatch. + Equivalent = false; + } + } else if (FunctionDecl *FD1 = dyn_cast<FunctionDecl>(D1)) { + if (FunctionDecl *FD2 = dyn_cast<FunctionDecl>(D2)) { + if (!::IsStructurallyEquivalent(FD1->getIdentifier(), + FD2->getIdentifier())) + Equivalent = false; + if (!::IsStructurallyEquivalent(*this, FD1, FD2)) + Equivalent = false; + } else { + // Kind mismatch. + Equivalent = false; + } + } else if (FriendDecl *FrD1 = dyn_cast<FriendDecl>(D1)) { + if (FriendDecl *FrD2 = dyn_cast<FriendDecl>(D2)) { + if (!::IsStructurallyEquivalent(*this, FrD1, FrD2)) + Equivalent = false; + } else { + // Kind mismatch. + Equivalent = false; + } } if (!Equivalent) { @@ -1374,4 +1636,3 @@ bool StructuralEquivalenceContext::Finish() { return false; } -} // namespace clang diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt index a6f1027856c7..4f868a3af59e 100644 --- a/lib/AST/CMakeLists.txt +++ b/lib/AST/CMakeLists.txt @@ -20,6 +20,7 @@ add_clang_library(clangAST CommentLexer.cpp CommentParser.cpp CommentSema.cpp + ComparisonCategories.cpp DataCollection.cpp Decl.cpp DeclarationName.cpp diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp index 24e96ba38015..2825329775ed 100644 --- a/lib/AST/CXXInheritance.cpp +++ b/lib/AST/CXXInheritance.cpp @@ -34,13 +34,13 @@ using namespace clang; -/// \brief Computes the set of declarations referenced by these base +/// Computes the set of declarations referenced by these base /// paths. void CXXBasePaths::ComputeDeclsFound() { assert(NumDeclsFound == 0 && !DeclsFound && "Already computed the set of declarations"); - llvm::SetVector<NamedDecl *, SmallVector<NamedDecl *, 8>> Decls; + llvm::SmallSetVector<NamedDecl *, 8> Decls; for (paths_iterator Path = begin(), PathEnd = end(); Path != PathEnd; ++Path) Decls.insert(Path->Decls.front()); @@ -63,8 +63,8 @@ CXXBasePaths::decl_range CXXBasePaths::found_decls() { /// an unqualified, canonical class type. bool CXXBasePaths::isAmbiguous(CanQualType BaseType) { BaseType = BaseType.getUnqualifiedType(); - std::pair<bool, unsigned>& Subobjects = ClassSubobjects[BaseType]; - return Subobjects.second + (Subobjects.first? 1 : 0) > 1; + IsVirtBaseAndNumberNonVirtBases Subobjects = ClassSubobjects[BaseType]; + return Subobjects.NumberOfNonVirtBases + (Subobjects.IsVirtBase ? 1 : 0) > 1; } /// clear - Clear out all prior path information. @@ -76,7 +76,7 @@ void CXXBasePaths::clear() { DetectedVirtual = nullptr; } -/// @brief Swaps the contents of this CXXBasePaths structure with the +/// Swaps the contents of this CXXBasePaths structure with the /// contents of Other. void CXXBasePaths::swap(CXXBasePaths &Other) { std::swap(Origin, Other.Origin); @@ -217,21 +217,21 @@ bool CXXBasePaths::lookupInBases(ASTContext &Context, // Determine whether we need to visit this base class at all, // updating the count of subobjects appropriately. - std::pair<bool, unsigned>& Subobjects = ClassSubobjects[BaseType]; + IsVirtBaseAndNumberNonVirtBases &Subobjects = ClassSubobjects[BaseType]; bool VisitBase = true; bool SetVirtual = false; if (BaseSpec.isVirtual()) { - VisitBase = !Subobjects.first; - Subobjects.first = true; + VisitBase = !Subobjects.IsVirtBase; + Subobjects.IsVirtBase = true; if (isDetectingVirtual() && DetectedVirtual == nullptr) { // If this is the first virtual we find, remember it. If it turns out // there is no base path here, we'll reset it later. DetectedVirtual = BaseType->getAs<RecordType>(); SetVirtual = true; } - } else - ++Subobjects.second; - + } else { + ++Subobjects.NumberOfNonVirtBases; + } if (isRecordingPaths()) { // Add this base specifier to the current path. CXXBasePathElement Element; @@ -240,7 +240,7 @@ bool CXXBasePaths::lookupInBases(ASTContext &Context, if (BaseSpec.isVirtual()) Element.SubobjectNumber = 0; else - Element.SubobjectNumber = Subobjects.second; + Element.SubobjectNumber = Subobjects.NumberOfNonVirtBases; ScratchPath.push_back(Element); // Calculate the "top-down" access to this base class. @@ -567,11 +567,11 @@ void OverridingMethods::replaceAll(UniqueVirtualMethod Overriding) { namespace { class FinalOverriderCollector { - /// \brief The number of subobjects of a given class type that + /// The number of subobjects of a given class type that /// occur within the class hierarchy. llvm::DenseMap<const CXXRecordDecl *, unsigned> SubobjectCount; - /// \brief Overriders for each virtual base subobject. + /// Overriders for each virtual base subobject. llvm::DenseMap<const CXXRecordDecl *, CXXFinalOverriderMap *> VirtualOverriders; CXXFinalOverriderMap FinalOverriders; @@ -637,8 +637,7 @@ void FinalOverriderCollector::Collect(const CXXRecordDecl *RD, OMEnd = BaseOverriders->end(); OM != OMEnd; ++OM) { - const CXXMethodDecl *CanonOM - = cast<CXXMethodDecl>(OM->first->getCanonicalDecl()); + const CXXMethodDecl *CanonOM = OM->first->getCanonicalDecl(); Overriders[CanonOM].add(OM->second); } } @@ -649,7 +648,7 @@ void FinalOverriderCollector::Collect(const CXXRecordDecl *RD, if (!M->isVirtual()) continue; - CXXMethodDecl *CanonM = cast<CXXMethodDecl>(M->getCanonicalDecl()); + CXXMethodDecl *CanonM = M->getCanonicalDecl(); using OverriddenMethodsRange = llvm::iterator_range<CXXMethodDecl::method_iterator>; OverriddenMethodsRange OverriddenMethods = CanonM->overridden_methods(); diff --git a/lib/AST/CommentBriefParser.cpp b/lib/AST/CommentBriefParser.cpp index eecea8fc11df..5ec7586a475d 100644 --- a/lib/AST/CommentBriefParser.cpp +++ b/lib/AST/CommentBriefParser.cpp @@ -122,8 +122,8 @@ std::string BriefParser::Parse() { if (Tok.is(tok::newline)) { ConsumeToken(); // We found a paragraph end. This ends the brief description if - // \\brief command or its equivalent was explicitly used. - // Stop scanning text because an explicit \\brief paragraph is the + // \command or its equivalent was explicitly used. + // Stop scanning text because an explicit \paragraph is the // preffered one. if (InBrief) break; diff --git a/lib/AST/CommentLexer.cpp b/lib/AST/CommentLexer.cpp index 65d0f56f09ab..6ff4d45a9572 100644 --- a/lib/AST/CommentLexer.cpp +++ b/lib/AST/CommentLexer.cpp @@ -294,6 +294,39 @@ void Lexer::lexCommentText(Token &T) { assert(CommentState == LCS_InsideBCPLComment || CommentState == LCS_InsideCComment); + // Handles lexing non-command text, i.e. text and newline. + auto HandleNonCommandToken = [&]() -> void { + assert(State == LS_Normal); + + const char *TokenPtr = BufferPtr; + assert(TokenPtr < CommentEnd); + switch (*TokenPtr) { + case '\n': + case '\r': + TokenPtr = skipNewline(TokenPtr, CommentEnd); + formTokenWithChars(T, TokenPtr, tok::newline); + + if (CommentState == LCS_InsideCComment) + skipLineStartingDecorations(); + return; + + default: { + StringRef TokStartSymbols = ParseCommands ? "\n\r\\@&<" : "\n\r"; + size_t End = StringRef(TokenPtr, CommentEnd - TokenPtr) + .find_first_of(TokStartSymbols); + if (End != StringRef::npos) + TokenPtr += End; + else + TokenPtr = CommentEnd; + formTextToken(T, TokenPtr); + return; + } + } + }; + + if (!ParseCommands) + return HandleNonCommandToken(); + switch (State) { case LS_Normal: break; @@ -315,136 +348,116 @@ void Lexer::lexCommentText(Token &T) { } assert(State == LS_Normal); - const char *TokenPtr = BufferPtr; assert(TokenPtr < CommentEnd); - while (TokenPtr != CommentEnd) { - switch(*TokenPtr) { - case '\\': - case '@': { - // Commands that start with a backslash and commands that start with - // 'at' have equivalent semantics. But we keep information about the - // exact syntax in AST for comments. - tok::TokenKind CommandKind = - (*TokenPtr == '@') ? tok::at_command : tok::backslash_command; + switch(*TokenPtr) { + case '\\': + case '@': { + // Commands that start with a backslash and commands that start with + // 'at' have equivalent semantics. But we keep information about the + // exact syntax in AST for comments. + tok::TokenKind CommandKind = + (*TokenPtr == '@') ? tok::at_command : tok::backslash_command; + TokenPtr++; + if (TokenPtr == CommentEnd) { + formTextToken(T, TokenPtr); + return; + } + char C = *TokenPtr; + switch (C) { + default: + break; + + case '\\': case '@': case '&': case '$': + case '#': case '<': case '>': case '%': + case '\"': case '.': case ':': + // This is one of \\ \@ \& \$ etc escape sequences. TokenPtr++; - if (TokenPtr == CommentEnd) { - formTextToken(T, TokenPtr); - return; - } - char C = *TokenPtr; - switch (C) { - default: - break; - - case '\\': case '@': case '&': case '$': - case '#': case '<': case '>': case '%': - case '\"': case '.': case ':': - // This is one of \\ \@ \& \$ etc escape sequences. + if (C == ':' && TokenPtr != CommentEnd && *TokenPtr == ':') { + // This is the \:: escape sequence. TokenPtr++; - if (C == ':' && TokenPtr != CommentEnd && *TokenPtr == ':') { - // This is the \:: escape sequence. - TokenPtr++; - } - StringRef UnescapedText(BufferPtr + 1, TokenPtr - (BufferPtr + 1)); - formTokenWithChars(T, TokenPtr, tok::text); - T.setText(UnescapedText); - return; } + StringRef UnescapedText(BufferPtr + 1, TokenPtr - (BufferPtr + 1)); + formTokenWithChars(T, TokenPtr, tok::text); + T.setText(UnescapedText); + return; + } - // Don't make zero-length commands. - if (!isCommandNameStartCharacter(*TokenPtr)) { - formTextToken(T, TokenPtr); - return; - } + // Don't make zero-length commands. + if (!isCommandNameStartCharacter(*TokenPtr)) { + formTextToken(T, TokenPtr); + return; + } - TokenPtr = skipCommandName(TokenPtr, CommentEnd); - unsigned Length = TokenPtr - (BufferPtr + 1); - - // Hardcoded support for lexing LaTeX formula commands - // \f$ \f[ \f] \f{ \f} as a single command. - if (Length == 1 && TokenPtr[-1] == 'f' && TokenPtr != CommentEnd) { - C = *TokenPtr; - if (C == '$' || C == '[' || C == ']' || C == '{' || C == '}') { - TokenPtr++; - Length++; - } - } + TokenPtr = skipCommandName(TokenPtr, CommentEnd); + unsigned Length = TokenPtr - (BufferPtr + 1); - StringRef CommandName(BufferPtr + 1, Length); - - const CommandInfo *Info = Traits.getCommandInfoOrNULL(CommandName); - if (!Info) { - if ((Info = Traits.getTypoCorrectCommandInfo(CommandName))) { - StringRef CorrectedName = Info->Name; - SourceLocation Loc = getSourceLocation(BufferPtr); - SourceLocation EndLoc = getSourceLocation(TokenPtr); - SourceRange FullRange = SourceRange(Loc, EndLoc); - SourceRange CommandRange(Loc.getLocWithOffset(1), EndLoc); - Diag(Loc, diag::warn_correct_comment_command_name) - << FullRange << 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) - << SourceRange(T.getLocation(), T.getEndLocation()); - return; - } - } - if (Info->IsVerbatimBlockCommand) { - setupAndLexVerbatimBlock(T, TokenPtr, *BufferPtr, Info); - return; - } - if (Info->IsVerbatimLineCommand) { - setupAndLexVerbatimLine(T, TokenPtr, Info); - return; + // Hardcoded support for lexing LaTeX formula commands + // \f$ \f[ \f] \f{ \f} as a single command. + if (Length == 1 && TokenPtr[-1] == 'f' && TokenPtr != CommentEnd) { + C = *TokenPtr; + if (C == '$' || C == '[' || C == ']' || C == '{' || C == '}') { + TokenPtr++; + Length++; } - formTokenWithChars(T, TokenPtr, CommandKind); - T.setCommandID(Info->getID()); - return; } - case '&': - lexHTMLCharacterReference(T); - return; - - case '<': { - TokenPtr++; - if (TokenPtr == CommentEnd) { - formTextToken(T, TokenPtr); + StringRef CommandName(BufferPtr + 1, Length); + + const CommandInfo *Info = Traits.getCommandInfoOrNULL(CommandName); + if (!Info) { + if ((Info = Traits.getTypoCorrectCommandInfo(CommandName))) { + StringRef CorrectedName = Info->Name; + SourceLocation Loc = getSourceLocation(BufferPtr); + SourceLocation EndLoc = getSourceLocation(TokenPtr); + SourceRange FullRange = SourceRange(Loc, EndLoc); + SourceRange CommandRange(Loc.getLocWithOffset(1), EndLoc); + Diag(Loc, diag::warn_correct_comment_command_name) + << FullRange << 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) + << SourceRange(T.getLocation(), T.getEndLocation()); return; } - const char C = *TokenPtr; - if (isHTMLIdentifierStartingCharacter(C)) - setupAndLexHTMLStartTag(T); - else if (C == '/') - setupAndLexHTMLEndTag(T); - else - formTextToken(T, TokenPtr); + } + if (Info->IsVerbatimBlockCommand) { + setupAndLexVerbatimBlock(T, TokenPtr, *BufferPtr, Info); return; } - - case '\n': - case '\r': - TokenPtr = skipNewline(TokenPtr, CommentEnd); - formTokenWithChars(T, TokenPtr, tok::newline); - - if (CommentState == LCS_InsideCComment) - skipLineStartingDecorations(); + if (Info->IsVerbatimLineCommand) { + setupAndLexVerbatimLine(T, TokenPtr, Info); return; + } + formTokenWithChars(T, TokenPtr, CommandKind); + T.setCommandID(Info->getID()); + return; + } - default: { - size_t End = StringRef(TokenPtr, CommentEnd - TokenPtr). - find_first_of("\n\r\\@&<"); - if (End != StringRef::npos) - TokenPtr += End; - else - TokenPtr = CommentEnd; + case '&': + lexHTMLCharacterReference(T); + return; + + case '<': { + TokenPtr++; + if (TokenPtr == CommentEnd) { formTextToken(T, TokenPtr); return; } + const char C = *TokenPtr; + if (isHTMLIdentifierStartingCharacter(C)) + setupAndLexHTMLStartTag(T); + else if (C == '/') + setupAndLexHTMLEndTag(T); + else + formTextToken(T, TokenPtr); + return; } + + default: + return HandleNonCommandToken(); } } @@ -727,14 +740,13 @@ void Lexer::lexHTMLEndTag(Token &T) { } Lexer::Lexer(llvm::BumpPtrAllocator &Allocator, DiagnosticsEngine &Diags, - const CommandTraits &Traits, - SourceLocation FileLoc, - const char *BufferStart, const char *BufferEnd): - Allocator(Allocator), Diags(Diags), Traits(Traits), - BufferStart(BufferStart), BufferEnd(BufferEnd), - FileLoc(FileLoc), BufferPtr(BufferStart), - CommentState(LCS_BeforeComment), State(LS_Normal) { -} + const CommandTraits &Traits, SourceLocation FileLoc, + const char *BufferStart, const char *BufferEnd, + bool ParseCommands) + : Allocator(Allocator), Diags(Diags), Traits(Traits), + BufferStart(BufferStart), BufferEnd(BufferEnd), FileLoc(FileLoc), + BufferPtr(BufferStart), CommentState(LCS_BeforeComment), State(LS_Normal), + ParseCommands(ParseCommands) {} void Lexer::lex(Token &T) { again: diff --git a/lib/AST/CommentSema.cpp b/lib/AST/CommentSema.cpp index 6c2019e1a72b..4bc98bf10765 100644 --- a/lib/AST/CommentSema.cpp +++ b/lib/AST/CommentSema.cpp @@ -215,7 +215,7 @@ void Sema::checkContainerDecl(const BlockCommandComment *Comment) { << Comment->getSourceRange(); } -/// \brief Turn a string into the corresponding PassDirection or -1 if it's not +/// Turn a string into the corresponding PassDirection or -1 if it's not /// valid. static int getParamPassDirection(StringRef Arg) { return llvm::StringSwitch<int>(Arg) diff --git a/lib/AST/ComparisonCategories.cpp b/lib/AST/ComparisonCategories.cpp new file mode 100644 index 000000000000..87f51facc59b --- /dev/null +++ b/lib/AST/ComparisonCategories.cpp @@ -0,0 +1,211 @@ +//===- ComparisonCategories.cpp - Three Way Comparison Data -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Comparison Category enum and data types, which +// store the types and expressions needed to support operator<=> +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ComparisonCategories.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/Type.h" +#include "llvm/ADT/SmallVector.h" + +using namespace clang; + +bool ComparisonCategoryInfo::ValueInfo::hasValidIntValue() const { + assert(VD && "must have var decl"); + if (!VD->checkInitIsICE()) + return false; + + // Before we attempt to get the value of the first field, ensure that we + // actually have one (and only one) field. + auto *Record = VD->getType()->getAsCXXRecordDecl(); + if (std::distance(Record->field_begin(), Record->field_end()) != 1 || + !Record->field_begin()->getType()->isIntegralOrEnumerationType()) + return false; + + return true; +} + +/// Attempt to determine the integer value used to represent the comparison +/// category result by evaluating the initializer for the specified VarDecl as +/// a constant expression and retreiving the value of the class's first +/// (and only) field. +/// +/// Note: The STL types are expected to have the form: +/// struct X { T value; }; +/// where T is an integral or enumeration type. +llvm::APSInt ComparisonCategoryInfo::ValueInfo::getIntValue() const { + assert(hasValidIntValue() && "must have a valid value"); + return VD->evaluateValue()->getStructField(0).getInt(); +} + +ComparisonCategoryInfo::ValueInfo *ComparisonCategoryInfo::lookupValueInfo( + ComparisonCategoryResult ValueKind) const { + // Check if we already have a cache entry for this value. + auto It = llvm::find_if( + Objects, [&](ValueInfo const &Info) { return Info.Kind == ValueKind; }); + if (It != Objects.end()) + return &(*It); + + // We don't have a cached result. Lookup the variable declaration and create + // a new entry representing it. + DeclContextLookupResult Lookup = Record->getCanonicalDecl()->lookup( + &Ctx.Idents.get(ComparisonCategories::getResultString(ValueKind))); + if (Lookup.size() != 1 || !isa<VarDecl>(Lookup.front())) + return nullptr; + Objects.emplace_back(ValueKind, cast<VarDecl>(Lookup.front())); + return &Objects.back(); +} + +static const NamespaceDecl *lookupStdNamespace(const ASTContext &Ctx, + NamespaceDecl *&StdNS) { + if (!StdNS) { + DeclContextLookupResult Lookup = + Ctx.getTranslationUnitDecl()->lookup(&Ctx.Idents.get("std")); + if (Lookup.size() == 1) + StdNS = dyn_cast<NamespaceDecl>(Lookup.front()); + } + return StdNS; +} + +static CXXRecordDecl *lookupCXXRecordDecl(const ASTContext &Ctx, + const NamespaceDecl *StdNS, + ComparisonCategoryType Kind) { + StringRef Name = ComparisonCategories::getCategoryString(Kind); + DeclContextLookupResult Lookup = StdNS->lookup(&Ctx.Idents.get(Name)); + if (Lookup.size() == 1) + if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Lookup.front())) + return RD; + return nullptr; +} + +const ComparisonCategoryInfo * +ComparisonCategories::lookupInfo(ComparisonCategoryType Kind) const { + auto It = Data.find(static_cast<char>(Kind)); + if (It != Data.end()) + return &It->second; + + if (const NamespaceDecl *NS = lookupStdNamespace(Ctx, StdNS)) + if (CXXRecordDecl *RD = lookupCXXRecordDecl(Ctx, NS, Kind)) + return &Data.try_emplace((char)Kind, Ctx, RD, Kind).first->second; + + return nullptr; +} + +const ComparisonCategoryInfo * +ComparisonCategories::lookupInfoForType(QualType Ty) const { + assert(!Ty.isNull() && "type must be non-null"); + using CCT = ComparisonCategoryType; + auto *RD = Ty->getAsCXXRecordDecl(); + if (!RD) + return nullptr; + + // Check to see if we have information for the specified type cached. + const auto *CanonRD = RD->getCanonicalDecl(); + for (auto &KV : Data) { + const ComparisonCategoryInfo &Info = KV.second; + if (CanonRD == Info.Record->getCanonicalDecl()) + return &Info; + } + + if (!RD->getEnclosingNamespaceContext()->isStdNamespace()) + return nullptr; + + // If not, check to see if the decl names a type in namespace std with a name + // matching one of the comparison category types. + for (unsigned I = static_cast<unsigned>(CCT::First), + End = static_cast<unsigned>(CCT::Last); + I <= End; ++I) { + CCT Kind = static_cast<CCT>(I); + + // We've found the comparison category type. Build a new cache entry for + // it. + if (getCategoryString(Kind) == RD->getName()) + return &Data.try_emplace((char)Kind, Ctx, RD, Kind).first->second; + } + + // We've found nothing. This isn't a comparison category type. + return nullptr; +} + +const ComparisonCategoryInfo &ComparisonCategories::getInfoForType(QualType Ty) const { + const ComparisonCategoryInfo *Info = lookupInfoForType(Ty); + assert(Info && "info for comparison category not found"); + return *Info; +} + +QualType ComparisonCategoryInfo::getType() const { + assert(Record); + return QualType(Record->getTypeForDecl(), 0); +} + +StringRef ComparisonCategories::getCategoryString(ComparisonCategoryType Kind) { + using CCKT = ComparisonCategoryType; + switch (Kind) { + case CCKT::WeakEquality: + return "weak_equality"; + case CCKT::StrongEquality: + return "strong_equality"; + case CCKT::PartialOrdering: + return "partial_ordering"; + case CCKT::WeakOrdering: + return "weak_ordering"; + case CCKT::StrongOrdering: + return "strong_ordering"; + } + llvm_unreachable("unhandled cases in switch"); +} + +StringRef ComparisonCategories::getResultString(ComparisonCategoryResult Kind) { + using CCVT = ComparisonCategoryResult; + switch (Kind) { + case CCVT::Equal: + return "equal"; + case CCVT::Nonequal: + return "nonequal"; + case CCVT::Equivalent: + return "equivalent"; + case CCVT::Nonequivalent: + return "nonequivalent"; + case CCVT::Less: + return "less"; + case CCVT::Greater: + return "greater"; + case CCVT::Unordered: + return "unordered"; + } + llvm_unreachable("unhandled case in switch"); +} + +std::vector<ComparisonCategoryResult> +ComparisonCategories::getPossibleResultsForType(ComparisonCategoryType Type) { + using CCT = ComparisonCategoryType; + using CCR = ComparisonCategoryResult; + std::vector<CCR> Values; + Values.reserve(6); + Values.push_back(CCR::Equivalent); + bool IsStrong = (Type == CCT::StrongEquality || Type == CCT::StrongOrdering); + if (IsStrong) + Values.push_back(CCR::Equal); + if (Type == CCT::StrongOrdering || Type == CCT::WeakOrdering || + Type == CCT::PartialOrdering) { + Values.push_back(CCR::Less); + Values.push_back(CCR::Greater); + } else { + Values.push_back(CCR::Nonequivalent); + if (IsStrong) + Values.push_back(CCR::Nonequal); + } + if (Type == CCT::PartialOrdering) + Values.push_back(CCR::Unordered); + return Values; +} diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 4c1d591b41e9..3b9b85a20af6 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -27,6 +27,7 @@ #include "clang/AST/ExprCXX.h" #include "clang/AST/ExternalASTSource.h" #include "clang/AST/ODRHash.h" +#include "clang/AST/PrettyDeclStackTrace.h" #include "clang/AST/PrettyPrinter.h" #include "clang/AST/Redeclarable.h" #include "clang/AST/Stmt.h" @@ -76,6 +77,24 @@ Decl *clang::getPrimaryMergedDecl(Decl *D) { return D->getASTContext().getPrimaryMergedDecl(D); } +void PrettyDeclStackTraceEntry::print(raw_ostream &OS) const { + SourceLocation Loc = this->Loc; + if (!Loc.isValid() && TheDecl) Loc = TheDecl->getLocation(); + if (Loc.isValid()) { + Loc.print(OS, Context.getSourceManager()); + OS << ": "; + } + OS << Message; + + if (auto *ND = dyn_cast_or_null<NamedDecl>(TheDecl)) { + OS << " '"; + ND->getNameForDiagnostic(OS, Context.getPrintingPolicy(), true); + OS << "'"; + } + + OS << '\n'; +} + // Defined here so that it can be inlined into its direct callers. bool Decl::isOutOfLine() const { return !getLexicalDeclContext()->Equals(getDeclContext()); @@ -224,7 +243,7 @@ LinkageInfo LinkageComputer::getLVForType(const Type &T, return getTypeLinkageAndVisibility(&T); } -/// \brief Get the most restrictive linkage for the types in the given +/// 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. LinkageInfo LinkageComputer::getLVForTemplateParameterList( @@ -291,7 +310,7 @@ static const Decl *getOutermostFuncOrBlockContext(const Decl *D) { return Ret; } -/// \brief Get the most restrictive linkage for the types and +/// 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 @@ -312,12 +331,12 @@ LinkageComputer::getLVForTemplateArgumentList(ArrayRef<TemplateArgument> Args, LV.merge(getLVForType(*Arg.getAsType(), computation)); continue; - case TemplateArgument::Declaration: - if (const auto *ND = dyn_cast<NamedDecl>(Arg.getAsDecl())) { - assert(!usesTypeVisibility(ND)); - LV.merge(getLVForDecl(ND, computation)); - } + case TemplateArgument::Declaration: { + const NamedDecl *ND = Arg.getAsDecl(); + assert(!usesTypeVisibility(ND)); + LV.merge(getLVForDecl(ND, computation)); continue; + } case TemplateArgument::NullPtr: LV.merge(getTypeLinkageAndVisibility(Arg.getNullPtrType())); @@ -779,7 +798,7 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D, // unique-external linkage, it's not legally usable from outside // this translation unit. However, we should use the C linkage // rules instead for extern "C" declarations. - if (Context.getLangOpts().CPlusPlus && !Function->isInExternCContext()) { + if (Context.getLangOpts().CPlusPlus && !isFirstInExternCContext(Function)) { // Only look at the type-as-written. Otherwise, deducing the return type // of a function could change its linkage. QualType TypeAsWritten = Function->getType(); @@ -1073,9 +1092,18 @@ getExplicitVisibilityAux(const NamedDecl *ND, // If there wasn't explicit visibility there, and this is a // specialization of a class template, check for visibility // on the pattern. - if (const auto *spec = dyn_cast<ClassTemplateSpecializationDecl>(ND)) - return getVisibilityOf(spec->getSpecializedTemplate()->getTemplatedDecl(), - kind); + if (const auto *spec = dyn_cast<ClassTemplateSpecializationDecl>(ND)) { + // Walk all the template decl till this point to see if there are + // explicit visibility attributes. + const auto *TD = spec->getSpecializedTemplate()->getTemplatedDecl(); + while (TD != nullptr) { + auto Vis = getVisibilityOf(TD, kind); + if (Vis != None) + return Vis; + TD = TD->getPreviousDecl(); + } + return None; + } // Use the most recent declaration. if (!IsMostRecent && !isa<NamespaceDecl>(ND)) { @@ -1165,7 +1193,7 @@ LinkageInfo LinkageComputer::getLVForLocalDecl(const NamedDecl *D, LVComputationKind computation) { if (const auto *Function = dyn_cast<FunctionDecl>(D)) { if (Function->isInAnonymousNamespace() && - !Function->isInExternCContext()) + !isFirstInExternCContext(Function)) return getInternalLinkageFor(Function); // This is a "void f();" which got merged with a file static. @@ -1188,7 +1216,7 @@ LinkageInfo LinkageComputer::getLVForLocalDecl(const NamedDecl *D, if (const auto *Var = dyn_cast<VarDecl>(D)) { if (Var->hasExternalStorage()) { - if (Var->isInAnonymousNamespace() && !Var->isInExternCContext()) + if (Var->isInAnonymousNamespace() && !isFirstInExternCContext(Var)) return getInternalLinkageFor(Var); LinkageInfo LV; @@ -1497,9 +1525,10 @@ void NamedDecl::printQualifiedName(raw_ostream &OS, using ContextsTy = SmallVector<const DeclContext *, 8>; ContextsTy Contexts; - // Collect contexts. - while (Ctx && isa<NamedDecl>(Ctx)) { - Contexts.push_back(Ctx); + // Collect named contexts. + while (Ctx) { + if (isa<NamedDecl>(Ctx)) + Contexts.push_back(Ctx); Ctx = Ctx->getParent(); } @@ -2403,6 +2432,23 @@ void VarDecl::setDescribedVarTemplate(VarTemplateDecl *Template) { getASTContext().setTemplateOrSpecializationInfo(this, Template); } +bool VarDecl::isKnownToBeDefined() const { + const auto &LangOpts = getASTContext().getLangOpts(); + // In CUDA mode without relocatable device code, variables of form 'extern + // __shared__ Foo foo[]' are pointers to the base of the GPU core's shared + // memory pool. These are never undefined variables, even if they appear + // inside of an anon namespace or static function. + // + // With CUDA relocatable device code enabled, these variables don't get + // special handling; they're treated like regular extern variables. + if (LangOpts.CUDA && !LangOpts.CUDARelocatableDeviceCode && + hasExternalStorage() && hasAttr<CUDASharedAttr>() && + isa<IncompleteArrayType>(getType())) + return true; + + return hasDefinition(); +} + MemberSpecializationInfo *VarDecl::getMemberSpecializationInfo() const { if (isStaticDataMember()) // FIXME: Remove ? @@ -2827,6 +2873,14 @@ bool FunctionDecl::isNoReturn() const { return false; } +bool FunctionDecl::isCPUDispatchMultiVersion() const { + return isMultiVersion() && hasAttr<CPUDispatchAttr>(); +} + +bool FunctionDecl::isCPUSpecificMultiVersion() const { + return isMultiVersion() && hasAttr<CPUSpecificAttr>(); +} + void FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) { redeclarable_base::setPreviousDecl(PrevDecl); @@ -2844,7 +2898,7 @@ FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) { FunctionDecl *FunctionDecl::getCanonicalDecl() { return getFirstDecl(); } -/// \brief Returns a value indicating whether this function +/// Returns a value indicating whether this function /// corresponds to a builtin function. /// /// The function corresponds to a built-in function if it is @@ -2901,6 +2955,13 @@ unsigned FunctionDecl::getBuiltinID() const { Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) return 0; + // CUDA does not have device-side standard library. printf and malloc are the + // only special cases that are supported by device-side runtime. + if (Context.getLangOpts().CUDA && hasAttr<CUDADeviceAttr>() && + !hasAttr<CUDAHostAttr>() && + !(BuiltinID == Builtin::BIprintf || BuiltinID == Builtin::BImalloc)) + return 0; + return BuiltinID; } @@ -2939,7 +3000,7 @@ unsigned FunctionDecl::getMinRequiredArguments() const { return NumRequiredArgs; } -/// \brief The combination of the extern and inline keywords under MSVC forces +/// The combination of the extern and inline keywords under MSVC forces /// the function to be required. /// /// Note: This function assumes that we will only get called when isInlined() @@ -2988,7 +3049,7 @@ static bool RedeclForcesDefC99(const FunctionDecl *Redecl) { return false; } -/// \brief For a function declaration in C or C++, determine whether this +/// For a function declaration in C or C++, determine whether this /// declaration causes the definition to be externally visible. /// /// For instance, this determines if adding the current declaration to the set @@ -3103,7 +3164,7 @@ const Attr *FunctionDecl::getUnusedResultAttr() const { return getAttr<WarnUnusedResultAttr>(); } -/// \brief For an inline function definition in C, or for a gnu_inline function +/// For an inline function definition in C, or for a gnu_inline function /// in C++, determine whether the definition will be externally visible. /// /// Inline function definitions are always available for inlining optimizations. @@ -3605,16 +3666,19 @@ unsigned FunctionDecl::getMemoryFunctionKind() const { return 0; } +unsigned FunctionDecl::getODRHash() const { + assert(HasODRHash); + return ODRHash; +} + unsigned FunctionDecl::getODRHash() { if (HasODRHash) return ODRHash; - if (FunctionDecl *Definition = getDefinition()) { - if (Definition != this) { - HasODRHash = true; - ODRHash = Definition->getODRHash(); - return ODRHash; - } + if (auto *FT = getInstantiatedFromMemberFunction()) { + HasODRHash = true; + ODRHash = FT->getODRHash(); + return ODRHash; } class ODRHash Hash; @@ -3658,6 +3722,11 @@ unsigned FieldDecl::getBitWidthValue(const ASTContext &Ctx) const { return getBitWidth()->EvaluateKnownConstInt(Ctx).getZExtValue(); } +bool FieldDecl::isZeroLengthBitField(const ASTContext &Ctx) const { + return isUnnamedBitfield() && !getBitWidth()->isValueDependent() && + getBitWidthValue(Ctx) == 0; +} + unsigned FieldDecl::getFieldIndex() const { const FieldDecl *Canonical = getCanonicalDecl(); if (Canonical != this) @@ -3904,6 +3973,17 @@ void EnumDecl::setInstantiationOfMemberEnum(ASTContext &C, EnumDecl *ED, SpecializationInfo = new (C) MemberSpecializationInfo(ED, TSK); } +unsigned EnumDecl::getODRHash() { + if (HasODRHash) + return ODRHash; + + class ODRHash Hash; + Hash.AddEnumDecl(this); + HasODRHash = true; + ODRHash = Hash.CalculateHash(); + return ODRHash; +} + //===----------------------------------------------------------------------===// // RecordDecl Implementation //===----------------------------------------------------------------------===// @@ -3915,7 +3995,10 @@ RecordDecl::RecordDecl(Kind DK, TagKind TK, const ASTContext &C, : TagDecl(DK, TK, C, DC, IdLoc, Id, PrevDecl, StartLoc), HasFlexibleArrayMember(false), AnonymousStructOrUnion(false), HasObjectMember(false), HasVolatileMember(false), - LoadedFieldsFromExternalStorage(false) { + LoadedFieldsFromExternalStorage(false), + NonTrivialToPrimitiveDefaultInitialize(false), + NonTrivialToPrimitiveCopy(false), NonTrivialToPrimitiveDestroy(false), + ParamDestroyedInCallee(false), ArgPassingRestrictions(APK_CanPassInRegs) { assert(classof(static_cast<Decl*>(this)) && "Invalid Kind!"); } @@ -4365,9 +4448,7 @@ bool TypedefNameDecl::isTransparentTagSlow() const { }; bool isTransparent = determineIsTransparent(); - CacheIsTransparentTag = 1; - if (isTransparent) - CacheIsTransparentTag |= 0x2; + MaybeModedTInfo.setInt((isTransparent << 1) | 1); return isTransparent; } @@ -4433,7 +4514,7 @@ EmptyDecl *EmptyDecl::CreateDeserialized(ASTContext &C, unsigned ID) { // ImportDecl Implementation //===----------------------------------------------------------------------===// -/// \brief Retrieve the number of module identifiers needed to name the given +/// Retrieve the number of module identifiers needed to name the given /// module. static unsigned getNumModuleIdentifiers(Module *Mod) { unsigned Result = 1; diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index 29ce7ae034b5..e3817c0abc38 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -34,7 +34,6 @@ #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/TargetInfo.h" -#include "clang/Basic/VersionTuple.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/SmallVector.h" @@ -42,6 +41,7 @@ #include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" +#include "llvm/Support/VersionTuple.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> #include <cassert> @@ -101,7 +101,7 @@ void *Decl::operator new(std::size_t Size, const ASTContext &Ctx, // padding at the start if required. size_t ExtraAlign = llvm::OffsetToAlignment(sizeof(Module *), alignof(Decl)); - char *Buffer = reinterpret_cast<char *>( + auto *Buffer = reinterpret_cast<char *>( ::operator new(ExtraAlign + sizeof(Module *) + Size + Extra, Ctx)); Buffer += ExtraAlign; auto *ParentModule = @@ -145,8 +145,8 @@ void Decl::setInvalidDecl(bool Invalid) { // Marking a DecompositionDecl as invalid implies all the child BindingDecl's // are invalid too. - if (DecompositionDecl *DD = dyn_cast<DecompositionDecl>(this)) { - for (BindingDecl *Binding : DD->bindings()) { + if (auto *DD = dyn_cast<DecompositionDecl>(this)) { + for (auto *Binding : DD->bindings()) { Binding->setInvalidDecl(); } } @@ -199,28 +199,26 @@ void Decl::add(Kind k) { } bool Decl::isTemplateParameterPack() const { - if (const TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(this)) + if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(this)) return TTP->isParameterPack(); - if (const NonTypeTemplateParmDecl *NTTP - = dyn_cast<NonTypeTemplateParmDecl>(this)) + if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(this)) return NTTP->isParameterPack(); - if (const TemplateTemplateParmDecl *TTP - = dyn_cast<TemplateTemplateParmDecl>(this)) + if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(this)) return TTP->isParameterPack(); return false; } bool Decl::isParameterPack() const { - if (const ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(this)) + if (const auto *Parm = dyn_cast<ParmVarDecl>(this)) return Parm->isParameterPack(); return isTemplateParameterPack(); } FunctionDecl *Decl::getAsFunction() { - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(this)) + if (auto *FD = dyn_cast<FunctionDecl>(this)) return FD; - if (const FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(this)) + if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(this)) return FTD->getTemplatedDecl(); return nullptr; } @@ -236,10 +234,23 @@ TemplateDecl *Decl::getDescribedTemplate() const { return RD->getDescribedClassTemplate(); else if (auto *VD = dyn_cast<VarDecl>(this)) return VD->getDescribedVarTemplate(); + else if (auto *AD = dyn_cast<TypeAliasDecl>(this)) + return AD->getDescribedAliasTemplate(); return nullptr; } +bool Decl::isTemplated() const { + // A declaration is dependent if it is a template or a template pattern, or + // is within (lexcially for a friend, semantically otherwise) a dependent + // context. + // FIXME: Should local extern declarations be treated like friends? + if (auto *AsDC = dyn_cast<DeclContext>(this)) + return AsDC->isDependentContext(); + auto *DC = getFriendObjectKind() ? getLexicalDeclContext() : getDeclContext(); + return DC->isDependentContext() || isTemplateDecl() || getDescribedTemplate(); +} + const DeclContext *Decl::getParentFunctionOrMethod() const { for (const DeclContext *DC = getDeclContext(); DC && !DC->isTranslationUnit() && !DC->isNamespace(); @@ -266,7 +277,7 @@ void PrettyStackTraceDecl::print(raw_ostream &OS) const { OS << Message; - if (const NamedDecl *DN = dyn_cast_or_null<NamedDecl>(TheDecl)) { + if (const auto *DN = dyn_cast_or_null<NamedDecl>(TheDecl)) { OS << " '"; DN->printQualifiedName(OS); OS << '\''; @@ -314,7 +325,7 @@ void Decl::setDeclContextsImpl(DeclContext *SemaDC, DeclContext *LexicalDC, if (SemaDC == LexicalDC) { DeclCtx = SemaDC; } else { - Decl::MultipleDC *MDC = new (Ctx) Decl::MultipleDC(); + auto *MDC = new (Ctx) Decl::MultipleDC(); MDC->SemanticDC = SemaDC; MDC->LexicalDC = LexicalDC; DeclCtx = MDC; @@ -335,7 +346,7 @@ bool Decl::isLexicallyWithinFunctionOrMethod() const { bool Decl::isInAnonymousNamespace() const { for (const DeclContext *DC = getDeclContext(); DC; DC = DC->getParent()) { - if (const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC)) + if (const auto *ND = dyn_cast<NamespaceDecl>(DC)) if (ND->isAnonymousNamespace()) return true; } @@ -348,7 +359,7 @@ bool Decl::isInStdNamespace() const { } TranslationUnitDecl *Decl::getTranslationUnitDecl() { - if (TranslationUnitDecl *TUD = dyn_cast<TranslationUnitDecl>(this)) + if (auto *TUD = dyn_cast<TranslationUnitDecl>(this)) return TUD; DeclContext *DC = getDeclContext(); @@ -413,7 +424,7 @@ bool Decl::isReferenced() const { return true; // Check redeclarations. - for (auto I : redecls()) + for (const auto *I : redecls()) if (I->Referenced) return true; @@ -438,11 +449,11 @@ bool Decl::isExported() const { ExternalSourceSymbolAttr *Decl::getExternalSourceSymbolAttr() const { const Decl *Definition = nullptr; - if (auto ID = dyn_cast<ObjCInterfaceDecl>(this)) { + if (auto *ID = dyn_cast<ObjCInterfaceDecl>(this)) { Definition = ID->getDefinition(); - } else if (auto PD = dyn_cast<ObjCProtocolDecl>(this)) { + } else if (auto *PD = dyn_cast<ObjCProtocolDecl>(this)) { Definition = PD->getDefinition(); - } else if (auto TD = dyn_cast<TagDecl>(this)) { + } else if (auto *TD = dyn_cast<TagDecl>(this)) { Definition = TD->getDefinition(); } if (!Definition) @@ -462,9 +473,9 @@ bool Decl::hasDefiningAttr() const { } const Attr *Decl::getDefiningAttr() const { - if (AliasAttr *AA = getAttr<AliasAttr>()) + if (auto *AA = getAttr<AliasAttr>()) return AA; - if (IFuncAttr *IFA = getAttr<IFuncAttr>()) + if (auto *IFA = getAttr<IFuncAttr>()) return IFA; return nullptr; } @@ -482,7 +493,7 @@ static StringRef getRealizedPlatform(const AvailabilityAttr *A, return RealizedPlatform; } -/// \brief Determine the availability of the given declaration based on +/// Determine the availability of the given declaration based on /// the target platform. /// /// When it returns an availability result other than \c AR_Available, @@ -539,7 +550,6 @@ static AvailabilityResult CheckAvailability(ASTContext &Context, Message->clear(); llvm::raw_string_ostream Out(*Message); VersionTuple VTI(A->getIntroduced()); - VTI.UseDotAsSeparator(); Out << "introduced in " << PrettyPlatformName << ' ' << VTI << HintMessage; } @@ -553,7 +563,6 @@ static AvailabilityResult CheckAvailability(ASTContext &Context, Message->clear(); llvm::raw_string_ostream Out(*Message); VersionTuple VTO(A->getObsoleted()); - VTO.UseDotAsSeparator(); Out << "obsoleted in " << PrettyPlatformName << ' ' << VTO << HintMessage; } @@ -567,7 +576,6 @@ static AvailabilityResult CheckAvailability(ASTContext &Context, Message->clear(); llvm::raw_string_ostream Out(*Message); VersionTuple VTD(A->getDeprecated()); - VTD.UseDotAsSeparator(); Out << "first deprecated in " << PrettyPlatformName << ' ' << VTD << HintMessage; } @@ -579,9 +587,11 @@ static AvailabilityResult CheckAvailability(ASTContext &Context, } AvailabilityResult Decl::getAvailability(std::string *Message, - VersionTuple EnclosingVersion) const { + VersionTuple EnclosingVersion, + StringRef *RealizedPlatform) const { if (auto *FTD = dyn_cast<FunctionTemplateDecl>(this)) - return FTD->getTemplatedDecl()->getAvailability(Message, EnclosingVersion); + return FTD->getTemplatedDecl()->getAvailability(Message, EnclosingVersion, + RealizedPlatform); AvailabilityResult Result = AR_Available; std::string ResultMessage; @@ -608,8 +618,11 @@ AvailabilityResult Decl::getAvailability(std::string *Message, AvailabilityResult AR = CheckAvailability(getASTContext(), Availability, Message, EnclosingVersion); - if (AR == AR_Unavailable) + if (AR == AR_Unavailable) { + if (RealizedPlatform) + *RealizedPlatform = Availability->getPlatform()->getName(); return AR_Unavailable; + } if (AR > Result) { Result = AR; @@ -636,14 +649,14 @@ VersionTuple Decl::getVersionIntroduced() const { return Availability->getIntroduced(); } } - return VersionTuple(); + return {}; } bool Decl::canBeWeakImported(bool &IsDefinition) const { IsDefinition = false; // Variables, if they aren't definitions. - if (const VarDecl *Var = dyn_cast<VarDecl>(this)) { + if (const auto *Var = dyn_cast<VarDecl>(this)) { if (Var->isThisDeclarationADefinition()) { IsDefinition = true; return false; @@ -651,7 +664,7 @@ bool Decl::canBeWeakImported(bool &IsDefinition) const { return true; // Functions, if they aren't definitions. - } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(this)) { + } else if (const auto *FD = dyn_cast<FunctionDecl>(this)) { if (FD->hasBody()) { IsDefinition = true; return false; @@ -834,14 +847,14 @@ Decl *Decl::castFromDeclContext (const DeclContext *D) { #define DECL(NAME, BASE) #define DECL_CONTEXT(NAME) \ case Decl::NAME: \ - return static_cast<NAME##Decl*>(const_cast<DeclContext*>(D)); + return static_cast<NAME##Decl *>(const_cast<DeclContext *>(D)); #define DECL_CONTEXT_BASE(NAME) #include "clang/AST/DeclNodes.inc" default: #define DECL(NAME, BASE) #define DECL_CONTEXT_BASE(NAME) \ if (DK >= first##NAME && DK <= last##NAME) \ - return static_cast<NAME##Decl*>(const_cast<DeclContext*>(D)); + return static_cast<NAME##Decl *>(const_cast<DeclContext *>(D)); #include "clang/AST/DeclNodes.inc" llvm_unreachable("a decl that inherits DeclContext isn't handled"); } @@ -853,14 +866,14 @@ DeclContext *Decl::castToDeclContext(const Decl *D) { #define DECL(NAME, BASE) #define DECL_CONTEXT(NAME) \ case Decl::NAME: \ - return static_cast<NAME##Decl*>(const_cast<Decl*>(D)); + return static_cast<NAME##Decl *>(const_cast<Decl *>(D)); #define DECL_CONTEXT_BASE(NAME) #include "clang/AST/DeclNodes.inc" default: #define DECL(NAME, BASE) #define DECL_CONTEXT_BASE(NAME) \ if (DK >= first##NAME && DK <= last##NAME) \ - return static_cast<NAME##Decl*>(const_cast<Decl*>(D)); + return static_cast<NAME##Decl *>(const_cast<Decl *>(D)); #include "clang/AST/DeclNodes.inc" llvm_unreachable("a decl that inherits DeclContext isn't handled"); } @@ -869,17 +882,17 @@ DeclContext *Decl::castToDeclContext(const Decl *D) { SourceLocation Decl::getBodyRBrace() const { // Special handling of FunctionDecl to avoid de-serializing the body from PCH. // FunctionDecl stores EndRangeLoc for this purpose. - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(this)) { + if (const auto *FD = dyn_cast<FunctionDecl>(this)) { const FunctionDecl *Definition; if (FD->hasBody(Definition)) return Definition->getSourceRange().getEnd(); - return SourceLocation(); + return {}; } if (Stmt *Body = getBody()) return Body->getSourceRange().getEnd(); - return SourceLocation(); + return {}; } bool Decl::AccessDeclContextSanity() const { @@ -891,12 +904,14 @@ bool Decl::AccessDeclContextSanity() const { // 4. the context is not a record // 5. it's invalid // 6. it's a C++0x static_assert. + // 7. it's a block literal declaration if (isa<TranslationUnitDecl>(this) || isa<TemplateTypeParmDecl>(this) || isa<NonTypeTemplateParmDecl>(this) || !isa<CXXRecordDecl>(getDeclContext()) || isInvalidDecl() || isa<StaticAssertDecl>(this) || + isa<BlockDecl>(this) || // FIXME: a ParmVarDecl can have ClassTemplateSpecialization // as DeclContext (?). isa<ParmVarDecl>(this) || @@ -917,9 +932,9 @@ static Decl::Kind getKind(const DeclContext *DC) { return DC->getDeclKind(); } const FunctionType *Decl::getFunctionType(bool BlocksToo) const { QualType Ty; - if (const ValueDecl *D = dyn_cast<ValueDecl>(this)) + if (const auto *D = dyn_cast<ValueDecl>(this)) Ty = D->getType(); - else if (const TypedefNameDecl *D = dyn_cast<TypedefNameDecl>(this)) + else if (const auto *D = dyn_cast<TypedefNameDecl>(this)) Ty = D->getUnderlyingType(); else return nullptr; @@ -936,22 +951,21 @@ const FunctionType *Decl::getFunctionType(bool BlocksToo) const { /// code context that is not a closure (a lambda, block, etc.). template <class T> static Decl *getNonClosureContext(T *D) { if (getKind(D) == Decl::CXXMethod) { - CXXMethodDecl *MD = cast<CXXMethodDecl>(D); + auto *MD = cast<CXXMethodDecl>(D); if (MD->getOverloadedOperator() == OO_Call && MD->getParent()->isLambda()) return getNonClosureContext(MD->getParent()->getParent()); return MD; - } else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + } else if (auto *FD = dyn_cast<FunctionDecl>(D)) return FD; - } else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { + else if (auto *MD = dyn_cast<ObjCMethodDecl>(D)) return MD; - } else if (BlockDecl *BD = dyn_cast<BlockDecl>(D)) { + else if (auto *BD = dyn_cast<BlockDecl>(D)) return getNonClosureContext(BD->getParent()); - } else if (CapturedDecl *CD = dyn_cast<CapturedDecl>(D)) { + else if (auto *CD = dyn_cast<CapturedDecl>(D)) return getNonClosureContext(CD->getParent()); - } else { + else return nullptr; - } } Decl *Decl::getNonClosureContext() { @@ -986,7 +1000,7 @@ bool DeclContext::classof(const Decl *D) { DeclContext::~DeclContext() = default; -/// \brief Find the parent context of this context that will be +/// Find the parent context of this context that will be /// used for unqualified name lookup. /// /// Generally, the parent lookup context is the semantic context. However, for @@ -1011,7 +1025,7 @@ bool DeclContext::isStdNamespace() const { if (!isNamespace()) return false; - const NamespaceDecl *ND = cast<NamespaceDecl>(this); + const auto *ND = cast<NamespaceDecl>(this); if (ND->isInline()) { return ND->getParent()->isStdNamespace(); } @@ -1030,7 +1044,7 @@ bool DeclContext::isDependentContext() const { if (isa<ClassTemplatePartialSpecializationDecl>(this)) return true; - if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(this)) { + if (const auto *Record = dyn_cast<CXXRecordDecl>(this)) { if (Record->getDescribedClassTemplate()) return true; @@ -1038,7 +1052,7 @@ bool DeclContext::isDependentContext() const { return true; } - if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(this)) { + if (const auto *Function = dyn_cast<FunctionDecl>(this)) { if (Function->getDescribedFunctionTemplate()) return true; @@ -1117,18 +1131,18 @@ DeclContext *DeclContext::getPrimaryContext() { case Decl::Namespace: // The original namespace is our primary context. - return static_cast<NamespaceDecl*>(this)->getOriginalNamespace(); + return static_cast<NamespaceDecl *>(this)->getOriginalNamespace(); case Decl::ObjCMethod: return this; case Decl::ObjCInterface: - if (ObjCInterfaceDecl *Def = cast<ObjCInterfaceDecl>(this)->getDefinition()) + if (auto *Def = cast<ObjCInterfaceDecl>(this)->getDefinition()) return Def; return this; case Decl::ObjCProtocol: - if (ObjCProtocolDecl *Def = cast<ObjCProtocolDecl>(this)->getDefinition()) + if (auto *Def = cast<ObjCProtocolDecl>(this)->getDefinition()) return Def; return this; @@ -1143,12 +1157,12 @@ DeclContext *DeclContext::getPrimaryContext() { if (DeclKind >= Decl::firstTag && DeclKind <= Decl::lastTag) { // If this is a tag type that has a definition or is currently // being defined, that definition is our primary context. - TagDecl *Tag = cast<TagDecl>(this); + auto *Tag = cast<TagDecl>(this); if (TagDecl *Def = Tag->getDefinition()) return Def; - if (const TagType *TagTy = dyn_cast<TagType>(Tag->getTypeForDecl())) { + if (const auto *TagTy = dyn_cast<TagType>(Tag->getTypeForDecl())) { // Note, TagType::getDecl returns the (partial) definition one exists. TagDecl *PossiblePartialDef = TagTy->getDecl(); if (PossiblePartialDef->isBeingDefined()) @@ -1175,7 +1189,7 @@ DeclContext::collectAllContexts(SmallVectorImpl<DeclContext *> &Contexts){ return; } - NamespaceDecl *Self = static_cast<NamespaceDecl *>(this); + auto *Self = static_cast<NamespaceDecl *>(this); for (NamespaceDecl *N = Self->getMostRecentDecl(); N; N = N->getPreviousDecl()) Contexts.push_back(N); @@ -1184,16 +1198,15 @@ DeclContext::collectAllContexts(SmallVectorImpl<DeclContext *> &Contexts){ } std::pair<Decl *, Decl *> -DeclContext::BuildDeclChain(ArrayRef<Decl*> Decls, +DeclContext::BuildDeclChain(ArrayRef<Decl *> Decls, bool FieldsAlreadyLoaded) { // Build up a chain of declarations via the Decl::NextInContextAndBits field. Decl *FirstNewDecl = nullptr; Decl *PrevDecl = nullptr; - for (unsigned I = 0, N = Decls.size(); I != N; ++I) { - if (FieldsAlreadyLoaded && isa<FieldDecl>(Decls[I])) + for (auto *D : Decls) { + if (FieldsAlreadyLoaded && isa<FieldDecl>(D)) continue; - Decl *D = Decls[I]; if (PrevDecl) PrevDecl->NextInContextAndBits.setPointer(D); else @@ -1205,7 +1218,7 @@ DeclContext::BuildDeclChain(ArrayRef<Decl*> Decls, return std::make_pair(FirstNewDecl, PrevDecl); } -/// \brief We have just acquired external visible storage, and we already have +/// We have just acquired external visible storage, and we already have /// built a lookup map. For every name in the map, pull in the new names from /// the external storage. void DeclContext::reconcileExternalVisibleStorage() const { @@ -1216,7 +1229,7 @@ void DeclContext::reconcileExternalVisibleStorage() const { Lookup.second.setHasExternalDecls(); } -/// \brief Load the declarations within this lexical storage from an +/// Load the declarations within this lexical storage from an /// external source. /// \return \c true if any declarations were added. bool @@ -1238,7 +1251,7 @@ DeclContext::LoadLexicalDeclsFromExternalStorage() const { // We may have already loaded just the fields of this record, in which case // we need to ignore them. bool FieldsAlreadyLoaded = false; - if (const RecordDecl *RD = dyn_cast<RecordDecl>(this)) + if (const auto *RD = dyn_cast<RecordDecl>(this)) FieldsAlreadyLoaded = RD->LoadedFieldsFromExternalStorage; // Splice the newly-read declarations into the beginning of the list @@ -1305,12 +1318,11 @@ ExternalASTSource::SetExternalVisibleDeclsForName(const DeclContext *DC, } } else { // Convert the array to a StoredDeclsList. - for (ArrayRef<NamedDecl*>::iterator - I = Decls.begin(), E = Decls.end(); I != E; ++I) { + for (auto *D : Decls) { if (List.isNull()) - List.setOnlyValue(*I); + List.setOnlyValue(D); else - List.AddSubsequentDecl(*I); + List.AddSubsequentDecl(D); } } @@ -1335,6 +1347,38 @@ bool DeclContext::containsDecl(Decl *D) const { (D->NextInContextAndBits.getPointer() || D == LastDecl)); } +bool DeclContext::containsDeclAndLoad(Decl *D) const { + if (hasExternalLexicalStorage()) + LoadLexicalDeclsFromExternalStorage(); + return containsDecl(D); +} + +/// shouldBeHidden - Determine whether a declaration which was declared +/// within its semantic context should be invisible to qualified name lookup. +static bool shouldBeHidden(NamedDecl *D) { + // Skip unnamed declarations. + if (!D->getDeclName()) + return true; + + // Skip entities that can't be found by name lookup into a particular + // context. + if ((D->getIdentifierNamespace() == 0 && !isa<UsingDirectiveDecl>(D)) || + D->isTemplateParameter()) + return true; + + // Skip template specializations. + // FIXME: This feels like a hack. Should DeclarationName support + // template-ids, or is there a better way to keep specializations + // from being visible? + if (isa<ClassTemplateSpecializationDecl>(D)) + return true; + if (auto *FD = dyn_cast<FunctionDecl>(D)) + if (FD->isFunctionTemplateSpecialization()) + return true; + + return false; +} + void DeclContext::removeDecl(Decl *D) { assert(D->getLexicalDeclContext() == this && "decl being removed from non-lexical context"); @@ -1357,16 +1401,22 @@ void DeclContext::removeDecl(Decl *D) { } } } - + // Mark that D is no longer in the decl chain. D->NextInContextAndBits.setPointer(nullptr); // Remove D from the lookup table if necessary. if (isa<NamedDecl>(D)) { - NamedDecl *ND = cast<NamedDecl>(D); + auto *ND = cast<NamedDecl>(D); + + // Do not try to remove the declaration if that is invisible to qualified + // lookup. E.g. template specializations are skipped. + if (shouldBeHidden(ND)) + return; // Remove only decls that have a name - if (!ND->getDeclName()) return; + if (!ND->getDeclName()) + return; auto *DC = D->getDeclContext(); do { @@ -1396,13 +1446,13 @@ void DeclContext::addHiddenDecl(Decl *D) { // Notify a C++ record declaration that we've added a member, so it can // update its class-specific state. - if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(this)) + if (auto *Record = dyn_cast<CXXRecordDecl>(this)) Record->addedMember(D); // If this is a newly-created (not de-serialized) import declaration, wire // it in to the list of local import declarations. if (!D->isFromASTFile()) { - if (ImportDecl *Import = dyn_cast<ImportDecl>(D)) + if (auto *Import = dyn_cast<ImportDecl>(D)) D->getASTContext().addedLocalImportDecl(Import); } } @@ -1410,7 +1460,7 @@ void DeclContext::addHiddenDecl(Decl *D) { void DeclContext::addDecl(Decl *D) { addHiddenDecl(D); - if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) + if (auto *ND = dyn_cast<NamedDecl>(D)) ND->getDeclContext()->getPrimaryContext()-> makeDeclVisibleInContextWithFlags(ND, false, true); } @@ -1418,37 +1468,11 @@ void DeclContext::addDecl(Decl *D) { void DeclContext::addDeclInternal(Decl *D) { addHiddenDecl(D); - if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) + if (auto *ND = dyn_cast<NamedDecl>(D)) ND->getDeclContext()->getPrimaryContext()-> makeDeclVisibleInContextWithFlags(ND, true, true); } -/// shouldBeHidden - Determine whether a declaration which was declared -/// within its semantic context should be invisible to qualified name lookup. -static bool shouldBeHidden(NamedDecl *D) { - // Skip unnamed declarations. - if (!D->getDeclName()) - return true; - - // Skip entities that can't be found by name lookup into a particular - // context. - if ((D->getIdentifierNamespace() == 0 && !isa<UsingDirectiveDecl>(D)) || - D->isTemplateParameter()) - return true; - - // Skip template specializations. - // FIXME: This feels like a hack. Should DeclarationName support - // template-ids, or is there a better way to keep specializations - // from being visible? - if (isa<ClassTemplateSpecializationDecl>(D)) - return true; - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) - if (FD->isFunctionTemplateSpecialization()) - return true; - - return false; -} - /// buildLookup - Build the lookup data structure with all of the /// declarations in this DeclContext (and any other contexts linked /// to it or transparent contexts nested within it) and return it. @@ -1490,7 +1514,7 @@ StoredDeclsMap *DeclContext::buildLookup() { /// DeclContext, a DeclContext linked to it, or a transparent context /// nested within it. void DeclContext::buildLookupImpl(DeclContext *DCtx, bool Internal) { - for (Decl *D : DCtx->noload_decls()) { + for (auto *D : DCtx->noload_decls()) { // 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. @@ -1499,7 +1523,7 @@ void DeclContext::buildLookupImpl(DeclContext *DCtx, bool Internal) { // 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 (auto *ND = dyn_cast<NamedDecl>(D)) if (ND->getDeclContext() == DCtx && !shouldBeHidden(ND) && (!ND->isFromASTFile() || (isTranslationUnit() && @@ -1509,7 +1533,7 @@ void DeclContext::buildLookupImpl(DeclContext *DCtx, bool Internal) { // If this declaration is itself a transparent declaration context // or inline namespace, add the members of this declaration of that // context (recursively). - if (DeclContext *InnerCtx = dyn_cast<DeclContext>(D)) + if (auto *InnerCtx = dyn_cast<DeclContext>(D)) if (InnerCtx->isTransparentContext() || InnerCtx->isInlineNamespace()) buildLookupImpl(InnerCtx, Internal); } @@ -1562,7 +1586,7 @@ DeclContext::lookup(DeclarationName Name) const { } } - return lookup_result(); + return {}; } StoredDeclsMap *Map = LookupPtr; @@ -1570,11 +1594,11 @@ DeclContext::lookup(DeclarationName Name) const { Map = const_cast<DeclContext*>(this)->buildLookup(); if (!Map) - return lookup_result(); + return {}; StoredDeclsMap::iterator I = Map->find(Name); if (I == Map->end()) - return lookup_result(); + return {}; return I->second.getLookupResult(); } @@ -1588,26 +1612,29 @@ DeclContext::noload_lookup(DeclarationName Name) { if (PrimaryContext != this) return PrimaryContext->noload_lookup(Name); - // If we have any lazy lexical declarations not in our lookup map, add them - // now. Don't import any external declarations, not even if we know we have - // some missing from the external visible lookups. - if (HasLazyLocalLexicalLookups) { - SmallVector<DeclContext *, 2> Contexts; - collectAllContexts(Contexts); - for (unsigned I = 0, N = Contexts.size(); I != N; ++I) - buildLookupImpl(Contexts[I], hasExternalVisibleStorage()); - HasLazyLocalLexicalLookups = false; - } - + loadLazyLocalLexicalLookups(); StoredDeclsMap *Map = LookupPtr; if (!Map) - return lookup_result(); + return {}; StoredDeclsMap::iterator I = Map->find(Name); return I != Map->end() ? I->second.getLookupResult() : lookup_result(); } +// If we have any lazy lexical declarations not in our lookup map, add them +// now. Don't import any external declarations, not even if we know we have +// some missing from the external visible lookups. +void DeclContext::loadLazyLocalLexicalLookups() { + if (HasLazyLocalLexicalLookups) { + SmallVector<DeclContext *, 2> Contexts; + collectAllContexts(Contexts); + for (auto *Context : Contexts) + buildLookupImpl(Context, hasExternalVisibleStorage()); + HasLazyLocalLexicalLookups = false; + } +} + void DeclContext::localUncachedLookup(DeclarationName Name, SmallVectorImpl<NamedDecl *> &Results) { Results.clear(); @@ -1639,7 +1666,7 @@ void DeclContext::localUncachedLookup(DeclarationName Name, // FIXME: If we have lazy external declarations, this will not find them! // FIXME: Should we CollectAllContexts and walk them all here? for (Decl *D = FirstDecl; D; D = D->getNextDeclInContext()) { - if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) + if (auto *ND = dyn_cast<NamedDecl>(D)) if (ND->getDeclName() == Name) Results.push_back(ND); } @@ -1681,7 +1708,7 @@ bool DeclContext::InEnclosingNamespaceSetOf(const DeclContext *O) const { if (O->Equals(this)) return true; - const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(O); + const auto *NS = dyn_cast<NamespaceDecl>(O); if (!NS || !NS->isInline()) break; O = NS->getParent(); @@ -1740,7 +1767,7 @@ void DeclContext::makeDeclVisibleInContextWithFlags(NamedDecl *D, bool Internal, getParent()->getPrimaryContext()-> makeDeclVisibleInContextWithFlags(D, Internal, Recoverable); - Decl *DCAsDecl = cast<Decl>(this); + auto *DCAsDecl = cast<Decl>(this); // Notify that a decl was made visible unless we are a Tag being defined. if (!(isa<TagDecl>(DCAsDecl) && cast<TagDecl>(DCAsDecl)->isBeingDefined())) if (ASTMutationListener *L = DCAsDecl->getASTMutationListener()) @@ -1858,8 +1885,7 @@ DependentDiagnostic *DependentDiagnostic::Create(ASTContext &C, if (!Parent->LookupPtr) Parent->CreateStoredDeclsMap(C); - DependentStoredDeclsMap *Map = - static_cast<DependentStoredDeclsMap *>(Parent->LookupPtr); + auto *Map = static_cast<DependentStoredDeclsMap *>(Parent->LookupPtr); // Allocate the copy of the PartialDiagnostic via the ASTContext's // BumpPtrAllocator, rather than the ASTContext itself. @@ -1867,7 +1893,7 @@ DependentDiagnostic *DependentDiagnostic::Create(ASTContext &C, if (PDiag.hasStorage()) DiagStorage = new (C) PartialDiagnostic::Storage; - DependentDiagnostic *DD = new (C) DependentDiagnostic(PDiag, DiagStorage); + auto *DD = new (C) DependentDiagnostic(PDiag, DiagStorage); // TODO: Maybe we shouldn't reverse the order during insertion. DD->NextDiagnostic = Map->FirstDiagnostic; diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 41f2449a9d6a..076e6376d157 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -74,7 +74,8 @@ void LazyASTUnresolvedSet::getFromExternalSource(ASTContext &C) const { CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D) : UserDeclaredConstructor(false), UserDeclaredSpecialMembers(0), Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false), - Abstract(false), IsStandardLayout(true), HasNoNonEmptyBases(true), + Abstract(false), IsStandardLayout(true), IsCXX11StandardLayout(true), + HasBasesWithFields(false), HasBasesWithNonStaticDataMembers(false), HasPrivateFields(false), HasProtectedFields(false), HasPublicFields(false), HasMutableFields(false), HasVariantMembers(false), HasOnlyCMembers(true), HasInClassInitializer(false), @@ -88,10 +89,11 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D) DefaultedMoveConstructorIsDeleted(false), DefaultedMoveAssignmentIsDeleted(false), DefaultedDestructorIsDeleted(false), HasTrivialSpecialMembers(SMF_All), - DeclaredNonTrivialSpecialMembers(0), HasIrrelevantDestructor(true), + HasTrivialSpecialMembersForCall(SMF_All), + DeclaredNonTrivialSpecialMembers(0), + DeclaredNonTrivialSpecialMembersForCall(0), HasIrrelevantDestructor(true), HasConstexprNonCopyMoveConstructor(false), HasDefaultedDefaultConstructor(false), - CanPassInRegisters(true), DefaultedDefaultConstructorIsConstexpr(true), HasConstexprDefaultConstructor(false), HasNonLiteralTypeFieldsOrBases(false), ComputedVisibleConversions(false), @@ -124,8 +126,8 @@ CXXRecordDecl *CXXRecordDecl::Create(const ASTContext &C, TagKind TK, SourceLocation IdLoc, IdentifierInfo *Id, CXXRecordDecl *PrevDecl, bool DelayTypeCreation) { - CXXRecordDecl *R = new (C, DC) CXXRecordDecl(CXXRecord, TK, C, DC, StartLoc, - IdLoc, Id, PrevDecl); + auto *R = new (C, DC) CXXRecordDecl(CXXRecord, TK, C, DC, StartLoc, IdLoc, Id, + PrevDecl); R->MayHaveOutOfDateDef = C.getLangOpts().Modules; // FIXME: DelayTypeCreation seems like such a hack @@ -139,9 +141,8 @@ CXXRecordDecl::CreateLambda(const ASTContext &C, DeclContext *DC, TypeSourceInfo *Info, SourceLocation Loc, bool Dependent, bool IsGeneric, LambdaCaptureDefault CaptureDefault) { - CXXRecordDecl *R = - new (C, DC) CXXRecordDecl(CXXRecord, TTK_Class, C, DC, Loc, Loc, - nullptr, nullptr); + auto *R = new (C, DC) CXXRecordDecl(CXXRecord, TTK_Class, C, DC, Loc, Loc, + nullptr, nullptr); R->IsBeingDefined = true; R->DefinitionData = new (C) struct LambdaDefinitionData(R, Info, Dependent, IsGeneric, @@ -154,13 +155,32 @@ CXXRecordDecl::CreateLambda(const ASTContext &C, DeclContext *DC, CXXRecordDecl * CXXRecordDecl::CreateDeserialized(const ASTContext &C, unsigned ID) { - CXXRecordDecl *R = new (C, ID) CXXRecordDecl( + auto *R = new (C, ID) CXXRecordDecl( CXXRecord, TTK_Struct, C, nullptr, SourceLocation(), SourceLocation(), nullptr, nullptr); R->MayHaveOutOfDateDef = false; return R; } +/// Determine whether a class has a repeated base class. This is intended for +/// use when determining if a class is standard-layout, so makes no attempt to +/// handle virtual bases. +static bool hasRepeatedBaseClass(const CXXRecordDecl *StartRD) { + llvm::SmallPtrSet<const CXXRecordDecl*, 8> SeenBaseTypes; + SmallVector<const CXXRecordDecl*, 8> WorkList = {StartRD}; + while (!WorkList.empty()) { + const CXXRecordDecl *RD = WorkList.pop_back_val(); + for (const CXXBaseSpecifier &BaseSpec : RD->bases()) { + if (const CXXRecordDecl *B = BaseSpec.getType()->getAsCXXRecordDecl()) { + if (!SeenBaseTypes.insert(B).second) + return true; + WorkList.push_back(B); + } + } + } + return false; +} + void CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, unsigned NumBases) { @@ -197,29 +217,40 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, // Skip dependent types; we can't do any checking on them now. if (BaseType->isDependentType()) continue; - CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl()); + auto *BaseClassDecl = + cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl()); - if (!BaseClassDecl->isEmpty()) { - if (!data().Empty) { - // C++0x [class]p7: - // A standard-layout class is a class that: - // [...] - // -- either has no non-static data members in the most derived - // class and at most one base class with non-static data members, - // or has no base classes with non-static data members, and - // If this is the second non-empty base, then neither of these two - // clauses can be true. + // C++2a [class]p7: + // A standard-layout class is a class that: + // [...] + // -- has all non-static data members and bit-fields in the class and + // its base classes first declared in the same class + if (BaseClassDecl->data().HasBasesWithFields || + !BaseClassDecl->field_empty()) { + if (data().HasBasesWithFields) + // Two bases have members or bit-fields: not standard-layout. data().IsStandardLayout = false; - } + data().HasBasesWithFields = true; + } + + // C++11 [class]p7: + // A standard-layout class is a class that: + // -- [...] has [...] at most one base class with non-static data + // members + if (BaseClassDecl->data().HasBasesWithNonStaticDataMembers || + BaseClassDecl->hasDirectFields()) { + if (data().HasBasesWithNonStaticDataMembers) + data().IsCXX11StandardLayout = false; + data().HasBasesWithNonStaticDataMembers = true; + } + if (!BaseClassDecl->isEmpty()) { // C++14 [meta.unary.prop]p4: // T is a class type [...] with [...] no base class B for which // is_empty<B>::value is false. data().Empty = false; - data().HasNoNonEmptyBases = false; } - + // C++1z [dcl.init.agg]p1: // An aggregate is a class with [...] no private or protected base classes if (Base->getAccessSpecifier() != AS_public) @@ -228,14 +259,20 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, // C++ [class.virtual]p1: // A class that declares or inherits a virtual function is called a // polymorphic class. - if (BaseClassDecl->isPolymorphic()) + if (BaseClassDecl->isPolymorphic()) { data().Polymorphic = true; + // An aggregate is a class with [...] no virtual functions. + data().Aggregate = false; + } + // C++0x [class]p7: // A standard-layout class is a class that: [...] // -- has no non-standard-layout base classes if (!BaseClassDecl->isStandardLayout()) data().IsStandardLayout = false; + if (!BaseClassDecl->isCXX11StandardLayout()) + data().IsCXX11StandardLayout = false; // Record if this base is the first non-literal field or base. if (!hasNonLiteralTypeFieldsOrBases() && !BaseType->isLiteralType(C)) @@ -281,11 +318,13 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, // operator for a class X] is trivial [...] if: // -- class X has [...] no virtual base classes data().HasTrivialSpecialMembers &= SMF_Destructor; + data().HasTrivialSpecialMembersForCall &= SMF_Destructor; // C++0x [class]p7: // A standard-layout class is a class that: [...] // -- has [...] no virtual base classes data().IsStandardLayout = false; + data().IsCXX11StandardLayout = false; // C++11 [dcl.constexpr]p4: // In the definition of a constexpr constructor [...] @@ -314,6 +353,10 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, // subobject is trivial, and if (!BaseClassDecl->hasTrivialCopyConstructor()) data().HasTrivialSpecialMembers &= ~SMF_CopyConstructor; + + if (!BaseClassDecl->hasTrivialCopyConstructorForCall()) + data().HasTrivialSpecialMembersForCall &= ~SMF_CopyConstructor; + // If the base class doesn't have a simple move constructor, we'll eagerly // declare it and perform overload resolution to determine which function // it actually calls. If it does have a simple move constructor, this @@ -321,6 +364,9 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, if (!BaseClassDecl->hasTrivialMoveConstructor()) data().HasTrivialSpecialMembers &= ~SMF_MoveConstructor; + if (!BaseClassDecl->hasTrivialMoveConstructorForCall()) + data().HasTrivialSpecialMembersForCall &= ~SMF_MoveConstructor; + // C++0x [class.copy]p27: // A copy/move assignment operator for class X is trivial if [...] // [...] @@ -357,6 +403,9 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, if (!BaseClassDecl->hasTrivialDestructor()) data().HasTrivialSpecialMembers &= ~SMF_Destructor; + if (!BaseClassDecl->hasTrivialDestructorForCall()) + data().HasTrivialSpecialMembersForCall &= ~SMF_Destructor; + if (!BaseClassDecl->hasIrrelevantDestructor()) data().HasIrrelevantDestructor = false; @@ -376,6 +425,10 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, if (BaseClassDecl->hasVolatileMember()) setHasVolatileMember(true); + if (BaseClassDecl->getArgPassingRestrictions() == + RecordDecl::APK_CanNeverPassInRegs) + setArgPassingRestrictions(RecordDecl::APK_CanNeverPassInRegs); + // Keep track of the presence of mutable fields. if (BaseClassDecl->hasMutableFields()) { data().HasMutableFields = true; @@ -390,6 +443,16 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, addedClassSubobject(BaseClassDecl); } + + // C++2a [class]p7: + // A class S is a standard-layout class if it: + // -- has at most one base class subobject of any given type + // + // Note that we only need to check this for classes with more than one base + // class. If there's only one base class, and it's standard layout, then + // we know there are no repeated base classes. + if (data().IsStandardLayout && NumBases > 1 && hasRepeatedBaseClass(this)) + data().IsStandardLayout = false; if (VBases.empty()) { data().IsParsingBaseSpecifiers = false; @@ -490,6 +553,81 @@ void CXXRecordDecl::markedVirtualFunctionPure() { data().Abstract = true; } +bool CXXRecordDecl::hasSubobjectAtOffsetZeroOfEmptyBaseType( + ASTContext &Ctx, const CXXRecordDecl *XFirst) { + if (!getNumBases()) + return false; + + llvm::SmallPtrSet<const CXXRecordDecl*, 8> Bases; + llvm::SmallPtrSet<const CXXRecordDecl*, 8> M; + SmallVector<const CXXRecordDecl*, 8> WorkList; + + // Visit a type that we have determined is an element of M(S). + auto Visit = [&](const CXXRecordDecl *RD) -> bool { + RD = RD->getCanonicalDecl(); + + // C++2a [class]p8: + // A class S is a standard-layout class if it [...] has no element of the + // set M(S) of types as a base class. + // + // If we find a subobject of an empty type, it might also be a base class, + // so we'll need to walk the base classes to check. + if (!RD->data().HasBasesWithFields) { + // Walk the bases the first time, stopping if we find the type. Build a + // set of them so we don't need to walk them again. + if (Bases.empty()) { + bool RDIsBase = !forallBases([&](const CXXRecordDecl *Base) -> bool { + Base = Base->getCanonicalDecl(); + if (RD == Base) + return false; + Bases.insert(Base); + return true; + }); + if (RDIsBase) + return true; + } else { + if (Bases.count(RD)) + return true; + } + } + + if (M.insert(RD).second) + WorkList.push_back(RD); + return false; + }; + + if (Visit(XFirst)) + return true; + + while (!WorkList.empty()) { + const CXXRecordDecl *X = WorkList.pop_back_val(); + + // FIXME: We don't check the bases of X. That matches the standard, but + // that sure looks like a wording bug. + + // -- If X is a non-union class type with a non-static data member + // [recurse to] the first non-static data member of X + // -- If X is a union type, [recurse to union members] + for (auto *FD : X->fields()) { + // FIXME: Should we really care about the type of the first non-static + // data member of a non-union if there are preceding unnamed bit-fields? + if (FD->isUnnamedBitfield()) + continue; + + // -- If X is n array type, [visit the element type] + QualType T = Ctx.getBaseElementType(FD->getType()); + if (auto *RD = T->getAsCXXRecordDecl()) + if (Visit(RD)) + return true; + + if (!X->isUnion()) + break; + } + } + + return false; +} + void CXXRecordDecl::addedMember(Decl *D) { if (!D->isImplicit() && !isa<FieldDecl>(D) && @@ -502,7 +640,7 @@ void CXXRecordDecl::addedMember(Decl *D) { if (D->getFriendObjectKind() || D->isInvalidDecl()) return; - FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D); + auto *FunTmpl = dyn_cast<FunctionTemplateDecl>(D); if (FunTmpl) D = FunTmpl->getTemplatedDecl(); @@ -510,12 +648,11 @@ void CXXRecordDecl::addedMember(Decl *D) { Decl *DUnderlying = D; if (auto *ND = dyn_cast<NamedDecl>(DUnderlying)) { DUnderlying = ND->getUnderlyingDecl(); - if (FunctionTemplateDecl *UnderlyingFunTmpl = - dyn_cast<FunctionTemplateDecl>(DUnderlying)) + if (auto *UnderlyingFunTmpl = dyn_cast<FunctionTemplateDecl>(DUnderlying)) DUnderlying = UnderlyingFunTmpl->getTemplatedDecl(); } - if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) { + if (const auto *Method = dyn_cast<CXXMethodDecl>(D)) { if (Method->isVirtual()) { // C++ [dcl.init.aggr]p1: // An aggregate is an array or a class with [...] no virtual functions. @@ -539,11 +676,13 @@ void CXXRecordDecl::addedMember(Decl *D) { // assignment operator for a class X] is trivial [...] if: // -- class X has no virtual functions [...] data().HasTrivialSpecialMembers &= SMF_Destructor; + data().HasTrivialSpecialMembersForCall &= SMF_Destructor; // C++0x [class]p7: // A standard-layout class is a class that: [...] // -- has no virtual functions data().IsStandardLayout = false; + data().IsCXX11StandardLayout = false; } } @@ -557,7 +696,7 @@ void CXXRecordDecl::addedMember(Decl *D) { unsigned SMKind = 0; // Handle constructors. - if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) { + if (const auto *Constructor = dyn_cast<CXXConstructorDecl>(D)) { if (!Constructor->isImplicit()) { // Note that we have a user-declared constructor. data().UserDeclaredConstructor = true; @@ -599,8 +738,7 @@ void CXXRecordDecl::addedMember(Decl *D) { } // Handle constructors, including those inherited from base classes. - if (CXXConstructorDecl *Constructor = - dyn_cast<CXXConstructorDecl>(DUnderlying)) { + if (const auto *Constructor = dyn_cast<CXXConstructorDecl>(DUnderlying)) { // Record if we see any constexpr constructors which are neither copy // nor move constructors. // C++1z [basic.types]p10: @@ -612,7 +750,7 @@ void CXXRecordDecl::addedMember(Decl *D) { } // Handle destructors. - if (CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(D)) { + if (const auto *DD = dyn_cast<CXXDestructorDecl>(D)) { SMKind |= SMF_Destructor; if (DD->isUserProvided()) @@ -623,17 +761,19 @@ void CXXRecordDecl::addedMember(Decl *D) { // C++11 [class.dtor]p5: // A destructor is trivial if [...] the destructor is not virtual. - if (DD->isVirtual()) + if (DD->isVirtual()) { data().HasTrivialSpecialMembers &= ~SMF_Destructor; + data().HasTrivialSpecialMembersForCall &= ~SMF_Destructor; + } } // Handle member functions. - if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) { + if (const auto *Method = dyn_cast<CXXMethodDecl>(D)) { if (Method->isCopyAssignmentOperator()) { SMKind |= SMF_CopyAssignment; - const ReferenceType *ParamTy = - Method->getParamDecl(0)->getType()->getAs<ReferenceType>(); + const auto *ParamTy = + Method->getParamDecl(0)->getType()->getAs<ReferenceType>(); if (!ParamTy || ParamTy->getPointeeType().isConstQualified()) data().HasDeclaredCopyAssignmentWithConstParam = true; } @@ -642,7 +782,7 @@ void CXXRecordDecl::addedMember(Decl *D) { SMKind |= SMF_MoveAssignment; // Keep the list of conversion functions up-to-date. - if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) { + if (auto *Conversion = dyn_cast<CXXConversionDecl>(D)) { // FIXME: We use the 'unsafe' accessor for the access specifier here, // because Sema may not have set it yet. That's really just a misdesign // in Sema. However, LLDB *will* have set the access specifier correctly, @@ -670,16 +810,30 @@ void CXXRecordDecl::addedMember(Decl *D) { // If this is the first declaration of a special member, we no longer have // an implicit trivial special member. data().HasTrivialSpecialMembers &= - data().DeclaredSpecialMembers | ~SMKind; + data().DeclaredSpecialMembers | ~SMKind; + data().HasTrivialSpecialMembersForCall &= + data().DeclaredSpecialMembers | ~SMKind; if (!Method->isImplicit() && !Method->isUserProvided()) { // This method is user-declared but not user-provided. We can't work out // whether it's trivial yet (not until we get to the end of the class). // We'll handle this method in finishedDefaultedOrDeletedMember. - } else if (Method->isTrivial()) + } else if (Method->isTrivial()) { data().HasTrivialSpecialMembers |= SMKind; - else + data().HasTrivialSpecialMembersForCall |= SMKind; + } else if (Method->isTrivialForCall()) { + data().HasTrivialSpecialMembersForCall |= SMKind; data().DeclaredNonTrivialSpecialMembers |= SMKind; + } else { + data().DeclaredNonTrivialSpecialMembers |= SMKind; + // If this is a user-provided function, do not set + // DeclaredNonTrivialSpecialMembersForCall here since we don't know + // yet whether the method would be considered non-trivial for the + // purpose of calls (attribute "trivial_abi" can be dropped from the + // class later, which can change the special method's triviality). + if (!Method->isUserProvided()) + data().DeclaredNonTrivialSpecialMembersForCall |= SMKind; + } // Note when we have declared a declared special member, and suppress the // implicit declaration of this special member. @@ -707,14 +861,39 @@ void CXXRecordDecl::addedMember(Decl *D) { } // Handle non-static data members. - if (FieldDecl *Field = dyn_cast<FieldDecl>(D)) { + if (const auto *Field = dyn_cast<FieldDecl>(D)) { + ASTContext &Context = getASTContext(); + + // C++2a [class]p7: + // A standard-layout class is a class that: + // [...] + // -- has all non-static data members and bit-fields in the class and + // its base classes first declared in the same class + if (data().HasBasesWithFields) + data().IsStandardLayout = false; + // C++ [class.bit]p2: // A declaration for a bit-field that omits the identifier declares an // unnamed bit-field. Unnamed bit-fields are not members and cannot be // initialized. - if (Field->isUnnamedBitfield()) + if (Field->isUnnamedBitfield()) { + // C++ [meta.unary.prop]p4: [LWG2358] + // T is a class type [...] with [...] no unnamed bit-fields of non-zero + // length + if (data().Empty && !Field->isZeroLengthBitField(Context) && + Context.getLangOpts().getClangABICompat() > + LangOptions::ClangABI::Ver6) + data().Empty = false; return; + } + // C++11 [class]p7: + // A standard-layout class is a class that: + // -- either has no non-static data members in the most derived class + // [...] or has no base classes with non-static data members + if (data().HasBasesWithNonStaticDataMembers) + data().IsCXX11StandardLayout = false; + // C++ [dcl.init.aggr]p1: // An aggregate is an array or a class (clause 9) with [...] no // private or protected non-static data members (clause 11). @@ -725,6 +904,11 @@ void CXXRecordDecl::addedMember(Decl *D) { data().PlainOldData = false; } + // Track whether this is the first field. We use this when checking + // whether the class is standard-layout below. + bool IsFirstField = !data().HasPrivateFields && + !data().HasProtectedFields && !data().HasPublicFields; + // C++0x [class]p7: // A standard-layout class is a class that: // [...] @@ -736,8 +920,10 @@ void CXXRecordDecl::addedMember(Decl *D) { case AS_none: llvm_unreachable("Invalid access specifier"); }; if ((data().HasPrivateFields + data().HasProtectedFields + - data().HasPublicFields) > 1) + data().HasPublicFields) > 1) { data().IsStandardLayout = false; + data().IsCXX11StandardLayout = false; + } // Keep track of the presence of mutable fields. if (Field->isMutable()) { @@ -758,7 +944,6 @@ void CXXRecordDecl::addedMember(Decl *D) { // // Automatic Reference Counting: the presence of a member of Objective-C pointer type // that does not explicitly have no lifetime makes the class a non-POD. - ASTContext &Context = getASTContext(); QualType T = Context.getBaseElementType(Field->getType()); if (T->isObjCRetainableType() || T.isObjCGCStrong()) { if (T.hasNonTrivialObjCLifetime()) { @@ -772,6 +957,17 @@ void CXXRecordDecl::addedMember(Decl *D) { struct DefinitionData &Data = data(); Data.PlainOldData = false; Data.HasTrivialSpecialMembers = 0; + + // __strong or __weak fields do not make special functions non-trivial + // for the purpose of calls. + Qualifiers::ObjCLifetime LT = T.getQualifiers().getObjCLifetime(); + if (LT != Qualifiers::OCL_Strong && LT != Qualifiers::OCL_Weak) + data().HasTrivialSpecialMembersForCall = 0; + + // Structs with __weak fields should never be passed directly. + if (LT == Qualifiers::OCL_Weak) + setArgPassingRestrictions(RecordDecl::APK_CanNeverPassInRegs); + Data.HasIrrelevantDestructor = false; } else if (!Context.getLangOpts().ObjCAutoRefCount) { setHasObjectMember(true); @@ -787,6 +983,7 @@ void CXXRecordDecl::addedMember(Decl *D) { // A standard-layout class is a class that: // -- has no non-static data members of type [...] reference, data().IsStandardLayout = false; + data().IsCXX11StandardLayout = false; // C++1z [class.copy.ctor]p10: // A defaulted copy constructor for a class X is defined as deleted if X has: @@ -838,8 +1035,8 @@ void CXXRecordDecl::addedMember(Decl *D) { if (T->isReferenceType()) data().DefaultedMoveAssignmentIsDeleted = true; - if (const RecordType *RecordTy = T->getAs<RecordType>()) { - CXXRecordDecl* FieldRec = cast<CXXRecordDecl>(RecordTy->getDecl()); + if (const auto *RecordTy = T->getAs<RecordType>()) { + auto *FieldRec = cast<CXXRecordDecl>(RecordTy->getDecl()); if (FieldRec->getDefinition()) { addedClassSubobject(FieldRec); @@ -899,12 +1096,19 @@ void CXXRecordDecl::addedMember(Decl *D) { // member is trivial; if (!FieldRec->hasTrivialCopyConstructor()) data().HasTrivialSpecialMembers &= ~SMF_CopyConstructor; + + if (!FieldRec->hasTrivialCopyConstructorForCall()) + data().HasTrivialSpecialMembersForCall &= ~SMF_CopyConstructor; + // If the field doesn't have a simple move constructor, we'll eagerly // declare the move constructor for this class and we'll decide whether // it's trivial then. if (!FieldRec->hasTrivialMoveConstructor()) data().HasTrivialSpecialMembers &= ~SMF_MoveConstructor; + if (!FieldRec->hasTrivialMoveConstructorForCall()) + data().HasTrivialSpecialMembersForCall &= ~SMF_MoveConstructor; + // C++0x [class.copy]p27: // A copy/move assignment operator for class X is trivial if [...] // [...] @@ -921,12 +1125,17 @@ void CXXRecordDecl::addedMember(Decl *D) { if (!FieldRec->hasTrivialDestructor()) data().HasTrivialSpecialMembers &= ~SMF_Destructor; + if (!FieldRec->hasTrivialDestructorForCall()) + data().HasTrivialSpecialMembersForCall &= ~SMF_Destructor; if (!FieldRec->hasIrrelevantDestructor()) data().HasIrrelevantDestructor = false; if (FieldRec->hasObjectMember()) setHasObjectMember(true); if (FieldRec->hasVolatileMember()) setHasVolatileMember(true); + if (FieldRec->getArgPassingRestrictions() == + RecordDecl::APK_CanNeverPassInRegs) + setArgPassingRestrictions(RecordDecl::APK_CanNeverPassInRegs); // C++0x [class]p7: // A standard-layout class is a class that: @@ -934,31 +1143,32 @@ void CXXRecordDecl::addedMember(Decl *D) { // class (or array of such types) [...] if (!FieldRec->isStandardLayout()) data().IsStandardLayout = false; + if (!FieldRec->isCXX11StandardLayout()) + data().IsCXX11StandardLayout = false; - // C++0x [class]p7: + // C++2a [class]p7: // A standard-layout class is a class that: // [...] + // -- has no element of the set M(S) of types as a base class. + if (data().IsStandardLayout && (isUnion() || IsFirstField) && + hasSubobjectAtOffsetZeroOfEmptyBaseType(Context, FieldRec)) + data().IsStandardLayout = false; + + // C++11 [class]p7: + // A standard-layout class is a class that: // -- has no base classes of the same type as the first non-static - // data member. - // We don't want to expend bits in the state of the record decl - // tracking whether this is the first non-static data member so we - // cheat a bit and use some of the existing state: the empty bit. - // Virtual bases and virtual methods make a class non-empty, but they - // also make it non-standard-layout so we needn't check here. - // A non-empty base class may leave the class standard-layout, but not - // if we have arrived here, and have at least one non-static data - // member. If IsStandardLayout remains true, then the first non-static - // data member must come through here with Empty still true, and Empty - // will subsequently be set to false below. - if (data().IsStandardLayout && data().Empty) { + // data member + if (data().IsCXX11StandardLayout && IsFirstField) { + // FIXME: We should check all base classes here, not just direct + // base classes. for (const auto &BI : bases()) { if (Context.hasSameUnqualifiedType(BI.getType(), T)) { - data().IsStandardLayout = false; + data().IsCXX11StandardLayout = false; break; } } } - + // Keep track of the presence of mutable fields. if (FieldRec->hasMutableFields()) { data().HasMutableFields = true; @@ -1021,31 +1231,13 @@ void CXXRecordDecl::addedMember(Decl *D) { data().DefaultedMoveAssignmentIsDeleted = true; } - // C++0x [class]p7: - // A standard-layout class is a class that: - // [...] - // -- either has no non-static data members in the most derived - // class and at most one base class with non-static data members, - // or has no base classes with non-static data members, and - // At this point we know that we have a non-static data member, so the last - // clause holds. - if (!data().HasNoNonEmptyBases) - data().IsStandardLayout = false; - // C++14 [meta.unary.prop]p4: - // T is a class type [...] with [...] no non-static data members other - // than bit-fields of length 0... - if (data().Empty) { - if (!Field->isBitField() || - (!Field->getBitWidth()->isTypeDependent() && - !Field->getBitWidth()->isValueDependent() && - Field->getBitWidthValue(Context) != 0)) - data().Empty = false; - } + // T is a class type [...] with [...] no non-static data members + data().Empty = false; } // Handle using declarations of conversion functions. - if (UsingShadowDecl *Shadow = dyn_cast<UsingShadowDecl>(D)) { + if (auto *Shadow = dyn_cast<UsingShadowDecl>(D)) { if (Shadow->getDeclName().getNameKind() == DeclarationName::CXXConversionFunctionName) { ASTContext &Ctx = getASTContext(); @@ -1053,7 +1245,7 @@ void CXXRecordDecl::addedMember(Decl *D) { } } - if (UsingDecl *Using = dyn_cast<UsingDecl>(D)) { + if (const auto *Using = dyn_cast<UsingDecl>(D)) { if (Using->getDeclName().getNameKind() == DeclarationName::CXXConstructorName) { data().HasInheritedConstructor = true; @@ -1073,7 +1265,7 @@ void CXXRecordDecl::finishedDefaultedOrDeletedMember(CXXMethodDecl *D) { // The kind of special member this declaration is, if any. unsigned SMKind = 0; - if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) { + if (const auto *Constructor = dyn_cast<CXXConstructorDecl>(D)) { if (Constructor->isDefaultConstructor()) { SMKind |= SMF_DefaultConstructor; if (Constructor->isConstexpr()) @@ -1103,6 +1295,23 @@ void CXXRecordDecl::finishedDefaultedOrDeletedMember(CXXMethodDecl *D) { data().DeclaredNonTrivialSpecialMembers |= SMKind; } +void CXXRecordDecl::setTrivialForCallFlags(CXXMethodDecl *D) { + unsigned SMKind = 0; + + if (const auto *Constructor = dyn_cast<CXXConstructorDecl>(D)) { + if (Constructor->isCopyConstructor()) + SMKind = SMF_CopyConstructor; + else if (Constructor->isMoveConstructor()) + SMKind = SMF_MoveConstructor; + } else if (isa<CXXDestructorDecl>(D)) + SMKind = SMF_Destructor; + + if (D->isTrivialForCall()) + data().HasTrivialSpecialMembersForCall |= SMKind; + else + data().DeclaredNonTrivialSpecialMembersForCall |= SMKind; +} + bool CXXRecordDecl::isCLike() const { if (getTagKind() == TTK_Class || getTagKind() == TTK_Interface || !TemplateOrInstantiation.isNull()) @@ -1128,8 +1337,7 @@ CXXMethodDecl* CXXRecordDecl::getLambdaCallOperator() const { assert(Calls.size() == 1 && "More than one lambda call operator!"); NamedDecl *CallOp = Calls.front(); - if (FunctionTemplateDecl *CallOpTmpl = - dyn_cast<FunctionTemplateDecl>(CallOp)) + if (const auto *CallOpTmpl = dyn_cast<FunctionTemplateDecl>(CallOp)) return cast<CXXMethodDecl>(CallOpTmpl->getTemplatedDecl()); return cast<CXXMethodDecl>(CallOp); @@ -1143,8 +1351,7 @@ CXXMethodDecl* CXXRecordDecl::getLambdaStaticInvoker() const { if (Invoker.empty()) return nullptr; assert(Invoker.size() == 1 && "More than one static invoker operator!"); NamedDecl *InvokerFun = Invoker.front(); - if (FunctionTemplateDecl *InvokerTemplate = - dyn_cast<FunctionTemplateDecl>(InvokerFun)) + if (const auto *InvokerTemplate = dyn_cast<FunctionTemplateDecl>(InvokerFun)) return cast<CXXMethodDecl>(InvokerTemplate->getTemplatedDecl()); return cast<CXXMethodDecl>(InvokerFun); @@ -1257,7 +1464,7 @@ static void CollectVisibleConversions(ASTContext &Context, = CXXRecordDecl::MergeAccess(Access, I.getAccessSpecifier()); bool BaseInVirtual = InVirtual || I.isVirtual(); - CXXRecordDecl *Base = cast<CXXRecordDecl>(RT->getDecl()); + auto *Base = cast<CXXRecordDecl>(RT->getDecl()); CollectVisibleConversions(Context, Base, BaseInVirtual, BaseAccess, *HiddenTypes, Output, VOutput, HiddenVBaseCs); } @@ -1384,8 +1591,7 @@ void CXXRecordDecl::setDescribedClassTemplate(ClassTemplateDecl *Template) { } TemplateSpecializationKind CXXRecordDecl::getTemplateSpecializationKind() const{ - if (const ClassTemplateSpecializationDecl *Spec - = dyn_cast<ClassTemplateSpecializationDecl>(this)) + if (const auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(this)) return Spec->getSpecializationKind(); if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo()) @@ -1396,8 +1602,7 @@ TemplateSpecializationKind CXXRecordDecl::getTemplateSpecializationKind() const{ void CXXRecordDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) { - if (ClassTemplateSpecializationDecl *Spec - = dyn_cast<ClassTemplateSpecializationDecl>(this)) { + if (auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(this)) { Spec->setSpecializationKind(TSK); return; } @@ -1575,7 +1780,7 @@ void CXXRecordDecl::completeDefinition(CXXFinalOverriderMap *FinalOverriders) { SOEnd = M->second.end(); SO != SOEnd && !Done; ++SO) { assert(SO->second.size() > 0 && - "All virtual functions have overridding virtual functions"); + "All virtual functions have overriding virtual functions"); // C++ [class.abstract]p4: // A class is abstract if it contains or inherits at least one @@ -1602,8 +1807,8 @@ bool CXXRecordDecl::mayBeAbstract() const { return false; for (const auto &B : bases()) { - CXXRecordDecl *BaseDecl - = cast<CXXRecordDecl>(B.getType()->getAs<RecordType>()->getDecl()); + const auto *BaseDecl = + cast<CXXRecordDecl>(B.getType()->getAs<RecordType>()->getDecl()); if (BaseDecl->isAbstract()) return true; } @@ -1670,7 +1875,7 @@ CXXMethodDecl::getCorrespondingMethodInClass(const CXXRecordDecl *RD, } for (auto *ND : RD->lookup(getDeclName())) { - CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(ND); + auto *MD = dyn_cast<CXXMethodDecl>(ND); if (!MD) continue; if (recursivelyOverrides(MD, this)) @@ -1683,7 +1888,7 @@ CXXMethodDecl::getCorrespondingMethodInClass(const CXXRecordDecl *RD, const RecordType *RT = I.getType()->getAs<RecordType>(); if (!RT) continue; - const CXXRecordDecl *Base = cast<CXXRecordDecl>(RT->getDecl()); + const auto *Base = cast<CXXRecordDecl>(RT->getDecl()); CXXMethodDecl *T = this->getCorrespondingMethodInClass(Base); if (T) return T; @@ -1758,8 +1963,8 @@ CXXMethodDecl *CXXMethodDecl::getDevirtualizedMethod(const Expr *Base, if (BestDynamicDecl->hasAttr<FinalAttr>()) return DevirtualizedMethod; - if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Base)) { - if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) + if (const auto *DRE = dyn_cast<DeclRefExpr>(Base)) { + if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) if (VD->getType()->isRecordType()) // This is a record decl. We know the type and can devirtualize it. return DevirtualizedMethod; @@ -1770,9 +1975,10 @@ CXXMethodDecl *CXXMethodDecl::getDevirtualizedMethod(const Expr *Base, // We can devirtualize calls on an object accessed by a class member access // expression, since by C++11 [basic.life]p6 we know that it can't refer to // a derived class object constructed in the same location. - if (const MemberExpr *ME = dyn_cast<MemberExpr>(Base)) - if (const ValueDecl *VD = dyn_cast<ValueDecl>(ME->getMemberDecl())) - return VD->getType()->isRecordType() ? DevirtualizedMethod : nullptr; + if (const auto *ME = dyn_cast<MemberExpr>(Base)) { + const ValueDecl *VD = ME->getMemberDecl(); + return VD->getType()->isRecordType() ? DevirtualizedMethod : nullptr; + } // Likewise for calls on an object accessed by a (non-reference) pointer to // member access. @@ -1848,7 +2054,7 @@ bool CXXMethodDecl::isUsualDeallocationFunction() const { DeclContext::lookup_result R = getDeclContext()->lookup(getDeclName()); for (DeclContext::lookup_result::iterator I = R.begin(), E = R.end(); I != E; ++I) { - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) + if (const auto *FD = dyn_cast<FunctionDecl>(*I)) if (FD->getNumParams() == 1) return false; } @@ -1868,7 +2074,7 @@ bool CXXMethodDecl::isCopyAssignmentOperator() const { return false; QualType ParamType = getParamDecl(0)->getType(); - if (const LValueReferenceType *Ref = ParamType->getAs<LValueReferenceType>()) + if (const auto *Ref = ParamType->getAs<LValueReferenceType>()) ParamType = Ref->getPointeeType(); ASTContext &Context = getASTContext(); @@ -2006,7 +2212,7 @@ TypeLoc CXXCtorInitializer::getBaseClassLoc() const { if (isBaseInitializer()) return Initializee.get<TypeSourceInfo*>()->getTypeLoc(); else - return TypeLoc(); + return {}; } const Type *CXXCtorInitializer::getBaseClass() const { @@ -2023,10 +2229,10 @@ SourceLocation CXXCtorInitializer::getSourceLocation() const { if (isAnyMemberInitializer()) return getMemberLocation(); - if (TypeSourceInfo *TSInfo = Initializee.get<TypeSourceInfo*>()) + if (const auto *TSInfo = Initializee.get<TypeSourceInfo *>()) return TSInfo->getTypeLoc().getLocalSourceRange().getBegin(); - return SourceLocation(); + return {}; } SourceRange CXXCtorInitializer::getSourceRange() const { @@ -2034,7 +2240,7 @@ SourceRange CXXCtorInitializer::getSourceRange() const { FieldDecl *D = getAnyMember(); if (Expr *I = D->getInClassInitializer()) return I->getSourceRange(); - return SourceRange(); + return {}; } return SourceRange(getSourceLocation(), getRParenLoc()); @@ -2078,7 +2284,7 @@ CXXConstructorDecl::init_const_iterator CXXConstructorDecl::init_begin() const { CXXConstructorDecl *CXXConstructorDecl::getTargetConstructor() const { assert(isDelegatingConstructor() && "Not a delegating constructor!"); Expr *E = (*init_begin())->getInit()->IgnoreImplicit(); - if (CXXConstructExpr *Construct = dyn_cast<CXXConstructExpr>(E)) + if (const auto *Construct = dyn_cast<CXXConstructExpr>(E)) return Construct->getConstructor(); return nullptr; @@ -2103,7 +2309,7 @@ bool CXXConstructorDecl::isMoveConstructor(unsigned &TypeQuals) const { getParamDecl(0)->getType()->isRValueReferenceType(); } -/// \brief Determine whether this is a copy or move constructor. +/// Determine whether this is a copy or move constructor. bool CXXConstructorDecl::isCopyOrMoveConstructor(unsigned &TypeQuals) const { // C++ [class.copy]p2: // A non-template constructor for class X is a copy constructor @@ -2124,7 +2330,7 @@ bool CXXConstructorDecl::isCopyOrMoveConstructor(unsigned &TypeQuals) const { const ParmVarDecl *Param = getParamDecl(0); // Do we have a reference type? - const ReferenceType *ParamRefType = Param->getType()->getAs<ReferenceType>(); + const auto *ParamRefType = Param->getType()->getAs<ReferenceType>(); if (!ParamRefType) return false; @@ -2174,7 +2380,7 @@ bool CXXConstructorDecl::isSpecializationCopyingObject() const { ASTContext &Context = getASTContext(); CanQualType ParamType = Context.getCanonicalType(Param->getType()); - // Is it the same as our our class type? + // Is it the same as our class type? CanQualType ClassTy = Context.getCanonicalType(Context.getTagDeclType(getParent())); if (ParamType.getUnqualifiedType() != ClassTy) @@ -2271,7 +2477,7 @@ UsingDirectiveDecl *UsingDirectiveDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation IdentLoc, NamedDecl *Used, DeclContext *CommonAncestor) { - if (NamespaceDecl *NS = dyn_cast_or_null<NamespaceDecl>(Used)) + if (auto *NS = dyn_cast_or_null<NamespaceDecl>(Used)) Used = NS->getOriginalNamespace(); return new (C, DC) UsingDirectiveDecl(DC, L, NamespaceLoc, QualifierLoc, IdentLoc, Used, CommonAncestor); @@ -2286,8 +2492,7 @@ UsingDirectiveDecl *UsingDirectiveDecl::CreateDeserialized(ASTContext &C, } NamespaceDecl *UsingDirectiveDecl::getNominatedNamespace() { - if (NamespaceAliasDecl *NA = - dyn_cast_or_null<NamespaceAliasDecl>(NominatedNamespace)) + if (auto *NA = dyn_cast_or_null<NamespaceAliasDecl>(NominatedNamespace)) return NA->getNamespace(); return cast_or_null<NamespaceDecl>(NominatedNamespace); } @@ -2367,7 +2572,7 @@ NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation IdentLoc, NamedDecl *Namespace) { // FIXME: Preserve the aliased namespace as written. - if (NamespaceDecl *NS = dyn_cast_or_null<NamespaceDecl>(Namespace)) + if (auto *NS = dyn_cast_or_null<NamespaceDecl>(Namespace)) Namespace = NS->getOriginalNamespace(); return new (C, DC) NamespaceAliasDecl(C, DC, UsingLoc, AliasLoc, Alias, QualifierLoc, IdentLoc, Namespace); @@ -2387,10 +2592,9 @@ UsingShadowDecl::UsingShadowDecl(Kind K, ASTContext &C, DeclContext *DC, SourceLocation Loc, UsingDecl *Using, NamedDecl *Target) : NamedDecl(K, DC, Loc, Using ? Using->getDeclName() : DeclarationName()), - redeclarable_base(C), Underlying(Target), - UsingOrNextShadow(cast<NamedDecl>(Using)) { + redeclarable_base(C), UsingOrNextShadow(cast<NamedDecl>(Using)) { if (Target) - IdentifierNamespace = Target->getIdentifierNamespace(); + setTargetDecl(Target); setImplicit(); } @@ -2405,8 +2609,8 @@ UsingShadowDecl::CreateDeserialized(ASTContext &C, unsigned ID) { UsingDecl *UsingShadowDecl::getUsingDecl() const { const UsingShadowDecl *Shadow = this; - while (const UsingShadowDecl *NextShadow = - dyn_cast<UsingShadowDecl>(Shadow->UsingOrNextShadow)) + while (const auto *NextShadow = + dyn_cast<UsingShadowDecl>(Shadow->UsingOrNextShadow)) Shadow = NextShadow; return cast<UsingDecl>(Shadow->UsingOrNextShadow); } @@ -2625,7 +2829,7 @@ DecompositionDecl *DecompositionDecl::CreateDeserialized(ASTContext &C, void DecompositionDecl::printName(llvm::raw_ostream &os) const { os << '['; bool Comma = false; - for (auto *B : bindings()) { + for (const auto *B : bindings()) { if (Comma) os << ", "; B->printName(os); diff --git a/lib/AST/DeclFriend.cpp b/lib/AST/DeclFriend.cpp index 461bf36858b7..08fbed361579 100644 --- a/lib/AST/DeclFriend.cpp +++ b/lib/AST/DeclFriend.cpp @@ -39,7 +39,7 @@ FriendDecl *FriendDecl::Create(ASTContext &C, DeclContext *DC, ArrayRef<TemplateParameterList *> FriendTypeTPLists) { #ifndef NDEBUG if (Friend.is<NamedDecl *>()) { - NamedDecl *D = Friend.get<NamedDecl*>(); + const auto *D = Friend.get<NamedDecl*>(); assert(isa<FunctionDecl>(D) || isa<CXXRecordDecl>(D) || isa<FunctionTemplateDecl>(D) || @@ -57,8 +57,8 @@ FriendDecl *FriendDecl::Create(ASTContext &C, DeclContext *DC, std::size_t Extra = FriendDecl::additionalSizeToAlloc<TemplateParameterList *>( FriendTypeTPLists.size()); - FriendDecl *FD = new (C, DC, Extra) FriendDecl(DC, L, Friend, FriendL, - FriendTypeTPLists); + auto *FD = new (C, DC, Extra) FriendDecl(DC, L, Friend, FriendL, + FriendTypeTPLists); cast<CXXRecordDecl>(DC)->pushFriendDecl(FD); return FD; } diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index f95d5def47ac..5db045099997 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -74,7 +74,7 @@ ObjCContainerDecl::getIvarDecl(IdentifierInfo *Id) const { lookup_result R = lookup(Id); for (lookup_iterator Ivar = R.begin(), IvarEnd = R.end(); Ivar != IvarEnd; ++Ivar) { - if (ObjCIvarDecl *ivar = dyn_cast<ObjCIvarDecl>(*Ivar)) + if (auto *ivar = dyn_cast<ObjCIvarDecl>(*Ivar)) return ivar; } return nullptr; @@ -86,7 +86,7 @@ ObjCContainerDecl::getMethod(Selector Sel, bool isInstance, bool AllowHidden) const { // If this context is a hidden protocol definition, don't find any // methods there. - if (const ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(this)) { + if (const auto *Proto = dyn_cast<ObjCProtocolDecl>(this)) { if (const ObjCProtocolDecl *Def = Proto->getDefinition()) if (Def->isHidden() && !AllowHidden) return nullptr; @@ -102,14 +102,14 @@ ObjCContainerDecl::getMethod(Selector Sel, bool isInstance, lookup_result R = lookup(Sel); for (lookup_iterator Meth = R.begin(), MethEnd = R.end(); Meth != MethEnd; ++Meth) { - ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*Meth); + auto *MD = dyn_cast<ObjCMethodDecl>(*Meth); if (MD && MD->isInstanceMethod() == isInstance) return MD; } return nullptr; } -/// \brief This routine returns 'true' if a user declared setter method was +/// This routine returns 'true' if a user declared setter method was /// found in the class, its protocols, its super classes or categories. /// It also returns 'true' if one of its categories has declared a 'readwrite' /// property. This is because, user must provide a setter method for the @@ -120,12 +120,12 @@ bool ObjCContainerDecl::HasUserDeclaredSetterMethod( lookup_result R = lookup(Sel); for (lookup_iterator Meth = R.begin(), MethEnd = R.end(); Meth != MethEnd; ++Meth) { - ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*Meth); + auto *MD = dyn_cast<ObjCMethodDecl>(*Meth); if (MD && MD->isInstanceMethod() && !MD->isImplicit()) return true; } - if (const ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(this)) { + if (const auto *ID = dyn_cast<ObjCInterfaceDecl>(this)) { // Also look into categories, including class extensions, looking // for a user declared instance method. for (const auto *Cat : ID->visible_categories()) { @@ -159,7 +159,7 @@ bool ObjCContainerDecl::HasUserDeclaredSetterMethod( OSC = OSC->getSuperClass(); } } - if (const ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(this)) + if (const auto *PD = dyn_cast<ObjCProtocolDecl>(this)) for (const auto *PI : PD->protocols()) if (PI->HasUserDeclaredSetterMethod(Property)) return true; @@ -172,7 +172,7 @@ ObjCPropertyDecl::findPropertyDecl(const DeclContext *DC, ObjCPropertyQueryKind queryKind) { // If this context is a hidden protocol definition, don't find any // property. - if (const ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(DC)) { + if (const auto *Proto = dyn_cast<ObjCProtocolDecl>(DC)) { if (const ObjCProtocolDecl *Def = Proto->getDefinition()) if (Def->isHidden()) return nullptr; @@ -192,7 +192,7 @@ ObjCPropertyDecl::findPropertyDecl(const DeclContext *DC, ObjCPropertyDecl *classProp = nullptr; for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E; ++I) - if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(*I)) { + if (auto *PD = dyn_cast<ObjCPropertyDecl>(*I)) { // If queryKind is unknown, we return the instance property if one // exists; otherwise we return the class property. if ((queryKind == ObjCPropertyQueryKind::OBJC_PR_query_unknown && @@ -230,7 +230,7 @@ ObjCPropertyDecl *ObjCContainerDecl::FindPropertyDeclaration( const IdentifierInfo *PropertyId, ObjCPropertyQueryKind QueryKind) const { // Don't find properties within hidden protocol definitions. - if (const ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(this)) { + if (const auto *Proto = dyn_cast<ObjCProtocolDecl>(this)) { if (const ObjCProtocolDecl *Def = Proto->getDefinition()) if (Def->isHidden()) return nullptr; @@ -254,7 +254,7 @@ ObjCPropertyDecl *ObjCContainerDecl::FindPropertyDeclaration( default: break; case Decl::ObjCProtocol: { - const ObjCProtocolDecl *PID = cast<ObjCProtocolDecl>(this); + const auto *PID = cast<ObjCProtocolDecl>(this); for (const auto *I : PID->protocols()) if (ObjCPropertyDecl *P = I->FindPropertyDeclaration(PropertyId, QueryKind)) @@ -262,7 +262,7 @@ ObjCPropertyDecl *ObjCContainerDecl::FindPropertyDeclaration( break; } case Decl::ObjCInterface: { - const ObjCInterfaceDecl *OID = cast<ObjCInterfaceDecl>(this); + const auto *OID = cast<ObjCInterfaceDecl>(this); // Look through categories (but not extensions; they were handled above). for (const auto *Cat : OID->visible_categories()) { if (!Cat->IsClassExtension()) @@ -283,7 +283,7 @@ ObjCPropertyDecl *ObjCContainerDecl::FindPropertyDeclaration( break; } case Decl::ObjCCategory: { - const ObjCCategoryDecl *OCD = cast<ObjCCategoryDecl>(this); + const auto *OCD = cast<ObjCCategoryDecl>(this); // Look through protocols. if (!OCD->IsClassExtension()) for (const auto *I : OCD->protocols()) @@ -310,7 +310,8 @@ ObjCTypeParamList *ObjCInterfaceDecl::getTypeParamList() const { // Otherwise, look at previous declarations to determine whether any // of them has a type parameter list, skipping over those // declarations that do not. - for (auto decl = getMostRecentDecl(); decl; decl = decl->getPreviousDecl()) { + for (const ObjCInterfaceDecl *decl = getMostRecentDecl(); decl; + decl = decl->getPreviousDecl()) { if (ObjCTypeParamList *written = decl->getTypeParamListAsWritten()) return written; } @@ -323,7 +324,7 @@ void ObjCInterfaceDecl::setTypeParamList(ObjCTypeParamList *TPL) { if (!TPL) return; // Set the declaration context of each of the type parameters. - for (auto typeParam : *TypeParamList) + for (auto *typeParam : *TypeParamList) typeParam->setDeclContext(this); } @@ -437,7 +438,7 @@ void ObjCInterfaceDecl::mergeClassExtensionProtocolList( // Check for duplicate protocol in class's protocol list. // This is O(n*m). But it is extremely rare and number of protocols in // class or its extension are very few. - SmallVector<ObjCProtocolDecl*, 8> ProtocolRefs; + SmallVector<ObjCProtocolDecl *, 8> ProtocolRefs; for (unsigned i = 0; i < ExtNum; i++) { bool protocolExists = false; ObjCProtocolDecl *ProtoInExtension = ExtList[i]; @@ -604,7 +605,7 @@ void ObjCInterfaceDecl::startDefinition() { allocateDefinitionData(); // Update all of the declarations with a pointer to the definition. - for (auto RD : redecls()) { + for (auto *RD : redecls()) { if (RD != this) RD->Data = Data; } @@ -710,9 +711,8 @@ ObjCMethodDecl *ObjCInterfaceDecl::lookupMethod(Selector Sel, // Didn't find one yet - look through protocols. const ObjCList<ObjCProtocolDecl> &Protocols = Cat->getReferencedProtocols(); - for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(), - E = Protocols.end(); I != E; ++I) - if ((MethodDecl = (*I)->lookupMethod(Sel, isInstance))) + for (auto *Protocol : Protocols) + if ((MethodDecl = Protocol->lookupMethod(Sel, isInstance))) if (C != Cat || !MethodDecl->isImplicit()) return MethodDecl; } @@ -854,7 +854,7 @@ void ObjCMethodDecl::setMethodParams(ASTContext &C, setParamsAndSelLocs(C, Params, SelLocs); } -/// \brief A definition will return its interface declaration. +/// A definition will return its interface declaration. /// An interface declaration will return its definition. /// Otherwise it will return itself. ObjCMethodDecl *ObjCMethodDecl::getNextRedeclarationImpl() { @@ -865,27 +865,25 @@ ObjCMethodDecl *ObjCMethodDecl::getNextRedeclarationImpl() { if (Redecl) return Redecl; - Decl *CtxD = cast<Decl>(getDeclContext()); + auto *CtxD = cast<Decl>(getDeclContext()); if (!CtxD->isInvalidDecl()) { - if (ObjCInterfaceDecl *IFD = dyn_cast<ObjCInterfaceDecl>(CtxD)) { + if (auto *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)) { + } else if (auto *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)) { + } else if (auto *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)) { + } else if (auto *CImplD = dyn_cast<ObjCCategoryImplDecl>(CtxD)) { if (ObjCCategoryDecl *CatD = CImplD->getCategoryDecl()) if (!CatD->isInvalidDecl()) Redecl = CatD->getMethod(getSelector(), isInstanceMethod()); @@ -908,15 +906,14 @@ ObjCMethodDecl *ObjCMethodDecl::getNextRedeclarationImpl() { } ObjCMethodDecl *ObjCMethodDecl::getCanonicalDecl() { - Decl *CtxD = cast<Decl>(getDeclContext()); + auto *CtxD = cast<Decl>(getDeclContext()); - if (ObjCImplementationDecl *ImplD = dyn_cast<ObjCImplementationDecl>(CtxD)) { + if (auto *ImplD = dyn_cast<ObjCImplementationDecl>(CtxD)) { if (ObjCInterfaceDecl *IFD = ImplD->getClassInterface()) if (ObjCMethodDecl *MD = IFD->getMethod(getSelector(), isInstanceMethod())) return MD; - } else if (ObjCCategoryImplDecl *CImplD = - dyn_cast<ObjCCategoryImplDecl>(CtxD)) { + } else if (auto *CImplD = dyn_cast<ObjCCategoryImplDecl>(CtxD)) { if (ObjCCategoryDecl *CatD = CImplD->getCategoryDecl()) if (ObjCMethodDecl *MD = CatD->getMethod(getSelector(), isInstanceMethod())) @@ -941,7 +938,7 @@ SourceLocation ObjCMethodDecl::getLocEnd() const { } ObjCMethodFamily ObjCMethodDecl::getMethodFamily() const { - ObjCMethodFamily family = static_cast<ObjCMethodFamily>(Family); + auto family = static_cast<ObjCMethodFamily>(Family); if (family != static_cast<unsigned>(InvalidObjCMethodFamily)) return family; @@ -1099,11 +1096,11 @@ void ObjCMethodDecl::createImplicitParams(ASTContext &Context, } ObjCInterfaceDecl *ObjCMethodDecl::getClassInterface() { - if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(getDeclContext())) + if (auto *ID = dyn_cast<ObjCInterfaceDecl>(getDeclContext())) return ID; - if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(getDeclContext())) + if (auto *CD = dyn_cast<ObjCCategoryDecl>(getDeclContext())) return CD->getClassInterface(); - if (ObjCImplDecl *IMD = dyn_cast<ObjCImplDecl>(getDeclContext())) + if (auto *IMD = dyn_cast<ObjCImplDecl>(getDeclContext())) return IMD->getClassInterface(); if (isa<ObjCProtocolDecl>(getDeclContext())) return nullptr; @@ -1138,11 +1135,10 @@ static void CollectOverriddenMethodsRecurse(const ObjCContainerDecl *Container, if (!Container) return; - // In categories look for overriden methods from protocols. A method from - // category is not "overriden" since it is considered as the "same" method + // In categories look for overridden methods from protocols. A method from + // category is not "overridden" since it is considered as the "same" method // (same USR) as the one from the interface. - if (const ObjCCategoryDecl * - Category = dyn_cast<ObjCCategoryDecl>(Container)) { + if (const auto *Category = dyn_cast<ObjCCategoryDecl>(Container)) { // Check whether we have a matching method at this category but only if we // are at the super class level. if (MovedToSuper) @@ -1174,13 +1170,12 @@ static void CollectOverriddenMethodsRecurse(const ObjCContainerDecl *Container, return; } - if (const ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Container)){ + if (const auto *Protocol = dyn_cast<ObjCProtocolDecl>(Container)){ for (const auto *P : Protocol->protocols()) CollectOverriddenMethodsRecurse(P, Method, Methods, MovedToSuper); } - if (const ObjCInterfaceDecl * - Interface = dyn_cast<ObjCInterfaceDecl>(Container)) { + if (const auto *Interface = dyn_cast<ObjCInterfaceDecl>(Container)) { for (const auto *P : Interface->protocols()) CollectOverriddenMethodsRecurse(P, Method, Methods, MovedToSuper); @@ -1204,12 +1199,12 @@ static void collectOverriddenMethodsSlow(const ObjCMethodDecl *Method, SmallVectorImpl<const ObjCMethodDecl *> &overridden) { assert(Method->isOverriding()); - if (const ObjCProtocolDecl * - ProtD = dyn_cast<ObjCProtocolDecl>(Method->getDeclContext())) { + if (const auto *ProtD = + dyn_cast<ObjCProtocolDecl>(Method->getDeclContext())) { CollectOverriddenMethods(ProtD, Method, overridden); - } else if (const ObjCImplDecl * - IMD = dyn_cast<ObjCImplDecl>(Method->getDeclContext())) { + } else if (const auto *IMD = + dyn_cast<ObjCImplDecl>(Method->getDeclContext())) { const ObjCInterfaceDecl *ID = IMD->getClassInterface(); if (!ID) return; @@ -1221,8 +1216,8 @@ static void collectOverriddenMethodsSlow(const ObjCMethodDecl *Method, Method = IFaceMeth; CollectOverriddenMethods(ID, Method, overridden); - } else if (const ObjCCategoryDecl * - CatD = dyn_cast<ObjCCategoryDecl>(Method->getDeclContext())) { + } else if (const auto *CatD = + dyn_cast<ObjCCategoryDecl>(Method->getDeclContext())) { const ObjCInterfaceDecl *ID = CatD->getClassInterface(); if (!ID) return; @@ -1265,7 +1260,7 @@ ObjCMethodDecl::findPropertyDecl(bool CheckOverrides) const { return nullptr; if (isPropertyAccessor()) { - const ObjCContainerDecl *Container = cast<ObjCContainerDecl>(getParent()); + const auto *Container = cast<ObjCContainerDecl>(getParent()); bool IsGetter = (NumArgs == 0); bool IsInstance = isInstanceMethod(); @@ -1328,11 +1323,9 @@ ObjCMethodDecl::findPropertyDecl(bool CheckOverrides) const { OverridesTy Overrides; getOverriddenMethods(Overrides); - for (OverridesTy::const_iterator I = Overrides.begin(), E = Overrides.end(); - I != E; ++I) { - if (const ObjCPropertyDecl *Prop = (*I)->findPropertyDecl(false)) + for (const auto *Override : Overrides) + if (const ObjCPropertyDecl *Prop = Override->findPropertyDecl(false)) return Prop; - } return nullptr; } @@ -1422,7 +1415,7 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::Create(const ASTContext &C, ObjCInterfaceDecl *PrevDecl, SourceLocation ClassLoc, bool isInternal){ - ObjCInterfaceDecl *Result = new (C, DC) + auto *Result = new (C, DC) ObjCInterfaceDecl(C, DC, atLoc, Id, typeParamList, ClassLoc, PrevDecl, isInternal); Result->Data.setInt(!C.getLangOpts().Modules); @@ -1432,12 +1425,9 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::Create(const ASTContext &C, ObjCInterfaceDecl *ObjCInterfaceDecl::CreateDeserialized(const ASTContext &C, unsigned ID) { - ObjCInterfaceDecl *Result = new (C, ID) ObjCInterfaceDecl(C, nullptr, - SourceLocation(), - nullptr, - nullptr, - SourceLocation(), - nullptr, false); + auto *Result = new (C, ID) + ObjCInterfaceDecl(C, nullptr, SourceLocation(), nullptr, nullptr, + SourceLocation(), nullptr, false); Result->Data.setInt(!C.getLangOpts().Modules); return Result; } @@ -1495,7 +1485,7 @@ bool ObjCInterfaceDecl::hasDesignatedInitializers() const { StringRef ObjCInterfaceDecl::getObjCRuntimeNameAsString() const { - if (ObjCRuntimeNameAttr *ObjCRTName = getAttr<ObjCRuntimeNameAttr>()) + if (const auto *ObjCRTName = getAttr<ObjCRuntimeNameAttr>()) return ObjCRTName->getMetadataName(); return getName(); @@ -1731,9 +1721,9 @@ ObjCIvarDecl *ObjCIvarDecl::Create(ASTContext &C, ObjCContainerDecl *DC, "Invalid ivar decl context!"); // Once a new ivar is created in any of class/class-extension/implementation // decl contexts, the previously built IvarList must be rebuilt. - ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(DC); + auto *ID = dyn_cast<ObjCInterfaceDecl>(DC); if (!ID) { - if (ObjCImplementationDecl *IM = dyn_cast<ObjCImplementationDecl>(DC)) + if (auto *IM = dyn_cast<ObjCImplementationDecl>(DC)) ID = IM->getClassInterface(); else ID = cast<ObjCCategoryDecl>(DC)->getClassInterface(); @@ -1752,7 +1742,7 @@ ObjCIvarDecl *ObjCIvarDecl::CreateDeserialized(ASTContext &C, unsigned ID) { } const ObjCInterfaceDecl *ObjCIvarDecl::getContainingInterface() const { - const ObjCContainerDecl *DC = cast<ObjCContainerDecl>(getDeclContext()); + const auto *DC = cast<ObjCContainerDecl>(getDeclContext()); switch (DC->getKind()) { default: @@ -1762,7 +1752,7 @@ const ObjCInterfaceDecl *ObjCIvarDecl::getContainingInterface() const { // Ivars can only appear in class extension categories. case ObjCCategory: { - const ObjCCategoryDecl *CD = cast<ObjCCategoryDecl>(DC); + const auto *CD = cast<ObjCCategoryDecl>(DC); assert(CD->IsClassExtension() && "invalid container for ivar!"); return CD->getClassInterface(); } @@ -1822,7 +1812,7 @@ ObjCProtocolDecl *ObjCProtocolDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation nameLoc, SourceLocation atStartLoc, ObjCProtocolDecl *PrevDecl) { - ObjCProtocolDecl *Result = + auto *Result = new (C, DC) ObjCProtocolDecl(C, DC, Id, nameLoc, atStartLoc, PrevDecl); Result->Data.setInt(!C.getLangOpts().Modules); return Result; @@ -1881,7 +1871,7 @@ void ObjCProtocolDecl::startDefinition() { allocateDefinitionData(); // Update all of the declarations with a pointer to the definition. - for (auto RD : redecls()) + for (auto *RD : redecls()) RD->Data = this->Data; } @@ -1923,7 +1913,7 @@ void ObjCProtocolDecl::collectInheritedProtocolProperties( StringRef ObjCProtocolDecl::getObjCRuntimeNameAsString() const { - if (ObjCRuntimeNameAttr *ObjCRTName = getAttr<ObjCRuntimeNameAttr>()) + if (const auto *ObjCRTName = getAttr<ObjCRuntimeNameAttr>()) return ObjCRTName->getMetadataName(); return getName(); @@ -1957,7 +1947,7 @@ ObjCCategoryDecl *ObjCCategoryDecl::Create(ASTContext &C, DeclContext *DC, ObjCTypeParamList *typeParamList, SourceLocation IvarLBraceLoc, SourceLocation IvarRBraceLoc) { - ObjCCategoryDecl *CatDecl = + auto *CatDecl = new (C, DC) ObjCCategoryDecl(DC, AtLoc, ClassNameLoc, CategoryNameLoc, Id, IDecl, typeParamList, IvarLBraceLoc, IvarRBraceLoc); @@ -1995,11 +1985,10 @@ void ObjCCategoryDecl::setTypeParamList(ObjCTypeParamList *TPL) { if (!TPL) return; // Set the declaration context of each of the type parameters. - for (auto typeParam : *TypeParamList) + for (auto *typeParam : *TypeParamList) typeParam->setDeclContext(this); } - //===----------------------------------------------------------------------===// // ObjCCategoryImplDecl //===----------------------------------------------------------------------===// @@ -2044,13 +2033,11 @@ void ObjCImplDecl::addPropertyImplementation(ObjCPropertyImplDecl *property) { void ObjCImplDecl::setClassInterface(ObjCInterfaceDecl *IFace) { ASTContext &Ctx = getASTContext(); - if (ObjCImplementationDecl *ImplD - = dyn_cast_or_null<ObjCImplementationDecl>(this)) { + if (auto *ImplD = dyn_cast_or_null<ObjCImplementationDecl>(this)) { if (IFace) Ctx.setObjCImplementation(IFace, ImplD); - } else if (ObjCCategoryImplDecl *ImplD = - dyn_cast_or_null<ObjCCategoryImplDecl>(this)) { + } else if (auto *ImplD = dyn_cast_or_null<ObjCCategoryImplDecl>(this)) { if (ObjCCategoryDecl *CD = IFace->FindCategoryDeclaration(getIdentifier())) Ctx.setObjCImplementation(CD, ImplD); } @@ -2139,8 +2126,7 @@ void ObjCImplementationDecl::setIvarInitializers(ASTContext &C, unsigned numInitializers) { if (numInitializers > 0) { NumIvarInitializers = numInitializers; - CXXCtorInitializer **ivarInitializers = - new (C) CXXCtorInitializer*[NumIvarInitializers]; + auto **ivarInitializers = new (C) CXXCtorInitializer*[NumIvarInitializers]; memcpy(ivarInitializers, initializers, numInitializers * sizeof(CXXCtorInitializer*)); IvarInitializers = ivarInitializers; diff --git a/lib/AST/DeclOpenMP.cpp b/lib/AST/DeclOpenMP.cpp index 95e44acca032..f5c3599ef6c6 100644 --- a/lib/AST/DeclOpenMP.cpp +++ b/lib/AST/DeclOpenMP.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// /// \file -/// \brief This file implements OMPThreadPrivateDecl, OMPCapturedExprDecl +/// This file implements OMPThreadPrivateDecl, OMPCapturedExprDecl /// classes. /// //===----------------------------------------------------------------------===// @@ -92,13 +92,14 @@ void OMPCapturedExprDecl::anchor() {} OMPCapturedExprDecl *OMPCapturedExprDecl::Create(ASTContext &C, DeclContext *DC, IdentifierInfo *Id, QualType T, SourceLocation StartLoc) { - return new (C, DC) OMPCapturedExprDecl(C, DC, Id, T, StartLoc); + return new (C, DC) OMPCapturedExprDecl( + C, DC, Id, T, C.getTrivialTypeSourceInfo(T), StartLoc); } OMPCapturedExprDecl *OMPCapturedExprDecl::CreateDeserialized(ASTContext &C, unsigned ID) { - return new (C, ID) - OMPCapturedExprDecl(C, nullptr, nullptr, QualType(), SourceLocation()); + return new (C, ID) OMPCapturedExprDecl(C, nullptr, nullptr, QualType(), + /*TInfo=*/nullptr, SourceLocation()); } SourceRange OMPCapturedExprDecl::getSourceRange() const { diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index b792c5920a55..d3d9c23cca6e 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -128,9 +128,7 @@ static QualType GetBaseType(QualType T) { // FIXME: This should be on the Type class! QualType BaseType = T; while (!BaseType->isSpecifierType()) { - if (isa<TypedefType>(BaseType)) - break; - else if (const PointerType* PTy = BaseType->getAs<PointerType>()) + if (const PointerType *PTy = BaseType->getAs<PointerType>()) BaseType = PTy->getPointeeType(); else if (const BlockPointerType *BPy = BaseType->getAs<BlockPointerType>()) BaseType = BPy->getPointeeType(); @@ -144,8 +142,11 @@ static QualType GetBaseType(QualType T) { BaseType = RTy->getPointeeType(); else if (const AutoType *ATy = BaseType->getAs<AutoType>()) BaseType = ATy->getDeducedType(); + else if (const ParenType *PTy = BaseType->getAs<ParenType>()) + BaseType = PTy->desugar(); else - llvm_unreachable("Unknown declarator!"); + // This must be a syntax error. + break; } return BaseType; } @@ -214,6 +215,8 @@ void DeclPrinter::prettyPrintAttributes(Decl *D) { if (D->hasAttrs()) { AttrVec &Attrs = D->getAttrs(); for (auto *A : Attrs) { + if (A->isInherited() || A->isImplicit()) + continue; switch (A->getKind()) { #define ATTR(X) #define PRAGMA_SPELLING_ATTR(X) case attr::X: @@ -372,21 +375,23 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) { !isa<ClassTemplateSpecializationDecl>(DC)) continue; - // The next bits of code handles stuff like "struct {int x;} a,b"; we're + // The next bits of code handle stuff like "struct {int x;} a,b"; we're // forced to merge the declarations because there's no other way to - // refer to the struct in question. This limited merging is safe without - // a bunch of other checks because it only merges declarations directly - // referring to the tag, not typedefs. + // refer to the struct in question. When that struct is named instead, we + // also need to merge to avoid splitting off a stand-alone struct + // declaration that produces the warning ext_no_declarators in some + // contexts. + // + // This limited merging is safe without a bunch of other checks because it + // only merges declarations directly referring to the tag, not typedefs. // // Check whether the current declaration should be grouped with a previous - // unnamed struct. + // non-free-standing tag declaration. 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]) { + if (!BaseType.isNull() && isa<ElaboratedType>(BaseType) && + cast<ElaboratedType>(BaseType)->getOwnedTagDecl() == Decls[0]) { Decls.push_back(*D); continue; } @@ -396,9 +401,9 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) { if (!Decls.empty()) ProcessDeclGroup(Decls); - // If the current declaration is an unnamed tag type, save it + // If the current declaration is not a free standing declaration, save it // so we can merge it with the subsequent declaration(s) using it. - if (isa<TagDecl>(*D) && !cast<TagDecl>(*D)->getIdentifier()) { + if (isa<TagDecl>(*D) && !cast<TagDecl>(*D)->isFreeStanding()) { Decls.push_back(*D); continue; } @@ -495,14 +500,17 @@ void DeclPrinter::VisitTypeAliasDecl(TypeAliasDecl *D) { void DeclPrinter::VisitEnumDecl(EnumDecl *D) { if (!Policy.SuppressSpecifiers && D->isModulePrivate()) Out << "__module_private__ "; - Out << "enum "; + Out << "enum"; if (D->isScoped()) { if (D->isScopedUsingClassTag()) - Out << "class "; + Out << " class"; else - Out << "struct "; + Out << " struct"; } - Out << *D; + + prettyPrintAttributes(D); + + Out << ' ' << *D; if (D->isFixed() && D->getASTContext().getLangOpts().CPlusPlus11) Out << " : " << D->getIntegerType().stream(Policy); @@ -512,7 +520,6 @@ void DeclPrinter::VisitEnumDecl(EnumDecl *D) { VisitDeclContext(D); Indent() << "}"; } - prettyPrintAttributes(D); } void DeclPrinter::VisitRecordDecl(RecordDecl *D) { @@ -669,7 +676,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { Proto += ")"; } else if (FT && isNoexceptExceptionSpec(FT->getExceptionSpecType())) { Proto += " noexcept"; - if (FT->getExceptionSpecType() == EST_ComputedNoexcept) { + if (isComputedNoexcept(FT->getExceptionSpecType())) { Proto += "("; llvm::raw_string_ostream EOut(Proto); FT->getNoexceptExpr()->printPretty(EOut, nullptr, SubPolicy, @@ -1526,7 +1533,7 @@ void DeclPrinter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) { E = D->varlist_end(); I != E; ++I) { Out << (I == D->varlist_begin() ? '(' : ','); - NamedDecl *ND = cast<NamedDecl>(cast<DeclRefExpr>(*I)->getDecl()); + NamedDecl *ND = cast<DeclRefExpr>(*I)->getDecl(); ND->printQualifiedName(Out); } Out << ")"; diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index a7949b310cef..8854f7879ac6 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -17,6 +17,7 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExternalASTSource.h" #include "clang/AST/TemplateBase.h" #include "clang/AST/TemplateName.h" #include "clang/AST/Type.h" @@ -56,11 +57,11 @@ TemplateParameterList::TemplateParameterList(SourceLocation TemplateLoc, begin()[Idx] = P; if (!P->isTemplateParameterPack()) { - if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P)) + if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P)) if (NTTP->getType()->containsUnexpandedParameterPack()) ContainsUnexpandedParameterPack = true; - if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(P)) + if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(P)) if (TTP->getTemplateParameters()->containsUnexpandedParameterPack()) ContainsUnexpandedParameterPack = true; @@ -118,11 +119,9 @@ unsigned TemplateParameterList::getDepth() const { return 0; const NamedDecl *FirstParm = getParam(0); - if (const TemplateTypeParmDecl *TTP - = dyn_cast<TemplateTypeParmDecl>(FirstParm)) + if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(FirstParm)) return TTP->getDepth(); - else if (const NonTypeTemplateParmDecl *NTTP - = dyn_cast<NonTypeTemplateParmDecl>(FirstParm)) + else if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(FirstParm)) return NTTP->getDepth(); else return cast<TemplateTemplateParmDecl>(FirstParm)->getDepth(); @@ -133,7 +132,7 @@ static void AdoptTemplateParameterList(TemplateParameterList *Params, for (NamedDecl *P : *Params) { P->setDeclContext(Owner); - if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(P)) + if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(P)) AdoptTemplateParameterList(TTP->getTemplateParameters(), Owner); } } @@ -258,7 +257,7 @@ FunctionTemplateDecl *FunctionTemplateDecl::CreateDeserialized(ASTContext &C, RedeclarableTemplateDecl::CommonBase * FunctionTemplateDecl::newCommon(ASTContext &C) const { - Common *CommonPtr = new (C) Common; + auto *CommonPtr = new (C) Common; C.addDestruction(CommonPtr); return CommonPtr; } @@ -318,8 +317,8 @@ ClassTemplateDecl *ClassTemplateDecl::Create(ASTContext &C, return new (C, DC) ClassTemplateDecl(C, DC, L, Name, Params, Decl); } - ConstrainedTemplateDeclInfo *const CTDI = new (C) ConstrainedTemplateDeclInfo; - ClassTemplateDecl *const New = + auto *const CTDI = new (C) ConstrainedTemplateDeclInfo; + auto *const New = new (C, DC) ClassTemplateDecl(CTDI, C, DC, L, Name, Params, Decl); New->setAssociatedConstraints(AssociatedConstraints); return New; @@ -349,7 +348,7 @@ ClassTemplateDecl::getPartialSpecializations() { RedeclarableTemplateDecl::CommonBase * ClassTemplateDecl::newCommon(ASTContext &C) const { - Common *CommonPtr = new (C) Common; + auto *CommonPtr = new (C) Common; C.addDestruction(CommonPtr); return CommonPtr; } @@ -453,8 +452,8 @@ TemplateTypeParmDecl::Create(const ASTContext &C, DeclContext *DC, SourceLocation KeyLoc, SourceLocation NameLoc, unsigned D, unsigned P, IdentifierInfo *Id, bool Typename, bool ParameterPack) { - TemplateTypeParmDecl *TTPDecl = - new (C, DC) TemplateTypeParmDecl(DC, KeyLoc, NameLoc, Id, Typename); + auto *TTPDecl = + new (C, DC) TemplateTypeParmDecl(DC, KeyLoc, NameLoc, Id, Typename); QualType TTPType = C.getTemplateTypeParmType(D, P, ParameterPack, TTPDecl); TTPDecl->setTypeForDecl(TTPType.getTypePtr()); return TTPDecl; @@ -709,7 +708,7 @@ ClassTemplateSpecializationDecl::Create(ASTContext &Context, TagKind TK, ClassTemplateDecl *SpecializedTemplate, ArrayRef<TemplateArgument> Args, ClassTemplateSpecializationDecl *PrevDecl) { - ClassTemplateSpecializationDecl *Result = + auto *Result = new (Context, DC) ClassTemplateSpecializationDecl( Context, ClassTemplateSpecialization, TK, DC, StartLoc, IdLoc, SpecializedTemplate, Args, PrevDecl); @@ -722,7 +721,7 @@ ClassTemplateSpecializationDecl::Create(ASTContext &Context, TagKind TK, ClassTemplateSpecializationDecl * ClassTemplateSpecializationDecl::CreateDeserialized(ASTContext &C, unsigned ID) { - ClassTemplateSpecializationDecl *Result = + auto *Result = new (C, ID) ClassTemplateSpecializationDecl(C, ClassTemplateSpecialization); Result->MayHaveOutOfDateDef = false; return Result; @@ -732,7 +731,7 @@ void ClassTemplateSpecializationDecl::getNameForDiagnostic( raw_ostream &OS, const PrintingPolicy &Policy, bool Qualified) const { NamedDecl::getNameForDiagnostic(OS, Policy, Qualified); - auto *PS = dyn_cast<ClassTemplatePartialSpecializationDecl>(this); + const auto *PS = dyn_cast<ClassTemplatePartialSpecializationDecl>(this); if (const ASTTemplateArgumentListInfo *ArgsAsWritten = PS ? PS->getTemplateArgsAsWritten() : nullptr) { printTemplateArgumentList(OS, ArgsAsWritten->arguments(), Policy); @@ -744,8 +743,8 @@ void ClassTemplateSpecializationDecl::getNameForDiagnostic( ClassTemplateDecl * ClassTemplateSpecializationDecl::getSpecializedTemplate() const { - if (SpecializedPartialSpecialization *PartialSpec - = SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization*>()) + if (const auto *PartialSpec = + SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization*>()) return PartialSpec->PartialSpecialization->getSpecializedTemplate(); return SpecializedTemplate.get<ClassTemplateDecl*>(); } @@ -770,7 +769,7 @@ ClassTemplateSpecializationDecl::getSourceRange() const { // uses ExplicitInfo to record the TypeAsWritten, but the source // locations should be retrieved from the instantiation pattern. using CTPSDecl = ClassTemplatePartialSpecializationDecl; - CTPSDecl *ctpsd = const_cast<CTPSDecl*>(cast<CTPSDecl>(this)); + auto *ctpsd = const_cast<CTPSDecl *>(cast<CTPSDecl>(this)); CTPSDecl *inst_from = ctpsd->getInstantiatedFromMember(); assert(inst_from != nullptr); return inst_from->getSourceRange(); @@ -782,9 +781,9 @@ ClassTemplateSpecializationDecl::getSourceRange() const { inst_from = getInstantiatedFrom(); if (inst_from.isNull()) return getSpecializedTemplate()->getSourceRange(); - if (ClassTemplateDecl *ctd = inst_from.dyn_cast<ClassTemplateDecl*>()) + if (const auto *ctd = inst_from.dyn_cast<ClassTemplateDecl *>()) return ctd->getSourceRange(); - return inst_from.get<ClassTemplatePartialSpecializationDecl*>() + return inst_from.get<ClassTemplatePartialSpecializationDecl *>() ->getSourceRange(); } } @@ -826,7 +825,7 @@ Create(ASTContext &Context, TagKind TK,DeclContext *DC, const ASTTemplateArgumentListInfo *ASTArgInfos = ASTTemplateArgumentListInfo::Create(Context, ArgInfos); - ClassTemplatePartialSpecializationDecl *Result = new (Context, DC) + auto *Result = new (Context, DC) ClassTemplatePartialSpecializationDecl(Context, TK, DC, StartLoc, IdLoc, Params, SpecializedTemplate, Args, ASTArgInfos, PrevDecl); @@ -840,8 +839,7 @@ Create(ASTContext &Context, TagKind TK,DeclContext *DC, ClassTemplatePartialSpecializationDecl * ClassTemplatePartialSpecializationDecl::CreateDeserialized(ASTContext &C, unsigned ID) { - ClassTemplatePartialSpecializationDecl *Result = - new (C, ID) ClassTemplatePartialSpecializationDecl(C); + auto *Result = new (C, ID) ClassTemplatePartialSpecializationDecl(C); Result->MayHaveOutOfDateDef = false; return Result; } @@ -887,7 +885,7 @@ TypeAliasTemplateDecl *TypeAliasTemplateDecl::CreateDeserialized(ASTContext &C, RedeclarableTemplateDecl::CommonBase * TypeAliasTemplateDecl::newCommon(ASTContext &C) const { - Common *CommonPtr = new (C) Common; + auto *CommonPtr = new (C) Common; C.addDestruction(CommonPtr); return CommonPtr; } @@ -950,7 +948,7 @@ VarTemplateDecl::getPartialSpecializations() { RedeclarableTemplateDecl::CommonBase * VarTemplateDecl::newCommon(ASTContext &C) const { - Common *CommonPtr = new (C) Common; + auto *CommonPtr = new (C) Common; C.addDestruction(CommonPtr); return CommonPtr; } @@ -1048,7 +1046,7 @@ void VarTemplateSpecializationDecl::getNameForDiagnostic( raw_ostream &OS, const PrintingPolicy &Policy, bool Qualified) const { NamedDecl::getNameForDiagnostic(OS, Policy, Qualified); - auto *PS = dyn_cast<VarTemplatePartialSpecializationDecl>(this); + const auto *PS = dyn_cast<VarTemplatePartialSpecializationDecl>(this); if (const ASTTemplateArgumentListInfo *ArgsAsWritten = PS ? PS->getTemplateArgsAsWritten() : nullptr) { printTemplateArgumentList(OS, ArgsAsWritten->arguments(), Policy); @@ -1059,7 +1057,7 @@ void VarTemplateSpecializationDecl::getNameForDiagnostic( } VarTemplateDecl *VarTemplateSpecializationDecl::getSpecializedTemplate() const { - if (SpecializedPartialSpecialization *PartialSpec = + if (const auto *PartialSpec = SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization *>()) return PartialSpec->PartialSpecialization->getSpecializedTemplate(); return SpecializedTemplate.get<VarTemplateDecl *>(); @@ -1104,7 +1102,7 @@ VarTemplatePartialSpecializationDecl::Create( const ASTTemplateArgumentListInfo *ASTArgInfos = ASTTemplateArgumentListInfo::Create(Context, ArgInfos); - VarTemplatePartialSpecializationDecl *Result = + auto *Result = new (Context, DC) VarTemplatePartialSpecializationDecl( Context, DC, StartLoc, IdLoc, Params, SpecializedTemplate, T, TInfo, S, Args, ASTArgInfos); diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 7ddab9356b54..193efa4e097d 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -108,7 +108,7 @@ const Expr *Expr::skipRValueSubobjectAdjustments( } } } else if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) { - if (BO->isPtrMemOp()) { + if (BO->getOpcode() == BO_PtrMemD) { assert(BO->getRHS()->isRValue()); E = BO->getLHS(); const MemberPointerType *MPT = @@ -230,7 +230,7 @@ SourceLocation Expr::getExprLoc() const { // Primary Expressions. //===----------------------------------------------------------------------===// -/// \brief Compute the type-, value-, and instantiation-dependence of a +/// Compute the type-, value-, and instantiation-dependence of a /// declaration reference /// based on the declaration being referenced. static void computeDeclRefDependence(const ASTContext &Ctx, NamedDecl *D, @@ -484,6 +484,8 @@ StringRef PredefinedExpr::getIdentTypeName(PredefinedExpr::IdentType IT) { return "__PRETTY_FUNCTION__"; case FuncSig: return "__FUNCSIG__"; + case LFuncSig: + return "L__FUNCSIG__"; case PrettyFunctionNoVirtual: break; } @@ -536,7 +538,8 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) { return Out.str(); } if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CurrentDecl)) { - if (IT != PrettyFunction && IT != PrettyFunctionNoVirtual && IT != FuncSig) + if (IT != PrettyFunction && IT != PrettyFunctionNoVirtual && + IT != FuncSig && IT != LFuncSig) return FD->getNameAsString(); SmallString<256> Name; @@ -561,7 +564,7 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) { if (FD->hasWrittenPrototype()) FT = dyn_cast<FunctionProtoType>(AFT); - if (IT == FuncSig) { + if (IT == FuncSig || IT == LFuncSig) { switch (AFT->getCallConv()) { case CC_C: POut << "__cdecl "; break; case CC_X86StdCall: POut << "__stdcall "; break; @@ -586,7 +589,8 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) { if (FT->isVariadic()) { if (FD->getNumParams()) POut << ", "; POut << "..."; - } else if ((IT == FuncSig || !Context.getLangOpts().CPlusPlus) && + } else if ((IT == FuncSig || IT == LFuncSig || + !Context.getLangOpts().CPlusPlus) && !Decl->getNumParams()) { POut << "void"; } @@ -755,6 +759,36 @@ IntegerLiteral::Create(const ASTContext &C, EmptyShell Empty) { return new (C) IntegerLiteral(Empty); } +FixedPointLiteral::FixedPointLiteral(const ASTContext &C, const llvm::APInt &V, + QualType type, SourceLocation l, + unsigned Scale) + : Expr(FixedPointLiteralClass, type, VK_RValue, OK_Ordinary, false, false, + false, false), + Loc(l), Scale(Scale) { + assert(type->isFixedPointType() && "Illegal type in FixedPointLiteral"); + assert(V.getBitWidth() == C.getTypeInfo(type).Width && + "Fixed point type is not the correct size for constant."); + setValue(C, V); +} + +FixedPointLiteral *FixedPointLiteral::CreateFromRawInt(const ASTContext &C, + const llvm::APInt &V, + QualType type, + SourceLocation l, + unsigned Scale) { + return new (C) FixedPointLiteral(C, V, type, l, Scale); +} + +std::string FixedPointLiteral::getValueAsString(unsigned Radix) const { + // Currently the longest decimal number that can be printed is the max for an + // unsigned long _Accum: 4294967295.99999999976716935634613037109375 + // which is 43 characters. + SmallString<64> S; + FixedPointValueToString( + S, llvm::APSInt::getUnsigned(getValue().getZExtValue()), Scale, Radix); + return S.str(); +} + FloatingLiteral::FloatingLiteral(const ASTContext &C, const llvm::APFloat &V, bool isexact, QualType Type, SourceLocation L) : Expr(FloatingLiteralClass, Type, VK_RValue, OK_Ordinary, false, false, @@ -881,7 +915,8 @@ StringLiteral *StringLiteral::CreateEmpty(const ASTContext &C, void *Mem = C.Allocate(sizeof(StringLiteral) + sizeof(SourceLocation) * (NumStrs - 1), alignof(StringLiteral)); - StringLiteral *SL = new (Mem) StringLiteral(QualType()); + StringLiteral *SL = + new (Mem) StringLiteral(C.adjustStringLiteralBaseType(QualType())); SL->CharByteWidth = 0; SL->Length = 0; SL->NumConcatenated = NumStrs; @@ -1633,8 +1668,8 @@ bool CastExpr::CastConsistency() const { return true; } -const char *CastExpr::getCastKindName() const { - switch (getCastKind()) { +const char *CastExpr::getCastKindName(CastKind CK) { + switch (CK) { #define CAST_OPERATION(Name) case CK_##Name: return #Name; #include "clang/AST/OperationKinds.def" } @@ -1642,23 +1677,22 @@ const char *CastExpr::getCastKindName() const { } namespace { - Expr *skipImplicitTemporary(Expr *expr) { + const Expr *skipImplicitTemporary(const Expr *E) { // Skip through reference binding to temporary. - if (MaterializeTemporaryExpr *Materialize - = dyn_cast<MaterializeTemporaryExpr>(expr)) - expr = Materialize->GetTemporaryExpr(); + if (auto *Materialize = dyn_cast<MaterializeTemporaryExpr>(E)) + E = Materialize->GetTemporaryExpr(); // Skip any temporary bindings; they're implicit. - if (CXXBindTemporaryExpr *Binder = dyn_cast<CXXBindTemporaryExpr>(expr)) - expr = Binder->getSubExpr(); + if (auto *Binder = dyn_cast<CXXBindTemporaryExpr>(E)) + E = Binder->getSubExpr(); - return expr; + return E; } } Expr *CastExpr::getSubExprAsWritten() { - Expr *SubExpr = nullptr; - CastExpr *E = this; + const Expr *SubExpr = nullptr; + const CastExpr *E = this; do { SubExpr = skipImplicitTemporary(E->getSubExpr()); @@ -1671,15 +1705,33 @@ Expr *CastExpr::getSubExprAsWritten() { assert((isa<CXXMemberCallExpr>(SubExpr) || isa<BlockExpr>(SubExpr)) && "Unexpected SubExpr for CK_UserDefinedConversion."); - if (isa<CXXMemberCallExpr>(SubExpr)) - SubExpr = cast<CXXMemberCallExpr>(SubExpr)->getImplicitObjectArgument(); + if (auto *MCE = dyn_cast<CXXMemberCallExpr>(SubExpr)) + SubExpr = MCE->getImplicitObjectArgument(); } // If the subexpression we're left with is an implicit cast, look // through that, too. } while ((E = dyn_cast<ImplicitCastExpr>(SubExpr))); - return SubExpr; + return const_cast<Expr*>(SubExpr); +} + +NamedDecl *CastExpr::getConversionFunction() const { + const Expr *SubExpr = nullptr; + + for (const CastExpr *E = this; E; E = dyn_cast<ImplicitCastExpr>(SubExpr)) { + SubExpr = skipImplicitTemporary(E->getSubExpr()); + + if (E->getCastKind() == CK_ConstructorConversion) + return cast<CXXConstructExpr>(SubExpr)->getConstructor(); + + if (E->getCastKind() == CK_UserDefinedConversion) { + if (auto *MCE = dyn_cast<CXXMemberCallExpr>(SubExpr)) + return MCE->getMethodDecl(); + } + } + + return nullptr; } CXXBaseSpecifier **CastExpr::path_buffer() { @@ -2049,6 +2101,10 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc, case GenericSelectionExprClass: return cast<GenericSelectionExpr>(this)->getResultExpr()-> isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx); + case CoawaitExprClass: + case CoyieldExprClass: + return cast<CoroutineSuspendExpr>(this)->getResumeExpr()-> + isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx); case ChooseExprClass: return cast<ChooseExpr>(this)->getChosenSubExpr()-> isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx); @@ -2628,7 +2684,7 @@ bool Expr::isDefaultArgument() const { return isa<CXXDefaultArgExpr>(E); } -/// \brief Skip over any no-op casts and any temporary-binding +/// Skip over any no-op casts and any temporary-binding /// expressions. static const Expr *skipTemporaryBindingsNoOpCastsAndParens(const Expr *E) { if (const MaterializeTemporaryExpr *M = dyn_cast<MaterializeTemporaryExpr>(E)) @@ -2917,8 +2973,20 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef, return false; } +bool CallExpr::isBuiltinAssumeFalse(const ASTContext &Ctx) const { + const FunctionDecl* FD = getDirectCallee(); + if (!FD || (FD->getBuiltinID() != Builtin::BI__assume && + FD->getBuiltinID() != Builtin::BI__builtin_assume)) + return false; + + const Expr* Arg = getArg(0); + bool ArgVal; + return !Arg->isValueDependent() && + Arg->EvaluateAsBooleanCondition(ArgVal, Ctx) && !ArgVal; +} + namespace { - /// \brief Look for any side effects within a Stmt. + /// Look for any side effects within a Stmt. class SideEffectFinder : public ConstEvaluatedExprVisitor<SideEffectFinder> { typedef ConstEvaluatedExprVisitor<SideEffectFinder> Inherited; const bool IncludePossibleEffects; @@ -2974,6 +3042,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx, case ObjCIvarRefExprClass: case PredefinedExprClass: case IntegerLiteralClass: + case FixedPointLiteralClass: case FloatingLiteralClass: case ImaginaryLiteralClass: case StringLiteralClass: @@ -3214,7 +3283,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx, } namespace { - /// \brief Look for a call to a non-trivial function within an expression. + /// Look for a call to a non-trivial function within an expression. class NonTrivialCallFinder : public ConstEvaluatedExprVisitor<NonTrivialCallFinder> { typedef ConstEvaluatedExprVisitor<NonTrivialCallFinder> Inherited; @@ -3390,7 +3459,7 @@ Expr::isNullPointerConstant(ASTContext &Ctx, return NPCK_ZeroExpression; } -/// \brief If this expression is an l-value for an Objective C +/// If this expression is an l-value for an Objective C /// property, find the underlying property reference expression. const ObjCPropertyRefExpr *Expr::getObjCProperty() const { const Expr *E = this; @@ -3446,10 +3515,11 @@ FieldDecl *Expr::getSourceBitField() { if (Field->isBitField()) return Field; - if (ObjCIvarRefExpr *IvarRef = dyn_cast<ObjCIvarRefExpr>(E)) - if (FieldDecl *Ivar = dyn_cast<FieldDecl>(IvarRef->getDecl())) - if (Ivar->isBitField()) - return Ivar; + if (ObjCIvarRefExpr *IvarRef = dyn_cast<ObjCIvarRefExpr>(E)) { + FieldDecl *Ivar = IvarRef->getDecl(); + if (Ivar->isBitField()) + return Ivar; + } if (DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(E)) { if (FieldDecl *Field = dyn_cast<FieldDecl>(DeclRef->getDecl())) @@ -3813,7 +3883,7 @@ Expr *DesignatedInitExpr::getArrayRangeEnd(const Designator &D) const { return getSubExpr(D.ArrayOrRange.Index + 2); } -/// \brief Replaces the designator at index @p Idx with the series +/// Replaces the designator at index @p Idx with the series /// of designators in [First, Last). void DesignatedInitExpr::ExpandDesignator(const ASTContext &C, unsigned Idx, const Designator *First, @@ -4034,6 +4104,8 @@ unsigned AtomicExpr::getNumSubExprs(AtomicOp Op) { case AO__atomic_or_fetch: case AO__atomic_xor_fetch: case AO__atomic_nand_fetch: + case AO__atomic_fetch_min: + case AO__atomic_fetch_max: return 3; case AO__opencl_atomic_store: diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index a0d611381123..3a204c244f68 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -169,8 +169,8 @@ void CXXNewExpr::AllocateArgsArray(const ASTContext &C, bool isArray, } bool CXXNewExpr::shouldNullCheckAllocation(const ASTContext &Ctx) const { - return getOperatorNew()->getType()->castAs<FunctionProtoType>()->isNothrow( - Ctx) && + return getOperatorNew()->getType()->castAs<FunctionProtoType>() + ->isNothrow() && !getOperatorNew()->isReservedGlobalPlacementOperator(); } @@ -181,7 +181,7 @@ QualType CXXDeleteExpr::getDestroyedType() const { // For a destroying operator delete, we may have implicitly converted the // pointer type to the type of the parameter of the 'operator delete' // function. - while (auto *ICE = dyn_cast<ImplicitCastExpr>(Arg)) { + while (const auto *ICE = dyn_cast<ImplicitCastExpr>(Arg)) { if (ICE->getCastKind() == CK_DerivedToBase || ICE->getCastKind() == CK_UncheckedDerivedToBase || ICE->getCastKind() == CK_NoOp) { @@ -290,7 +290,7 @@ UnresolvedLookupExpr::CreateEmpty(const ASTContext &C, totalSizeToAlloc<ASTTemplateKWAndArgsInfo, TemplateArgumentLoc>( HasTemplateKWAndArgsInfo, NumTemplateArgs); void *Mem = C.Allocate(Size, alignof(UnresolvedLookupExpr)); - UnresolvedLookupExpr *E = new (Mem) UnresolvedLookupExpr(EmptyShell()); + auto *E = new (Mem) UnresolvedLookupExpr(EmptyShell()); E->HasTemplateKWAndArgsInfo = HasTemplateKWAndArgsInfo; return E; } @@ -442,8 +442,8 @@ DependentScopeDeclRefExpr::CreateEmpty(const ASTContext &C, totalSizeToAlloc<ASTTemplateKWAndArgsInfo, TemplateArgumentLoc>( HasTemplateKWAndArgsInfo, NumTemplateArgs); void *Mem = C.Allocate(Size); - DependentScopeDeclRefExpr *E - = new (Mem) DependentScopeDeclRefExpr(QualType(), NestedNameSpecifierLoc(), + auto *E = + new (Mem) DependentScopeDeclRefExpr(QualType(), NestedNameSpecifierLoc(), SourceLocation(), DeclarationNameInfo(), nullptr); E->HasTemplateKWAndArgsInfo = HasTemplateKWAndArgsInfo; @@ -504,9 +504,9 @@ SourceRange CXXOperatorCallExpr::getSourceRangeImpl() const { Expr *CXXMemberCallExpr::getImplicitObjectArgument() const { const Expr *Callee = getCallee()->IgnoreParens(); - if (const MemberExpr *MemExpr = dyn_cast<MemberExpr>(Callee)) + if (const auto *MemExpr = dyn_cast<MemberExpr>(Callee)) return MemExpr->getBase(); - if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(Callee)) + if (const auto *BO = dyn_cast<BinaryOperator>(Callee)) if (BO->getOpcode() == BO_PtrMemD || BO->getOpcode() == BO_PtrMemI) return BO->getLHS(); @@ -515,8 +515,7 @@ Expr *CXXMemberCallExpr::getImplicitObjectArgument() const { } CXXMethodDecl *CXXMemberCallExpr::getMethodDecl() const { - if (const MemberExpr *MemExpr = - dyn_cast<MemberExpr>(getCallee()->IgnoreParens())) + if (const auto *MemExpr = dyn_cast<MemberExpr>(getCallee()->IgnoreParens())) return cast<CXXMethodDecl>(MemExpr->getMemberDecl()); // FIXME: Will eventually need to cope with member pointers. @@ -561,9 +560,9 @@ CXXStaticCastExpr *CXXStaticCastExpr::Create(const ASTContext &C, QualType T, SourceRange AngleBrackets) { unsigned PathSize = (BasePath ? BasePath->size() : 0); void *Buffer = C.Allocate(totalSizeToAlloc<CXXBaseSpecifier *>(PathSize)); - CXXStaticCastExpr *E = - new (Buffer) CXXStaticCastExpr(T, VK, K, Op, PathSize, WrittenTy, L, - RParenLoc, AngleBrackets); + auto *E = + new (Buffer) CXXStaticCastExpr(T, VK, K, Op, PathSize, WrittenTy, L, + RParenLoc, AngleBrackets); if (PathSize) std::uninitialized_copy_n(BasePath->data(), BasePath->size(), E->getTrailingObjects<CXXBaseSpecifier *>()); @@ -586,9 +585,9 @@ CXXDynamicCastExpr *CXXDynamicCastExpr::Create(const ASTContext &C, QualType T, SourceRange AngleBrackets) { unsigned PathSize = (BasePath ? BasePath->size() : 0); void *Buffer = C.Allocate(totalSizeToAlloc<CXXBaseSpecifier *>(PathSize)); - CXXDynamicCastExpr *E = - new (Buffer) CXXDynamicCastExpr(T, VK, K, Op, PathSize, WrittenTy, L, - RParenLoc, AngleBrackets); + auto *E = + new (Buffer) CXXDynamicCastExpr(T, VK, K, Op, PathSize, WrittenTy, L, + RParenLoc, AngleBrackets); if (PathSize) std::uninitialized_copy_n(BasePath->data(), BasePath->size(), E->getTrailingObjects<CXXBaseSpecifier *>()); @@ -614,7 +613,7 @@ bool CXXDynamicCastExpr::isAlwaysNull() const QualType SrcType = getSubExpr()->getType(); QualType DestType = getType(); - if (const PointerType *SrcPTy = SrcType->getAs<PointerType>()) { + if (const auto *SrcPTy = SrcType->getAs<PointerType>()) { SrcType = SrcPTy->getPointeeType(); DestType = DestType->castAs<PointerType>()->getPointeeType(); } @@ -622,14 +621,14 @@ bool CXXDynamicCastExpr::isAlwaysNull() const if (DestType->isVoidType()) return false; - const CXXRecordDecl *SrcRD = - cast<CXXRecordDecl>(SrcType->castAs<RecordType>()->getDecl()); + const auto *SrcRD = + cast<CXXRecordDecl>(SrcType->castAs<RecordType>()->getDecl()); if (!SrcRD->hasAttr<FinalAttr>()) return false; - const CXXRecordDecl *DestRD = - cast<CXXRecordDecl>(DestType->castAs<RecordType>()->getDecl()); + const auto *DestRD = + cast<CXXRecordDecl>(DestType->castAs<RecordType>()->getDecl()); return !DestRD->isDerivedFrom(SrcRD); } @@ -643,9 +642,9 @@ CXXReinterpretCastExpr::Create(const ASTContext &C, QualType T, SourceRange AngleBrackets) { unsigned PathSize = (BasePath ? BasePath->size() : 0); void *Buffer = C.Allocate(totalSizeToAlloc<CXXBaseSpecifier *>(PathSize)); - CXXReinterpretCastExpr *E = - new (Buffer) CXXReinterpretCastExpr(T, VK, K, Op, PathSize, WrittenTy, L, - RParenLoc, AngleBrackets); + auto *E = + new (Buffer) CXXReinterpretCastExpr(T, VK, K, Op, PathSize, WrittenTy, L, + RParenLoc, AngleBrackets); if (PathSize) std::uninitialized_copy_n(BasePath->data(), BasePath->size(), E->getTrailingObjects<CXXBaseSpecifier *>()); @@ -678,8 +677,8 @@ CXXFunctionalCastExpr::Create(const ASTContext &C, QualType T, ExprValueKind VK, SourceLocation L, SourceLocation R) { unsigned PathSize = (BasePath ? BasePath->size() : 0); void *Buffer = C.Allocate(totalSizeToAlloc<CXXBaseSpecifier *>(PathSize)); - CXXFunctionalCastExpr *E = - new (Buffer) CXXFunctionalCastExpr(T, VK, Written, K, Op, PathSize, L, R); + auto *E = + new (Buffer) CXXFunctionalCastExpr(T, VK, Written, K, Op, PathSize, L, R); if (PathSize) std::uninitialized_copy_n(BasePath->data(), BasePath->size(), E->getTrailingObjects<CXXBaseSpecifier *>()); @@ -1079,7 +1078,7 @@ CXXUnresolvedConstructExpr::CXXUnresolvedConstructExpr(TypeSourceInfo *Type, true, true, Type->getType()->containsUnexpandedParameterPack()), Type(Type), LParenLoc(LParenLoc), RParenLoc(RParenLoc), NumArgs(Args.size()) { - Expr **StoredArgs = getTrailingObjects<Expr *>(); + auto **StoredArgs = getTrailingObjects<Expr *>(); for (unsigned I = 0; I != Args.size(); ++I) { if (Args[I]->containsUnexpandedParameterPack()) ExprBits.ContainsUnexpandedParameterPack = true; @@ -1176,12 +1175,12 @@ CXXDependentScopeMemberExpr::CreateEmpty(const ASTContext &C, totalSizeToAlloc<ASTTemplateKWAndArgsInfo, TemplateArgumentLoc>( HasTemplateKWAndArgsInfo, NumTemplateArgs); void *Mem = C.Allocate(Size, alignof(CXXDependentScopeMemberExpr)); - CXXDependentScopeMemberExpr *E - = new (Mem) CXXDependentScopeMemberExpr(C, nullptr, QualType(), - false, SourceLocation(), - NestedNameSpecifierLoc(), - SourceLocation(), nullptr, - DeclarationNameInfo(), nullptr); + auto *E = + new (Mem) CXXDependentScopeMemberExpr(C, nullptr, QualType(), + false, SourceLocation(), + NestedNameSpecifierLoc(), + SourceLocation(), nullptr, + DeclarationNameInfo(), nullptr); E->HasTemplateKWAndArgsInfo = HasTemplateKWAndArgsInfo; return E; } @@ -1274,7 +1273,7 @@ UnresolvedMemberExpr::CreateEmpty(const ASTContext &C, HasTemplateKWAndArgsInfo, NumTemplateArgs); void *Mem = C.Allocate(Size, alignof(UnresolvedMemberExpr)); - UnresolvedMemberExpr *E = new (Mem) UnresolvedMemberExpr(EmptyShell()); + auto *E = new (Mem) UnresolvedMemberExpr(EmptyShell()); E->HasTemplateKWAndArgsInfo = HasTemplateKWAndArgsInfo; return E; } @@ -1297,7 +1296,7 @@ CXXRecordDecl *UnresolvedMemberExpr::getNamingClass() const { else { QualType BaseType = getBaseType().getNonReferenceType(); if (isArrow()) { - const PointerType *PT = BaseType->getAs<PointerType>(); + const auto *PT = BaseType->getAs<PointerType>(); assert(PT && "base of arrow member access is not pointer"); BaseType = PT->getPointeeType(); } @@ -1330,10 +1329,11 @@ SizeOfPackExpr *SizeOfPackExpr::CreateDeserialized(ASTContext &Context, SubstNonTypeTemplateParmPackExpr:: SubstNonTypeTemplateParmPackExpr(QualType T, + ExprValueKind ValueKind, NonTypeTemplateParmDecl *Param, SourceLocation NameLoc, const TemplateArgument &ArgPack) - : Expr(SubstNonTypeTemplateParmPackExprClass, T, VK_RValue, OK_Ordinary, + : Expr(SubstNonTypeTemplateParmPackExprClass, T, ValueKind, OK_Ordinary, true, true, true, true), Param(Param), Arguments(ArgPack.pack_begin()), NumArguments(ArgPack.pack_size()), NameLoc(NameLoc) {} @@ -1378,7 +1378,7 @@ void MaterializeTemporaryExpr::setExtendingDecl(const ValueDecl *ExtendedBy, // We may need to allocate extra storage for the mangling number and the // extended-by ValueDecl. if (!State.is<ExtraState *>()) { - auto ES = new (ExtendedBy->getASTContext()) ExtraState; + auto *ES = new (ExtendedBy->getASTContext()) ExtraState; ES->Temporary = State.get<Stmt *>(); State = ES; } @@ -1402,7 +1402,7 @@ TypeTraitExpr::TypeTraitExpr(QualType T, SourceLocation Loc, TypeTrait Kind, TypeTraitExprBits.Value = Value; TypeTraitExprBits.NumArgs = Args.size(); - TypeSourceInfo **ToArgs = getTrailingObjects<TypeSourceInfo *>(); + auto **ToArgs = getTrailingObjects<TypeSourceInfo *>(); for (unsigned I = 0, N = Args.size(); I != N; ++I) { if (Args[I]->getType()->isDependentType()) diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp index 3bb2b4eb5fc1..c5b3b361a0a5 100644 --- a/lib/AST/ExprClassification.cpp +++ b/lib/AST/ExprClassification.cpp @@ -1,4 +1,4 @@ -//===--- ExprClassification.cpp - Expression AST Node Implementation ------===// +//===- ExprClassification.cpp - Expression AST Node Implementation --------===// // // The LLVM Compiler Infrastructure // @@ -19,9 +19,10 @@ #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" #include "llvm/Support/ErrorHandling.h" + using namespace clang; -typedef Expr::Classification Cl; +using Cl = Expr::Classification; static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E); static Cl::Kinds ClassifyDecl(ASTContext &Ctx, const Decl *D); @@ -160,6 +161,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::ShuffleVectorExprClass: case Expr::ConvertVectorExprClass: case Expr::IntegerLiteralClass: + case Expr::FixedPointLiteralClass: case Expr::CharacterLiteralClass: case Expr::AddrLabelExprClass: case Expr::CXXDeleteExprClass: @@ -348,14 +350,14 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::BinaryConditionalOperatorClass: { if (!Lang.CPlusPlus) return Cl::CL_PRValue; - const BinaryConditionalOperator *co = cast<BinaryConditionalOperator>(E); + const auto *co = cast<BinaryConditionalOperator>(E); return ClassifyConditional(Ctx, co->getTrueExpr(), co->getFalseExpr()); } case Expr::ConditionalOperatorClass: { // Once again, only C++ is interesting. if (!Lang.CPlusPlus) return Cl::CL_PRValue; - const ConditionalOperator *co = cast<ConditionalOperator>(E); + const auto *co = cast<ConditionalOperator>(E); return ClassifyConditional(Ctx, co->getTrueExpr(), co->getFalseExpr()); } @@ -385,7 +387,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::StmtExprClass: { const CompoundStmt *S = cast<StmtExpr>(E)->getSubStmt(); - if (const Expr *LastExpr = dyn_cast_or_null<Expr>(S->body_back())) + if (const auto *LastExpr = dyn_cast_or_null<Expr>(S->body_back())) return ClassifyUnnamed(Ctx, LastExpr->getType()); return Cl::CL_PRValue; } @@ -434,8 +436,7 @@ static Cl::Kinds ClassifyDecl(ASTContext &Ctx, const Decl *D) { return Cl::CL_MemberFunction; bool islvalue; - if (const NonTypeTemplateParmDecl *NTTParm = - dyn_cast<NonTypeTemplateParmDecl>(D)) + if (const auto *NTTParm = dyn_cast<NonTypeTemplateParmDecl>(D)) islvalue = NTTParm->getType()->isReferenceType(); else islvalue = isa<VarDecl>(D) || isa<FieldDecl>(D) || @@ -461,7 +462,7 @@ static Cl::Kinds ClassifyUnnamed(ASTContext &Ctx, QualType T) { // otherwise. if (T->isLValueReferenceType()) return Cl::CL_LValue; - const RValueReferenceType *RV = T->getAs<RValueReferenceType>(); + const auto *RV = T->getAs<RValueReferenceType>(); if (!RV) // Could still be a class temporary, though. return ClassifyTemporary(T); @@ -491,7 +492,7 @@ static Cl::Kinds ClassifyMemberExpr(ASTContext &Ctx, const MemberExpr *E) { // C++ [expr.ref]p3: E1->E2 is converted to the equivalent form (*(E1)).E2. // C++ [expr.ref]p4: If E2 is declared to have type "reference to T", then // E1.E2 is an lvalue. - if (ValueDecl *Value = dyn_cast<ValueDecl>(Member)) + if (const auto *Value = dyn_cast<ValueDecl>(Member)) if (Value->getType()->isReferenceType()) return Cl::CL_LValue; @@ -517,7 +518,7 @@ static Cl::Kinds ClassifyMemberExpr(ASTContext &Ctx, const MemberExpr *E) { // -- If it refers to a static member function [...], then E1.E2 is an // lvalue; [...] // -- Otherwise [...] E1.E2 is a prvalue. - if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Member)) + if (const auto *Method = dyn_cast<CXXMethodDecl>(Member)) return Method->isStatic() ? Cl::CL_LValue : Cl::CL_MemberFunction; // -- If E2 is a member enumerator [...], the expression E1.E2 is a prvalue. @@ -599,8 +600,7 @@ static Cl::ModifiableType IsModifiable(ASTContext &Ctx, const Expr *E, if (Kind == Cl::CL_PRValue) { // For the sake of better diagnostics, we want to specifically recognize // use of the GCC cast-as-lvalue extension. - if (const ExplicitCastExpr *CE = - dyn_cast<ExplicitCastExpr>(E->IgnoreParens())) { + if (const auto *CE = dyn_cast<ExplicitCastExpr>(E->IgnoreParens())) { if (CE->getSubExpr()->IgnoreParenImpCasts()->isLValue()) { Loc = CE->getExprLoc(); return Cl::CM_LValueCast; @@ -617,7 +617,7 @@ static Cl::ModifiableType IsModifiable(ASTContext &Ctx, const Expr *E, // Assignment to a property in ObjC is an implicit setter access. But a // setter might not exist. - if (const ObjCPropertyRefExpr *Expr = dyn_cast<ObjCPropertyRefExpr>(E)) { + if (const auto *Expr = dyn_cast<ObjCPropertyRefExpr>(E)) { if (Expr->isImplicitProperty() && Expr->getImplicitPropertySetter() == nullptr) return Cl::CM_NoSetterProperty; diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 8d9b3c3bebc0..e69914f25da2 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -48,6 +48,8 @@ #include <cstring> #include <functional> +#define DEBUG_TYPE "exprconstant" + using namespace clang; using llvm::APSInt; using llvm::APFloat; @@ -61,14 +63,22 @@ namespace { static QualType getType(APValue::LValueBase B) { if (!B) return QualType(); - if (const ValueDecl *D = B.dyn_cast<const ValueDecl*>()) + if (const ValueDecl *D = B.dyn_cast<const ValueDecl*>()) { // FIXME: It's unclear where we're supposed to take the type from, and - // this actually matters for arrays of unknown bound. Using the type of - // the most recent declaration isn't clearly correct in general. Eg: + // this actually matters for arrays of unknown bound. Eg: // // extern int arr[]; void f() { extern int arr[3]; }; // constexpr int *p = &arr[1]; // valid? - return cast<ValueDecl>(D->getMostRecentDecl())->getType(); + // + // For now, we take the array bound from the most recent declaration. + for (auto *Redecl = cast<ValueDecl>(D->getMostRecentDecl()); Redecl; + Redecl = cast_or_null<ValueDecl>(Redecl->getPreviousDecl())) { + QualType T = Redecl->getType(); + if (!T->isIncompleteArrayType()) + return T; + } + return D->getType(); + } const Expr *Base = B.get<const Expr*>(); @@ -131,7 +141,11 @@ namespace { E = E->IgnoreParens(); // If we're doing a variable assignment from e.g. malloc(N), there will - // probably be a cast of some kind. Ignore it. + // probably be a cast of some kind. In exotic cases, we might also see a + // top-level ExprWithCleanups. Ignore them either way. + if (const auto *EC = dyn_cast<ExprWithCleanups>(E)) + E = EC->getSubExpr()->IgnoreParens(); + if (const auto *Cast = dyn_cast<CastExpr>(E)) E = Cast->getSubExpr()->IgnoreParens(); @@ -438,8 +452,8 @@ namespace { // Note that we intentionally use std::map here so that references to // values are stable. - typedef std::map<const void*, APValue> MapTy; - typedef MapTy::const_iterator temp_iterator; + typedef std::pair<const void *, unsigned> MapKeyTy; + typedef std::map<MapKeyTy, APValue> MapTy; /// Temporaries - Temporary lvalues materialized within this stack frame. MapTy Temporaries; @@ -449,6 +463,20 @@ namespace { /// Index - The call index of this call. unsigned Index; + /// The stack of integers for tracking version numbers for temporaries. + SmallVector<unsigned, 2> TempVersionStack = {1}; + unsigned CurTempVersion = TempVersionStack.back(); + + unsigned getTempVersion() const { return TempVersionStack.back(); } + + void pushTempVersion() { + TempVersionStack.push_back(++CurTempVersion); + } + + void popTempVersion() { + TempVersionStack.pop_back(); + } + // FIXME: Adding this to every 'CallStackFrame' may have a nontrivial impact // on the overall stack usage of deeply-recursing constexpr evaluataions. // (We should cache this map rather than recomputing it repeatedly.) @@ -465,10 +493,36 @@ namespace { APValue *Arguments); ~CallStackFrame(); - APValue *getTemporary(const void *Key) { - MapTy::iterator I = Temporaries.find(Key); - return I == Temporaries.end() ? nullptr : &I->second; + // Return the temporary for Key whose version number is Version. + APValue *getTemporary(const void *Key, unsigned Version) { + MapKeyTy KV(Key, Version); + auto LB = Temporaries.lower_bound(KV); + if (LB != Temporaries.end() && LB->first == KV) + return &LB->second; + // Pair (Key,Version) wasn't found in the map. Check that no elements + // in the map have 'Key' as their key. + assert((LB == Temporaries.end() || LB->first.first != Key) && + (LB == Temporaries.begin() || std::prev(LB)->first.first != Key) && + "Element with key 'Key' found in map"); + return nullptr; + } + + // Return the current temporary for Key in the map. + APValue *getCurrentTemporary(const void *Key) { + auto UB = Temporaries.upper_bound(MapKeyTy(Key, UINT_MAX)); + if (UB != Temporaries.begin() && std::prev(UB)->first.first == Key) + return &std::prev(UB)->second; + return nullptr; + } + + // Return the version number of the current temporary for Key. + unsigned getCurrentTemporaryVersion(const void *Key) const { + auto UB = Temporaries.upper_bound(MapKeyTy(Key, UINT_MAX)); + if (UB != Temporaries.begin() && std::prev(UB)->first.first == Key) + return std::prev(UB)->first.second; + return 0; } + APValue &createTemporary(const void *Key, bool IsLifetimeExtended); }; @@ -598,7 +652,8 @@ namespace { /// EvaluatingObject - Pair of the AST node that an lvalue represents and /// the call index that that lvalue was allocated in. - typedef std::pair<APValue::LValueBase, unsigned> EvaluatingObject; + typedef std::pair<APValue::LValueBase, std::pair<unsigned, unsigned>> + EvaluatingObject; /// EvaluatingConstructors - Set of objects that are currently being /// constructed. @@ -617,8 +672,10 @@ namespace { } }; - bool isEvaluatingConstructor(APValue::LValueBase Decl, unsigned CallIndex) { - return EvaluatingConstructors.count(EvaluatingObject(Decl, CallIndex)); + bool isEvaluatingConstructor(APValue::LValueBase Decl, unsigned CallIndex, + unsigned Version) { + return EvaluatingConstructors.count( + EvaluatingObject(Decl, {CallIndex, Version})); } /// The current array initialization index, if we're performing array @@ -629,11 +686,11 @@ namespace { /// notes attached to it will also be stored, otherwise they will not be. bool HasActiveDiagnostic; - /// \brief Have we emitted a diagnostic explaining why we couldn't constant + /// Have we emitted a diagnostic explaining why we couldn't constant /// fold (not just why it's not strictly a constant expression)? bool HasFoldFailureDiagnostic; - /// \brief Whether or not we're currently speculatively evaluating. + /// Whether or not we're currently speculatively evaluating. bool IsSpeculativelyEvaluating; enum EvaluationMode { @@ -714,7 +771,7 @@ namespace { void setEvaluatingDecl(APValue::LValueBase Base, APValue &Value) { EvaluatingDecl = Base; EvaluatingDeclValue = &Value; - EvaluatingConstructors.insert({Base, 0}); + EvaluatingConstructors.insert({Base, {0, 0}}); } const LangOptions &getLangOpts() const { return Ctx.getLangOpts(); } @@ -1078,11 +1135,16 @@ namespace { unsigned OldStackSize; public: ScopeRAII(EvalInfo &Info) - : Info(Info), OldStackSize(Info.CleanupStack.size()) {} + : Info(Info), OldStackSize(Info.CleanupStack.size()) { + // Push a new temporary version. This is needed to distinguish between + // temporaries created in different iterations of a loop. + Info.CurrentCall->pushTempVersion(); + } ~ScopeRAII() { // Body moved to a static method to encourage the compiler to inline away // instances of this class. cleanup(Info, OldStackSize); + Info.CurrentCall->popTempVersion(); } private: static void cleanup(EvalInfo &Info, unsigned OldStackSize) { @@ -1162,7 +1224,8 @@ CallStackFrame::~CallStackFrame() { APValue &CallStackFrame::createTemporary(const void *Key, bool IsLifetimeExtended) { - APValue &Result = Temporaries[Key]; + unsigned Version = Info.CurrentCall->getTempVersion(); + APValue &Result = Temporaries[MapKeyTy(Key, Version)]; assert(Result.isUninit() && "temporary created multiple times"); Info.CleanupStack.push_back(Cleanup(&Result, IsLifetimeExtended)); return Result; @@ -1254,27 +1317,27 @@ namespace { struct LValue { APValue::LValueBase Base; CharUnits Offset; - unsigned InvalidBase : 1; - unsigned CallIndex : 31; SubobjectDesignator Designator; - bool IsNullPtr; + bool IsNullPtr : 1; + bool InvalidBase : 1; const APValue::LValueBase getLValueBase() const { return Base; } CharUnits &getLValueOffset() { return Offset; } const CharUnits &getLValueOffset() const { return Offset; } - unsigned getLValueCallIndex() const { return CallIndex; } SubobjectDesignator &getLValueDesignator() { return Designator; } const SubobjectDesignator &getLValueDesignator() const { return Designator;} bool isNullPointer() const { return IsNullPtr;} + unsigned getLValueCallIndex() const { return Base.getCallIndex(); } + unsigned getLValueVersion() const { return Base.getVersion(); } + void moveInto(APValue &V) const { if (Designator.Invalid) - V = APValue(Base, Offset, APValue::NoLValuePath(), CallIndex, - IsNullPtr); + V = APValue(Base, Offset, APValue::NoLValuePath(), IsNullPtr); else { assert(!InvalidBase && "APValues can't handle invalid LValue bases"); V = APValue(Base, Offset, Designator.Entries, - Designator.IsOnePastTheEnd, CallIndex, IsNullPtr); + Designator.IsOnePastTheEnd, IsNullPtr); } } void setFrom(ASTContext &Ctx, const APValue &V) { @@ -1282,12 +1345,11 @@ namespace { Base = V.getLValueBase(); Offset = V.getLValueOffset(); InvalidBase = false; - CallIndex = V.getLValueCallIndex(); Designator = SubobjectDesignator(Ctx, V); IsNullPtr = V.isNullPointer(); } - void set(APValue::LValueBase B, unsigned I = 0, bool BInvalid = false) { + void set(APValue::LValueBase B, bool BInvalid = false) { #ifndef NDEBUG // We only allow a few types of invalid bases. Enforce that here. if (BInvalid) { @@ -1300,7 +1362,6 @@ namespace { Base = B; Offset = CharUnits::fromQuantity(0); InvalidBase = BInvalid; - CallIndex = I; Designator = SubobjectDesignator(getType(B)); IsNullPtr = false; } @@ -1309,13 +1370,12 @@ namespace { Base = (Expr *)nullptr; Offset = CharUnits::fromQuantity(TargetVal); InvalidBase = false; - CallIndex = 0; Designator = SubobjectDesignator(PointerTy->getPointeeType()); IsNullPtr = true; } void setInvalid(APValue::LValueBase B, unsigned I = 0) { - set(B, I, true); + set(B, true); } // Check that this LValue is not based on a null pointer. If it is, produce @@ -1517,6 +1577,15 @@ static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result); // Misc utilities //===----------------------------------------------------------------------===// +/// A helper function to create a temporary and set an LValue. +template <class KeyTy> +static APValue &createTemporary(const KeyTy *Key, bool IsLifetimeExtended, + LValue &LV, CallStackFrame &Frame) { + LV.set({Key, Frame.Info.CurrentCall->Index, + Frame.Info.CurrentCall->getTempVersion()}); + return Frame.createTemporary(Key, IsLifetimeExtended); +} + /// Negate an APSInt in place, converting it to a signed form if necessary, and /// preserving its value (by extending by up to one bit as needed). static void negateAsSigned(APSInt &Int) { @@ -1651,7 +1720,8 @@ static void NoteLValueLocation(EvalInfo &Info, APValue::LValueBase Base) { /// value for an address or reference constant expression. Return true if we /// can fold this expression, whether or not it's a constant expression. static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc, - QualType Type, const LValue &LVal) { + QualType Type, const LValue &LVal, + Expr::ConstExprUsage Usage) { bool IsReferenceType = Type->isReferenceType(); APValue::LValueBase Base = LVal.getLValueBase(); @@ -1684,7 +1754,7 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc, return false; // A dllimport variable never acts like a constant. - if (Var->hasAttr<DLLImportAttr>()) + if (Usage == Expr::EvaluateForCodeGen && Var->hasAttr<DLLImportAttr>()) return false; } if (const auto *FD = dyn_cast<const FunctionDecl>(VD)) { @@ -1698,7 +1768,8 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc, // The C language has no notion of ODR; furthermore, it has no notion of // dynamic initialization. This means that we are permitted to // perform initialization with the address of the thunk. - if (Info.getLangOpts().CPlusPlus && FD->hasAttr<DLLImportAttr>()) + if (Info.getLangOpts().CPlusPlus && Usage == Expr::EvaluateForCodeGen && + FD->hasAttr<DLLImportAttr>()) return false; } } @@ -1731,12 +1802,14 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc, static bool CheckMemberPointerConstantExpression(EvalInfo &Info, SourceLocation Loc, QualType Type, - const APValue &Value) { + const APValue &Value, + Expr::ConstExprUsage Usage) { const ValueDecl *Member = Value.getMemberPointerDecl(); const auto *FD = dyn_cast_or_null<CXXMethodDecl>(Member); if (!FD) return true; - return FD->isVirtual() || !FD->hasAttr<DLLImportAttr>(); + return Usage == Expr::EvaluateForMangling || FD->isVirtual() || + !FD->hasAttr<DLLImportAttr>(); } /// Check that this core constant expression is of literal type, and if not, @@ -1774,8 +1847,10 @@ static bool CheckLiteralType(EvalInfo &Info, const Expr *E, /// Check that this core constant expression value is a valid value for a /// constant expression. If not, report an appropriate diagnostic. Does not /// check that the expression is of literal type. -static bool CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc, - QualType Type, const APValue &Value) { +static bool +CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc, QualType Type, + const APValue &Value, + Expr::ConstExprUsage Usage = Expr::EvaluateForCodeGen) { if (Value.isUninit()) { Info.FFDiag(DiagLoc, diag::note_constexpr_uninitialized) << true << Type; @@ -1794,28 +1869,28 @@ static bool CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc, QualType EltTy = Type->castAsArrayTypeUnsafe()->getElementType(); for (unsigned I = 0, N = Value.getArrayInitializedElts(); I != N; ++I) { if (!CheckConstantExpression(Info, DiagLoc, EltTy, - Value.getArrayInitializedElt(I))) + Value.getArrayInitializedElt(I), Usage)) return false; } if (!Value.hasArrayFiller()) return true; - return CheckConstantExpression(Info, DiagLoc, EltTy, - Value.getArrayFiller()); + return CheckConstantExpression(Info, DiagLoc, EltTy, Value.getArrayFiller(), + Usage); } if (Value.isUnion() && Value.getUnionField()) { return CheckConstantExpression(Info, DiagLoc, Value.getUnionField()->getType(), - Value.getUnionValue()); + Value.getUnionValue(), Usage); } if (Value.isStruct()) { RecordDecl *RD = Type->castAs<RecordType>()->getDecl(); if (const CXXRecordDecl *CD = dyn_cast<CXXRecordDecl>(RD)) { unsigned BaseIndex = 0; - for (CXXRecordDecl::base_class_const_iterator I = CD->bases_begin(), - End = CD->bases_end(); I != End; ++I, ++BaseIndex) { - if (!CheckConstantExpression(Info, DiagLoc, I->getType(), - Value.getStructBase(BaseIndex))) + for (const CXXBaseSpecifier &BS : CD->bases()) { + if (!CheckConstantExpression(Info, DiagLoc, BS.getType(), + Value.getStructBase(BaseIndex), Usage)) return false; + ++BaseIndex; } } for (const auto *I : RD->fields()) { @@ -1823,7 +1898,8 @@ static bool CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc, continue; if (!CheckConstantExpression(Info, DiagLoc, I->getType(), - Value.getStructField(I->getFieldIndex()))) + Value.getStructField(I->getFieldIndex()), + Usage)) return false; } } @@ -1831,11 +1907,11 @@ static bool CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc, if (Value.isLValue()) { LValue LVal; LVal.setFrom(Info.Ctx, Value); - return CheckLValueConstantExpression(Info, DiagLoc, Type, LVal); + return CheckLValueConstantExpression(Info, DiagLoc, Type, LVal, Usage); } if (Value.isMemberPointer()) - return CheckMemberPointerConstantExpression(Info, DiagLoc, Type, Value); + return CheckMemberPointerConstantExpression(Info, DiagLoc, Type, Value, Usage); // Everything else is fine. return true; @@ -1846,7 +1922,7 @@ static const ValueDecl *GetLValueBaseDecl(const LValue &LVal) { } static bool IsLiteralLValue(const LValue &Value) { - if (Value.CallIndex) + if (Value.getLValueCallIndex()) return false; const Expr *E = Value.Base.dyn_cast<const Expr*>(); return E && !isa<MaterializeTemporaryExpr>(E); @@ -2173,6 +2249,8 @@ static bool handleIntIntBinOp(EvalInfo &Info, const Expr *E, const APSInt &LHS, case BO_GE: Result = LHS >= RHS; return true; case BO_EQ: Result = LHS == RHS; return true; case BO_NE: Result = LHS != RHS; return true; + case BO_Cmp: + llvm_unreachable("BO_Cmp should be handled elsewhere"); } } @@ -2396,7 +2474,7 @@ static bool handleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv, /// \param Result Filled in with a pointer to the value of the variable. static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E, const VarDecl *VD, CallStackFrame *Frame, - APValue *&Result) { + APValue *&Result, const LValue *LVal) { // If this is a parameter to an active constexpr function call, perform // argument substitution. @@ -2415,7 +2493,8 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E, // If this is a local variable, dig out its value. if (Frame) { - Result = Frame->getTemporary(VD); + Result = LVal ? Frame->getTemporary(VD, LVal->getLValueVersion()) + : Frame->getCurrentTemporary(VD); if (!Result) { // Assume variables referenced within a lambda's call operator that were // not declared within the call operator are captures and during checking @@ -2644,10 +2723,13 @@ struct CompleteObject { APValue *Value; /// The type of the complete object. QualType Type; + bool LifetimeStartedInEvaluation; CompleteObject() : Value(nullptr) {} - CompleteObject(APValue *Value, QualType Type) - : Value(Value), Type(Type) { + CompleteObject(APValue *Value, QualType Type, + bool LifetimeStartedInEvaluation) + : Value(Value), Type(Type), + LifetimeStartedInEvaluation(LifetimeStartedInEvaluation) { assert(Value && "missing value for complete object"); } @@ -2677,6 +2759,8 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, APValue *O = Obj.Value; QualType ObjType = Obj.Type; const FieldDecl *LastField = nullptr; + const bool MayReadMutableMembers = + Obj.LifetimeStartedInEvaluation && Info.getLangOpts().CPlusPlus14; // Walk the designator's path to find the subobject. for (unsigned I = 0, N = Sub.Entries.size(); /**/; ++I) { @@ -2692,7 +2776,7 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, // cannot perform this read. (This only happens when performing a trivial // copy or assignment.) if (ObjType->isRecordType() && handler.AccessKind == AK_Read && - diagnoseUnreadableFields(Info, E, ObjType)) + !MayReadMutableMembers && diagnoseUnreadableFields(Info, E, ObjType)) return handler.failed(); if (!handler.found(*O, ObjType)) @@ -2772,7 +2856,11 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, : O->getComplexFloatReal(), ObjType); } } else if (const FieldDecl *Field = getAsField(Sub.Entries[I])) { - if (Field->isMutable() && handler.AccessKind == AK_Read) { + // In C++14 onwards, it is permitted to read a mutable member whose + // lifetime began within the evaluation. + // FIXME: Should we also allow this in C++11? + if (Field->isMutable() && handler.AccessKind == AK_Read && + !MayReadMutableMembers) { Info.FFDiag(E, diag::note_constexpr_ltor_mutable, 1) << Field; Info.Note(Field->getLocation(), diag::note_declared_at); @@ -2992,8 +3080,8 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, } CallStackFrame *Frame = nullptr; - if (LVal.CallIndex) { - Frame = Info.getCallFrame(LVal.CallIndex); + if (LVal.getLValueCallIndex()) { + Frame = Info.getCallFrame(LVal.getLValueCallIndex()); if (!Frame) { Info.FFDiag(E, diag::note_constexpr_lifetime_ended, 1) << AK << LVal.Base.is<const ValueDecl*>(); @@ -3018,6 +3106,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, // Compute value storage location and type of base object. APValue *BaseVal = nullptr; QualType BaseType = getType(LVal.Base); + bool LifetimeStartedInEvaluation = Frame; if (const ValueDecl *D = LVal.Base.dyn_cast<const ValueDecl*>()) { // In C++98, const, non-volatile integers initialized with ICEs are ICEs. @@ -3105,7 +3194,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, } } - if (!evaluateVarDeclInit(Info, E, VD, Frame, BaseVal)) + if (!evaluateVarDeclInit(Info, E, VD, Frame, BaseVal, &LVal)) return CompleteObject(); } else { const Expr *Base = LVal.Base.dyn_cast<const Expr*>(); @@ -3129,7 +3218,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, // int &&r = 1; // int x = ++r; // constexpr int k = r; - // Therefore we use the C++1y rules in C++11 too. + // Therefore we use the C++14 rules in C++11 too. const ValueDecl *VD = Info.EvaluatingDecl.dyn_cast<const ValueDecl*>(); const ValueDecl *ED = MTE->getExtendingDecl(); if (!(BaseType.isConstQualified() && @@ -3142,12 +3231,13 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, BaseVal = Info.Ctx.getMaterializedTemporaryValue(MTE, false); assert(BaseVal && "got reference to unevaluated temporary"); + LifetimeStartedInEvaluation = true; } else { Info.FFDiag(E); return CompleteObject(); } } else { - BaseVal = Frame->getTemporary(Base); + BaseVal = Frame->getTemporary(Base, LVal.Base.getVersion()); assert(BaseVal && "missing value for temporary"); } @@ -3167,12 +3257,15 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, // During the construction of an object, it is not yet 'const'. // FIXME: This doesn't do quite the right thing for const subobjects of the // object under construction. - if (Info.isEvaluatingConstructor(LVal.getLValueBase(), LVal.CallIndex)) { + if (Info.isEvaluatingConstructor(LVal.getLValueBase(), + LVal.getLValueCallIndex(), + LVal.getLValueVersion())) { BaseType = Info.Ctx.getCanonicalType(BaseType); BaseType.removeLocalConst(); + LifetimeStartedInEvaluation = true; } - // In C++1y, we can't safely access any mutable state when we might be + // In C++14, we can't safely access any mutable state when we might be // evaluating after an unmodeled side effect. // // FIXME: Not all local state is mutable. Allow local constant subobjects @@ -3182,10 +3275,10 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, (AK != AK_Read && Info.IsSpeculativelyEvaluating)) return CompleteObject(); - return CompleteObject(BaseVal, BaseType); + return CompleteObject(BaseVal, BaseType, LifetimeStartedInEvaluation); } -/// \brief Perform an lvalue-to-rvalue conversion on the given glvalue. This +/// Perform an lvalue-to-rvalue conversion on the given glvalue. This /// can also be used for 'lvalue-to-lvalue' conversions for looking up the /// glvalue referred to by an entity of reference type. /// @@ -3204,7 +3297,7 @@ static bool handleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv, // Check for special cases where there is no existing APValue to look at. const Expr *Base = LVal.Base.dyn_cast<const Expr*>(); - if (Base && !LVal.CallIndex && !Type.isVolatileQualified()) { + if (Base && !LVal.getLValueCallIndex() && !Type.isVolatileQualified()) { if (const CompoundLiteralExpr *CLE = dyn_cast<CompoundLiteralExpr>(Base)) { // In C99, a CompoundLiteralExpr is an lvalue, and we defer evaluating the // initializer until now for such expressions. Such an expression can't be @@ -3216,14 +3309,14 @@ static bool handleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv, APValue Lit; if (!Evaluate(Lit, Info, CLE->getInitializer())) return false; - CompleteObject LitObj(&Lit, Base->getType()); + CompleteObject LitObj(&Lit, Base->getType(), false); return extractSubobject(Info, Conv, LitObj, LVal.Designator, RVal); } else if (isa<StringLiteral>(Base) || isa<PredefinedExpr>(Base)) { // We represent a string literal array as an lvalue pointing at the // corresponding expression, rather than building an array of chars. // FIXME: Support ObjCEncodeExpr, MakeStringConstant APValue Str(Base, CharUnits::Zero(), APValue::NoLValuePath(), 0); - CompleteObject StrObj(&Str, Base->getType()); + CompleteObject StrObj(&Str, Base->getType(), false); return extractSubobject(Info, Conv, StrObj, LVal.Designator, RVal); } } @@ -3247,11 +3340,6 @@ static bool handleAssignment(EvalInfo &Info, const Expr *E, const LValue &LVal, return Obj && modifySubobject(Info, E, Obj, LVal.Designator, Val); } -static bool isOverflowingIntegerType(ASTContext &Ctx, QualType T) { - return T->isSignedIntegerType() && - Ctx.getIntWidth(T) >= Ctx.getIntWidth(Ctx.IntTy); -} - namespace { struct CompoundAssignSubobjectHandler { EvalInfo &Info; @@ -3373,7 +3461,7 @@ static bool handleCompoundAssignment( namespace { struct IncDecSubobjectHandler { EvalInfo &Info; - const Expr *E; + const UnaryOperator *E; AccessKinds AccessKind; APValue *Old; @@ -3445,16 +3533,14 @@ struct IncDecSubobjectHandler { if (AccessKind == AK_Increment) { ++Value; - if (!WasNegative && Value.isNegative() && - isOverflowingIntegerType(Info.Ctx, SubobjType)) { + if (!WasNegative && Value.isNegative() && E->canOverflow()) { APSInt ActualValue(Value, /*IsUnsigned*/true); return HandleOverflow(Info, E, ActualValue, SubobjType); } } else { --Value; - if (WasNegative && !Value.isNegative() && - isOverflowingIntegerType(Info.Ctx, SubobjType)) { + if (WasNegative && !Value.isNegative() && E->canOverflow()) { unsigned BitWidth = Value.getBitWidth(); APSInt ActualValue(Value.sext(BitWidth + 1), /*IsUnsigned*/false); ActualValue.setBit(BitWidth); @@ -3515,7 +3601,7 @@ static bool handleIncDec(EvalInfo &Info, const Expr *E, const LValue &LVal, AccessKinds AK = IsIncrement ? AK_Increment : AK_Decrement; CompleteObject Obj = findCompleteObject(Info, E, AK, LVal, LValType); - IncDecSubobjectHandler Handler = { Info, E, AK, Old }; + IncDecSubobjectHandler Handler = {Info, cast<UnaryOperator>(E), AK, Old}; return Obj && findSubobject(Info, E, Obj, LVal.Designator, Handler); } @@ -3707,8 +3793,7 @@ static bool EvaluateVarDecl(EvalInfo &Info, const VarDecl *VD) { return true; LValue Result; - Result.set(VD, Info.CurrentCall->Index); - APValue &Val = Info.CurrentCall->createTemporary(VD, true); + APValue &Val = createTemporary(VD, true, Result, *Info.CurrentCall); const Expr *InitE = VD->getInit(); if (!InitE) { @@ -3756,7 +3841,7 @@ static bool EvaluateCond(EvalInfo &Info, const VarDecl *CondDecl, } namespace { -/// \brief A location where the result (returned value) of evaluating a +/// A location where the result (returned value) of evaluating a /// statement should be stored. struct StmtResult { /// The APValue that should be filled in with the returned value. @@ -3764,6 +3849,19 @@ struct StmtResult { /// The location containing the result, if any (used to support RVO). const LValue *Slot; }; + +struct TempVersionRAII { + CallStackFrame &Frame; + + TempVersionRAII(CallStackFrame &Frame) : Frame(Frame) { + Frame.pushTempVersion(); + } + + ~TempVersionRAII() { + Frame.popTempVersion(); + } +}; + } static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info, @@ -4290,9 +4388,15 @@ static bool HandleFunctionCall(SourceLocation CallLoc, This->moveInto(Result); return true; } else if (MD && isLambdaCallOperator(MD)) { - // We're in a lambda; determine the lambda capture field maps. - MD->getParent()->getCaptureFields(Frame.LambdaCaptureFields, - Frame.LambdaThisCaptureField); + // We're in a lambda; determine the lambda capture field maps unless we're + // just constexpr checking a lambda's call operator. constexpr checking is + // done before the captures have been added to the closure object (unless + // we're inferring constexpr-ness), so we don't have access to them in this + // case. But since we don't need the captures to constexpr check, we can + // just ignore them. + if (!Info.checkingPotentialConstantExpression()) + MD->getParent()->getCaptureFields(Frame.LambdaCaptureFields, + Frame.LambdaThisCaptureField); } StmtResult Ret = {Result, ResultSlot}; @@ -4321,7 +4425,8 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This, } EvalInfo::EvaluatingConstructorRAII EvalObj( - Info, {This.getLValueBase(), This.CallIndex}); + Info, {This.getLValueBase(), + {This.getLValueCallIndex(), This.getLValueVersion()}}); CallStackFrame Frame(Info, CallLoc, Definition, &This, ArgValues); // FIXME: Creating an APValue just to hold a nonexistent return value is @@ -4376,6 +4481,7 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This, #endif for (const auto *I : Definition->inits()) { LValue Subobject = This; + LValue SubobjectParent = This; APValue *Value = &Result; // Determine the subobject to initialize. @@ -4406,7 +4512,8 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This, } else if (IndirectFieldDecl *IFD = I->getIndirectMember()) { // Walk the indirect field decl's chain to find the object to initialize, // and make sure we've initialized every step along it. - for (auto *C : IFD->chain()) { + auto IndirectFieldChain = IFD->chain(); + for (auto *C : IndirectFieldChain) { FD = cast<FieldDecl>(C); CXXRecordDecl *CD = cast<CXXRecordDecl>(FD->getParent()); // Switch the union field if it differs. This happens if we had @@ -4422,6 +4529,10 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This, *Value = APValue(APValue::UninitStruct(), CD->getNumBases(), std::distance(CD->field_begin(), CD->field_end())); } + // Store Subobject as its parent before updating it for the last element + // in the chain. + if (C == IndirectFieldChain.back()) + SubobjectParent = Subobject; if (!HandleLValueMember(Info, I->getInit(), Subobject, FD)) return false; if (CD->isUnion()) @@ -4433,10 +4544,16 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This, llvm_unreachable("unknown base initializer kind"); } + // Need to override This for implicit field initializers as in this case + // This refers to innermost anonymous struct/union containing initializer, + // not to currently constructed class. + const Expr *Init = I->getInit(); + ThisOverrideRAII ThisOverride(*Info.CurrentCall, &SubobjectParent, + isa<CXXDefaultInitExpr>(Init)); FullExpressionRAII InitScope(Info); - if (!EvaluateInPlace(*Value, Info, Subobject, I->getInit()) || - (FD && FD->isBitField() && !truncateBitfieldValue(Info, I->getInit(), - *Value, FD))) { + if (!EvaluateInPlace(*Value, Info, Subobject, Init) || + (FD && FD->isBitField() && + !truncateBitfieldValue(Info, Init, *Value, FD))) { // If we're checking for a potential constant expression, evaluate all // initializers even if some of them fail. if (!Info.noteFailure()) @@ -4570,9 +4687,12 @@ public: { return StmtVisitorTy::Visit(E->getResultExpr()); } bool VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E) { return StmtVisitorTy::Visit(E->getReplacement()); } - bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E) - { return StmtVisitorTy::Visit(E->getExpr()); } + bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E) { + TempVersionRAII RAII(*Info.CurrentCall); + return StmtVisitorTy::Visit(E->getExpr()); + } bool VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E) { + TempVersionRAII RAII(*Info.CurrentCall); // The initializer may not have been parsed yet, or might be erroneous. if (!E->getExpr()) return Error(E); @@ -4650,7 +4770,7 @@ public: } bool VisitOpaqueValueExpr(const OpaqueValueExpr *E) { - if (APValue *Value = Info.CurrentCall->getTemporary(E)) + if (APValue *Value = Info.CurrentCall->getCurrentTemporary(E)) return DerivedSuccess(*Value, E); const Expr *Source = E->getSourceExpr(); @@ -4828,7 +4948,7 @@ public: assert(BaseTy->castAs<RecordType>()->getDecl()->getCanonicalDecl() == FD->getParent()->getCanonicalDecl() && "record / field mismatch"); - CompleteObject Obj(&Val, BaseTy); + CompleteObject Obj(&Val, BaseTy, true); SubobjectDesignator Designator(BaseTy); Designator.addDeclUnchecked(FD); @@ -4948,7 +5068,7 @@ public: } }; -} +} // namespace //===----------------------------------------------------------------------===// // Common base class for lvalue and temporary evaluation. @@ -5170,10 +5290,17 @@ bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) { // to within 'E' actually represents a lambda-capture that maps to a // data-member/field within the closure object, and if so, evaluate to the // field or what the field refers to. - if (Info.CurrentCall && isLambdaCallOperator(Info.CurrentCall->Callee)) { + if (Info.CurrentCall && isLambdaCallOperator(Info.CurrentCall->Callee) && + isa<DeclRefExpr>(E) && + cast<DeclRefExpr>(E)->refersToEnclosingVariableOrCapture()) { + // We don't always have a complete capture-map when checking or inferring if + // the function call operator meets the requirements of a constexpr function + // - but we don't need to evaluate the captures to determine constexprness + // (dcl.constexpr C++17). + if (Info.checkingPotentialConstantExpression()) + return false; + if (auto *FD = Info.CurrentCall->LambdaCaptureFields.lookup(VD)) { - if (Info.checkingPotentialConstantExpression()) - return false; // Start with 'Result' referring to the complete closure object... Result = *Info.CurrentCall->This; // ... then update it to refer to the field of the closure object @@ -5208,14 +5335,15 @@ bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) { if (!VD->getType()->isReferenceType()) { if (Frame) { - Result.set(VD, Frame->Index); + Result.set({VD, Frame->Index, + Info.CurrentCall->getCurrentTemporaryVersion(VD)}); return true; } return Success(VD); } APValue *V; - if (!evaluateVarDeclInit(Info, E, VD, Frame, V)) + if (!evaluateVarDeclInit(Info, E, VD, Frame, V, nullptr)) return false; if (V->isUninit()) { if (!Info.checkingPotentialConstantExpression()) @@ -5247,9 +5375,8 @@ bool LValueExprEvaluator::VisitMaterializeTemporaryExpr( *Value = APValue(); Result.set(E); } else { - Value = &Info.CurrentCall-> - createTemporary(E, E->getStorageDuration() == SD_Automatic); - Result.set(E, Info.CurrentCall->Index); + Value = &createTemporary(E, E->getStorageDuration() == SD_Automatic, Result, + *Info.CurrentCall); } QualType Type = Inner->getType(); @@ -5433,7 +5560,7 @@ bool LValueExprEvaluator::VisitBinAssign(const BinaryOperator *E) { // Pointer Evaluation //===----------------------------------------------------------------------===// -/// \brief Attempts to compute the number of bytes available at the pointer +/// Attempts to compute the number of bytes available at the pointer /// returned by a function with the alloc_size attribute. Returns true if we /// were successful. Places an unsigned number into `Result`. /// @@ -5444,9 +5571,8 @@ static bool getBytesReturnedByAllocSizeCall(const ASTContext &Ctx, llvm::APInt &Result) { const AllocSizeAttr *AllocSize = getAllocSizeAttr(Call); - // alloc_size args are 1-indexed, 0 means not present. - assert(AllocSize && AllocSize->getElemSizeParam() != 0); - unsigned SizeArgNo = AllocSize->getElemSizeParam() - 1; + assert(AllocSize && AllocSize->getElemSizeParam().isValid()); + unsigned SizeArgNo = AllocSize->getElemSizeParam().getASTIndex(); unsigned BitsInSizeT = Ctx.getTypeSize(Ctx.getSizeType()); if (Call->getNumArgs() <= SizeArgNo) return false; @@ -5464,14 +5590,13 @@ static bool getBytesReturnedByAllocSizeCall(const ASTContext &Ctx, if (!EvaluateAsSizeT(Call->getArg(SizeArgNo), SizeOfElem)) return false; - if (!AllocSize->getNumElemsParam()) { + if (!AllocSize->getNumElemsParam().isValid()) { Result = std::move(SizeOfElem); return true; } APSInt NumberOfElems; - // Argument numbers start at 1 - unsigned NumArgNo = AllocSize->getNumElemsParam() - 1; + unsigned NumArgNo = AllocSize->getNumElemsParam().getASTIndex(); if (!EvaluateAsSizeT(Call->getArg(NumArgNo), NumberOfElems)) return false; @@ -5484,7 +5609,7 @@ static bool getBytesReturnedByAllocSizeCall(const ASTContext &Ctx, return true; } -/// \brief Convenience function. LVal's base must be a call to an alloc_size +/// Convenience function. LVal's base must be a call to an alloc_size /// function. static bool getBytesReturnedByAllocSizeCall(const ASTContext &Ctx, const LValue &LVal, @@ -5496,7 +5621,7 @@ static bool getBytesReturnedByAllocSizeCall(const ASTContext &Ctx, return getBytesReturnedByAllocSizeCall(Ctx, CE, Result); } -/// \brief Attempts to evaluate the given LValueBase as the result of a call to +/// Attempts to evaluate the given LValueBase as the result of a call to /// a function with the alloc_size attribute. If it was possible to do so, this /// function will return true, make Result's Base point to said function call, /// and mark Result's Base as invalid. @@ -5662,8 +5787,8 @@ bool PointerExprEvaluator::VisitUnaryAddrOf(const UnaryOperator *E) { return evaluateLValue(E->getSubExpr(), Result); } -bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { - const Expr* SubExpr = E->getSubExpr(); +bool PointerExprEvaluator::VisitCastExpr(const CastExpr *E) { + const Expr *SubExpr = E->getSubExpr(); switch (E->getCastKind()) { default: @@ -5680,7 +5805,11 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { // permitted in constant expressions in C++11. Bitcasts from cv void* are // also static_casts, but we disallow them as a resolution to DR1312. if (!E->getType()->isVoidPointerType()) { - Result.Designator.setInvalid(); + // If we changed anything other than cvr-qualifiers, we can't use this + // value for constant folding. FIXME: Qualification conversions should + // always be CK_NoOp, but we get this wrong in C. + if (!Info.Ctx.hasCvrSimilarType(E->getType(), E->getSubExpr()->getType())) + Result.Designator.setInvalid(); if (SubExpr->getType()->isVoidPointerType()) CCEDiag(E, diag::note_constexpr_invalid_cast) << 3 << SubExpr->getType(); @@ -5728,7 +5857,6 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { Result.Base = (Expr*)nullptr; Result.InvalidBase = false; Result.Offset = CharUnits::fromQuantity(N); - Result.CallIndex = 0; Result.Designator.setInvalid(); Result.IsNullPtr = false; return true; @@ -5744,9 +5872,9 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { if (!evaluateLValue(SubExpr, Result)) return false; } else { - Result.set(SubExpr, Info.CurrentCall->Index); - if (!EvaluateInPlace(Info.CurrentCall->createTemporary(SubExpr, false), - Info, Result, SubExpr)) + APValue &Value = createTemporary(SubExpr, false, Result, + *Info.CurrentCall); + if (!EvaluateInPlace(Value, Info, Result, SubExpr)) return false; } // The result is a pointer to the first element of the array. @@ -6117,6 +6245,8 @@ namespace { bool VisitCXXInheritedCtorInitExpr(const CXXInheritedCtorInitExpr *E); bool VisitCXXConstructExpr(const CXXConstructExpr *E, QualType T); bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *E); + + bool VisitBinCmp(const BinaryOperator *E); }; } @@ -6512,9 +6642,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->createTemporary(E, false), - Info, Result, E); + APValue &Value = createTemporary(E, false, Result, *Info.CurrentCall); + return EvaluateInPlace(Value, Info, Result, E); } bool VisitCastExpr(const CastExpr *E) { @@ -6787,6 +6916,22 @@ static bool EvaluateArray(const Expr *E, const LValue &This, return ArrayExprEvaluator(Info, This, Result).Visit(E); } +// Return true iff the given array filler may depend on the element index. +static bool MaybeElementDependentArrayFiller(const Expr *FillerExpr) { + // For now, just whitelist non-class value-initialization and initialization + // lists comprised of them. + if (isa<ImplicitValueInitExpr>(FillerExpr)) + return false; + if (const InitListExpr *ILE = dyn_cast<InitListExpr>(FillerExpr)) { + for (unsigned I = 0, E = ILE->getNumInits(); I != E; ++I) { + if (MaybeElementDependentArrayFiller(ILE->getInit(I))) + return true; + } + return false; + } + return true; +} + bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E) { const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(E->getType()); if (!CAT) @@ -6816,10 +6961,13 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E) { const Expr *FillerExpr = E->hasArrayFiller() ? E->getArrayFiller() : nullptr; // If the initializer might depend on the array index, run it for each - // array element. For now, just whitelist non-class value-initialization. - if (NumEltsToInit != NumElts && !isa<ImplicitValueInitExpr>(FillerExpr)) + // array element. + if (NumEltsToInit != NumElts && MaybeElementDependentArrayFiller(FillerExpr)) NumEltsToInit = NumElts; + LLVM_DEBUG(llvm::dbgs() << "The number of elements to initialize: " + << NumEltsToInit << ".\n"); + Result = APValue(APValue::UninitArray(), NumEltsToInit, NumElts); // If the array was previously zero-initialized, preserve the @@ -6939,11 +7087,11 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E, namespace { class IntExprEvaluator - : public ExprEvaluatorBase<IntExprEvaluator> { + : public ExprEvaluatorBase<IntExprEvaluator> { APValue &Result; public: IntExprEvaluator(EvalInfo &info, APValue &result) - : ExprEvaluatorBaseTy(info), Result(result) {} + : ExprEvaluatorBaseTy(info), Result(result) {} bool Success(const llvm::APSInt &SI, const Expr *E, APValue &Result) { assert(E->getType()->isIntegralOrEnumerationType() && @@ -6974,7 +7122,7 @@ public: } bool Success(uint64_t Value, const Expr *E, APValue &Result) { - assert(E->getType()->isIntegralOrEnumerationType() && + assert(E->getType()->isIntegralOrEnumerationType() && "Invalid evaluation result."); Result = APValue(Info.Ctx.MakeIntValue(Value, E->getType())); return true; @@ -7076,6 +7224,73 @@ public: // FIXME: Missing: array subscript of vector, member of vector }; + +class FixedPointExprEvaluator + : public ExprEvaluatorBase<FixedPointExprEvaluator> { + APValue &Result; + + public: + FixedPointExprEvaluator(EvalInfo &info, APValue &result) + : ExprEvaluatorBaseTy(info), Result(result) {} + + bool Success(const llvm::APSInt &SI, const Expr *E, APValue &Result) { + assert(E->getType()->isFixedPointType() && "Invalid evaluation result."); + assert(SI.isSigned() == E->getType()->isSignedFixedPointType() && + "Invalid evaluation result."); + assert(SI.getBitWidth() == Info.Ctx.getIntWidth(E->getType()) && + "Invalid evaluation result."); + Result = APValue(SI); + return true; + } + bool Success(const llvm::APSInt &SI, const Expr *E) { + return Success(SI, E, Result); + } + + bool Success(const llvm::APInt &I, const Expr *E, APValue &Result) { + assert(E->getType()->isFixedPointType() && "Invalid evaluation result."); + assert(I.getBitWidth() == Info.Ctx.getIntWidth(E->getType()) && + "Invalid evaluation result."); + Result = APValue(APSInt(I)); + Result.getInt().setIsUnsigned(E->getType()->isUnsignedFixedPointType()); + return true; + } + bool Success(const llvm::APInt &I, const Expr *E) { + return Success(I, E, Result); + } + + bool Success(uint64_t Value, const Expr *E, APValue &Result) { + assert(E->getType()->isFixedPointType() && "Invalid evaluation result."); + Result = APValue(Info.Ctx.MakeIntValue(Value, E->getType())); + return true; + } + bool Success(uint64_t Value, const Expr *E) { + return Success(Value, E, Result); + } + + bool Success(CharUnits Size, const Expr *E) { + return Success(Size.getQuantity(), E); + } + + bool Success(const APValue &V, const Expr *E) { + if (V.isLValue() || V.isAddrLabelDiff()) { + Result = V; + return true; + } + return Success(V.getInt(), E); + } + + bool ZeroInitialization(const Expr *E) { return Success(0, E); } + + //===--------------------------------------------------------------------===// + // Visitor Methods + //===--------------------------------------------------------------------===// + + bool VisitFixedPointLiteral(const FixedPointLiteral *E) { + return Success(E->getValue(), E); + } + + bool VisitUnaryOperator(const UnaryOperator *E); +}; } // end anonymous namespace /// EvaluateIntegerOrLValue - Evaluate an rvalue integral-typed expression, and @@ -7133,30 +7348,43 @@ bool IntExprEvaluator::CheckReferencedDecl(const Expr* E, const Decl* D) { return false; } +/// Values returned by __builtin_classify_type, chosen to match the values +/// produced by GCC's builtin. +enum class GCCTypeClass { + None = -1, + Void = 0, + Integer = 1, + // GCC reserves 2 for character types, but instead classifies them as + // integers. + Enum = 3, + Bool = 4, + Pointer = 5, + // GCC reserves 6 for references, but appears to never use it (because + // expressions never have reference type, presumably). + PointerToDataMember = 7, + RealFloat = 8, + Complex = 9, + // GCC reserves 10 for functions, but does not use it since GCC version 6 due + // to decay to pointer. (Prior to version 6 it was only used in C++ mode). + // GCC claims to reserve 11 for pointers to member functions, but *actually* + // uses 12 for that purpose, same as for a class or struct. Maybe it + // internally implements a pointer to member as a struct? Who knows. + PointerToMemberFunction = 12, // Not a bug, see above. + ClassOrStruct = 12, + Union = 13, + // GCC reserves 14 for arrays, but does not use it since GCC version 6 due to + // decay to pointer. (Prior to version 6 it was only used in C++ mode). + // GCC reserves 15 for strings, but actually uses 5 (pointer) for string + // literals. +}; + /// EvaluateBuiltinClassifyType - Evaluate __builtin_classify_type the same way /// as GCC. -static int EvaluateBuiltinClassifyType(const CallExpr *E, - const LangOptions &LangOpts) { - // The following enum mimics the values returned by GCC. - // FIXME: Does GCC differ between lvalue and rvalue references here? - enum gcc_type_class { - no_type_class = -1, - void_type_class, integer_type_class, char_type_class, - enumeral_type_class, boolean_type_class, - pointer_type_class, reference_type_class, offset_type_class, - real_type_class, complex_type_class, - function_type_class, method_type_class, - record_type_class, union_type_class, - array_type_class, string_type_class, - lang_type_class - }; +static GCCTypeClass +EvaluateBuiltinClassifyType(QualType T, const LangOptions &LangOpts) { + assert(!T->isDependentType() && "unexpected dependent type"); - // If no argument was supplied, default to "no_type_class". This isn't - // ideal, however it is what gcc does. - if (E->getNumArgs() == 0) - return no_type_class; - - QualType CanTy = E->getArg(0)->getType().getCanonicalType(); + QualType CanTy = T.getCanonicalType(); const BuiltinType *BT = dyn_cast<BuiltinType>(CanTy); switch (CanTy->getTypeClass()) { @@ -7165,36 +7393,55 @@ static int EvaluateBuiltinClassifyType(const CallExpr *E, #define NON_CANONICAL_TYPE(ID, BASE) case Type::ID: #define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(ID, BASE) case Type::ID: #include "clang/AST/TypeNodes.def" - llvm_unreachable("CallExpr::isBuiltinClassifyType(): unimplemented type"); + case Type::Auto: + case Type::DeducedTemplateSpecialization: + llvm_unreachable("unexpected non-canonical or dependent type"); case Type::Builtin: switch (BT->getKind()) { #define BUILTIN_TYPE(ID, SINGLETON_ID) -#define SIGNED_TYPE(ID, SINGLETON_ID) case BuiltinType::ID: return integer_type_class; -#define FLOATING_TYPE(ID, SINGLETON_ID) case BuiltinType::ID: return real_type_class; -#define PLACEHOLDER_TYPE(ID, SINGLETON_ID) case BuiltinType::ID: break; +#define SIGNED_TYPE(ID, SINGLETON_ID) \ + case BuiltinType::ID: return GCCTypeClass::Integer; +#define FLOATING_TYPE(ID, SINGLETON_ID) \ + case BuiltinType::ID: return GCCTypeClass::RealFloat; +#define PLACEHOLDER_TYPE(ID, SINGLETON_ID) \ + case BuiltinType::ID: break; #include "clang/AST/BuiltinTypes.def" case BuiltinType::Void: - return void_type_class; + return GCCTypeClass::Void; case BuiltinType::Bool: - return boolean_type_class; + return GCCTypeClass::Bool; - case BuiltinType::Char_U: // gcc doesn't appear to use char_type_class + case BuiltinType::Char_U: case BuiltinType::UChar: + case BuiltinType::WChar_U: + case BuiltinType::Char8: + case BuiltinType::Char16: + case BuiltinType::Char32: case BuiltinType::UShort: case BuiltinType::UInt: case BuiltinType::ULong: case BuiltinType::ULongLong: case BuiltinType::UInt128: - return integer_type_class; + return GCCTypeClass::Integer; + + case BuiltinType::UShortAccum: + case BuiltinType::UAccum: + case BuiltinType::ULongAccum: + case BuiltinType::UShortFract: + case BuiltinType::UFract: + case BuiltinType::ULongFract: + case BuiltinType::SatUShortAccum: + case BuiltinType::SatUAccum: + case BuiltinType::SatULongAccum: + case BuiltinType::SatUShortFract: + case BuiltinType::SatUFract: + case BuiltinType::SatULongFract: + return GCCTypeClass::None; case BuiltinType::NullPtr: - return pointer_type_class; - case BuiltinType::WChar_U: - case BuiltinType::Char16: - case BuiltinType::Char32: case BuiltinType::ObjCId: case BuiltinType::ObjCClass: case BuiltinType::ObjCSel: @@ -7206,74 +7453,73 @@ static int EvaluateBuiltinClassifyType(const CallExpr *E, case BuiltinType::OCLClkEvent: case BuiltinType::OCLQueue: case BuiltinType::OCLReserveID: + return GCCTypeClass::None; + case BuiltinType::Dependent: - llvm_unreachable("CallExpr::isBuiltinClassifyType(): unimplemented type"); + llvm_unreachable("unexpected dependent type"); }; - break; + llvm_unreachable("unexpected placeholder type"); case Type::Enum: - return LangOpts.CPlusPlus ? enumeral_type_class : integer_type_class; - break; + return LangOpts.CPlusPlus ? GCCTypeClass::Enum : GCCTypeClass::Integer; case Type::Pointer: - return pointer_type_class; - break; + case Type::ConstantArray: + case Type::VariableArray: + case Type::IncompleteArray: + case Type::FunctionNoProto: + case Type::FunctionProto: + return GCCTypeClass::Pointer; case Type::MemberPointer: - if (CanTy->isMemberDataPointerType()) - return offset_type_class; - else { - // We expect member pointers to be either data or function pointers, - // nothing else. - assert(CanTy->isMemberFunctionPointerType()); - return method_type_class; - } + return CanTy->isMemberDataPointerType() + ? GCCTypeClass::PointerToDataMember + : GCCTypeClass::PointerToMemberFunction; case Type::Complex: - return complex_type_class; - - case Type::FunctionNoProto: - case Type::FunctionProto: - return LangOpts.CPlusPlus ? function_type_class : pointer_type_class; + return GCCTypeClass::Complex; case Type::Record: - if (const RecordType *RT = CanTy->getAs<RecordType>()) { - switch (RT->getDecl()->getTagKind()) { - case TagTypeKind::TTK_Struct: - case TagTypeKind::TTK_Class: - case TagTypeKind::TTK_Interface: - return record_type_class; - - case TagTypeKind::TTK_Enum: - return LangOpts.CPlusPlus ? enumeral_type_class : integer_type_class; - - case TagTypeKind::TTK_Union: - return union_type_class; - } - } - llvm_unreachable("CallExpr::isBuiltinClassifyType(): unimplemented type"); + return CanTy->isUnionType() ? GCCTypeClass::Union + : GCCTypeClass::ClassOrStruct; - case Type::ConstantArray: - case Type::VariableArray: - case Type::IncompleteArray: - return LangOpts.CPlusPlus ? array_type_class : pointer_type_class; + case Type::Atomic: + // GCC classifies _Atomic T the same as T. + return EvaluateBuiltinClassifyType( + CanTy->castAs<AtomicType>()->getValueType(), LangOpts); case Type::BlockPointer: - case Type::LValueReference: - case Type::RValueReference: case Type::Vector: case Type::ExtVector: - case Type::Auto: - case Type::DeducedTemplateSpecialization: case Type::ObjCObject: case Type::ObjCInterface: case Type::ObjCObjectPointer: case Type::Pipe: - case Type::Atomic: - llvm_unreachable("CallExpr::isBuiltinClassifyType(): unimplemented type"); + // GCC classifies vectors as None. We follow its lead and classify all + // other types that don't fit into the regular classification the same way. + return GCCTypeClass::None; + + case Type::LValueReference: + case Type::RValueReference: + llvm_unreachable("invalid type for expression"); } - llvm_unreachable("CallExpr::isBuiltinClassifyType(): unimplemented type"); + llvm_unreachable("unexpected type class"); +} + +/// EvaluateBuiltinClassifyType - Evaluate __builtin_classify_type the same way +/// as GCC. +static GCCTypeClass +EvaluateBuiltinClassifyType(const CallExpr *E, const LangOptions &LangOpts) { + // If no argument was supplied, default to None. This isn't + // ideal, however it is what gcc does. + if (E->getNumArgs() == 0) + return GCCTypeClass::None; + + // FIXME: Bizarrely, GCC treats a call with more than one argument as not + // being an ICE, but still folds it to a constant using the type of the first + // argument. + return EvaluateBuiltinClassifyType(E->getArg(0)->getType(), LangOpts); } /// EvaluateBuiltinConstantPForLValue - Determine the result of @@ -7592,7 +7838,7 @@ static bool determineEndOffset(EvalInfo &Info, SourceLocation ExprLoc, return true; } -/// \brief Tries to evaluate the __builtin_object_size for @p E. If successful, +/// Tries to evaluate the __builtin_object_size for @p E. If successful, /// returns true and stores the result in @p Size. /// /// If @p WasError is non-null, this will report whether the failure to evaluate @@ -7697,7 +7943,7 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, } case Builtin::BI__builtin_classify_type: - return Success(EvaluateBuiltinClassifyType(E, Info.getLangOpts()), E); + return Success((int)EvaluateBuiltinClassifyType(E, Info.getLangOpts()), E); // FIXME: BI__builtin_clrsb // FIXME: BI__builtin_clrsbl @@ -7913,14 +8159,24 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, BuiltinOp != Builtin::BIwmemcmp && BuiltinOp != Builtin::BI__builtin_memcmp && BuiltinOp != Builtin::BI__builtin_wmemcmp); + bool IsWide = BuiltinOp == Builtin::BIwcscmp || + BuiltinOp == Builtin::BIwcsncmp || + BuiltinOp == Builtin::BIwmemcmp || + BuiltinOp == Builtin::BI__builtin_wcscmp || + BuiltinOp == Builtin::BI__builtin_wcsncmp || + BuiltinOp == Builtin::BI__builtin_wmemcmp; for (; MaxLength; --MaxLength) { APValue Char1, Char2; if (!handleLValueToRValueConversion(Info, E, CharTy, String1, Char1) || !handleLValueToRValueConversion(Info, E, CharTy, String2, Char2) || !Char1.isInt() || !Char2.isInt()) return false; - if (Char1.getInt() != Char2.getInt()) - return Success(Char1.getInt() < Char2.getInt() ? -1 : 1, E); + if (Char1.getInt() != Char2.getInt()) { + if (IsWide) // wmemcmp compares with wchar_t signedness. + return Success(Char1.getInt() < Char2.getInt() ? -1 : 1, E); + // memcmp always compares unsigned chars. + return Success(Char1.getInt().ult(Char2.getInt()) ? -1 : 1, E); + } if (StopAtNull && !Char1.getInt()) return Success(0, E); assert(!(StopAtNull && !Char2.getInt())); @@ -7979,6 +8235,125 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, case Builtin::BIomp_is_initial_device: // We can decide statically which value the runtime would return if called. return Success(Info.getLangOpts().OpenMPIsDevice ? 0 : 1, E); + case Builtin::BI__builtin_add_overflow: + case Builtin::BI__builtin_sub_overflow: + case Builtin::BI__builtin_mul_overflow: + case Builtin::BI__builtin_sadd_overflow: + case Builtin::BI__builtin_uadd_overflow: + case Builtin::BI__builtin_uaddl_overflow: + case Builtin::BI__builtin_uaddll_overflow: + case Builtin::BI__builtin_usub_overflow: + case Builtin::BI__builtin_usubl_overflow: + case Builtin::BI__builtin_usubll_overflow: + case Builtin::BI__builtin_umul_overflow: + case Builtin::BI__builtin_umull_overflow: + case Builtin::BI__builtin_umulll_overflow: + case Builtin::BI__builtin_saddl_overflow: + case Builtin::BI__builtin_saddll_overflow: + case Builtin::BI__builtin_ssub_overflow: + case Builtin::BI__builtin_ssubl_overflow: + case Builtin::BI__builtin_ssubll_overflow: + case Builtin::BI__builtin_smul_overflow: + case Builtin::BI__builtin_smull_overflow: + case Builtin::BI__builtin_smulll_overflow: { + LValue ResultLValue; + APSInt LHS, RHS; + + QualType ResultType = E->getArg(2)->getType()->getPointeeType(); + if (!EvaluateInteger(E->getArg(0), LHS, Info) || + !EvaluateInteger(E->getArg(1), RHS, Info) || + !EvaluatePointer(E->getArg(2), ResultLValue, Info)) + return false; + + APSInt Result; + bool DidOverflow = false; + + // If the types don't have to match, enlarge all 3 to the largest of them. + if (BuiltinOp == Builtin::BI__builtin_add_overflow || + BuiltinOp == Builtin::BI__builtin_sub_overflow || + BuiltinOp == Builtin::BI__builtin_mul_overflow) { + bool IsSigned = LHS.isSigned() || RHS.isSigned() || + ResultType->isSignedIntegerOrEnumerationType(); + bool AllSigned = LHS.isSigned() && RHS.isSigned() && + ResultType->isSignedIntegerOrEnumerationType(); + uint64_t LHSSize = LHS.getBitWidth(); + uint64_t RHSSize = RHS.getBitWidth(); + uint64_t ResultSize = Info.Ctx.getTypeSize(ResultType); + uint64_t MaxBits = std::max(std::max(LHSSize, RHSSize), ResultSize); + + // Add an additional bit if the signedness isn't uniformly agreed to. We + // could do this ONLY if there is a signed and an unsigned that both have + // MaxBits, but the code to check that is pretty nasty. The issue will be + // caught in the shrink-to-result later anyway. + if (IsSigned && !AllSigned) + ++MaxBits; + + LHS = APSInt(IsSigned ? LHS.sextOrSelf(MaxBits) : LHS.zextOrSelf(MaxBits), + !IsSigned); + RHS = APSInt(IsSigned ? RHS.sextOrSelf(MaxBits) : RHS.zextOrSelf(MaxBits), + !IsSigned); + Result = APSInt(MaxBits, !IsSigned); + } + + // Find largest int. + switch (BuiltinOp) { + default: + llvm_unreachable("Invalid value for BuiltinOp"); + case Builtin::BI__builtin_add_overflow: + case Builtin::BI__builtin_sadd_overflow: + case Builtin::BI__builtin_saddl_overflow: + case Builtin::BI__builtin_saddll_overflow: + case Builtin::BI__builtin_uadd_overflow: + case Builtin::BI__builtin_uaddl_overflow: + case Builtin::BI__builtin_uaddll_overflow: + Result = LHS.isSigned() ? LHS.sadd_ov(RHS, DidOverflow) + : LHS.uadd_ov(RHS, DidOverflow); + break; + case Builtin::BI__builtin_sub_overflow: + case Builtin::BI__builtin_ssub_overflow: + case Builtin::BI__builtin_ssubl_overflow: + case Builtin::BI__builtin_ssubll_overflow: + case Builtin::BI__builtin_usub_overflow: + case Builtin::BI__builtin_usubl_overflow: + case Builtin::BI__builtin_usubll_overflow: + Result = LHS.isSigned() ? LHS.ssub_ov(RHS, DidOverflow) + : LHS.usub_ov(RHS, DidOverflow); + break; + case Builtin::BI__builtin_mul_overflow: + case Builtin::BI__builtin_smul_overflow: + case Builtin::BI__builtin_smull_overflow: + case Builtin::BI__builtin_smulll_overflow: + case Builtin::BI__builtin_umul_overflow: + case Builtin::BI__builtin_umull_overflow: + case Builtin::BI__builtin_umulll_overflow: + Result = LHS.isSigned() ? LHS.smul_ov(RHS, DidOverflow) + : LHS.umul_ov(RHS, DidOverflow); + break; + } + + // In the case where multiple sizes are allowed, truncate and see if + // the values are the same. + if (BuiltinOp == Builtin::BI__builtin_add_overflow || + BuiltinOp == Builtin::BI__builtin_sub_overflow || + BuiltinOp == Builtin::BI__builtin_mul_overflow) { + // APSInt doesn't have a TruncOrSelf, so we use extOrTrunc instead, + // since it will give us the behavior of a TruncOrSelf in the case where + // its parameter <= its size. We previously set Result to be at least the + // type-size of the result, so getTypeSize(ResultType) <= Result.BitWidth + // will work exactly like TruncOrSelf. + APSInt Temp = Result.extOrTrunc(Info.Ctx.getTypeSize(ResultType)); + Temp.setIsSigned(ResultType->isSignedIntegerOrEnumerationType()); + + if (!APSInt::isSameValue(Temp, Result)) + DidOverflow = true; + Result = Temp; + } + + APValue APV{Result}; + if (!handleAssignment(Info, E, ResultLValue, ResultType, APV)) + return false; + return Success(DidOverflow, E); + } } } @@ -7999,10 +8374,11 @@ static bool HasSameBase(const LValue &A, const LValue &B) { } return IsGlobalLValue(A.getLValueBase()) || - A.getLValueCallIndex() == B.getLValueCallIndex(); + (A.getLValueCallIndex() == B.getLValueCallIndex() && + A.getLValueVersion() == B.getLValueVersion()); } -/// \brief Determine whether this is a pointer past the end of the complete +/// Determine whether this is a pointer past the end of the complete /// object referred to by the lvalue. static bool isOnePastTheEndOfCompleteObject(const ASTContext &Ctx, const LValue &LV) { @@ -8031,7 +8407,7 @@ static bool isOnePastTheEndOfCompleteObject(const ASTContext &Ctx, namespace { -/// \brief Data recursive integer evaluator of certain binary operators. +/// Data recursive integer evaluator of certain binary operators. /// /// We use a data recursive algorithm for binary operators so that we are able /// to handle extreme cases of chained binary operators without causing stack @@ -8076,15 +8452,13 @@ public: DataRecursiveIntBinOpEvaluator(IntExprEvaluator &IntEval, APValue &Result) : IntEval(IntEval), Info(IntEval.getEvalInfo()), FinalResult(Result) { } - /// \brief True if \param E is a binary operator that we are going to handle + /// True if \param E is a binary operator that we are going to handle /// data recursively. /// We handle binary operators that are comma, logical, or that have operands /// with integral or enumeration type. static bool shouldEnqueue(const BinaryOperator *E) { - return E->getOpcode() == BO_Comma || - E->isLogicalOp() || - (E->isRValue() && - E->getType()->isIntegralOrEnumerationType() && + return E->getOpcode() == BO_Comma || E->isLogicalOp() || + (E->isRValue() && E->getType()->isIntegralOrEnumerationType() && E->getLHS()->getType()->isIntegralOrEnumerationType() && E->getRHS()->getType()->isIntegralOrEnumerationType()); } @@ -8119,7 +8493,7 @@ private: return Info.CCEDiag(E, D); } - // \brief Returns true if visiting the RHS is necessary, false otherwise. + // Returns true if visiting the RHS is necessary, false otherwise. bool VisitBinOpLHSOnly(EvalResult &LHSResult, const BinaryOperator *E, bool &SuppressRHSDiags); @@ -8363,19 +8737,47 @@ public: }; } -bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { - // We don't call noteFailure immediately because the assignment happens after - // we evaluate LHS and RHS. - if (!Info.keepEvaluatingAfterFailure() && E->isAssignmentOp()) - return Error(E); +template <class SuccessCB, class AfterCB> +static bool +EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E, + SuccessCB &&Success, AfterCB &&DoAfter) { + assert(E->isComparisonOp() && "expected comparison operator"); + assert((E->getOpcode() == BO_Cmp || + E->getType()->isIntegralOrEnumerationType()) && + "unsupported binary expression evaluation"); + auto Error = [&](const Expr *E) { + Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr); + return false; + }; - DelayedNoteFailureRAII MaybeNoteFailureLater(Info, E->isAssignmentOp()); - if (DataRecursiveIntBinOpEvaluator::shouldEnqueue(E)) - return DataRecursiveIntBinOpEvaluator(*this, Result).Traverse(E); + using CCR = ComparisonCategoryResult; + bool IsRelational = E->isRelationalOp(); + bool IsEquality = E->isEqualityOp(); + if (E->getOpcode() == BO_Cmp) { + const ComparisonCategoryInfo &CmpInfo = + Info.Ctx.CompCategories.getInfoForType(E->getType()); + IsRelational = CmpInfo.isOrdered(); + IsEquality = CmpInfo.isEquality(); + } QualType LHSTy = E->getLHS()->getType(); QualType RHSTy = E->getRHS()->getType(); + if (LHSTy->isIntegralOrEnumerationType() && + RHSTy->isIntegralOrEnumerationType()) { + APSInt LHS, RHS; + bool LHSOK = EvaluateInteger(E->getLHS(), LHS, Info); + if (!LHSOK && !Info.noteFailure()) + return false; + if (!EvaluateInteger(E->getRHS(), RHS, Info) || !LHSOK) + return false; + if (LHS < RHS) + return Success(CCR::Less, E); + if (LHS > RHS) + return Success(CCR::Greater, E); + return Success(CCR::Equal, E); + } + if (LHSTy->isAnyComplexType() || RHSTy->isAnyComplexType()) { ComplexValue LHS, RHS; bool LHSOK; @@ -8408,30 +8810,13 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { LHS.getComplexFloatReal().compare(RHS.getComplexFloatReal()); APFloat::cmpResult CR_i = LHS.getComplexFloatImag().compare(RHS.getComplexFloatImag()); - - if (E->getOpcode() == BO_EQ) - return Success((CR_r == APFloat::cmpEqual && - CR_i == APFloat::cmpEqual), E); - else { - assert(E->getOpcode() == BO_NE && - "Invalid complex comparison."); - return Success(((CR_r == APFloat::cmpGreaterThan || - CR_r == APFloat::cmpLessThan || - CR_r == APFloat::cmpUnordered) || - (CR_i == APFloat::cmpGreaterThan || - CR_i == APFloat::cmpLessThan || - CR_i == APFloat::cmpUnordered)), E); - } + bool IsEqual = CR_r == APFloat::cmpEqual && CR_i == APFloat::cmpEqual; + return Success(IsEqual ? CCR::Equal : CCR::Nonequal, E); } else { - if (E->getOpcode() == BO_EQ) - return Success((LHS.getComplexIntReal() == RHS.getComplexIntReal() && - LHS.getComplexIntImag() == RHS.getComplexIntImag()), E); - else { - assert(E->getOpcode() == BO_NE && - "Invalid compex comparison."); - return Success((LHS.getComplexIntReal() != RHS.getComplexIntReal() || - LHS.getComplexIntImag() != RHS.getComplexIntImag()), E); - } + assert(IsEquality && "invalid complex comparison"); + bool IsEqual = LHS.getComplexIntReal() == RHS.getComplexIntReal() && + LHS.getComplexIntImag() == RHS.getComplexIntImag(); + return Success(IsEqual ? CCR::Equal : CCR::Nonequal, E); } } @@ -8446,246 +8831,161 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { if (!EvaluateFloat(E->getLHS(), LHS, Info) || !LHSOK) return false; - APFloat::cmpResult CR = LHS.compare(RHS); - - switch (E->getOpcode()) { - default: - llvm_unreachable("Invalid binary operator!"); - case BO_LT: - return Success(CR == APFloat::cmpLessThan, E); - case BO_GT: - return Success(CR == APFloat::cmpGreaterThan, E); - case BO_LE: - return Success(CR == APFloat::cmpLessThan || CR == APFloat::cmpEqual, E); - case BO_GE: - return Success(CR == APFloat::cmpGreaterThan || CR == APFloat::cmpEqual, - E); - case BO_EQ: - return Success(CR == APFloat::cmpEqual, E); - case BO_NE: - return Success(CR == APFloat::cmpGreaterThan - || CR == APFloat::cmpLessThan - || CR == APFloat::cmpUnordered, E); - } + assert(E->isComparisonOp() && "Invalid binary operator!"); + auto GetCmpRes = [&]() { + switch (LHS.compare(RHS)) { + case APFloat::cmpEqual: + return CCR::Equal; + case APFloat::cmpLessThan: + return CCR::Less; + case APFloat::cmpGreaterThan: + return CCR::Greater; + case APFloat::cmpUnordered: + return CCR::Unordered; + } + llvm_unreachable("Unrecognised APFloat::cmpResult enum"); + }; + return Success(GetCmpRes(), E); } if (LHSTy->isPointerType() && RHSTy->isPointerType()) { - if (E->getOpcode() == BO_Sub || E->isComparisonOp()) { - LValue LHSValue, RHSValue; - - bool LHSOK = EvaluatePointer(E->getLHS(), LHSValue, Info); - if (!LHSOK && !Info.noteFailure()) - return false; - - if (!EvaluatePointer(E->getRHS(), RHSValue, Info) || !LHSOK) - return false; - - // Reject differing bases from the normal codepath; we special-case - // comparisons to null. - if (!HasSameBase(LHSValue, RHSValue)) { - if (E->getOpcode() == BO_Sub) { - // Handle &&A - &&B. - if (!LHSValue.Offset.isZero() || !RHSValue.Offset.isZero()) - return Error(E); - const Expr *LHSExpr = LHSValue.Base.dyn_cast<const Expr*>(); - const Expr *RHSExpr = RHSValue.Base.dyn_cast<const Expr*>(); - if (!LHSExpr || !RHSExpr) - return Error(E); - const AddrLabelExpr *LHSAddrExpr = dyn_cast<AddrLabelExpr>(LHSExpr); - const AddrLabelExpr *RHSAddrExpr = dyn_cast<AddrLabelExpr>(RHSExpr); - if (!LHSAddrExpr || !RHSAddrExpr) - return Error(E); - // Make sure both labels come from the same function. - if (LHSAddrExpr->getLabel()->getDeclContext() != - RHSAddrExpr->getLabel()->getDeclContext()) - return Error(E); - return Success(APValue(LHSAddrExpr, RHSAddrExpr), E); - } - // Inequalities and subtractions between unrelated pointers have - // unspecified or undefined behavior. - if (!E->isEqualityOp()) - return Error(E); - // A constant address may compare equal to the address of a symbol. - // The one exception is that address of an object cannot compare equal - // to a null pointer constant. - if ((!LHSValue.Base && !LHSValue.Offset.isZero()) || - (!RHSValue.Base && !RHSValue.Offset.isZero())) - return Error(E); - // It's implementation-defined whether distinct literals will have - // distinct addresses. In clang, the result of such a comparison is - // unspecified, so it is not a constant expression. However, we do know - // that the address of a literal will be non-null. - if ((IsLiteralLValue(LHSValue) || IsLiteralLValue(RHSValue)) && - LHSValue.Base && RHSValue.Base) - return Error(E); - // We can't tell whether weak symbols will end up pointing to the same - // object. - if (IsWeakLValue(LHSValue) || IsWeakLValue(RHSValue)) - return Error(E); - // We can't compare the address of the start of one object with the - // past-the-end address of another object, per C++ DR1652. - if ((LHSValue.Base && LHSValue.Offset.isZero() && - isOnePastTheEndOfCompleteObject(Info.Ctx, RHSValue)) || - (RHSValue.Base && RHSValue.Offset.isZero() && - isOnePastTheEndOfCompleteObject(Info.Ctx, LHSValue))) - return Error(E); - // We can't tell whether an object is at the same address as another - // zero sized object. - if ((RHSValue.Base && isZeroSized(LHSValue)) || - (LHSValue.Base && isZeroSized(RHSValue))) - return Error(E); - // Pointers with different bases cannot represent the same object. - // (Note that clang defaults to -fmerge-all-constants, which can - // lead to inconsistent results for comparisons involving the address - // of a constant; this generally doesn't matter in practice.) - return Success(E->getOpcode() == BO_NE, E); - } - - const CharUnits &LHSOffset = LHSValue.getLValueOffset(); - const CharUnits &RHSOffset = RHSValue.getLValueOffset(); - - SubobjectDesignator &LHSDesignator = LHSValue.getLValueDesignator(); - SubobjectDesignator &RHSDesignator = RHSValue.getLValueDesignator(); - - if (E->getOpcode() == BO_Sub) { - // C++11 [expr.add]p6: - // Unless both pointers point to elements of the same array object, or - // one past the last element of the array object, the behavior is - // undefined. - if (!LHSDesignator.Invalid && !RHSDesignator.Invalid && - !AreElementsOfSameArray(getType(LHSValue.Base), - LHSDesignator, RHSDesignator)) - CCEDiag(E, diag::note_constexpr_pointer_subtraction_not_same_array); - - QualType Type = E->getLHS()->getType(); - QualType ElementType = Type->getAs<PointerType>()->getPointeeType(); + LValue LHSValue, RHSValue; - CharUnits ElementSize; - 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.FFDiag(E, diag::note_constexpr_pointer_subtraction_zero_size) - << ElementType; - return false; - } + bool LHSOK = EvaluatePointer(E->getLHS(), LHSValue, Info); + if (!LHSOK && !Info.noteFailure()) + 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 - // assume the standard intended for such cases to be undefined behavior - // and check for them. - - // Compute (LHSOffset - RHSOffset) / Size carefully, checking for - // overflow in the final conversion to ptrdiff_t. - APSInt LHS( - llvm::APInt(65, (int64_t)LHSOffset.getQuantity(), true), false); - APSInt RHS( - llvm::APInt(65, (int64_t)RHSOffset.getQuantity(), true), false); - APSInt ElemSize( - llvm::APInt(65, (int64_t)ElementSize.getQuantity(), true), false); - APSInt TrueResult = (LHS - RHS) / ElemSize; - APSInt Result = TrueResult.trunc(Info.Ctx.getIntWidth(E->getType())); - - if (Result.extend(65) != TrueResult && - !HandleOverflow(Info, E, TrueResult, E->getType())) - return false; - return Success(Result, E); - } + if (!EvaluatePointer(E->getRHS(), RHSValue, Info) || !LHSOK) + return false; - // C++11 [expr.rel]p3: - // Pointers to void (after pointer conversions) can be compared, with a - // result defined as follows: If both pointers represent the same - // address or are both the null pointer value, the result is true if the - // operator is <= or >= and false otherwise; otherwise the result is - // unspecified. - // We interpret this as applying to pointers to *cv* void. - if (LHSTy->isVoidPointerType() && LHSOffset != RHSOffset && - E->isRelationalOp()) - CCEDiag(E, diag::note_constexpr_void_comparison); - - // C++11 [expr.rel]p2: - // - If two pointers point to non-static data members of the same object, - // or to subobjects or array elements fo such members, recursively, the - // pointer to the later declared member compares greater provided the - // two members have the same access control and provided their class is - // not a union. - // [...] - // - Otherwise pointer comparisons are unspecified. - if (!LHSDesignator.Invalid && !RHSDesignator.Invalid && - E->isRelationalOp()) { - bool WasArrayIndex; - unsigned Mismatch = - FindDesignatorMismatch(getType(LHSValue.Base), LHSDesignator, - RHSDesignator, WasArrayIndex); - // At the point where the designators diverge, the comparison has a - // specified value if: - // - we are comparing array indices - // - we are comparing fields of a union, or fields with the same access - // Otherwise, the result is unspecified and thus the comparison is not a - // constant expression. - if (!WasArrayIndex && Mismatch < LHSDesignator.Entries.size() && - Mismatch < RHSDesignator.Entries.size()) { - const FieldDecl *LF = getAsField(LHSDesignator.Entries[Mismatch]); - const FieldDecl *RF = getAsField(RHSDesignator.Entries[Mismatch]); - if (!LF && !RF) - CCEDiag(E, diag::note_constexpr_pointer_comparison_base_classes); - else if (!LF) - CCEDiag(E, diag::note_constexpr_pointer_comparison_base_field) + // Reject differing bases from the normal codepath; we special-case + // comparisons to null. + if (!HasSameBase(LHSValue, RHSValue)) { + // Inequalities and subtractions between unrelated pointers have + // unspecified or undefined behavior. + if (!IsEquality) + return Error(E); + // A constant address may compare equal to the address of a symbol. + // The one exception is that address of an object cannot compare equal + // to a null pointer constant. + if ((!LHSValue.Base && !LHSValue.Offset.isZero()) || + (!RHSValue.Base && !RHSValue.Offset.isZero())) + return Error(E); + // It's implementation-defined whether distinct literals will have + // distinct addresses. In clang, the result of such a comparison is + // unspecified, so it is not a constant expression. However, we do know + // that the address of a literal will be non-null. + if ((IsLiteralLValue(LHSValue) || IsLiteralLValue(RHSValue)) && + LHSValue.Base && RHSValue.Base) + return Error(E); + // We can't tell whether weak symbols will end up pointing to the same + // object. + if (IsWeakLValue(LHSValue) || IsWeakLValue(RHSValue)) + return Error(E); + // We can't compare the address of the start of one object with the + // past-the-end address of another object, per C++ DR1652. + if ((LHSValue.Base && LHSValue.Offset.isZero() && + isOnePastTheEndOfCompleteObject(Info.Ctx, RHSValue)) || + (RHSValue.Base && RHSValue.Offset.isZero() && + isOnePastTheEndOfCompleteObject(Info.Ctx, LHSValue))) + return Error(E); + // We can't tell whether an object is at the same address as another + // zero sized object. + if ((RHSValue.Base && isZeroSized(LHSValue)) || + (LHSValue.Base && isZeroSized(RHSValue))) + return Error(E); + return Success(CCR::Nonequal, E); + } + + const CharUnits &LHSOffset = LHSValue.getLValueOffset(); + const CharUnits &RHSOffset = RHSValue.getLValueOffset(); + + SubobjectDesignator &LHSDesignator = LHSValue.getLValueDesignator(); + SubobjectDesignator &RHSDesignator = RHSValue.getLValueDesignator(); + + // C++11 [expr.rel]p3: + // Pointers to void (after pointer conversions) can be compared, with a + // result defined as follows: If both pointers represent the same + // address or are both the null pointer value, the result is true if the + // operator is <= or >= and false otherwise; otherwise the result is + // unspecified. + // We interpret this as applying to pointers to *cv* void. + if (LHSTy->isVoidPointerType() && LHSOffset != RHSOffset && IsRelational) + Info.CCEDiag(E, diag::note_constexpr_void_comparison); + + // C++11 [expr.rel]p2: + // - If two pointers point to non-static data members of the same object, + // or to subobjects or array elements fo such members, recursively, the + // pointer to the later declared member compares greater provided the + // two members have the same access control and provided their class is + // not a union. + // [...] + // - Otherwise pointer comparisons are unspecified. + if (!LHSDesignator.Invalid && !RHSDesignator.Invalid && IsRelational) { + bool WasArrayIndex; + unsigned Mismatch = FindDesignatorMismatch( + getType(LHSValue.Base), LHSDesignator, RHSDesignator, WasArrayIndex); + // At the point where the designators diverge, the comparison has a + // specified value if: + // - we are comparing array indices + // - we are comparing fields of a union, or fields with the same access + // Otherwise, the result is unspecified and thus the comparison is not a + // constant expression. + if (!WasArrayIndex && Mismatch < LHSDesignator.Entries.size() && + Mismatch < RHSDesignator.Entries.size()) { + const FieldDecl *LF = getAsField(LHSDesignator.Entries[Mismatch]); + const FieldDecl *RF = getAsField(RHSDesignator.Entries[Mismatch]); + if (!LF && !RF) + Info.CCEDiag(E, diag::note_constexpr_pointer_comparison_base_classes); + else if (!LF) + Info.CCEDiag(E, diag::note_constexpr_pointer_comparison_base_field) << getAsBaseClass(LHSDesignator.Entries[Mismatch]) << RF->getParent() << RF; - else if (!RF) - CCEDiag(E, diag::note_constexpr_pointer_comparison_base_field) + else if (!RF) + Info.CCEDiag(E, diag::note_constexpr_pointer_comparison_base_field) << getAsBaseClass(RHSDesignator.Entries[Mismatch]) << LF->getParent() << LF; - else if (!LF->getParent()->isUnion() && - LF->getAccess() != RF->getAccess()) - CCEDiag(E, diag::note_constexpr_pointer_comparison_differing_access) + else if (!LF->getParent()->isUnion() && + LF->getAccess() != RF->getAccess()) + Info.CCEDiag(E, + diag::note_constexpr_pointer_comparison_differing_access) << LF << LF->getAccess() << RF << RF->getAccess() << LF->getParent(); - } - } - - // The comparison here must be unsigned, and performed with the same - // width as the pointer. - unsigned PtrSize = Info.Ctx.getTypeSize(LHSTy); - uint64_t CompareLHS = LHSOffset.getQuantity(); - uint64_t CompareRHS = RHSOffset.getQuantity(); - assert(PtrSize <= 64 && "Unexpected pointer width"); - uint64_t Mask = ~0ULL >> (64 - PtrSize); - CompareLHS &= Mask; - CompareRHS &= Mask; - - // If there is a base and this is a relational operator, we can only - // compare pointers within the object in question; otherwise, the result - // depends on where the object is located in memory. - if (!LHSValue.Base.isNull() && E->isRelationalOp()) { - QualType BaseTy = getType(LHSValue.Base); - if (BaseTy->isIncompleteType()) - return Error(E); - CharUnits Size = Info.Ctx.getTypeSizeInChars(BaseTy); - uint64_t OffsetLimit = Size.getQuantity(); - if (CompareLHS > OffsetLimit || CompareRHS > OffsetLimit) - return Error(E); } + } - switch (E->getOpcode()) { - default: llvm_unreachable("missing comparison operator"); - case BO_LT: return Success(CompareLHS < CompareRHS, E); - case BO_GT: return Success(CompareLHS > CompareRHS, E); - case BO_LE: return Success(CompareLHS <= CompareRHS, E); - case BO_GE: return Success(CompareLHS >= CompareRHS, E); - case BO_EQ: return Success(CompareLHS == CompareRHS, E); - case BO_NE: return Success(CompareLHS != CompareRHS, E); - } + // The comparison here must be unsigned, and performed with the same + // width as the pointer. + unsigned PtrSize = Info.Ctx.getTypeSize(LHSTy); + uint64_t CompareLHS = LHSOffset.getQuantity(); + uint64_t CompareRHS = RHSOffset.getQuantity(); + assert(PtrSize <= 64 && "Unexpected pointer width"); + uint64_t Mask = ~0ULL >> (64 - PtrSize); + CompareLHS &= Mask; + CompareRHS &= Mask; + + // If there is a base and this is a relational operator, we can only + // compare pointers within the object in question; otherwise, the result + // depends on where the object is located in memory. + if (!LHSValue.Base.isNull() && IsRelational) { + QualType BaseTy = getType(LHSValue.Base); + if (BaseTy->isIncompleteType()) + return Error(E); + CharUnits Size = Info.Ctx.getTypeSizeInChars(BaseTy); + uint64_t OffsetLimit = Size.getQuantity(); + if (CompareLHS > OffsetLimit || CompareRHS > OffsetLimit) + return Error(E); } + + if (CompareLHS < CompareRHS) + return Success(CCR::Less, E); + if (CompareLHS > CompareRHS) + return Success(CCR::Greater, E); + return Success(CCR::Equal, E); } if (LHSTy->isMemberPointerType()) { - assert(E->isEqualityOp() && "unexpected member pointer operation"); + assert(IsEquality && "unexpected member pointer operation"); assert(RHSTy->isMemberPointerType() && "invalid comparison"); MemberPtr LHSValue, RHSValue; @@ -8702,24 +9002,24 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { // null, they compare unequal. if (!LHSValue.getDecl() || !RHSValue.getDecl()) { bool Equal = !LHSValue.getDecl() && !RHSValue.getDecl(); - return Success(E->getOpcode() == BO_EQ ? Equal : !Equal, E); + return Success(Equal ? CCR::Equal : CCR::Nonequal, E); } // Otherwise if either is a pointer to a virtual member function, the // result is unspecified. if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(LHSValue.getDecl())) if (MD->isVirtual()) - CCEDiag(E, diag::note_constexpr_compare_virtual_mem_ptr) << MD; + Info.CCEDiag(E, diag::note_constexpr_compare_virtual_mem_ptr) << MD; if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(RHSValue.getDecl())) if (MD->isVirtual()) - CCEDiag(E, diag::note_constexpr_compare_virtual_mem_ptr) << MD; + Info.CCEDiag(E, diag::note_constexpr_compare_virtual_mem_ptr) << MD; // Otherwise they compare equal if and only if they would refer to the // same member of the same most derived object or the same subobject if // they were dereferenced with a hypothetical object of the associated // class type. bool Equal = LHSValue == RHSValue; - return Success(E->getOpcode() == BO_EQ ? Equal : !Equal, E); + return Success(Equal ? CCR::Equal : CCR::Nonequal, E); } if (LHSTy->isNullPtrType()) { @@ -8728,14 +9028,163 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { // C++11 [expr.rel]p4, [expr.eq]p3: If two operands of type std::nullptr_t // are compared, the result is true of the operator is <=, >= or ==, and // false otherwise. - BinaryOperator::Opcode Opcode = E->getOpcode(); - return Success(Opcode == BO_EQ || Opcode == BO_LE || Opcode == BO_GE, E); + return Success(CCR::Equal, E); } - assert((!LHSTy->isIntegralOrEnumerationType() || - !RHSTy->isIntegralOrEnumerationType()) && + return DoAfter(); +} + +bool RecordExprEvaluator::VisitBinCmp(const BinaryOperator *E) { + if (!CheckLiteralType(Info, E)) + return false; + + auto OnSuccess = [&](ComparisonCategoryResult ResKind, + const BinaryOperator *E) { + // Evaluation succeeded. Lookup the information for the comparison category + // type and fetch the VarDecl for the result. + const ComparisonCategoryInfo &CmpInfo = + Info.Ctx.CompCategories.getInfoForType(E->getType()); + const VarDecl *VD = + CmpInfo.getValueInfo(CmpInfo.makeWeakResult(ResKind))->VD; + // Check and evaluate the result as a constant expression. + LValue LV; + LV.set(VD); + if (!handleLValueToRValueConversion(Info, E, E->getType(), LV, Result)) + return false; + return CheckConstantExpression(Info, E->getExprLoc(), E->getType(), Result); + }; + return EvaluateComparisonBinaryOperator(Info, E, OnSuccess, [&]() { + return ExprEvaluatorBaseTy::VisitBinCmp(E); + }); +} + +bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { + // We don't call noteFailure immediately because the assignment happens after + // we evaluate LHS and RHS. + if (!Info.keepEvaluatingAfterFailure() && E->isAssignmentOp()) + return Error(E); + + DelayedNoteFailureRAII MaybeNoteFailureLater(Info, E->isAssignmentOp()); + if (DataRecursiveIntBinOpEvaluator::shouldEnqueue(E)) + return DataRecursiveIntBinOpEvaluator(*this, Result).Traverse(E); + + assert((!E->getLHS()->getType()->isIntegralOrEnumerationType() || + !E->getRHS()->getType()->isIntegralOrEnumerationType()) && "DataRecursiveIntBinOpEvaluator should have handled integral types"); - // We can't continue from here for non-integral types. + + if (E->isComparisonOp()) { + // Evaluate builtin binary comparisons by evaluating them as C++2a three-way + // comparisons and then translating the result. + auto OnSuccess = [&](ComparisonCategoryResult ResKind, + const BinaryOperator *E) { + using CCR = ComparisonCategoryResult; + bool IsEqual = ResKind == CCR::Equal, + IsLess = ResKind == CCR::Less, + IsGreater = ResKind == CCR::Greater; + auto Op = E->getOpcode(); + switch (Op) { + default: + llvm_unreachable("unsupported binary operator"); + case BO_EQ: + case BO_NE: + return Success(IsEqual == (Op == BO_EQ), E); + case BO_LT: return Success(IsLess, E); + case BO_GT: return Success(IsGreater, E); + case BO_LE: return Success(IsEqual || IsLess, E); + case BO_GE: return Success(IsEqual || IsGreater, E); + } + }; + return EvaluateComparisonBinaryOperator(Info, E, OnSuccess, [&]() { + return ExprEvaluatorBaseTy::VisitBinaryOperator(E); + }); + } + + QualType LHSTy = E->getLHS()->getType(); + QualType RHSTy = E->getRHS()->getType(); + + if (LHSTy->isPointerType() && RHSTy->isPointerType() && + E->getOpcode() == BO_Sub) { + LValue LHSValue, RHSValue; + + bool LHSOK = EvaluatePointer(E->getLHS(), LHSValue, Info); + if (!LHSOK && !Info.noteFailure()) + return false; + + if (!EvaluatePointer(E->getRHS(), RHSValue, Info) || !LHSOK) + return false; + + // Reject differing bases from the normal codepath; we special-case + // comparisons to null. + if (!HasSameBase(LHSValue, RHSValue)) { + // Handle &&A - &&B. + if (!LHSValue.Offset.isZero() || !RHSValue.Offset.isZero()) + return Error(E); + const Expr *LHSExpr = LHSValue.Base.dyn_cast<const Expr *>(); + const Expr *RHSExpr = RHSValue.Base.dyn_cast<const Expr *>(); + if (!LHSExpr || !RHSExpr) + return Error(E); + const AddrLabelExpr *LHSAddrExpr = dyn_cast<AddrLabelExpr>(LHSExpr); + const AddrLabelExpr *RHSAddrExpr = dyn_cast<AddrLabelExpr>(RHSExpr); + if (!LHSAddrExpr || !RHSAddrExpr) + return Error(E); + // Make sure both labels come from the same function. + if (LHSAddrExpr->getLabel()->getDeclContext() != + RHSAddrExpr->getLabel()->getDeclContext()) + return Error(E); + return Success(APValue(LHSAddrExpr, RHSAddrExpr), E); + } + const CharUnits &LHSOffset = LHSValue.getLValueOffset(); + const CharUnits &RHSOffset = RHSValue.getLValueOffset(); + + SubobjectDesignator &LHSDesignator = LHSValue.getLValueDesignator(); + SubobjectDesignator &RHSDesignator = RHSValue.getLValueDesignator(); + + // C++11 [expr.add]p6: + // Unless both pointers point to elements of the same array object, or + // one past the last element of the array object, the behavior is + // undefined. + if (!LHSDesignator.Invalid && !RHSDesignator.Invalid && + !AreElementsOfSameArray(getType(LHSValue.Base), LHSDesignator, + RHSDesignator)) + Info.CCEDiag(E, diag::note_constexpr_pointer_subtraction_not_same_array); + + QualType Type = E->getLHS()->getType(); + QualType ElementType = Type->getAs<PointerType>()->getPointeeType(); + + CharUnits ElementSize; + 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.FFDiag(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 + // assume the standard intended for such cases to be undefined behavior + // and check for them. + + // Compute (LHSOffset - RHSOffset) / Size carefully, checking for + // overflow in the final conversion to ptrdiff_t. + APSInt LHS(llvm::APInt(65, (int64_t)LHSOffset.getQuantity(), true), false); + APSInt RHS(llvm::APInt(65, (int64_t)RHSOffset.getQuantity(), true), false); + APSInt ElemSize(llvm::APInt(65, (int64_t)ElementSize.getQuantity(), true), + false); + APSInt TrueResult = (LHS - RHS) / ElemSize; + APSInt Result = TrueResult.trunc(Info.Ctx.getIntWidth(E->getType())); + + if (Result.extend(65) != TrueResult && + !HandleOverflow(Info, E, TrueResult, E->getType())) + return false; + return Success(Result, E); + } + return ExprEvaluatorBaseTy::VisitBinaryOperator(E); } @@ -8878,7 +9327,7 @@ bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { return false; if (!Result.isInt()) return Error(E); const APSInt &Value = Result.getInt(); - if (Value.isSigned() && Value.isMinSignedValue() && + if (Value.isSigned() && Value.isMinSignedValue() && E->canOverflow() && !HandleOverflow(Info, E, -Value.extend(Value.getBitWidth() + 1), E->getType())) return false; @@ -9083,6 +9532,37 @@ bool IntExprEvaluator::VisitCXXNoexceptExpr(const CXXNoexceptExpr *E) { return Success(E->getValue(), E); } +bool FixedPointExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { + switch (E->getOpcode()) { + default: + // Invalid unary operators + return Error(E); + case UO_Plus: + // The result is just the value. + return Visit(E->getSubExpr()); + case UO_Minus: { + if (!Visit(E->getSubExpr())) return false; + if (!Result.isInt()) return Error(E); + const APSInt &Value = Result.getInt(); + if (Value.isSigned() && Value.isMinSignedValue() && E->canOverflow()) { + SmallString<64> S; + FixedPointValueToString(S, Value, + Info.Ctx.getTypeInfo(E->getType()).Width, + /*Radix=*/10); + Info.CCEDiag(E, diag::note_constexpr_overflow) << S << E->getType(); + if (Info.noteUndefinedBehavior()) return false; + } + return Success(-Value, E); + } + case UO_LNot: { + bool bres; + if (!EvaluateAsBooleanCondition(E->getSubExpr(), bres, Info)) + return false; + return Success(!bres, E); + } + } +} + //===----------------------------------------------------------------------===// // Float Evaluation //===----------------------------------------------------------------------===// @@ -9170,9 +9650,11 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) { case Builtin::BI__builtin_huge_val: case Builtin::BI__builtin_huge_valf: case Builtin::BI__builtin_huge_vall: + case Builtin::BI__builtin_huge_valf128: case Builtin::BI__builtin_inf: case Builtin::BI__builtin_inff: - case Builtin::BI__builtin_infl: { + case Builtin::BI__builtin_infl: + case Builtin::BI__builtin_inff128: { const llvm::fltSemantics &Sem = Info.Ctx.getFloatTypeSemantics(E->getType()); Result = llvm::APFloat::getInf(Sem); @@ -9182,6 +9664,7 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) { case Builtin::BI__builtin_nans: case Builtin::BI__builtin_nansf: case Builtin::BI__builtin_nansl: + case Builtin::BI__builtin_nansf128: if (!TryEvaluateBuiltinNaN(Info.Ctx, E->getType(), E->getArg(0), true, Result)) return Error(E); @@ -9190,6 +9673,7 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) { case Builtin::BI__builtin_nan: case Builtin::BI__builtin_nanf: case Builtin::BI__builtin_nanl: + case Builtin::BI__builtin_nanf128: // If this is __builtin_nan() turn this into a nan, otherwise we // can't constant fold it. if (!TryEvaluateBuiltinNaN(Info.Ctx, E->getType(), E->getArg(0), @@ -9200,6 +9684,7 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) { case Builtin::BI__builtin_fabs: case Builtin::BI__builtin_fabsf: case Builtin::BI__builtin_fabsl: + case Builtin::BI__builtin_fabsf128: if (!EvaluateFloat(E->getArg(0), Result, Info)) return false; @@ -9213,7 +9698,8 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) { case Builtin::BI__builtin_copysign: case Builtin::BI__builtin_copysignf: - case Builtin::BI__builtin_copysignl: { + case Builtin::BI__builtin_copysignl: + case Builtin::BI__builtin_copysignf128: { APFloat RHS(0.); if (!EvaluateFloat(E->getArg(0), Result, Info) || !EvaluateFloat(E->getArg(1), RHS, Info)) @@ -9928,6 +10414,8 @@ static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) { if (!EvaluateComplex(E, C, Info)) return false; C.moveInto(Result); + } else if (T->isFixedPointType()) { + if (!FixedPointExprEvaluator(Info, Result).Visit(E)) return false; } else if (T->isMemberPointerType()) { MemberPtr P; if (!EvaluateMemberPointer(E, P, Info)) @@ -9936,15 +10424,13 @@ static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) { return true; } else if (T->isArrayType()) { LValue LV; - LV.set(E, Info.CurrentCall->Index); - APValue &Value = Info.CurrentCall->createTemporary(E, false); + APValue &Value = createTemporary(E, false, LV, *Info.CurrentCall); if (!EvaluateArray(E, LV, Value, Info)) return false; Result = Value; } else if (T->isRecordType()) { LValue LV; - LV.set(E, Info.CurrentCall->Index); - APValue &Value = Info.CurrentCall->createTemporary(E, false); + APValue &Value = createTemporary(E, false, LV, *Info.CurrentCall); if (!EvaluateRecord(E, LV, Value, Info)) return false; Result = Value; @@ -9958,8 +10444,7 @@ static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) { QualType Unqual = T.getAtomicUnqualifiedType(); if (Unqual->isArrayType() || Unqual->isRecordType()) { LValue LV; - LV.set(E, Info.CurrentCall->Index); - APValue &Value = Info.CurrentCall->createTemporary(E, false); + APValue &Value = createTemporary(E, false, LV, *Info.CurrentCall); if (!EvaluateAtomic(E, &LV, Value, Info)) return false; } else { @@ -10120,13 +10605,25 @@ bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx) const { LValue LV; if (!EvaluateLValue(this, LV, Info) || Result.HasSideEffects || !CheckLValueConstantExpression(Info, getExprLoc(), - Ctx.getLValueReferenceType(getType()), LV)) + Ctx.getLValueReferenceType(getType()), LV, + Expr::EvaluateForCodeGen)) return false; LV.moveInto(Result.Val); return true; } +bool Expr::EvaluateAsConstantExpr(EvalResult &Result, ConstExprUsage Usage, + const ASTContext &Ctx) const { + EvalInfo::EvaluationMode EM = EvalInfo::EM_ConstantExpression; + EvalInfo Info(Ctx, Result, EM); + if (!::Evaluate(Result.Val, Info, this)) + return false; + + return CheckConstantExpression(Info, getExprLoc(), getType(), Result.Val, + Usage); +} + bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx, const VarDecl *VD, SmallVectorImpl<PartialDiagnosticAt> &Notes) const { @@ -10367,6 +10864,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { case Expr::GenericSelectionExprClass: return CheckICE(cast<GenericSelectionExpr>(E)->getResultExpr(), Ctx); case Expr::IntegerLiteralClass: + case Expr::FixedPointLiteralClass: case Expr::CharacterLiteralClass: case Expr::ObjCBoolLiteralExprClass: case Expr::CXXBoolLiteralExprClass: @@ -10389,7 +10887,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { case Expr::DeclRefExprClass: { if (isa<EnumConstantDecl>(cast<DeclRefExpr>(E)->getDecl())) return NoDiag(); - const ValueDecl *D = dyn_cast<ValueDecl>(cast<DeclRefExpr>(E)->getDecl()); + const ValueDecl *D = cast<DeclRefExpr>(E)->getDecl(); if (Ctx.getLangOpts().CPlusPlus && D && IsConstNonVolatile(D->getType())) { // Parameter variables are never constants. Without this check, @@ -10475,7 +10973,6 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { case BO_AndAssign: case BO_XorAssign: case BO_OrAssign: - case BO_Cmp: // FIXME: Re-enable once we can evaluate this. // C99 6.6/3 allows assignments within unevaluated subexpressions of // constant expressions, but they can never be ICEs because an ICE cannot // contain an lvalue operand. @@ -10497,7 +10994,8 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { case BO_And: case BO_Xor: case BO_Or: - case BO_Comma: { + case BO_Comma: + case BO_Cmp: { ICEDiag LHSResult = CheckICE(Exp->getLHS(), Ctx); ICEDiag RHSResult = CheckICE(Exp->getRHS(), Ctx); if (Exp->getOpcode() == BO_Div || @@ -10644,7 +11142,7 @@ static bool EvaluateCPlusPlus11IntegralConstantExpr(const ASTContext &Ctx, const Expr *E, llvm::APSInt *Value, SourceLocation *Loc) { - if (!E->getType()->isIntegralOrEnumerationType()) { + if (!E->getType()->isIntegralOrUnscopedEnumerationType()) { if (Loc) *Loc = E->getExprLoc(); return false; } @@ -10781,7 +11279,7 @@ bool Expr::isPotentialConstantExpr(const FunctionDecl *FD, // is a temporary being used as the 'this' pointer. LValue This; ImplicitValueInitExpr VIE(RD ? Info.Ctx.getRecordType(RD) : Info.Ctx.IntTy); - This.set(&VIE, Info.CurrentCall->Index); + This.set({&VIE, Info.CurrentCall->Index}); ArrayRef<const Expr*> Args; diff --git a/lib/AST/ExternalASTMerger.cpp b/lib/AST/ExternalASTMerger.cpp index 6b75c51c6420..ae28c588ca31 100644 --- a/lib/AST/ExternalASTMerger.cpp +++ b/lib/AST/ExternalASTMerger.cpp @@ -16,6 +16,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/ExternalASTMerger.h" using namespace clang; @@ -153,7 +154,7 @@ public: ToContainer->setMustBuildLookupTable(); assert(Parent.CanComplete(ToContainer)); } - return ASTImporter::Imported(From, To); + return To; } ASTImporter &GetReverse() { return Reverse; } }; @@ -228,7 +229,7 @@ void ExternalASTMerger::CompleteType(TagDecl *Tag) { SourceTag->getASTContext().getExternalSource()->CompleteType(SourceTag); if (!SourceTag->getDefinition()) return false; - Forward.Imported(SourceTag, Tag); + Forward.MapImported(SourceTag, Tag); Forward.ImportDefinition(SourceTag); Tag->setCompleteDefinition(SourceTag->isCompleteDefinition()); return true; @@ -247,7 +248,7 @@ void ExternalASTMerger::CompleteType(ObjCInterfaceDecl *Interface) { SourceInterface); if (!SourceInterface->getDefinition()) return false; - Forward.Imported(SourceInterface, Interface); + Forward.MapImported(SourceInterface, Interface); Forward.ImportDefinition(SourceInterface); return true; }); @@ -303,7 +304,7 @@ void ExternalASTMerger::ForceRecordOrigin(const DeclContext *ToDC, void ExternalASTMerger::RecordOriginImpl(const DeclContext *ToDC, DCOrigin Origin, ASTImporter &Importer) { Origins[ToDC] = Origin; - Importer.ASTImporter::Imported(cast<Decl>(Origin.DC), const_cast<Decl*>(cast<Decl>(ToDC))); + Importer.ASTImporter::MapImported(cast<Decl>(Origin.DC), const_cast<Decl*>(cast<Decl>(ToDC))); } ExternalASTMerger::ExternalASTMerger(const ImporterTarget &Target, @@ -351,6 +352,27 @@ void ExternalASTMerger::RemoveSources(llvm::ArrayRef<ImporterSource> Sources) { } } +template <typename DeclTy> +static bool importSpecializations(DeclTy *D, ASTImporter *Importer) { + for (auto *Spec : D->specializations()) + if (!Importer->Import(Spec)) + return true; + return false; +} + +/// Imports specializations from template declarations that can be specialized. +static bool importSpecializationsIfNeeded(Decl *D, ASTImporter *Importer) { + if (!isa<TemplateDecl>(D)) + return false; + if (auto *FunctionTD = dyn_cast<FunctionTemplateDecl>(D)) + return importSpecializations(FunctionTD, Importer); + else if (auto *ClassTD = dyn_cast<ClassTemplateDecl>(D)) + return importSpecializations(ClassTD, Importer); + else if (auto *VarTD = dyn_cast<VarTemplateDecl>(D)) + return importSpecializations(VarTD, Importer); + return false; +} + bool ExternalASTMerger::FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name) { llvm::SmallVector<NamedDecl *, 1> Decls; @@ -376,9 +398,18 @@ bool ExternalASTMerger::FindExternalVisibleDeclsByName(const DeclContext *DC, Decls.reserve(Candidates.size()); for (const Candidate &C : Candidates) { - NamedDecl *d = cast<NamedDecl>(C.second->Import(C.first.get())); - assert(d); - Decls.push_back(d); + Decl *LookupRes = C.first.get(); + ASTImporter *Importer = C.second; + NamedDecl *ND = cast_or_null<NamedDecl>(Importer->Import(LookupRes)); + assert(ND); + // If we don't import specialization, they are not available via lookup + // because the lookup result is imported TemplateDecl and it does not + // reference its specializations until they are imported explicitly. + bool IsSpecImportFailed = + importSpecializationsIfNeeded(LookupRes, Importer); + assert(!IsSpecImportFailed); + (void)IsSpecImportFailed; + Decls.push_back(ND); } SetExternalVisibleDeclsForName(DC, Name, Decls); return true; diff --git a/lib/AST/ItaniumCXXABI.cpp b/lib/AST/ItaniumCXXABI.cpp index d6bc16b6350f..a75ae14f9015 100644 --- a/lib/AST/ItaniumCXXABI.cpp +++ b/lib/AST/ItaniumCXXABI.cpp @@ -24,6 +24,7 @@ #include "clang/AST/RecordLayout.h" #include "clang/AST/Type.h" #include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/iterator.h" using namespace clang; @@ -50,12 +51,64 @@ static const IdentifierInfo *findAnonymousUnionVarDeclName(const VarDecl& VD) { return nullptr; } -/// \brief Keeps track of the mangled names of lambda expressions and block +/// The name of a decomposition declaration. +struct DecompositionDeclName { + using BindingArray = ArrayRef<const BindingDecl*>; + + /// Representative example of a set of bindings with these names. + BindingArray Bindings; + + /// Iterators over the sequence of identifiers in the name. + struct Iterator + : llvm::iterator_adaptor_base<Iterator, BindingArray::const_iterator, + std::random_access_iterator_tag, + const IdentifierInfo *> { + Iterator(BindingArray::const_iterator It) : iterator_adaptor_base(It) {} + const IdentifierInfo *operator*() const { + return (*this->I)->getIdentifier(); + } + }; + Iterator begin() const { return Iterator(Bindings.begin()); } + Iterator end() const { return Iterator(Bindings.end()); } +}; +} + +namespace llvm { +template<> +struct DenseMapInfo<DecompositionDeclName> { + using ArrayInfo = llvm::DenseMapInfo<ArrayRef<const BindingDecl*>>; + using IdentInfo = llvm::DenseMapInfo<const IdentifierInfo*>; + static DecompositionDeclName getEmptyKey() { + return {ArrayInfo::getEmptyKey()}; + } + static DecompositionDeclName getTombstoneKey() { + return {ArrayInfo::getTombstoneKey()}; + } + static unsigned getHashValue(DecompositionDeclName Key) { + assert(!isEqual(Key, getEmptyKey()) && !isEqual(Key, getTombstoneKey())); + return llvm::hash_combine_range(Key.begin(), Key.end()); + } + static bool isEqual(DecompositionDeclName LHS, DecompositionDeclName RHS) { + if (ArrayInfo::isEqual(LHS.Bindings, ArrayInfo::getEmptyKey())) + return ArrayInfo::isEqual(RHS.Bindings, ArrayInfo::getEmptyKey()); + if (ArrayInfo::isEqual(LHS.Bindings, ArrayInfo::getTombstoneKey())) + return ArrayInfo::isEqual(RHS.Bindings, ArrayInfo::getTombstoneKey()); + return LHS.Bindings.size() == RHS.Bindings.size() && + std::equal(LHS.begin(), LHS.end(), RHS.begin()); + } +}; +} + +namespace { + +/// Keeps track of the mangled names of lambda expressions and block /// literals within a particular context. class ItaniumNumberingContext : public MangleNumberingContext { llvm::DenseMap<const Type *, unsigned> ManglingNumbers; llvm::DenseMap<const IdentifierInfo *, unsigned> VarManglingNumbers; llvm::DenseMap<const IdentifierInfo *, unsigned> TagManglingNumbers; + llvm::DenseMap<DecompositionDeclName, unsigned> + DecompsitionDeclManglingNumbers; public: unsigned getManglingNumber(const CXXMethodDecl *CallOperator) override { @@ -82,9 +135,15 @@ public: /// Variable decls are numbered by identifier. unsigned getManglingNumber(const VarDecl *VD, unsigned) override { + if (auto *DD = dyn_cast<DecompositionDecl>(VD)) { + DecompositionDeclName Name{DD->bindings()}; + return ++DecompsitionDeclManglingNumbers[Name]; + } + const IdentifierInfo *Identifier = VD->getIdentifier(); if (!Identifier) { - // VarDecl without an identifier represents an anonymous union declaration. + // VarDecl without an identifier represents an anonymous union + // declaration. Identifier = findAnonymousUnionVarDeclName(*VD); } return ++VarManglingNumbers[Identifier]; diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index 3c7e26d41370..3b99a3d9afda 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -323,7 +323,7 @@ class CXXNameMangler { AdditionalAbiTags->end()); } - std::sort(TagList.begin(), TagList.end()); + llvm::sort(TagList.begin(), TagList.end()); TagList.erase(std::unique(TagList.begin(), TagList.end()), TagList.end()); writeSortedUniqueAbiTags(Out, TagList); @@ -339,7 +339,7 @@ class CXXNameMangler { } const AbiTagList &getSortedUniqueUsedAbiTags() { - std::sort(UsedAbiTags.begin(), UsedAbiTags.end()); + llvm::sort(UsedAbiTags.begin(), UsedAbiTags.end()); UsedAbiTags.erase(std::unique(UsedAbiTags.begin(), UsedAbiTags.end()), UsedAbiTags.end()); return UsedAbiTags; @@ -539,7 +539,9 @@ private: void mangleBareFunctionType(const FunctionProtoType *T, bool MangleReturnType, const FunctionDecl *FD = nullptr); void mangleNeonVectorType(const VectorType *T); + void mangleNeonVectorType(const DependentVectorType *T); void mangleAArch64NeonVectorType(const VectorType *T); + void mangleAArch64NeonVectorType(const DependentVectorType *T); void mangleIntegerLiteral(QualType T, const llvm::APSInt &Value); void mangleMemberExprBase(const Expr *base, bool isArrow); @@ -590,6 +592,18 @@ bool ItaniumMangleContextImpl::shouldMangleCXXName(const NamedDecl *D) { if (FD->isMain()) return false; + // The Windows 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; + // C++ functions and those whose names are not a simple identifier need // mangling. if (!FD->getDeclName().isIdentifier() || L == CXXLanguageLinkage) @@ -1324,8 +1338,7 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) { // We must have an anonymous union or struct declaration. - const RecordDecl *RD = - cast<RecordDecl>(VD->getType()->getAs<RecordType>()->getDecl()); + const RecordDecl *RD = VD->getType()->getAs<RecordType>()->getDecl(); // Itanium C++ ABI 5.1.2: // @@ -1931,6 +1944,7 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty, case Type::VariableArray: case Type::DependentSizedArray: case Type::DependentAddressSpace: + case Type::DependentVector: case Type::DependentSizedExtVector: case Type::Vector: case Type::ExtVector: @@ -2330,7 +2344,8 @@ void CXXNameMangler::mangleObjCMethodName(const ObjCMethodDecl *MD) { Context.mangleObjCMethodName(MD, Out); } -static bool isTypeSubstitutable(Qualifiers Quals, const Type *Ty) { +static bool isTypeSubstitutable(Qualifiers Quals, const Type *Ty, + ASTContext &Ctx) { if (Quals) return true; if (Ty->isSpecificBuiltinType(BuiltinType::ObjCSel)) @@ -2339,7 +2354,11 @@ static bool isTypeSubstitutable(Qualifiers Quals, const Type *Ty) { return true; if (Ty->isBuiltinType()) return false; - + // Through to Clang 6.0, we accidentally treated undeduced auto types as + // substitution candidates. + if (Ctx.getLangOpts().getClangABICompat() > LangOptions::ClangABI::Ver6 && + isa<AutoType>(Ty)) + return false; return true; } @@ -2400,7 +2419,8 @@ void CXXNameMangler::mangleType(QualType T) { Qualifiers quals = split.Quals; const Type *ty = split.Ty; - bool isSubstitutable = isTypeSubstitutable(quals, ty); + bool isSubstitutable = + isTypeSubstitutable(quals, ty, Context.getASTContext()); if (isSubstitutable && mangleSubstitution(T)) return; @@ -2520,6 +2540,9 @@ void CXXNameMangler::mangleType(const BuiltinType *T) { case BuiltinType::WChar_U: Out << 'w'; break; + case BuiltinType::Char8: + Out << "Du"; + break; case BuiltinType::Char16: Out << "Ds"; break; @@ -2544,6 +2567,31 @@ void CXXNameMangler::mangleType(const BuiltinType *T) { case BuiltinType::Float16: Out << "DF16_"; break; + case BuiltinType::ShortAccum: + case BuiltinType::Accum: + case BuiltinType::LongAccum: + case BuiltinType::UShortAccum: + case BuiltinType::UAccum: + case BuiltinType::ULongAccum: + case BuiltinType::ShortFract: + case BuiltinType::Fract: + case BuiltinType::LongFract: + case BuiltinType::UShortFract: + case BuiltinType::UFract: + case BuiltinType::ULongFract: + case BuiltinType::SatShortAccum: + case BuiltinType::SatAccum: + case BuiltinType::SatLongAccum: + case BuiltinType::SatUShortAccum: + case BuiltinType::SatUAccum: + case BuiltinType::SatULongAccum: + case BuiltinType::SatShortFract: + case BuiltinType::SatFract: + case BuiltinType::SatLongFract: + case BuiltinType::SatUShortFract: + case BuiltinType::SatUFract: + case BuiltinType::SatULongFract: + llvm_unreachable("Fixed point types are disabled for c++"); case BuiltinType::Half: Out << "Dh"; break; @@ -2689,12 +2737,12 @@ void CXXNameMangler::mangleType(const FunctionProtoType *T) { // Mangle CV-qualifiers, if present. These are 'this' qualifiers, // e.g. "const" in "int (A::*)() const". - mangleQualifiers(Qualifiers::fromCVRMask(T->getTypeQuals())); + mangleQualifiers(Qualifiers::fromCVRUMask(T->getTypeQuals())); // Mangle instantiation-dependent exception-specification, if present, // per cxx-abi-dev proposal on 2016-10-11. if (T->hasInstantiationDependentExceptionSpec()) { - if (T->getExceptionSpecType() == EST_ComputedNoexcept) { + if (isComputedNoexcept(T->getExceptionSpecType())) { Out << "DO"; mangleExpression(T->getNoexceptExpr()); Out << "E"; @@ -2705,7 +2753,7 @@ void CXXNameMangler::mangleType(const FunctionProtoType *T) { mangleType(ExceptTy); Out << "E"; } - } else if (T->isNothrow(getASTContext())) { + } else if (T->isNothrow()) { Out << "Do"; } @@ -2967,6 +3015,14 @@ void CXXNameMangler::mangleNeonVectorType(const VectorType *T) { Out << BaseName << EltName; } +void CXXNameMangler::mangleNeonVectorType(const DependentVectorType *T) { + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID( + DiagnosticsEngine::Error, + "cannot mangle this dependent neon vector type yet"); + Diags.Report(T->getAttributeLoc(), DiagID); +} + static StringRef mangleAArch64VectorBase(const BuiltinType *EltType) { switch (EltType->getKind()) { case BuiltinType::SChar: @@ -3034,6 +3090,13 @@ void CXXNameMangler::mangleAArch64NeonVectorType(const VectorType *T) { ("__" + EltName + "x" + Twine(T->getNumElements()) + "_t").str(); Out << TypeName.length() << TypeName; } +void CXXNameMangler::mangleAArch64NeonVectorType(const DependentVectorType *T) { + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID( + DiagnosticsEngine::Error, + "cannot mangle this dependent neon vector type yet"); + Diags.Report(T->getAttributeLoc(), DiagID); +} // GNU extension: vector types // <type> ::= <vector-type> @@ -3064,6 +3127,32 @@ void CXXNameMangler::mangleType(const VectorType *T) { else mangleType(T->getElementType()); } + +void CXXNameMangler::mangleType(const DependentVectorType *T) { + if ((T->getVectorKind() == VectorType::NeonVector || + T->getVectorKind() == VectorType::NeonPolyVector)) { + llvm::Triple Target = getASTContext().getTargetInfo().getTriple(); + llvm::Triple::ArchType Arch = + getASTContext().getTargetInfo().getTriple().getArch(); + if ((Arch == llvm::Triple::aarch64 || Arch == llvm::Triple::aarch64_be) && + !Target.isOSDarwin()) + mangleAArch64NeonVectorType(T); + else + mangleNeonVectorType(T); + return; + } + + Out << "Dv"; + mangleExpression(T->getSizeExpr()); + Out << '_'; + if (T->getVectorKind() == VectorType::AltiVecPixel) + Out << 'p'; + else if (T->getVectorKind() == VectorType::AltiVecBool) + Out << 'b'; + else + mangleType(T->getElementType()); +} + void CXXNameMangler::mangleType(const ExtVectorType *T) { mangleType(static_cast<const VectorType*>(T)); } @@ -3251,14 +3340,13 @@ void CXXNameMangler::mangleType(const UnaryTransformType *T) { } void CXXNameMangler::mangleType(const AutoType *T) { - QualType D = T->getDeducedType(); - // <builtin-type> ::= Da # dependent auto - if (D.isNull()) { - assert(T->getKeyword() != AutoTypeKeyword::GNUAutoType && - "shouldn't need to mangle __auto_type!"); - Out << (T->isDecltypeAuto() ? "Dc" : "Da"); - } else - mangleType(D); + assert(T->getDeducedType().isNull() && + "Deduced AutoType shouldn't be handled here!"); + assert(T->getKeyword() != AutoTypeKeyword::GNUAutoType && + "shouldn't need to mangle __auto_type!"); + // <builtin-type> ::= Da # auto + // ::= Dc # decltype(auto) + Out << (T->isDecltypeAuto() ? "Dc" : "Da"); } void CXXNameMangler::mangleType(const DeducedTemplateSpecializationType *T) { @@ -3471,6 +3559,7 @@ recurse: case Expr::AsTypeExprClass: case Expr::PseudoObjectExprClass: case Expr::AtomicExprClass: + case Expr::FixedPointLiteralClass: { if (!NullOut) { // As bad as this diagnostic is, it's better than crashing. diff --git a/lib/AST/MicrosoftCXXABI.cpp b/lib/AST/MicrosoftCXXABI.cpp index b19491f31304..3b417c135285 100644 --- a/lib/AST/MicrosoftCXXABI.cpp +++ b/lib/AST/MicrosoftCXXABI.cpp @@ -25,7 +25,7 @@ using namespace clang; namespace { -/// \brief Numbers things which need to correspond across multiple TUs. +/// Numbers things which need to correspond across multiple TUs. /// Typically these are things like static locals, lambdas, or blocks. class MicrosoftNumberingContext : public MangleNumberingContext { llvm::DenseMap<const Type *, unsigned> ManglingNumbers; @@ -106,7 +106,7 @@ public: void addTypedefNameForUnnamedTagDecl(TagDecl *TD, TypedefNameDecl *DD) override { TD = TD->getCanonicalDecl(); - DD = cast<TypedefNameDecl>(DD->getCanonicalDecl()); + DD = DD->getCanonicalDecl(); TypedefNameDecl *&I = UnnamedTagDeclToTypedefNameDecl[TD]; if (!I) I = DD; diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp index 0c55c1a92287..e45f9f7902e2 100644 --- a/lib/AST/MicrosoftMangle.cpp +++ b/lib/AST/MicrosoftMangle.cpp @@ -76,7 +76,7 @@ getLambdaDefaultArgumentDeclContext(const Decl *D) { return nullptr; } -/// \brief Retrieve the declaration context that should be used when mangling +/// 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 @@ -135,7 +135,8 @@ public: bool shouldMangleStringLiteral(const StringLiteral *SL) override; void mangleCXXName(const NamedDecl *D, raw_ostream &Out) override; void mangleVirtualMemPtrThunk(const CXXMethodDecl *MD, - raw_ostream &) override; + const MethodVFTableLocation &ML, + raw_ostream &Out) override; void mangleThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk, raw_ostream &) override; void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type, @@ -290,16 +291,15 @@ public: raw_ostream &getStream() const { return Out; } - void mangle(const NamedDecl *D, StringRef Prefix = "\01?"); + void mangle(const NamedDecl *D, StringRef Prefix = "?"); void mangleName(const NamedDecl *ND); void mangleFunctionEncoding(const FunctionDecl *FD, bool ShouldMangle); void mangleVariableEncoding(const VarDecl *VD); void mangleMemberDataPointer(const CXXRecordDecl *RD, const ValueDecl *VD); void mangleMemberFunctionPointer(const CXXRecordDecl *RD, const CXXMethodDecl *MD); - void mangleVirtualMemPtrThunk( - const CXXMethodDecl *MD, - const MicrosoftVTableContext::MethodVFTableLocation &ML); + void mangleVirtualMemPtrThunk(const CXXMethodDecl *MD, + const MethodVFTableLocation &ML); void mangleNumber(int64_t Number); void mangleTagTypeKind(TagTypeKind TK); void mangleArtificalTagType(TagTypeKind TK, StringRef UnqualifiedName, @@ -337,6 +337,8 @@ private: void mangleArgumentType(QualType T, SourceRange Range); void manglePassObjectSizeArg(const PassObjectSizeAttr *POSA); + bool isArtificialTagType(QualType T) const; + // Declare manglers for every type class. #define ABSTRACT_TYPE(CLASS, PARENT) #define NON_CANONICAL_TYPE(CLASS, PARENT) @@ -362,6 +364,10 @@ private: const TemplateArgumentList &TemplateArgs); void mangleTemplateArg(const TemplateDecl *TD, const TemplateArgument &TA, const NamedDecl *Parm); + + void mangleObjCProtocol(const ObjCProtocolDecl *PD); + void mangleObjCLifetime(const QualType T, Qualifiers Quals, + SourceRange Range); }; } @@ -603,7 +609,7 @@ MicrosoftCXXNameMangler::mangleMemberFunctionPointer(const CXXRecordDecl *RD, if (MD->isVirtual()) { MicrosoftVTableContext *VTContext = cast<MicrosoftVTableContext>(getASTContext().getVTableContext()); - const MicrosoftVTableContext::MethodVFTableLocation &ML = + MethodVFTableLocation ML = VTContext->getMethodVFTableLocation(GlobalDecl(MD)); mangleVirtualMemPtrThunk(MD, ML); NVOffset = ML.VFPtrOffset.getQuantity(); @@ -640,8 +646,7 @@ MicrosoftCXXNameMangler::mangleMemberFunctionPointer(const CXXRecordDecl *RD, } void MicrosoftCXXNameMangler::mangleVirtualMemPtrThunk( - const CXXMethodDecl *MD, - const MicrosoftVTableContext::MethodVFTableLocation &ML) { + const CXXMethodDecl *MD, const MethodVFTableLocation &ML) { // Get the vftable offset. CharUnits PointerWidth = getASTContext().toCharUnitsFromBits( getASTContext().getTargetInfo().getPointerWidth(0)); @@ -881,11 +886,13 @@ void MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, // associate typedef mangled in if they have one. Name += "<unnamed-type-"; Name += TND->getName(); - } else if (auto *ED = dyn_cast<EnumDecl>(TD)) { - auto EnumeratorI = ED->enumerator_begin(); - assert(EnumeratorI != ED->enumerator_end()); + } else if (isa<EnumDecl>(TD) && + cast<EnumDecl>(TD)->enumerator_begin() != + cast<EnumDecl>(TD)->enumerator_end()) { + // Anonymous non-empty enums mangle in the first enumerator. + auto *ED = cast<EnumDecl>(TD); Name += "<unnamed-enum-"; - Name += EnumeratorI->getName(); + Name += ED->enumerator_begin()->getName(); } else { // Otherwise, number the types using a $S prefix. Name += "<unnamed-type-$S"; @@ -950,11 +957,10 @@ void MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, } } +// <postfix> ::= <unqualified-name> [<postfix>] +// ::= <substitution> [<postfix>] void MicrosoftCXXNameMangler::mangleNestedName(const NamedDecl *ND) { - // <postfix> ::= <unqualified-name> [<postfix>] - // ::= <substitution> [<postfix>] const DeclContext *DC = getEffectiveDeclContext(ND); - while (!DC->isTranslationUnit()) { if (isa<TagDecl>(ND) || isa<VarDecl>(ND)) { unsigned Disc; @@ -1007,7 +1013,7 @@ void MicrosoftCXXNameMangler::mangleNestedName(const NamedDecl *ND) { if (const auto *ND = dyn_cast<NamedDecl>(MC)) mangleUnqualifiedName(ND); // MS ABI and Itanium manglings are in inverted scopes. In the case of a - // RecordDecl, mangle the entire scope hierachy at this point rather than + // RecordDecl, mangle the entire scope hierarchy at this point rather than // just the unqualified name to get the ordering correct. if (const auto *RD = dyn_cast<RecordDecl>(DC)) mangleName(RD); @@ -1365,15 +1371,15 @@ void MicrosoftCXXNameMangler::mangleTemplateArg(const TemplateDecl *TD, break; } case TemplateArgument::Declaration: { - const NamedDecl *ND = cast<NamedDecl>(TA.getAsDecl()); + const NamedDecl *ND = TA.getAsDecl(); if (isa<FieldDecl>(ND) || isa<IndirectFieldDecl>(ND)) { mangleMemberDataPointer( - cast<CXXRecordDecl>(ND->getDeclContext())->getMostRecentDecl(), + cast<CXXRecordDecl>(ND->getDeclContext())->getMostRecentNonInjectedDecl(), cast<ValueDecl>(ND)); } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) { const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD); if (MD && MD->isInstance()) { - mangleMemberFunctionPointer(MD->getParent()->getMostRecentDecl(), MD); + mangleMemberFunctionPointer(MD->getParent()->getMostRecentNonInjectedDecl(), MD); } else { Out << "$1?"; mangleName(FD); @@ -1457,6 +1463,47 @@ void MicrosoftCXXNameMangler::mangleTemplateArg(const TemplateDecl *TD, } } +void MicrosoftCXXNameMangler::mangleObjCProtocol(const ObjCProtocolDecl *PD) { + llvm::SmallString<64> TemplateMangling; + llvm::raw_svector_ostream Stream(TemplateMangling); + MicrosoftCXXNameMangler Extra(Context, Stream); + + Stream << "?$"; + Extra.mangleSourceName("Protocol"); + Extra.mangleArtificalTagType(TTK_Struct, PD->getName()); + + mangleArtificalTagType(TTK_Struct, TemplateMangling, {"__ObjC"}); +} + +void MicrosoftCXXNameMangler::mangleObjCLifetime(const QualType Type, + Qualifiers Quals, + SourceRange Range) { + llvm::SmallString<64> TemplateMangling; + llvm::raw_svector_ostream Stream(TemplateMangling); + MicrosoftCXXNameMangler Extra(Context, Stream); + + Stream << "?$"; + switch (Quals.getObjCLifetime()) { + case Qualifiers::OCL_None: + case Qualifiers::OCL_ExplicitNone: + break; + case Qualifiers::OCL_Autoreleasing: + Extra.mangleSourceName("Autoreleasing"); + break; + case Qualifiers::OCL_Strong: + Extra.mangleSourceName("Strong"); + break; + case Qualifiers::OCL_Weak: + Extra.mangleSourceName("Weak"); + break; + } + Extra.manglePointerCVQualifiers(Quals); + Extra.manglePointerExtQualifiers(Quals, Type); + Extra.mangleType(Type, Range); + + mangleArtificalTagType(TTK_Struct, TemplateMangling, {"__ObjC"}); +} + void MicrosoftCXXNameMangler::mangleQualifiers(Qualifiers Quals, bool IsMember) { // <cvr-qualifiers> ::= [E] [F] [I] <base-cvr-qualifiers> @@ -1559,12 +1606,11 @@ MicrosoftCXXNameMangler::mangleRefQualifier(RefQualifierKind RefQualifier) { void MicrosoftCXXNameMangler::manglePointerExtQualifiers(Qualifiers Quals, QualType PointeeType) { - bool HasRestrict = Quals.hasRestrict(); if (PointersAre64Bit && (PointeeType.isNull() || !PointeeType->isFunctionType())) Out << 'E'; - if (HasRestrict) + if (Quals.hasRestrict()) Out << 'I'; if (Quals.hasUnaligned() || @@ -1685,6 +1731,8 @@ void MicrosoftCXXNameMangler::mangleType(QualType T, SourceRange Range, switch (QMM) { case QMM_Drop: + if (Quals.hasObjCLifetime()) + Quals = Quals.withoutObjCLifetime(); break; case QMM_Mangle: if (const FunctionType *FT = dyn_cast<FunctionType>(T)) { @@ -1703,7 +1751,9 @@ void MicrosoftCXXNameMangler::mangleType(QualType T, SourceRange Range, case QMM_Result: // Presence of __unaligned qualifier shouldn't affect mangling here. Quals.removeUnaligned(); - if ((!IsPointer && Quals) || isa<TagType>(T)) { + if (Quals.hasObjCLifetime()) + Quals = Quals.withoutObjCLifetime(); + if ((!IsPointer && Quals) || isa<TagType>(T) || isArtificialTagType(T)) { Out << '?'; mangleQualifiers(Quals, false); } @@ -1833,15 +1883,12 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T, Qualifiers, llvm_unreachable("placeholder types shouldn't get to name mangling"); case BuiltinType::ObjCId: - Out << "PA"; mangleArtificalTagType(TTK_Struct, "objc_object"); break; case BuiltinType::ObjCClass: - Out << "PA"; mangleArtificalTagType(TTK_Struct, "objc_class"); break; case BuiltinType::ObjCSel: - Out << "PA"; mangleArtificalTagType(TTK_Struct, "objc_selector"); break; @@ -1876,8 +1923,39 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T, Qualifiers, break; case BuiltinType::Float16: - case BuiltinType::Float128: - case BuiltinType::Half: { + mangleArtificalTagType(TTK_Struct, "_Float16", {"__clang"}); + break; + + case BuiltinType::Half: + mangleArtificalTagType(TTK_Struct, "_Half", {"__clang"}); + break; + + case BuiltinType::ShortAccum: + case BuiltinType::Accum: + case BuiltinType::LongAccum: + case BuiltinType::UShortAccum: + case BuiltinType::UAccum: + case BuiltinType::ULongAccum: + case BuiltinType::ShortFract: + case BuiltinType::Fract: + case BuiltinType::LongFract: + case BuiltinType::UShortFract: + case BuiltinType::UFract: + case BuiltinType::ULongFract: + case BuiltinType::SatShortAccum: + case BuiltinType::SatAccum: + case BuiltinType::SatLongAccum: + case BuiltinType::SatUShortAccum: + case BuiltinType::SatUAccum: + case BuiltinType::SatULongAccum: + case BuiltinType::SatShortFract: + case BuiltinType::SatFract: + case BuiltinType::SatLongFract: + case BuiltinType::SatUShortFract: + case BuiltinType::SatUFract: + case BuiltinType::SatULongFract: + case BuiltinType::Char8: + case BuiltinType::Float128: { DiagnosticsEngine &Diags = Context.getDiags(); unsigned DiagID = Diags.getCustomDiagID( DiagnosticsEngine::Error, "cannot mangle this built-in %0 type yet"); @@ -2140,6 +2218,8 @@ void MicrosoftCXXNameMangler::mangleCallingConvention(CallingConv CC) { case CC_X86StdCall: Out << 'G'; break; case CC_X86FastCall: Out << 'I'; break; case CC_X86VectorCall: Out << 'Q'; break; + case CC_Swift: Out << 'S'; break; + case CC_PreserveMost: Out << 'U'; break; case CC_X86RegCall: Out << 'w'; break; } } @@ -2202,6 +2282,8 @@ void MicrosoftCXXNameMangler::mangleType(const TagDecl *TD) { mangleTagTypeKind(TD->getTagKind()); mangleName(TD); } + +// If you add a call to this, consider updating isArtificialTagType() too. void MicrosoftCXXNameMangler::mangleArtificalTagType( TagTypeKind TK, StringRef UnqualifiedName, ArrayRef<StringRef> NestedNames) { // <name> ::= <unscoped-name> {[<named-scope>]+ | [<nested-name>]}? @ @@ -2337,10 +2419,16 @@ void MicrosoftCXXNameMangler::mangleType(const PointerType *T, Qualifiers Quals, void MicrosoftCXXNameMangler::mangleType(const ObjCObjectPointerType *T, Qualifiers Quals, SourceRange Range) { - if (T->isObjCIdType() || T->isObjCClassType()) - return mangleType(T->getPointeeType(), Range, QMM_Drop); - QualType PointeeType = T->getPointeeType(); + switch (Quals.getObjCLifetime()) { + case Qualifiers::OCL_None: + case Qualifiers::OCL_ExplicitNone: + break; + case Qualifiers::OCL_Autoreleasing: + case Qualifiers::OCL_Strong: + case Qualifiers::OCL_Weak: + return mangleObjCLifetime(PointeeType, Quals, Range); + } manglePointerCVQualifiers(Quals); manglePointerExtQualifiers(Quals, PointeeType); mangleType(PointeeType, Range); @@ -2384,6 +2472,26 @@ void MicrosoftCXXNameMangler::mangleType(const ComplexType *T, Qualifiers, mangleArtificalTagType(TTK_Struct, TemplateMangling, {"__clang"}); } +// Returns true for types that mangleArtificalTagType() gets called for with +// TTK_Union, TTK_Struct, TTK_Class and where compatibility with MSVC's +// mangling matters. +// (It doesn't matter for Objective-C types and the like that cl.exe doesn't +// support.) +bool MicrosoftCXXNameMangler::isArtificialTagType(QualType T) const { + const Type *ty = T.getTypePtr(); + switch (ty->getTypeClass()) { + default: + return false; + + case Type::Vector: { + // For ABI compatibility only __m64, __m128(id), and __m256(id) matter, + // but since mangleType(VectorType*) always calls mangleArtificalTagType() + // just always return true (the other vector types are clang-only). + return true; + } + } +} + void MicrosoftCXXNameMangler::mangleType(const VectorType *T, Qualifiers Quals, SourceRange Range) { const BuiltinType *ET = T->getElementType()->getAs<BuiltinType>(); @@ -2430,6 +2538,16 @@ void MicrosoftCXXNameMangler::mangleType(const ExtVectorType *T, Qualifiers Quals, SourceRange Range) { mangleType(static_cast<const VectorType *>(T), Quals, Range); } + +void MicrosoftCXXNameMangler::mangleType(const DependentVectorType *T, + Qualifiers, SourceRange Range) { + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID( + DiagnosticsEngine::Error, + "cannot mangle this dependent-sized vector type yet"); + Diags.Report(Range.getBegin(), DiagID) << Range; +} + void MicrosoftCXXNameMangler::mangleType(const DependentSizedExtVectorType *T, Qualifiers, SourceRange Range) { DiagnosticsEngine &Diags = Context.getDiags(); @@ -2457,9 +2575,33 @@ void MicrosoftCXXNameMangler::mangleType(const ObjCInterfaceType *T, Qualifiers, void MicrosoftCXXNameMangler::mangleType(const ObjCObjectType *T, Qualifiers, SourceRange Range) { - // We don't allow overloading by different protocol qualification, - // so mangling them isn't necessary. - mangleType(T->getBaseType(), Range, QMM_Drop); + if (T->qual_empty()) + return mangleType(T->getBaseType(), Range, QMM_Drop); + + ArgBackRefMap OuterArgsContext; + BackRefVec OuterTemplateContext; + + TypeBackReferences.swap(OuterArgsContext); + NameBackReferences.swap(OuterTemplateContext); + + mangleTagTypeKind(TTK_Struct); + + Out << "?$"; + if (T->isObjCId()) + mangleSourceName("objc_object"); + else if (T->isObjCClass()) + mangleSourceName("objc_class"); + else + mangleSourceName(T->getInterface()->getName()); + + for (const auto &Q : T->quals()) + mangleObjCProtocol(Q); + Out << '@'; + + Out << '@'; + + TypeBackReferences.swap(OuterArgsContext); + NameBackReferences.swap(OuterTemplateContext); } void MicrosoftCXXNameMangler::mangleType(const BlockPointerType *T, @@ -2700,17 +2842,12 @@ static void mangleThunkThisAdjustment(const CXXMethodDecl *MD, } } -void -MicrosoftMangleContextImpl::mangleVirtualMemPtrThunk(const CXXMethodDecl *MD, - raw_ostream &Out) { - MicrosoftVTableContext *VTContext = - cast<MicrosoftVTableContext>(getASTContext().getVTableContext()); - const MicrosoftVTableContext::MethodVFTableLocation &ML = - VTContext->getMethodVFTableLocation(GlobalDecl(MD)); - +void MicrosoftMangleContextImpl::mangleVirtualMemPtrThunk( + const CXXMethodDecl *MD, const MethodVFTableLocation &ML, + raw_ostream &Out) { msvc_hashing_ostream MHO(Out); MicrosoftCXXNameMangler Mangler(*this, MHO); - Mangler.getStream() << "\01?"; + Mangler.getStream() << '?'; Mangler.mangleVirtualMemPtrThunk(MD, ML); } @@ -2719,7 +2856,7 @@ void MicrosoftMangleContextImpl::mangleThunk(const CXXMethodDecl *MD, raw_ostream &Out) { msvc_hashing_ostream MHO(Out); MicrosoftCXXNameMangler Mangler(*this, MHO); - Mangler.getStream() << "\01?"; + Mangler.getStream() << '?'; Mangler.mangleName(MD); mangleThunkThisAdjustment(MD, Thunk.This, Mangler, MHO); if (!Thunk.Return.isEmpty()) @@ -2740,7 +2877,7 @@ void MicrosoftMangleContextImpl::mangleCXXDtorThunk( assert(Type == Dtor_Deleting); msvc_hashing_ostream MHO(Out); MicrosoftCXXNameMangler Mangler(*this, MHO, DD, Type); - Mangler.getStream() << "\01??_E"; + Mangler.getStream() << "??_E"; Mangler.mangleName(DD->getParent()); mangleThunkThisAdjustment(DD, Adjustment, Mangler, MHO); Mangler.mangleFunctionType(DD->getType()->castAs<FunctionProtoType>(), DD); @@ -2756,9 +2893,9 @@ void MicrosoftMangleContextImpl::mangleCXXVFTable( msvc_hashing_ostream MHO(Out); MicrosoftCXXNameMangler Mangler(*this, MHO); if (Derived->hasAttr<DLLImportAttr>()) - Mangler.getStream() << "\01??_S"; + Mangler.getStream() << "??_S"; else - Mangler.getStream() << "\01??_7"; + Mangler.getStream() << "??_7"; Mangler.mangleName(Derived); Mangler.getStream() << "6B"; // '6' for vftable, 'B' for const. for (const CXXRecordDecl *RD : BasePath) @@ -2775,7 +2912,7 @@ void MicrosoftMangleContextImpl::mangleCXXVBTable( // is always '7' for vbtables. msvc_hashing_ostream MHO(Out); MicrosoftCXXNameMangler Mangler(*this, MHO); - Mangler.getStream() << "\01??_8"; + Mangler.getStream() << "??_8"; Mangler.mangleName(Derived); Mangler.getStream() << "7B"; // '7' for vbtable, 'B' for const. for (const CXXRecordDecl *RD : BasePath) @@ -2786,7 +2923,7 @@ void MicrosoftMangleContextImpl::mangleCXXVBTable( void MicrosoftMangleContextImpl::mangleCXXRTTI(QualType T, raw_ostream &Out) { msvc_hashing_ostream MHO(Out); MicrosoftCXXNameMangler Mangler(*this, MHO); - Mangler.getStream() << "\01??_R0"; + Mangler.getStream() << "??_R0"; Mangler.mangleType(T, SourceRange(), MicrosoftCXXNameMangler::QMM_Result); Mangler.getStream() << "@8"; } @@ -2802,7 +2939,7 @@ void MicrosoftMangleContextImpl::mangleCXXVirtualDisplacementMap( const CXXRecordDecl *SrcRD, const CXXRecordDecl *DstRD, raw_ostream &Out) { msvc_hashing_ostream MHO(Out); MicrosoftCXXNameMangler Mangler(*this, MHO); - Mangler.getStream() << "\01??_K"; + Mangler.getStream() << "??_K"; Mangler.mangleName(SrcRD); Mangler.getStream() << "$C"; Mangler.mangleName(DstRD); @@ -2848,7 +2985,7 @@ void MicrosoftMangleContextImpl::mangleCXXCatchableType( msvc_hashing_ostream MHO(Stream); mangleCXXRTTI(T, MHO); } - Mangler.getStream() << RTTIMangling.substr(1); + Mangler.getStream() << RTTIMangling; // VS2015 CTP6 omits the copy-constructor in the mangled name. This name is, // in fact, superfluous but I'm not sure the change was made consciously. @@ -2860,7 +2997,7 @@ void MicrosoftMangleContextImpl::mangleCXXCatchableType( msvc_hashing_ostream MHO(Stream); mangleCXXCtor(CD, CT, MHO); } - Mangler.getStream() << CopyCtorMangling.substr(1); + Mangler.getStream() << CopyCtorMangling; Mangler.getStream() << Size; if (VBPtrOffset == -1) { @@ -2879,7 +3016,7 @@ void MicrosoftMangleContextImpl::mangleCXXRTTIBaseClassDescriptor( uint32_t VBTableOffset, uint32_t Flags, raw_ostream &Out) { msvc_hashing_ostream MHO(Out); MicrosoftCXXNameMangler Mangler(*this, MHO); - Mangler.getStream() << "\01??_R1"; + Mangler.getStream() << "??_R1"; Mangler.mangleNumber(NVOffset); Mangler.mangleNumber(VBPtrOffset); Mangler.mangleNumber(VBTableOffset); @@ -2892,7 +3029,7 @@ void MicrosoftMangleContextImpl::mangleCXXRTTIBaseClassArray( const CXXRecordDecl *Derived, raw_ostream &Out) { msvc_hashing_ostream MHO(Out); MicrosoftCXXNameMangler Mangler(*this, MHO); - Mangler.getStream() << "\01??_R2"; + Mangler.getStream() << "??_R2"; Mangler.mangleName(Derived); Mangler.getStream() << "8"; } @@ -2901,7 +3038,7 @@ void MicrosoftMangleContextImpl::mangleCXXRTTIClassHierarchyDescriptor( const CXXRecordDecl *Derived, raw_ostream &Out) { msvc_hashing_ostream MHO(Out); MicrosoftCXXNameMangler Mangler(*this, MHO); - Mangler.getStream() << "\01??_R3"; + Mangler.getStream() << "??_R3"; Mangler.mangleName(Derived); Mangler.getStream() << "8"; } @@ -2917,16 +3054,16 @@ void MicrosoftMangleContextImpl::mangleCXXRTTICompleteObjectLocator( llvm::raw_svector_ostream Stream(VFTableMangling); mangleCXXVFTable(Derived, BasePath, Stream); - if (VFTableMangling.startswith("\01??@")) { + if (VFTableMangling.startswith("??@")) { assert(VFTableMangling.endswith("@")); Out << VFTableMangling << "??_R4@"; return; } - assert(VFTableMangling.startswith("\01??_7") || - VFTableMangling.startswith("\01??_S")); + assert(VFTableMangling.startswith("??_7") || + VFTableMangling.startswith("??_S")); - Out << "\01??_R4" << StringRef(VFTableMangling).drop_front(5); + Out << "??_R4" << StringRef(VFTableMangling).drop_front(4); } void MicrosoftMangleContextImpl::mangleSEHFilterExpression( @@ -2937,7 +3074,7 @@ void MicrosoftMangleContextImpl::mangleSEHFilterExpression( // so the numbering here doesn't have to be the same across TUs. // // <mangled-name> ::= ?filt$ <filter-number> @0 - Mangler.getStream() << "\01?filt$" << SEHFilterIds[EnclosingDecl]++ << "@0@"; + Mangler.getStream() << "?filt$" << SEHFilterIds[EnclosingDecl]++ << "@0@"; Mangler.mangleName(EnclosingDecl); } @@ -2949,7 +3086,7 @@ void MicrosoftMangleContextImpl::mangleSEHFinallyBlock( // so the numbering here doesn't have to be the same across TUs. // // <mangled-name> ::= ?fin$ <filter-number> @0 - Mangler.getStream() << "\01?fin$" << SEHFinallyIds[EnclosingDecl]++ << "@0@"; + Mangler.getStream() << "?fin$" << SEHFinallyIds[EnclosingDecl]++ << "@0@"; Mangler.mangleName(EnclosingDecl); } @@ -2982,7 +3119,7 @@ void MicrosoftMangleContextImpl::mangleReferenceTemporary( msvc_hashing_ostream MHO(Out); MicrosoftCXXNameMangler Mangler(*this, MHO); - Mangler.getStream() << "\01?$RT" << ManglingNumber << '@'; + Mangler.getStream() << "?$RT" << ManglingNumber << '@'; Mangler.mangle(VD, ""); } @@ -2991,7 +3128,7 @@ void MicrosoftMangleContextImpl::mangleThreadSafeStaticGuardVariable( msvc_hashing_ostream MHO(Out); MicrosoftCXXNameMangler Mangler(*this, MHO); - Mangler.getStream() << "\01?$TSS" << GuardNum << '@'; + Mangler.getStream() << "?$TSS" << GuardNum << '@'; Mangler.mangleNestedName(VD); Mangler.getStream() << "@4HA"; } @@ -3013,9 +3150,9 @@ void MicrosoftMangleContextImpl::mangleStaticGuardVariable(const VarDecl *VD, bool Visible = VD->isExternallyVisible(); if (Visible) { - Mangler.getStream() << (VD->getTLSKind() ? "\01??__J" : "\01??_B"); + Mangler.getStream() << (VD->getTLSKind() ? "??__J" : "??_B"); } else { - Mangler.getStream() << "\01?$S1@"; + Mangler.getStream() << "?$S1@"; } unsigned ScopeDepth = 0; if (Visible && !getNextDiscriminator(VD, ScopeDepth)) @@ -3035,7 +3172,7 @@ void MicrosoftMangleContextImpl::mangleInitFiniStub(const VarDecl *D, raw_ostream &Out) { msvc_hashing_ostream MHO(Out); MicrosoftCXXNameMangler Mangler(*this, MHO); - Mangler.getStream() << "\01??__" << CharCode; + Mangler.getStream() << "??__" << CharCode; Mangler.mangleName(D); if (D->isStaticDataMember()) { Mangler.mangleVariableEncoding(D); @@ -3061,14 +3198,14 @@ MicrosoftMangleContextImpl::mangleDynamicAtExitDestructor(const VarDecl *D, void MicrosoftMangleContextImpl::mangleStringLiteral(const StringLiteral *SL, raw_ostream &Out) { - // <char-type> ::= 0 # char - // ::= 1 # wchar_t - // ::= ??? # char16_t/char32_t will need a mangling too... + // <char-type> ::= 0 # char, char16_t, char32_t + // # (little endian char data in mangling) + // ::= 1 # wchar_t (big endian char data in mangling) // // <literal-length> ::= <non-negative integer> # the length of the literal // // <encoded-crc> ::= <hex digit>+ @ # crc of the literal including - // # null-terminator + // # trailing null bytes // // <encoded-string> ::= <simple character> # uninteresting character // ::= '?$' <hex digit> <hex digit> # these two nibbles @@ -3081,7 +3218,19 @@ void MicrosoftMangleContextImpl::mangleStringLiteral(const StringLiteral *SL, // <literal> ::= '??_C@_' <char-type> <literal-length> <encoded-crc> // <encoded-string> '@' MicrosoftCXXNameMangler Mangler(*this, Out); - Mangler.getStream() << "\01??_C@_"; + Mangler.getStream() << "??_C@_"; + + // The actual string length might be different from that of the string literal + // in cases like: + // char foo[3] = "foobar"; + // char bar[42] = "foobar"; + // Where it is truncated or zero-padded to fit the array. This is the length + // used for mangling, and any trailing null-bytes also need to be mangled. + unsigned StringLength = getASTContext() + .getAsConstantArrayType(SL->getType()) + ->getSize() + .getZExtValue(); + unsigned StringByteLength = StringLength * SL->getCharByteWidth(); // <char-type>: The "kind" of string literal is encoded into the mangled name. if (SL->isWide()) @@ -3090,14 +3239,13 @@ void MicrosoftMangleContextImpl::mangleStringLiteral(const StringLiteral *SL, Mangler.getStream() << '0'; // <literal-length>: The next part of the mangled name consists of the length - // of the string. - // The StringLiteral does not consider the NUL terminator byte(s) but the - // mangling does. - // N.B. The length is in terms of bytes, not characters. - Mangler.mangleNumber(SL->getByteLength() + SL->getCharByteWidth()); + // of the string in bytes. + Mangler.mangleNumber(StringByteLength); auto GetLittleEndianByte = [&SL](unsigned Index) { unsigned CharByteWidth = SL->getCharByteWidth(); + if (Index / CharByteWidth >= SL->getLength()) + return static_cast<char>(0); uint32_t CodeUnit = SL->getCodeUnit(Index / CharByteWidth); unsigned OffsetInCodeUnit = Index % CharByteWidth; return static_cast<char>((CodeUnit >> (8 * OffsetInCodeUnit)) & 0xff); @@ -3105,6 +3253,8 @@ void MicrosoftMangleContextImpl::mangleStringLiteral(const StringLiteral *SL, auto GetBigEndianByte = [&SL](unsigned Index) { unsigned CharByteWidth = SL->getCharByteWidth(); + if (Index / CharByteWidth >= SL->getLength()) + return static_cast<char>(0); uint32_t CodeUnit = SL->getCodeUnit(Index / CharByteWidth); unsigned OffsetInCodeUnit = (CharByteWidth - 1) - (Index % CharByteWidth); return static_cast<char>((CodeUnit >> (8 * OffsetInCodeUnit)) & 0xff); @@ -3112,21 +3262,15 @@ void MicrosoftMangleContextImpl::mangleStringLiteral(const StringLiteral *SL, // CRC all the bytes of the StringLiteral. llvm::JamCRC JC; - for (unsigned I = 0, E = SL->getByteLength(); I != E; ++I) + for (unsigned I = 0, E = StringByteLength; I != E; ++I) JC.update(GetLittleEndianByte(I)); - // The NUL terminator byte(s) were not present earlier, - // we need to manually process those bytes into the CRC. - for (unsigned NullTerminator = 0; NullTerminator < SL->getCharByteWidth(); - ++NullTerminator) - JC.update('\x00'); - // <encoded-crc>: The CRC is encoded utilizing the standard number mangling // scheme. Mangler.mangleNumber(JC.getCRC()); - // <encoded-string>: The mangled name also contains the first 32 _characters_ - // (including null-terminator bytes) of the StringLiteral. + // <encoded-string>: The mangled name also contains the first 32 bytes + // (including null-terminator bytes) of the encoded StringLiteral. // Each character is encoded by splitting them into bytes and then encoding // the constituent bytes. auto MangleByte = [&Mangler](char Byte) { @@ -3155,20 +3299,15 @@ void MicrosoftMangleContextImpl::mangleStringLiteral(const StringLiteral *SL, } }; - // Enforce our 32 character max. - unsigned NumCharsToMangle = std::min(32U, SL->getLength()); - for (unsigned I = 0, E = NumCharsToMangle * SL->getCharByteWidth(); I != E; - ++I) + // Enforce our 32 bytes max, except wchar_t which gets 32 chars instead. + unsigned MaxBytesToMangle = SL->isWide() ? 64U : 32U; + unsigned NumBytesToMangle = std::min(MaxBytesToMangle, StringByteLength); + for (unsigned I = 0; I != NumBytesToMangle; ++I) { if (SL->isWide()) MangleByte(GetBigEndianByte(I)); else MangleByte(GetLittleEndianByte(I)); - - // Encode the NUL terminator if there is room. - if (NumCharsToMangle < 32) - for (unsigned NullTerminator = 0; NullTerminator < SL->getCharByteWidth(); - ++NullTerminator) - MangleByte(0); + } Mangler.getStream() << '@'; } diff --git a/lib/AST/NSAPI.cpp b/lib/AST/NSAPI.cpp index 8adaef1fb640..536bf2c378fa 100644 --- a/lib/AST/NSAPI.cpp +++ b/lib/AST/NSAPI.cpp @@ -436,10 +436,35 @@ NSAPI::getNSNumberFactoryMethodKind(QualType T) const { case BuiltinType::Void: case BuiltinType::WChar_U: case BuiltinType::WChar_S: + case BuiltinType::Char8: case BuiltinType::Char16: case BuiltinType::Char32: case BuiltinType::Int128: case BuiltinType::LongDouble: + case BuiltinType::ShortAccum: + case BuiltinType::Accum: + case BuiltinType::LongAccum: + case BuiltinType::UShortAccum: + case BuiltinType::UAccum: + case BuiltinType::ULongAccum: + case BuiltinType::ShortFract: + case BuiltinType::Fract: + case BuiltinType::LongFract: + case BuiltinType::UShortFract: + case BuiltinType::UFract: + case BuiltinType::ULongFract: + case BuiltinType::SatShortAccum: + case BuiltinType::SatAccum: + case BuiltinType::SatLongAccum: + case BuiltinType::SatUShortAccum: + case BuiltinType::SatUAccum: + case BuiltinType::SatULongAccum: + case BuiltinType::SatShortFract: + case BuiltinType::SatFract: + case BuiltinType::SatLongFract: + case BuiltinType::SatUShortFract: + case BuiltinType::SatUFract: + case BuiltinType::SatULongFract: case BuiltinType::UInt128: case BuiltinType::Float16: case BuiltinType::Float128: @@ -470,15 +495,15 @@ NSAPI::getNSNumberFactoryMethodKind(QualType T) const { return None; } -/// \brief Returns true if \param T is a typedef of "BOOL" in objective-c. +/// Returns true if \param T is a typedef of "BOOL" in objective-c. bool NSAPI::isObjCBOOLType(QualType T) const { return isObjCTypedef(T, "BOOL", BOOLId); } -/// \brief Returns true if \param T is a typedef of "NSInteger" in objective-c. +/// Returns true if \param T is a typedef of "NSInteger" in objective-c. bool NSAPI::isObjCNSIntegerType(QualType T) const { return isObjCTypedef(T, "NSInteger", NSIntegerId); } -/// \brief Returns true if \param T is a typedef of "NSUInteger" in objective-c. +/// Returns true if \param T is a typedef of "NSUInteger" in objective-c. bool NSAPI::isObjCNSUIntegerType(QualType T) const { return isObjCTypedef(T, "NSUInteger", NSUIntegerId); } diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp index 889f8308a93c..503d0eb65e1e 100644 --- a/lib/AST/NestedNameSpecifier.cpp +++ b/lib/AST/NestedNameSpecifier.cpp @@ -164,7 +164,7 @@ NestedNameSpecifier::SpecifierKind NestedNameSpecifier::getKind() const { llvm_unreachable("Invalid NNS Kind!"); } -/// \brief Retrieve the namespace stored in this nested name specifier. +/// Retrieve the namespace stored in this nested name specifier. NamespaceDecl *NestedNameSpecifier::getAsNamespace() const { if (Prefix.getInt() == StoredDecl) return dyn_cast<NamespaceDecl>(static_cast<NamedDecl *>(Specifier)); @@ -172,7 +172,7 @@ NamespaceDecl *NestedNameSpecifier::getAsNamespace() const { return nullptr; } -/// \brief Retrieve the namespace alias stored in this nested name specifier. +/// Retrieve the namespace alias stored in this nested name specifier. NamespaceAliasDecl *NestedNameSpecifier::getAsNamespaceAlias() const { if (Prefix.getInt() == StoredDecl) return dyn_cast<NamespaceAliasDecl>(static_cast<NamedDecl *>(Specifier)); @@ -180,7 +180,7 @@ NamespaceAliasDecl *NestedNameSpecifier::getAsNamespaceAlias() const { return nullptr; } -/// \brief Retrieve the record declaration stored in this nested name specifier. +/// Retrieve the record declaration stored in this nested name specifier. CXXRecordDecl *NestedNameSpecifier::getAsRecordDecl() const { switch (Prefix.getInt()) { case StoredIdentifier: @@ -197,7 +197,7 @@ CXXRecordDecl *NestedNameSpecifier::getAsRecordDecl() const { llvm_unreachable("Invalid NNS Kind!"); } -/// \brief Whether this nested name specifier refers to a dependent +/// Whether this nested name specifier refers to a dependent /// type or not. bool NestedNameSpecifier::isDependent() const { switch (getKind()) { @@ -227,7 +227,7 @@ bool NestedNameSpecifier::isDependent() const { llvm_unreachable("Invalid NNS Kind!"); } -/// \brief Whether this nested name specifier refers to a dependent +/// Whether this nested name specifier refers to a dependent /// type or not. bool NestedNameSpecifier::isInstantiationDependent() const { switch (getKind()) { @@ -268,7 +268,7 @@ bool NestedNameSpecifier::containsUnexpandedParameterPack() const { llvm_unreachable("Invalid NNS Kind!"); } -/// \brief Print this nested name specifier to the given output +/// Print this nested name specifier to the given output /// stream. void NestedNameSpecifier::print(raw_ostream &OS, @@ -387,7 +387,7 @@ NestedNameSpecifierLoc::getDataLength(NestedNameSpecifier *Qualifier) { return Length; } -/// \brief Load a (possibly unaligned) source location from a given address +/// Load a (possibly unaligned) source location from a given address /// and offset. static SourceLocation LoadSourceLocation(void *Data, unsigned Offset) { unsigned Raw; @@ -395,7 +395,7 @@ static SourceLocation LoadSourceLocation(void *Data, unsigned Offset) { return SourceLocation::getFromRawEncoding(Raw); } -/// \brief Load a (possibly unaligned) pointer from a given address and +/// Load a (possibly unaligned) pointer from a given address and /// offset. static void *LoadPointer(void *Data, unsigned Offset) { void *Result; @@ -466,7 +466,7 @@ static void Append(char *Start, char *End, char *&Buffer, unsigned &BufferSize, unsigned NewCapacity = std::max( (unsigned)(BufferCapacity ? BufferCapacity * 2 : sizeof(void *) * 2), (unsigned)(BufferSize + (End - Start))); - char *NewBuffer = static_cast<char *>(malloc(NewCapacity)); + char *NewBuffer = static_cast<char *>(llvm::safe_malloc(NewCapacity)); if (BufferCapacity) { memcpy(NewBuffer, Buffer, BufferSize); free(Buffer); @@ -479,7 +479,7 @@ static void Append(char *Start, char *End, char *&Buffer, unsigned &BufferSize, BufferSize += End-Start; } -/// \brief Save a source location to the given buffer. +/// Save a source location to the given buffer. static void SaveSourceLocation(SourceLocation Loc, char *&Buffer, unsigned &BufferSize, unsigned &BufferCapacity) { unsigned Raw = Loc.getRawEncoding(); @@ -488,7 +488,7 @@ static void SaveSourceLocation(SourceLocation Loc, char *&Buffer, Buffer, BufferSize, BufferCapacity); } -/// \brief Save a pointer to the given buffer. +/// Save a pointer to the given buffer. static void SavePointer(void *Ptr, char *&Buffer, unsigned &BufferSize, unsigned &BufferCapacity) { Append(reinterpret_cast<char *>(&Ptr), diff --git a/lib/AST/ODRHash.cpp b/lib/AST/ODRHash.cpp index 088d8bedd453..e710d3780337 100644 --- a/lib/AST/ODRHash.cpp +++ b/lib/AST/ODRHash.cpp @@ -33,6 +33,15 @@ void ODRHash::AddIdentifierInfo(const IdentifierInfo *II) { } void ODRHash::AddDeclarationName(DeclarationName Name) { + // Index all DeclarationName and use index numbers to refer to them. + auto Result = DeclNameMap.insert(std::make_pair(Name, DeclNameMap.size())); + ID.AddInteger(Result.first->second); + if (!Result.second) { + // If found in map, the the DeclarationName has previously been processed. + return; + } + + // First time processing each DeclarationName, also process its details. AddBoolean(Name.isEmpty()); if (Name.isEmpty()) return; @@ -139,6 +148,8 @@ void ODRHash::AddTemplateArgument(TemplateArgument TA) { AddQualType(TA.getAsType()); break; case TemplateArgument::Declaration: + AddDecl(TA.getAsDecl()); + break; case TemplateArgument::NullPtr: case TemplateArgument::Integral: break; @@ -168,8 +179,7 @@ void ODRHash::AddTemplateParameterList(const TemplateParameterList *TPL) { } void ODRHash::clear() { - DeclMap.clear(); - TypeMap.clear(); + DeclNameMap.clear(); Bools.clear(); ID.clear(); } @@ -307,26 +317,14 @@ public: } void VisitFunctionDecl(const FunctionDecl *D) { - ID.AddInteger(D->getStorageClass()); - Hash.AddBoolean(D->isInlineSpecified()); - Hash.AddBoolean(D->isVirtualAsWritten()); - Hash.AddBoolean(D->isPure()); - Hash.AddBoolean(D->isDeletedAsWritten()); - - ID.AddInteger(D->param_size()); - - for (auto *Param : D->parameters()) { - Hash.AddSubDecl(Param); - } - - AddQualType(D->getReturnType()); + // Handled by the ODRHash for FunctionDecl + ID.AddInteger(D->getODRHash()); Inherited::VisitFunctionDecl(D); } void VisitCXXMethodDecl(const CXXMethodDecl *D) { - Hash.AddBoolean(D->isConst()); - Hash.AddBoolean(D->isVolatile()); + // Handled by the ODRHash for FunctionDecl Inherited::VisitCXXMethodDecl(D); } @@ -363,6 +361,7 @@ public: if (hasDefaultArgument) { AddTemplateArgument(D->getDefaultArgument()); } + Hash.AddBoolean(D->isParameterPack()); Inherited::VisitTemplateTypeParmDecl(D); } @@ -375,6 +374,7 @@ public: if (hasDefaultArgument) { AddStmt(D->getDefaultArgument()); } + Hash.AddBoolean(D->isParameterPack()); Inherited::VisitNonTypeTemplateParmDecl(D); } @@ -387,15 +387,37 @@ public: if (hasDefaultArgument) { AddTemplateArgument(D->getDefaultArgument().getArgument()); } + Hash.AddBoolean(D->isParameterPack()); Inherited::VisitTemplateTemplateParmDecl(D); } + + void VisitTemplateDecl(const TemplateDecl *D) { + Hash.AddTemplateParameterList(D->getTemplateParameters()); + + Inherited::VisitTemplateDecl(D); + } + + void VisitRedeclarableTemplateDecl(const RedeclarableTemplateDecl *D) { + Hash.AddBoolean(D->isMemberSpecialization()); + Inherited::VisitRedeclarableTemplateDecl(D); + } + + void VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) { + AddDecl(D->getTemplatedDecl()); + Inherited::VisitFunctionTemplateDecl(D); + } + + void VisitEnumConstantDecl(const EnumConstantDecl *D) { + AddStmt(D->getInitExpr()); + Inherited::VisitEnumConstantDecl(D); + } }; } // namespace // Only allow a small portion of Decl's to be processed. Remove this once // all Decl's can be handled. -bool ODRHash::isWhitelistedDecl(const Decl *D, const CXXRecordDecl *Parent) { +bool ODRHash::isWhitelistedDecl(const Decl *D, const DeclContext *Parent) { if (D->isImplicit()) return false; if (D->getDeclContext() != Parent) return false; @@ -406,8 +428,10 @@ bool ODRHash::isWhitelistedDecl(const Decl *D, const CXXRecordDecl *Parent) { case Decl::CXXConstructor: case Decl::CXXDestructor: case Decl::CXXMethod: + case Decl::EnumConstant: // Only found in EnumDecl's. case Decl::Field: case Decl::Friend: + case Decl::FunctionTemplate: case Decl::StaticAssert: case Decl::TypeAlias: case Decl::Typedef: @@ -418,7 +442,6 @@ bool ODRHash::isWhitelistedDecl(const Decl *D, const CXXRecordDecl *Parent) { void ODRHash::AddSubDecl(const Decl *D) { assert(D && "Expecting non-null pointer."); - AddDecl(D); ODRDeclVisitor(ID, *this).Visit(D); } @@ -440,9 +463,13 @@ void ODRHash::AddCXXRecordDecl(const CXXRecordDecl *Record) { // Filter out sub-Decls which will not be processed in order to get an // accurate count of Decl's. llvm::SmallVector<const Decl *, 16> Decls; - for (const Decl *SubDecl : Record->decls()) { + for (Decl *SubDecl : Record->decls()) { if (isWhitelistedDecl(SubDecl, Record)) { Decls.push_back(SubDecl); + if (auto *Function = dyn_cast<FunctionDecl>(SubDecl)) { + // Compute/Preload ODRHash into FunctionDecl. + Function->getODRHash(); + } } } @@ -466,28 +493,48 @@ void ODRHash::AddCXXRecordDecl(const CXXRecordDecl *Record) { } } -void ODRHash::AddFunctionDecl(const FunctionDecl *Function) { +void ODRHash::AddFunctionDecl(const FunctionDecl *Function, + bool SkipBody) { assert(Function && "Expecting non-null pointer."); - // Skip hashing these kinds of function. - if (Function->isImplicit()) return; - if (Function->isDefaulted()) return; - if (Function->isDeleted()) return; - if (!Function->hasBody()) return; - if (!Function->getBody()) return; - - // TODO: Fix hashing for class methods. - if (isa<CXXMethodDecl>(Function)) return; - // Skip functions that are specializations or in specialization context. const DeclContext *DC = Function; while (DC) { if (isa<ClassTemplateSpecializationDecl>(DC)) return; - if (auto *F = dyn_cast<FunctionDecl>(DC)) - if (F->isFunctionTemplateSpecialization()) return; + if (auto *F = dyn_cast<FunctionDecl>(DC)) { + if (F->isFunctionTemplateSpecialization()) { + if (!isa<CXXMethodDecl>(DC)) return; + if (DC->getLexicalParent()->isFileContext()) return; + // Inline method specializations are the only supported + // specialization for now. + } + } DC = DC->getParent(); } + ID.AddInteger(Function->getDeclKind()); + + const auto *SpecializationArgs = Function->getTemplateSpecializationArgs(); + AddBoolean(SpecializationArgs); + if (SpecializationArgs) { + ID.AddInteger(SpecializationArgs->size()); + for (const TemplateArgument &TA : SpecializationArgs->asArray()) { + AddTemplateArgument(TA); + } + } + + if (const auto *Method = dyn_cast<CXXMethodDecl>(Function)) { + AddBoolean(Method->isConst()); + AddBoolean(Method->isVolatile()); + } + + ID.AddInteger(Function->getStorageClass()); + AddBoolean(Function->isInlineSpecified()); + AddBoolean(Function->isVirtualAsWritten()); + AddBoolean(Function->isPure()); + AddBoolean(Function->isDeletedAsWritten()); + AddBoolean(Function->isExplicitlyDefaulted()); + AddDecl(Function); AddQualType(Function->getReturnType()); @@ -496,25 +543,62 @@ void ODRHash::AddFunctionDecl(const FunctionDecl *Function) { for (auto Param : Function->parameters()) AddSubDecl(Param); - AddStmt(Function->getBody()); + if (SkipBody) { + AddBoolean(false); + return; + } + + const bool HasBody = Function->isThisDeclarationADefinition() && + !Function->isDefaulted() && !Function->isDeleted() && + !Function->isLateTemplateParsed(); + AddBoolean(HasBody); + if (HasBody) { + auto *Body = Function->getBody(); + AddBoolean(Body); + if (Body) + AddStmt(Body); + } +} + +void ODRHash::AddEnumDecl(const EnumDecl *Enum) { + assert(Enum); + AddDeclarationName(Enum->getDeclName()); + + AddBoolean(Enum->isScoped()); + if (Enum->isScoped()) + AddBoolean(Enum->isScopedUsingClassTag()); + + if (Enum->getIntegerTypeSourceInfo()) + AddQualType(Enum->getIntegerType()); + + // Filter out sub-Decls which will not be processed in order to get an + // accurate count of Decl's. + llvm::SmallVector<const Decl *, 16> Decls; + for (Decl *SubDecl : Enum->decls()) { + if (isWhitelistedDecl(SubDecl, Enum)) { + assert(isa<EnumConstantDecl>(SubDecl) && "Unexpected Decl"); + Decls.push_back(SubDecl); + } + } + + ID.AddInteger(Decls.size()); + for (auto SubDecl : Decls) { + AddSubDecl(SubDecl); + } + } void ODRHash::AddDecl(const Decl *D) { assert(D && "Expecting non-null pointer."); D = D->getCanonicalDecl(); - auto Result = DeclMap.insert(std::make_pair(D, DeclMap.size())); - ID.AddInteger(Result.first->second); - // On first encounter of a Decl pointer, process it. Every time afterwards, - // only the index value is needed. - if (!Result.second) { - return; - } - - ID.AddInteger(D->getKind()); if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) { AddDeclarationName(ND->getDeclName()); + return; } + + ID.AddInteger(D->getKind()); + // TODO: Handle non-NamedDecl here. } namespace { @@ -642,13 +726,41 @@ public: VisitFunctionType(T); } + void VisitPointerType(const PointerType *T) { + AddQualType(T->getPointeeType()); + VisitType(T); + } + + void VisitReferenceType(const ReferenceType *T) { + AddQualType(T->getPointeeTypeAsWritten()); + VisitType(T); + } + + void VisitLValueReferenceType(const LValueReferenceType *T) { + VisitReferenceType(T); + } + + void VisitRValueReferenceType(const RValueReferenceType *T) { + VisitReferenceType(T); + } + void VisitTypedefType(const TypedefType *T) { AddDecl(T->getDecl()); QualType UnderlyingType = T->getDecl()->getUnderlyingType(); VisitQualifiers(UnderlyingType.getQualifiers()); - while (const TypedefType *Underlying = - dyn_cast<TypedefType>(UnderlyingType.getTypePtr())) { - UnderlyingType = Underlying->getDecl()->getUnderlyingType(); + while (true) { + if (const TypedefType *Underlying = + dyn_cast<TypedefType>(UnderlyingType.getTypePtr())) { + UnderlyingType = Underlying->getDecl()->getUnderlyingType(); + continue; + } + if (const ElaboratedType *Underlying = + dyn_cast<ElaboratedType>(UnderlyingType.getTypePtr())) { + UnderlyingType = Underlying->getNamedType(); + continue; + } + + break; } AddType(UnderlyingType.getTypePtr()); VisitType(T); @@ -710,14 +822,6 @@ public: void ODRHash::AddType(const Type *T) { assert(T && "Expecting non-null pointer."); - auto Result = TypeMap.insert(std::make_pair(T, TypeMap.size())); - ID.AddInteger(Result.first->second); - // On first encounter of a Type pointer, process it. Every time afterwards, - // only the index value is needed. - if (!Result.second) { - return; - } - ODRTypeVisitor(ID, *this).Visit(T); } diff --git a/lib/AST/OpenMPClause.cpp b/lib/AST/OpenMPClause.cpp index 4feac0cfd041..50729264bfe1 100644 --- a/lib/AST/OpenMPClause.cpp +++ b/lib/AST/OpenMPClause.cpp @@ -702,10 +702,10 @@ unsigned OMPClauseMappableExprCommon::getComponentsTotalNumber( } unsigned OMPClauseMappableExprCommon::getUniqueDeclarationsTotalNumber( - ArrayRef<ValueDecl *> Declarations) { + ArrayRef<const ValueDecl *> Declarations) { unsigned TotalNum = 0u; llvm::SmallPtrSet<const ValueDecl *, 8> Cache; - for (auto *D : Declarations) { + for (const ValueDecl *D : Declarations) { const ValueDecl *VD = D ? cast<ValueDecl>(D->getCanonicalDecl()) : nullptr; if (Cache.count(VD)) continue; diff --git a/lib/AST/ParentMap.cpp b/lib/AST/ParentMap.cpp index d8882c9030b2..bc57b20790d9 100644 --- a/lib/AST/ParentMap.cpp +++ b/lib/AST/ParentMap.cpp @@ -15,6 +15,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/StmtObjC.h" #include "llvm/ADT/DenseMap.h" using namespace clang; @@ -193,6 +194,8 @@ bool ParentMap::isConsumedExpr(Expr* E) const { return DirectChild == cast<IndirectGotoStmt>(P)->getTarget(); case Stmt::SwitchStmtClass: return DirectChild == cast<SwitchStmt>(P)->getCond(); + case Stmt::ObjCForCollectionStmtClass: + return DirectChild == cast<ObjCForCollectionStmt>(P)->getCollection(); case Stmt::ReturnStmtClass: return true; } diff --git a/lib/AST/QualTypeNames.cpp b/lib/AST/QualTypeNames.cpp index 86c0eff9f78c..8b605ef295a0 100644 --- a/lib/AST/QualTypeNames.cpp +++ b/lib/AST/QualTypeNames.cpp @@ -22,7 +22,7 @@ namespace clang { namespace TypeName { -/// \brief Create a NestedNameSpecifier for Namesp and its enclosing +/// Create a NestedNameSpecifier for Namesp and its enclosing /// scopes. /// /// \param[in] Ctx - the AST Context to be used. @@ -35,7 +35,7 @@ static NestedNameSpecifier *createNestedNameSpecifier( const NamespaceDecl *Namesp, bool WithGlobalNsPrefix); -/// \brief Create a NestedNameSpecifier for TagDecl and its enclosing +/// Create a NestedNameSpecifier for TagDecl and its enclosing /// scopes. /// /// \param[in] Ctx - the AST Context to be used. @@ -210,7 +210,7 @@ static NestedNameSpecifier *createOuterNNS(const ASTContext &Ctx, const Decl *D, return nullptr; // no starting '::' if |WithGlobalNsPrefix| is false } -/// \brief Return a fully qualified version of this name specifier. +/// Return a fully qualified version of this name specifier. static NestedNameSpecifier *getFullyQualifiedNestedNameSpecifier( const ASTContext &Ctx, NestedNameSpecifier *Scope, bool WithGlobalNsPrefix) { @@ -262,7 +262,7 @@ static NestedNameSpecifier *getFullyQualifiedNestedNameSpecifier( llvm_unreachable("bad NNS kind"); } -/// \brief Create a nested name specifier for the declaring context of +/// Create a nested name specifier for the declaring context of /// the type. static NestedNameSpecifier *createNestedNameSpecifierForScopeOf( const ASTContext &Ctx, const Decl *Decl, @@ -314,7 +314,7 @@ static NestedNameSpecifier *createNestedNameSpecifierForScopeOf( return nullptr; } -/// \brief Create a nested name specifier for the declaring context of +/// Create a nested name specifier for the declaring context of /// the type. static NestedNameSpecifier *createNestedNameSpecifierForScopeOf( const ASTContext &Ctx, const Type *TypePtr, @@ -366,7 +366,7 @@ NestedNameSpecifier *createNestedNameSpecifier(const ASTContext &Ctx, TD->getTypeForDecl()); } -/// \brief Return the fully qualified type, including fully-qualified +/// Return the fully qualified type, including fully-qualified /// versions of any template parameters. QualType getFullyQualifiedType(QualType QT, const ASTContext &Ctx, bool WithGlobalNsPrefix) { @@ -408,7 +408,7 @@ QualType getFullyQualifiedType(QualType QT, const ASTContext &Ctx, // Get the qualifiers. Qualifiers Quals = QT.getQualifiers(); - QT = dyn_cast<SubstTemplateTypeParmType>(QT.getTypePtr())->desugar(); + QT = cast<SubstTemplateTypeParmType>(QT.getTypePtr())->desugar(); // Add back the qualifiers. QT = Ctx.getQualifiedType(QT, Quals); @@ -452,12 +452,8 @@ QualType getFullyQualifiedType(QualType QT, const ASTContext &Ctx, std::string getFullyQualifiedName(QualType QT, const ASTContext &Ctx, + const PrintingPolicy &Policy, bool WithGlobalNsPrefix) { - PrintingPolicy Policy(Ctx.getPrintingPolicy()); - Policy.SuppressScope = false; - Policy.AnonymousTagLocations = false; - Policy.PolishForDeclaration = true; - Policy.SuppressUnwrittenScope = true; QualType FQQT = getFullyQualifiedType(QT, Ctx, WithGlobalNsPrefix); return FQQT.getAsString(Policy); } diff --git a/lib/AST/RawCommentList.cpp b/lib/AST/RawCommentList.cpp index 881a7d9c61be..95da9ed6d238 100644 --- a/lib/AST/RawCommentList.cpp +++ b/lib/AST/RawCommentList.cpp @@ -80,7 +80,7 @@ bool commentsStartOnSameColumn(const SourceManager &SM, const RawComment &R1, } } // unnamed namespace -/// \brief Determines whether there is only whitespace in `Buffer` between `P` +/// Determines whether there is only whitespace in `Buffer` between `P` /// and the previous line. /// \param Buffer The buffer to search in. /// \param P The offset from the beginning of `Buffer` to start from. @@ -107,10 +107,10 @@ static bool isOrdinaryKind(RawComment::CommentKind K) { } RawComment::RawComment(const SourceManager &SourceMgr, SourceRange SR, - bool Merged, bool ParseAllComments) : + const CommentOptions &CommentOpts, bool Merged) : Range(SR), RawTextValid(false), BriefTextValid(false), - IsAttached(false), IsTrailingComment(false), IsAlmostTrailingComment(false), - ParseAllComments(ParseAllComments) { + IsAttached(false), IsTrailingComment(false), + IsAlmostTrailingComment(false) { // Extract raw comment text, if possible. if (SR.getBegin() == SR.getEnd() || getRawText(SourceMgr).empty()) { Kind = RCK_Invalid; @@ -118,10 +118,11 @@ RawComment::RawComment(const SourceManager &SourceMgr, SourceRange SR, } // Guess comment kind. - std::pair<CommentKind, bool> K = getCommentKind(RawText, ParseAllComments); + std::pair<CommentKind, bool> K = + getCommentKind(RawText, CommentOpts.ParseAllComments); // Guess whether an ordinary comment is trailing. - if (ParseAllComments && isOrdinaryKind(K.first)) { + if (CommentOpts.ParseAllComments && isOrdinaryKind(K.first)) { FileID BeginFileID; unsigned BeginOffset; std::tie(BeginFileID, BeginOffset) = @@ -270,6 +271,7 @@ static bool onlyWhitespaceBetween(SourceManager &SM, } void RawCommentList::addComment(const RawComment &RC, + const CommentOptions &CommentOpts, llvm::BumpPtrAllocator &Allocator) { if (RC.isInvalid()) return; @@ -284,7 +286,7 @@ void RawCommentList::addComment(const RawComment &RC, } // Ordinary comments are not interesting for us. - if (RC.isOrdinary()) + if (RC.isOrdinary() && !CommentOpts.ParseAllComments) return; // If this is the first Doxygen comment, save it (because there isn't @@ -317,8 +319,7 @@ void RawCommentList::addComment(const RawComment &RC, onlyWhitespaceBetween(SourceMgr, C1.getLocEnd(), C2.getLocStart(), /*MaxNewlinesAllowed=*/1)) { SourceRange MergedRange(C1.getLocStart(), C2.getLocEnd()); - *Comments.back() = RawComment(SourceMgr, MergedRange, true, - RC.isParseAllComments()); + *Comments.back() = RawComment(SourceMgr, MergedRange, CommentOpts, true); } else { Comments.push_back(new (Allocator) RawComment(RC)); } @@ -334,3 +335,94 @@ void RawCommentList::addDeserializedComments(ArrayRef<RawComment *> Deserialized BeforeThanCompare<RawComment>(SourceMgr)); std::swap(Comments, MergedComments); } + +std::string RawComment::getFormattedText(const SourceManager &SourceMgr, + DiagnosticsEngine &Diags) const { + llvm::StringRef CommentText = getRawText(SourceMgr); + if (CommentText.empty()) + return ""; + + llvm::BumpPtrAllocator Allocator; + // We do not parse any commands, so CommentOptions are ignored by + // comments::Lexer. Therefore, we just use default-constructed options. + CommentOptions DefOpts; + comments::CommandTraits EmptyTraits(Allocator, DefOpts); + comments::Lexer L(Allocator, Diags, EmptyTraits, getSourceRange().getBegin(), + CommentText.begin(), CommentText.end(), + /*ParseCommands=*/false); + + std::string Result; + // A column number of the first non-whitespace token in the comment text. + // We skip whitespace up to this column, but keep the whitespace after this + // column. IndentColumn is calculated when lexing the first line and reused + // for the rest of lines. + unsigned IndentColumn = 0; + + // Processes one line of the comment and adds it to the result. + // Handles skipping the indent at the start of the line. + // Returns false when eof is reached and true otherwise. + auto LexLine = [&](bool IsFirstLine) -> bool { + comments::Token Tok; + // Lex the first token on the line. We handle it separately, because we to + // fix up its indentation. + L.lex(Tok); + if (Tok.is(comments::tok::eof)) + return false; + if (Tok.is(comments::tok::newline)) { + Result += "\n"; + return true; + } + llvm::StringRef TokText = L.getSpelling(Tok, SourceMgr); + bool LocInvalid = false; + unsigned TokColumn = + SourceMgr.getSpellingColumnNumber(Tok.getLocation(), &LocInvalid); + assert(!LocInvalid && "getFormattedText for invalid location"); + + // Amount of leading whitespace in TokText. + size_t WhitespaceLen = TokText.find_first_not_of(" \t"); + if (WhitespaceLen == StringRef::npos) + WhitespaceLen = TokText.size(); + // Remember the amount of whitespace we skipped in the first line to remove + // indent up to that column in the following lines. + if (IsFirstLine) + IndentColumn = TokColumn + WhitespaceLen; + + // Amount of leading whitespace we actually want to skip. + // For the first line we skip all the whitespace. + // For the rest of the lines, we skip whitespace up to IndentColumn. + unsigned SkipLen = + IsFirstLine + ? WhitespaceLen + : std::min<size_t>( + WhitespaceLen, + std::max<int>(static_cast<int>(IndentColumn) - TokColumn, 0)); + llvm::StringRef Trimmed = TokText.drop_front(SkipLen); + Result += Trimmed; + // Lex all tokens in the rest of the line. + for (L.lex(Tok); Tok.isNot(comments::tok::eof); L.lex(Tok)) { + if (Tok.is(comments::tok::newline)) { + Result += "\n"; + return true; + } + Result += L.getSpelling(Tok, SourceMgr); + } + // We've reached the end of file token. + return false; + }; + + auto DropTrailingNewLines = [](std::string &Str) { + while (Str.back() == '\n') + Str.pop_back(); + }; + + // Proces first line separately to remember indent for the following lines. + if (!LexLine(/*IsFirstLine=*/true)) { + DropTrailingNewLines(Result); + return Result; + } + // Process the rest of the lines. + while (LexLine(/*IsFirstLine=*/false)) + ; + DropTrailingNewLines(Result); + return Result; +} diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index a9d43dfa80c5..b4b09c7cecd7 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -54,25 +54,25 @@ struct BaseSubobjectInfo { const BaseSubobjectInfo *Derived; }; -/// \brief Externally provided layout. Typically used when the AST source, such +/// Externally provided layout. Typically used when the AST source, such /// as DWARF, lacks all the information that was available at compile time, such /// as alignment attributes on fields and pragmas in effect. struct ExternalLayout { ExternalLayout() : Size(0), Align(0) {} - /// \brief Overall record size in bits. + /// Overall record size in bits. uint64_t Size; - /// \brief Overall record alignment in bits. + /// Overall record alignment in bits. uint64_t Align; - /// \brief Record field offsets in bits. + /// Record field offsets in bits. llvm::DenseMap<const FieldDecl *, uint64_t> FieldOffsets; - /// \brief Direct, non-virtual base offsets. + /// Direct, non-virtual base offsets. llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsets; - /// \brief Virtual base offsets. + /// Virtual base offsets. llvm::DenseMap<const CXXRecordDecl *, CharUnits> VirtualBaseOffsets; /// Get the offset of the given field. The external source must provide @@ -579,16 +579,16 @@ protected: /// Alignment - The current alignment of the record layout. CharUnits Alignment; - /// \brief The alignment if attribute packed is not used. + /// The alignment if attribute packed is not used. CharUnits UnpackedAlignment; SmallVector<uint64_t, 16> FieldOffsets; - /// \brief Whether the external AST source has provided a layout for this + /// Whether the external AST source has provided a layout for this /// record. unsigned UseExternalLayout : 1; - /// \brief Whether we need to infer alignment, even when we have an + /// Whether we need to infer alignment, even when we have an /// externally-provided layout. unsigned InferAlignment : 1; @@ -632,7 +632,7 @@ protected: /// pointer, as opposed to inheriting one from a primary base class. bool HasOwnVFPtr; - /// \brief the flag of field offset changing due to packed attribute. + /// the flag of field offset changing due to packed attribute. bool HasPackedField; typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsetsMapTy; @@ -749,7 +749,7 @@ protected: UpdateAlignment(NewAlignment, NewAlignment); } - /// \brief Retrieve the externally-supplied field offset for the given + /// Retrieve the externally-supplied field offset for the given /// field. /// /// \param Field The field whose offset is being queried. @@ -967,7 +967,7 @@ void ItaniumRecordLayoutBuilder::ComputeBaseSubobjectInfo( void ItaniumRecordLayoutBuilder::EnsureVTablePointerAlignment( CharUnits UnpackedBaseAlign) { - CharUnits BaseAlign = (Packed) ? CharUnits::One() : UnpackedBaseAlign; + CharUnits BaseAlign = Packed ? CharUnits::One() : UnpackedBaseAlign; // The maximum field alignment overrides base align. if (!MaxFieldAlignment.isZero()) { @@ -1175,9 +1175,16 @@ ItaniumRecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) { HasExternalLayout = External.getExternalVBaseOffset(Base->Class, Offset); } + // Clang <= 6 incorrectly applied the 'packed' attribute to base classes. + // Per GCC's documentation, it only applies to non-static data members. CharUnits UnpackedBaseAlign = Layout.getNonVirtualAlignment(); - CharUnits BaseAlign = (Packed) ? CharUnits::One() : UnpackedBaseAlign; - + CharUnits BaseAlign = + (Packed && ((Context.getLangOpts().getClangABICompat() <= + LangOptions::ClangABI::Ver6) || + Context.getTargetInfo().getTriple().isPS4())) + ? 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()) && @@ -1504,9 +1511,10 @@ void ItaniumRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { FieldAlign = TypeSize; // If the previous field was not a bitfield, or was a bitfield - // with a different storage unit size, we're done with that - // storage unit. - if (LastBitfieldTypeSize != TypeSize) { + // with a different storage unit size, or if this field doesn't fit into + // the current storage unit, we're done with that storage unit. + if (LastBitfieldTypeSize != TypeSize || + UnfilledBitsInLastUnit < FieldSize) { // Also, ignore zero-length bitfields after non-bitfields. if (!LastBitfieldTypeSize && !FieldSize) FieldAlign = 1; @@ -1751,7 +1759,34 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D, QualType T = Context.getBaseElementType(D->getType()); if (const BuiltinType *BTy = T->getAs<BuiltinType>()) { CharUnits TypeSize = Context.getTypeSizeInChars(BTy); - if (TypeSize > FieldAlign) + + if (!llvm::isPowerOf2_64(TypeSize.getQuantity())) { + assert( + !Context.getTargetInfo().getTriple().isWindowsMSVCEnvironment() && + "Non PowerOf2 size in MSVC mode"); + // Base types with sizes that aren't a power of two don't work + // with the layout rules for MS structs. This isn't an issue in + // MSVC itself since there are no such base data types there. + // On e.g. x86_32 mingw and linux, long double is 12 bytes though. + // Any structs involving that data type obviously can't be ABI + // compatible with MSVC regardless of how it is laid out. + + // Since ms_struct can be mass enabled (via a pragma or via the + // -mms-bitfields command line parameter), this can trigger for + // structs that don't actually need MSVC compatibility, so we + // need to be able to sidestep the ms_struct layout for these types. + + // Since the combination of -mms-bitfields together with structs + // like max_align_t (which contains a long double) for mingw is + // quite comon (and GCC handles it silently), just handle it + // silently there. For other targets that have ms_struct enabled + // (most probably via a pragma or attribute), trigger a diagnostic + // that defaults to an error. + if (!Context.getTargetInfo().getTriple().isWindowsGNUEnvironment()) + Diag(D->getLocation(), diag::warn_npot_ms_struct); + } + if (TypeSize > FieldAlign && + llvm::isPowerOf2_64(TypeSize.getQuantity())) FieldAlign = TypeSize; } } @@ -1929,7 +1964,7 @@ ItaniumRecordLayoutBuilder::updateExternalFieldOffset(const FieldDecl *Field, return ExternalFieldOffset; } -/// \brief Get diagnostic %select index for tag kind for +/// Get diagnostic %select index for tag kind for /// field padding diagnostic message. /// WARNING: Indexes apply to particular diagnostics only! /// @@ -2106,7 +2141,7 @@ static bool mustSkipTailPadding(TargetCXXABI ABI, const CXXRecordDecl *RD) { // mode; fortunately, that is true because we want to assign // consistently semantics to the type-traits intrinsics (or at // least as many of them as possible). - return RD->isTrivial() && RD->isStandardLayout(); + return RD->isTrivial() && RD->isCXX11StandardLayout(); } llvm_unreachable("bad tail-padding use kind"); @@ -2220,9 +2255,9 @@ private: public: void layout(const RecordDecl *RD); void cxxLayout(const CXXRecordDecl *RD); - /// \brief Initializes size and alignment and honors some flags. + /// Initializes size and alignment and honors some flags. void initializeLayout(const RecordDecl *RD); - /// \brief Initialized C++ layout, compute alignment and virtual alignment and + /// Initialized C++ layout, compute alignment and virtual alignment and /// existence of vfptrs and vbptrs. Alignment is needed before the vfptr is /// laid out. void initializeCXXLayout(const CXXRecordDecl *RD); @@ -2233,93 +2268,93 @@ public: const ASTRecordLayout *&PreviousBaseLayout); void injectVFPtr(const CXXRecordDecl *RD); void injectVBPtr(const CXXRecordDecl *RD); - /// \brief Lays out the fields of the record. Also rounds size up to + /// 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 + /// 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 finalizeLayout(const RecordDecl *RD); - /// \brief Gets the size and alignment of a base taking pragma pack and + /// Gets the size and alignment of a base taking pragma pack and /// __declspec(align) into account. ElementInfo getAdjustedElementInfo(const ASTRecordLayout &Layout); - /// \brief Gets the size and alignment of a field taking pragma pack and + /// Gets the size and alignment of a field taking pragma pack and /// __declspec(align) into account. It also updates RequiredAlignment as a /// side effect because it is most convenient to do so here. ElementInfo getAdjustedElementInfo(const FieldDecl *FD); - /// \brief Places a field at an offset in CharUnits. + /// 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. + /// 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. + /// Compute the set of virtual bases for which vtordisps are required. void computeVtorDispSet( llvm::SmallPtrSetImpl<const CXXRecordDecl *> &HasVtorDispSet, const CXXRecordDecl *RD) const; const ASTContext &Context; - /// \brief The size of the record being laid out. + /// The size of the record being laid out. CharUnits Size; - /// \brief The non-virtual size of the record layout. + /// The non-virtual size of the record layout. CharUnits NonVirtualSize; - /// \brief The data size of the record layout. + /// The data size of the record layout. CharUnits DataSize; - /// \brief The current alignment of the record layout. + /// The current alignment of the record layout. CharUnits Alignment; - /// \brief The maximum allowed field alignment. This is set by #pragma pack. + /// The maximum allowed field alignment. This is set by #pragma pack. CharUnits MaxFieldAlignment; - /// \brief The alignment that this record must obey. This is imposed by + /// The alignment that this record must obey. This is imposed by /// __declspec(align()) on the record itself or one of its fields or bases. CharUnits RequiredAlignment; - /// \brief The size of the allocation of the currently active bitfield. + /// The size of the allocation of the currently active bitfield. /// This value isn't meaningful unless LastFieldIsNonZeroWidthBitfield /// is true. CharUnits CurrentBitfieldSize; - /// \brief Offset to the virtual base table pointer (if one exists). + /// Offset to the virtual base table pointer (if one exists). CharUnits VBPtrOffset; - /// \brief Minimum record size possible. + /// Minimum record size possible. CharUnits MinEmptyStructSize; - /// \brief The size and alignment info of a pointer. + /// The size and alignment info of a pointer. ElementInfo PointerInfo; - /// \brief The primary base class (if one exists). + /// The primary base class (if one exists). const CXXRecordDecl *PrimaryBase; - /// \brief The class we share our vb-pointer with. + /// The class we share our vb-pointer with. const CXXRecordDecl *SharedVBPtrBase; - /// \brief The collection of field offsets. + /// The collection of field offsets. SmallVector<uint64_t, 16> FieldOffsets; - /// \brief Base classes and their offsets in the record. + /// Base classes and their offsets in the record. BaseOffsetsMapTy Bases; - /// \brief virtual base classes and their offsets in the record. + /// virtual base classes and their offsets in the record. ASTRecordLayout::VBaseOffsetsMapTy VBases; - /// \brief The number of remaining bits in our last bitfield allocation. + /// The number of remaining bits in our last bitfield allocation. /// This value isn't meaningful unless LastFieldIsNonZeroWidthBitfield is /// true. unsigned RemainingBitsInField; bool IsUnion : 1; - /// \brief True if the last field laid out was a bitfield and was not 0 + /// True if the last field laid out was a bitfield and was not 0 /// width. bool LastFieldIsNonZeroWidthBitfield : 1; - /// \brief True if the class has its own vftable pointer. + /// True if the class has its own vftable pointer. bool HasOwnVFPtr : 1; - /// \brief True if the class has a vbtable pointer. + /// True if the class has a vbtable pointer. bool HasVBPtr : 1; - /// \brief True if the last sub-object within the type is zero sized or the + /// True if the last sub-object within the type is zero sized or the /// object itself is zero sized. This *does not* count members that are not /// records. Only used for MS-ABI. bool EndsWithZeroSizedObject : 1; - /// \brief True if this class is zero sized or first base is zero sized or + /// True if this class is zero sized or first base is zero sized or /// has this property. Only used for MS-ABI. bool LeadsWithZeroSizedBase : 1; - /// \brief True if the external AST source provided a layout for this record. + /// True if the external AST source provided a layout for this record. bool UseExternalLayout : 1; - /// \brief The layout provided by the external AST source. Only active if + /// The layout provided by the external AST source. Only active if /// UseExternalLayout is true. ExternalLayout External; }; @@ -2584,8 +2619,8 @@ void MicrosoftRecordLayoutBuilder::layoutNonVirtualBase( } if (!FoundBase) { - if (MDCUsesEBO && BaseDecl->isEmpty() && - BaseLayout.getNonVirtualSize() == CharUnits::Zero()) { + if (MDCUsesEBO && BaseDecl->isEmpty()) { + assert(BaseLayout.getNonVirtualSize() == CharUnits::Zero()); BaseOffset = CharUnits::Zero(); } else { // Otherwise, lay the base out at the end of the MDC. @@ -2642,7 +2677,7 @@ void MicrosoftRecordLayoutBuilder::layoutBitField(const FieldDecl *FD) { // 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 && + if (!UseExternalLayout && !IsUnion && LastFieldIsNonZeroWidthBitfield && CurrentBitfieldSize == Info.Size && Width <= RemainingBitsInField) { placeFieldAtBitOffset(Context.toBits(Size) - RemainingBitsInField); RemainingBitsInField -= Width; @@ -2654,6 +2689,14 @@ void MicrosoftRecordLayoutBuilder::layoutBitField(const FieldDecl *FD) { placeFieldAtOffset(CharUnits::Zero()); Size = std::max(Size, Info.Size); // TODO: Add a Sema warning that MS ignores bitfield alignment in unions. + } else if (UseExternalLayout) { + auto FieldBitOffset = External.getExternalFieldOffset(FD); + placeFieldAtBitOffset(FieldBitOffset); + auto NewSize = Context.toCharUnitsFromBits( + llvm::alignTo(FieldBitOffset + Width, Context.getCharWidth())); + assert(NewSize >= Size && "bit field offset already allocated"); + Size = NewSize; + Alignment = std::max(Alignment, Info.Alignment); } else { // Allocate a new block of memory and place the bitfield in it. CharUnits FieldOffset = Size.alignTo(Info.Alignment); @@ -3010,7 +3053,7 @@ const CXXMethodDecl *ASTContext::getCurrentKeyFunction(const CXXRecordDecl *RD) return nullptr; assert(RD->getDefinition() && "Cannot get key function for forward decl!"); - RD = cast<CXXRecordDecl>(RD->getDefinition()); + RD = RD->getDefinition(); // Beware: // 1) computing the key function might trigger deserialization, which might diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index 982fd458493f..a041006c905e 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -11,14 +11,15 @@ // //===----------------------------------------------------------------------===// +#include "clang/AST/Stmt.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTDiagnostic.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclGroup.h" +#include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/ExprOpenMP.h" -#include "clang/AST/Stmt.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtObjC.h" #include "clang/AST/StmtOpenMP.h" @@ -55,7 +56,7 @@ static StmtClassNameTable &getStmtInfoTableEntry(Stmt::StmtClass E) { if (Initialized) return StmtClassInfo[E]; - // Intialize the table on the first use. + // Initialize the table on the first use. Initialized = true; #define ABSTRACT_STMT(STMT) #define STMT(CLASS, PARENT) \ @@ -127,7 +128,7 @@ Stmt *Stmt::IgnoreImplicit() { return s; } -/// \brief Skip no-op (attributed, compound) container stmts and skip captured +/// Skip no-op (attributed, compound) container stmts and skip captured /// stmt at the top, if \a IgnoreCaptured is true. Stmt *Stmt::IgnoreContainers(bool IgnoreCaptured) { Stmt *S = this; @@ -147,18 +148,18 @@ Stmt *Stmt::IgnoreContainers(bool IgnoreCaptured) { return S; } -/// \brief Strip off all label-like statements. +/// Strip off all label-like statements. /// /// This will strip off label statements, case statements, attributed /// statements and default statements recursively. const Stmt *Stmt::stripLabelLikeStatements() const { const Stmt *S = this; while (true) { - if (const LabelStmt *LS = dyn_cast<LabelStmt>(S)) + if (const auto *LS = dyn_cast<LabelStmt>(S)) S = LS->getSubStmt(); - else if (const SwitchCase *SC = dyn_cast<SwitchCase>(S)) + else if (const auto *SC = dyn_cast<SwitchCase>(S)) S = SC->getSubStmt(); - else if (const AttributedStmt *AS = dyn_cast<AttributedStmt>(S)) + else if (const auto *AS = dyn_cast<AttributedStmt>(S)) S = AS->getSubStmt(); else return S; @@ -173,14 +174,14 @@ namespace { // These silly little functions have to be static inline to suppress // unused warnings, and they have to be defined to suppress other // warnings. - static inline good is_good(good) { return good(); } + static good is_good(good) { return good(); } typedef Stmt::child_range children_t(); template <class T> good implements_children(children_t T::*) { return good(); } LLVM_ATTRIBUTE_UNUSED - static inline bad implements_children(children_t Stmt::*) { + static bad implements_children(children_t Stmt::*) { return bad(); } @@ -189,7 +190,7 @@ namespace { return good(); } LLVM_ATTRIBUTE_UNUSED - static inline bad implements_getLocStart(getLocStart_t Stmt::*) { + static bad implements_getLocStart(getLocStart_t Stmt::*) { return bad(); } @@ -198,7 +199,7 @@ namespace { return good(); } LLVM_ATTRIBUTE_UNUSED - static inline bad implements_getLocEnd(getLocEnd_t Stmt::*) { + static bad implements_getLocEnd(getLocEnd_t Stmt::*) { return bad(); } @@ -351,49 +352,49 @@ AttributedStmt *AttributedStmt::CreateEmpty(const ASTContext &C, } std::string AsmStmt::generateAsmString(const ASTContext &C) const { - if (const GCCAsmStmt *gccAsmStmt = dyn_cast<GCCAsmStmt>(this)) + if (const auto *gccAsmStmt = dyn_cast<GCCAsmStmt>(this)) return gccAsmStmt->generateAsmString(C); - if (const MSAsmStmt *msAsmStmt = dyn_cast<MSAsmStmt>(this)) + if (const auto *msAsmStmt = dyn_cast<MSAsmStmt>(this)) return msAsmStmt->generateAsmString(C); llvm_unreachable("unknown asm statement kind!"); } StringRef AsmStmt::getOutputConstraint(unsigned i) const { - if (const GCCAsmStmt *gccAsmStmt = dyn_cast<GCCAsmStmt>(this)) + if (const auto *gccAsmStmt = dyn_cast<GCCAsmStmt>(this)) return gccAsmStmt->getOutputConstraint(i); - if (const MSAsmStmt *msAsmStmt = dyn_cast<MSAsmStmt>(this)) + if (const auto *msAsmStmt = dyn_cast<MSAsmStmt>(this)) return msAsmStmt->getOutputConstraint(i); llvm_unreachable("unknown asm statement kind!"); } const Expr *AsmStmt::getOutputExpr(unsigned i) const { - if (const GCCAsmStmt *gccAsmStmt = dyn_cast<GCCAsmStmt>(this)) + if (const auto *gccAsmStmt = dyn_cast<GCCAsmStmt>(this)) return gccAsmStmt->getOutputExpr(i); - if (const MSAsmStmt *msAsmStmt = dyn_cast<MSAsmStmt>(this)) + if (const auto *msAsmStmt = dyn_cast<MSAsmStmt>(this)) return msAsmStmt->getOutputExpr(i); llvm_unreachable("unknown asm statement kind!"); } StringRef AsmStmt::getInputConstraint(unsigned i) const { - if (const GCCAsmStmt *gccAsmStmt = dyn_cast<GCCAsmStmt>(this)) + if (const auto *gccAsmStmt = dyn_cast<GCCAsmStmt>(this)) return gccAsmStmt->getInputConstraint(i); - if (const MSAsmStmt *msAsmStmt = dyn_cast<MSAsmStmt>(this)) + if (const auto *msAsmStmt = dyn_cast<MSAsmStmt>(this)) return msAsmStmt->getInputConstraint(i); llvm_unreachable("unknown asm statement kind!"); } const Expr *AsmStmt::getInputExpr(unsigned i) const { - if (const GCCAsmStmt *gccAsmStmt = dyn_cast<GCCAsmStmt>(this)) + if (const auto *gccAsmStmt = dyn_cast<GCCAsmStmt>(this)) return gccAsmStmt->getInputExpr(i); - if (const MSAsmStmt *msAsmStmt = dyn_cast<MSAsmStmt>(this)) + if (const auto *msAsmStmt = dyn_cast<MSAsmStmt>(this)) return msAsmStmt->getInputExpr(i); llvm_unreachable("unknown asm statement kind!"); } StringRef AsmStmt::getClobber(unsigned i) const { - if (const GCCAsmStmt *gccAsmStmt = dyn_cast<GCCAsmStmt>(this)) + if (const auto *gccAsmStmt = dyn_cast<GCCAsmStmt>(this)) return gccAsmStmt->getClobber(i); - if (const MSAsmStmt *msAsmStmt = dyn_cast<MSAsmStmt>(this)) + if (const auto *msAsmStmt = dyn_cast<MSAsmStmt>(this)) return msAsmStmt->getClobber(i); llvm_unreachable("unknown asm statement kind!"); } @@ -681,14 +682,14 @@ std::string GCCAsmStmt::generateAsmString(const ASTContext &C) const { AnalyzeAsmString(Pieces, C, DiagOffs); std::string AsmString; - for (unsigned i = 0, e = Pieces.size(); i != e; ++i) { - if (Pieces[i].isString()) - AsmString += Pieces[i].getString(); - else if (Pieces[i].getModifier() == '\0') - AsmString += '$' + llvm::utostr(Pieces[i].getOperandNo()); + for (const auto &Piece : Pieces) { + if (Piece.isString()) + AsmString += Piece.getString(); + else if (Piece.getModifier() == '\0') + AsmString += '$' + llvm::utostr(Piece.getOperandNo()); else - AsmString += "${" + llvm::utostr(Pieces[i].getOperandNo()) + ':' + - Pieces[i].getModifier() + '}'; + AsmString += "${" + llvm::utostr(Piece.getOperandNo()) + ':' + + Piece.getModifier() + '}'; } return AsmString; } @@ -804,7 +805,7 @@ VarDecl *IfStmt::getConditionVariable() const { if (!SubExprs[VAR]) return nullptr; - DeclStmt *DS = cast<DeclStmt>(SubExprs[VAR]); + auto *DS = cast<DeclStmt>(SubExprs[VAR]); return cast<VarDecl>(DS->getSingleDecl()); } @@ -839,7 +840,7 @@ VarDecl *ForStmt::getConditionVariable() const { if (!SubExprs[CONDVAR]) return nullptr; - DeclStmt *DS = cast<DeclStmt>(SubExprs[CONDVAR]); + auto *DS = cast<DeclStmt>(SubExprs[CONDVAR]); return cast<VarDecl>(DS->getSingleDecl()); } @@ -867,7 +868,7 @@ VarDecl *SwitchStmt::getConditionVariable() const { if (!SubExprs[VAR]) return nullptr; - DeclStmt *DS = cast<DeclStmt>(SubExprs[VAR]); + auto *DS = cast<DeclStmt>(SubExprs[VAR]); return cast<VarDecl>(DS->getSingleDecl()); } @@ -901,7 +902,7 @@ VarDecl *WhileStmt::getConditionVariable() const { if (!SubExprs[VAR]) return nullptr; - DeclStmt *DS = cast<DeclStmt>(SubExprs[VAR]); + auto *DS = cast<DeclStmt>(SubExprs[VAR]); return cast<VarDecl>(DS->getSingleDecl()); } @@ -918,8 +919,7 @@ void WhileStmt::setConditionVariable(const ASTContext &C, VarDecl *V) { // IndirectGotoStmt LabelDecl *IndirectGotoStmt::getConstantTarget() { - if (AddrLabelExpr *E = - dyn_cast<AddrLabelExpr>(getTarget()->IgnoreParenImpCasts())) + if (auto *E = dyn_cast<AddrLabelExpr>(getTarget()->IgnoreParenImpCasts())) return E->getLabel(); return nullptr; } @@ -1105,18 +1105,18 @@ const CapturedDecl *CapturedStmt::getCapturedDecl() const { return CapDeclAndKind.getPointer(); } -/// \brief Set the outlined function declaration. +/// Set the outlined function declaration. void CapturedStmt::setCapturedDecl(CapturedDecl *D) { assert(D && "null CapturedDecl"); CapDeclAndKind.setPointer(D); } -/// \brief Retrieve the captured region kind. +/// Retrieve the captured region kind. CapturedRegionKind CapturedStmt::getCapturedRegionKind() const { return CapDeclAndKind.getInt(); } -/// \brief Set the captured region kind. +/// Set the captured region kind. void CapturedStmt::setCapturedRegionKind(CapturedRegionKind Kind) { CapDeclAndKind.setInt(Kind); } diff --git a/lib/AST/StmtCXX.cpp b/lib/AST/StmtCXX.cpp index 666f5dcc9d97..bf2d6a16fb5f 100644 --- a/lib/AST/StmtCXX.cpp +++ b/lib/AST/StmtCXX.cpp @@ -25,18 +25,14 @@ QualType CXXCatchStmt::getCaughtType() const { 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 *)); - + const size_t Size = totalSizeToAlloc<Stmt *>(handlers.size() + 1); void *Mem = C.Allocate(Size, alignof(CXXTryStmt)); return new (Mem) CXXTryStmt(tryLoc, tryBlock, handlers); } CXXTryStmt *CXXTryStmt::Create(const ASTContext &C, EmptyShell Empty, unsigned numHandlers) { - std::size_t Size = sizeof(CXXTryStmt); - Size += ((numHandlers + 1) * sizeof(Stmt *)); - + const size_t Size = totalSizeToAlloc<Stmt *>(numHandlers + 1); void *Mem = C.Allocate(Size, alignof(CXXTryStmt)); return new (Mem) CXXTryStmt(Empty, numHandlers); } @@ -44,7 +40,7 @@ CXXTryStmt *CXXTryStmt::Create(const ASTContext &C, EmptyShell Empty, CXXTryStmt::CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock, ArrayRef<Stmt *> handlers) : Stmt(CXXTryStmtClass), TryLoc(tryLoc), NumHandlers(handlers.size()) { - Stmt **Stmts = reinterpret_cast<Stmt **>(this + 1); + Stmt **Stmts = getStmts(); Stmts[0] = tryBlock; std::copy(handlers.begin(), handlers.end(), Stmts + 1); } diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index d7e668a83280..dad57de8940b 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -1,4 +1,4 @@ -//===--- StmtPrinter.cpp - Printing implementation for Stmt ASTs ----------===// +//===- StmtPrinter.cpp - Printing implementation for Stmt ASTs ------------===// // // The LLVM Compiler Infrastructure // @@ -14,30 +14,60 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclOpenMP.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" #include "clang/AST/ExprOpenMP.h" +#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/OpenMPClause.h" #include "clang/AST/PrettyPrinter.h" +#include "clang/AST/Stmt.h" +#include "clang/AST/StmtCXX.h" +#include "clang/AST/StmtObjC.h" +#include "clang/AST/StmtOpenMP.h" #include "clang/AST/StmtVisitor.h" +#include "clang/AST/TemplateBase.h" +#include "clang/AST/Type.h" #include "clang/Basic/CharInfo.h" +#include "clang/Basic/ExpressionTraits.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/Lambda.h" +#include "clang/Basic/OpenMPKinds.h" +#include "clang/Basic/OperatorKinds.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/TypeTraits.h" #include "clang/Lex/Lexer.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" +#include <cassert> +#include <string> + using namespace clang; //===----------------------------------------------------------------------===// // StmtPrinter Visitor //===----------------------------------------------------------------------===// -namespace { +namespace { + class StmtPrinter : public StmtVisitor<StmtPrinter> { raw_ostream &OS; unsigned IndentLevel; - clang::PrinterHelper* Helper; + PrinterHelper* Helper; PrintingPolicy Policy; const ASTContext *Context; @@ -100,9 +130,11 @@ namespace { void VisitStmt(Stmt *Node) LLVM_ATTRIBUTE_UNUSED { Indent() << "<<unknown stmt type>>\n"; } + void VisitExpr(Expr *Node) LLVM_ATTRIBUTE_UNUSED { OS << "<<unknown expr type>>"; } + void VisitCXXNamedCastExpr(CXXNamedCastExpr *Node); #define ABSTRACT_STMT(CLASS) @@ -110,7 +142,8 @@ namespace { void Visit##CLASS(CLASS *Node); #include "clang/AST/StmtNodes.inc" }; -} + +} // namespace //===----------------------------------------------------------------------===// // Stmt printing methods. @@ -131,7 +164,7 @@ void StmtPrinter::PrintRawDecl(Decl *D) { } void StmtPrinter::PrintRawDeclStmt(const DeclStmt *S) { - SmallVector<Decl*, 2> Decls(S->decls()); + SmallVector<Decl *, 2> Decls(S->decls()); Decl::printGroup(Decls.data(), Decls.size(), OS, Policy, IndentLevel); } @@ -189,7 +222,7 @@ void StmtPrinter::PrintRawIfStmt(IfStmt *If) { PrintExpr(If->getCond()); OS << ')'; - if (CompoundStmt *CS = dyn_cast<CompoundStmt>(If->getThen())) { + if (auto *CS = dyn_cast<CompoundStmt>(If->getThen())) { OS << ' '; PrintRawCompoundStmt(CS); OS << (If->getElse() ? ' ' : '\n'); @@ -202,11 +235,11 @@ void StmtPrinter::PrintRawIfStmt(IfStmt *If) { if (Stmt *Else = If->getElse()) { OS << "else"; - if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Else)) { + if (auto *CS = dyn_cast<CompoundStmt>(Else)) { OS << ' '; PrintRawCompoundStmt(CS); OS << '\n'; - } else if (IfStmt *ElseIf = dyn_cast<IfStmt>(Else)) { + } else if (auto *ElseIf = dyn_cast<IfStmt>(Else)) { OS << ' '; PrintRawIfStmt(ElseIf); } else { @@ -230,7 +263,7 @@ void StmtPrinter::VisitSwitchStmt(SwitchStmt *Node) { OS << ")"; // Pretty print compoundstmt bodies (very common). - if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Node->getBody())) { + if (auto *CS = dyn_cast<CompoundStmt>(Node->getBody())) { OS << " "; PrintRawCompoundStmt(CS); OS << "\n"; @@ -252,7 +285,7 @@ void StmtPrinter::VisitWhileStmt(WhileStmt *Node) { void StmtPrinter::VisitDoStmt(DoStmt *Node) { Indent() << "do "; - if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Node->getBody())) { + if (auto *CS = dyn_cast<CompoundStmt>(Node->getBody())) { PrintRawCompoundStmt(CS); OS << " "; } else { @@ -269,7 +302,7 @@ void StmtPrinter::VisitDoStmt(DoStmt *Node) { void StmtPrinter::VisitForStmt(ForStmt *Node) { Indent() << "for ("; if (Node->getInit()) { - if (DeclStmt *DS = dyn_cast<DeclStmt>(Node->getInit())) + if (auto *DS = dyn_cast<DeclStmt>(Node->getInit())) PrintRawDeclStmt(DS); else PrintExpr(cast<Expr>(Node->getInit())); @@ -286,7 +319,7 @@ void StmtPrinter::VisitForStmt(ForStmt *Node) { } OS << ") "; - if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Node->getBody())) { + if (auto *CS = dyn_cast<CompoundStmt>(Node->getBody())) { PrintRawCompoundStmt(CS); OS << "\n"; } else { @@ -297,7 +330,7 @@ void StmtPrinter::VisitForStmt(ForStmt *Node) { void StmtPrinter::VisitObjCForCollectionStmt(ObjCForCollectionStmt *Node) { Indent() << "for ("; - if (DeclStmt *DS = dyn_cast<DeclStmt>(Node->getElement())) + if (auto *DS = dyn_cast<DeclStmt>(Node->getElement())) PrintRawDeclStmt(DS); else PrintExpr(cast<Expr>(Node->getElement())); @@ -305,7 +338,7 @@ void StmtPrinter::VisitObjCForCollectionStmt(ObjCForCollectionStmt *Node) { PrintExpr(Node->getCollection()); OS << ") "; - if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Node->getBody())) { + if (auto *CS = dyn_cast<CompoundStmt>(Node->getBody())) { PrintRawCompoundStmt(CS); OS << "\n"; } else { @@ -365,7 +398,6 @@ void StmtPrinter::VisitBreakStmt(BreakStmt *Node) { if (Policy.IncludeNewlines) OS << "\n"; } - void StmtPrinter::VisitReturnStmt(ReturnStmt *Node) { Indent() << "return"; if (Node->getRetValue()) { @@ -376,7 +408,6 @@ void StmtPrinter::VisitReturnStmt(ReturnStmt *Node) { if (Policy.IncludeNewlines) OS << "\n"; } - void StmtPrinter::VisitGCCAsmStmt(GCCAsmStmt *Node) { Indent() << "asm "; @@ -458,7 +489,7 @@ void StmtPrinter::VisitCapturedStmt(CapturedStmt *Node) { void StmtPrinter::VisitObjCAtTryStmt(ObjCAtTryStmt *Node) { Indent() << "@try"; - if (CompoundStmt *TS = dyn_cast<CompoundStmt>(Node->getTryBody())) { + if (auto *TS = dyn_cast<CompoundStmt>(Node->getTryBody())) { PrintRawCompoundStmt(TS); OS << "\n"; } @@ -471,14 +502,13 @@ void StmtPrinter::VisitObjCAtTryStmt(ObjCAtTryStmt *Node) { PrintRawDecl(DS); } OS << ")"; - if (CompoundStmt *CS = dyn_cast<CompoundStmt>(catchStmt->getCatchBody())) { + if (auto *CS = dyn_cast<CompoundStmt>(catchStmt->getCatchBody())) { PrintRawCompoundStmt(CS); OS << "\n"; } } - if (ObjCAtFinallyStmt *FS = static_cast<ObjCAtFinallyStmt *>( - Node->getFinallyStmt())) { + if (auto *FS = static_cast<ObjCAtFinallyStmt *>(Node->getFinallyStmt())) { Indent() << "@finally"; PrintRawCompoundStmt(dyn_cast<CompoundStmt>(FS->getFinallyBody())); OS << "\n"; @@ -596,20 +626,26 @@ void StmtPrinter::VisitSEHLeaveStmt(SEHLeaveStmt *Node) { //===----------------------------------------------------------------------===// namespace { + class OMPClausePrinter : public OMPClauseVisitor<OMPClausePrinter> { raw_ostream &OS; const PrintingPolicy &Policy; - /// \brief Process clauses with list of variables. + + /// Process clauses with list of variables. template <typename T> void VisitOMPClauseList(T *Node, char StartSym); + public: OMPClausePrinter(raw_ostream &OS, const PrintingPolicy &Policy) - : OS(OS), Policy(Policy) { } + : OS(OS), Policy(Policy) {} + #define OPENMP_CLAUSE(Name, Class) \ void Visit##Class(Class *S); #include "clang/Basic/OpenMPKinds.def" }; +} // namespace + void OMPClausePrinter::VisitOMPIfClause(OMPIfClause *Node) { OS << "if("; if (Node->getNameModifier() != OMPD_unknown) @@ -776,7 +812,7 @@ void OMPClausePrinter::VisitOMPClauseList(T *Node, char StartSym) { I != E; ++I) { assert(*I && "Expected non-null Stmt"); OS << (I == Node->varlist_begin() ? StartSym : ','); - if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(*I)) { + if (auto *DRE = dyn_cast<DeclRefExpr>(*I)) { if (isa<OMPCapturedExprDecl>(DRE->getDecl())) DRE->printPretty(OS, nullptr, Policy, 0); else @@ -1017,7 +1053,6 @@ void OMPClausePrinter::VisitOMPIsDevicePtrClause(OMPIsDevicePtrClause *Node) { OS << ")"; } } -} //===----------------------------------------------------------------------===// // OpenMP directives printing methods @@ -1027,43 +1062,38 @@ void StmtPrinter::PrintOMPExecutableDirective(OMPExecutableDirective *S, bool ForceNoStmt) { OMPClausePrinter Printer(OS, Policy); ArrayRef<OMPClause *> Clauses = S->clauses(); - for (ArrayRef<OMPClause *>::iterator I = Clauses.begin(), E = Clauses.end(); - I != E; ++I) - if (*I && !(*I)->isImplicit()) { - Printer.Visit(*I); + for (auto *Clause : Clauses) + if (Clause && !Clause->isImplicit()) { OS << ' '; + Printer.Visit(Clause); } OS << "\n"; - if (S->hasAssociatedStmt() && S->getAssociatedStmt() && !ForceNoStmt) { - assert(isa<CapturedStmt>(S->getAssociatedStmt()) && - "Expected captured statement!"); - Stmt *CS = cast<CapturedStmt>(S->getAssociatedStmt())->getCapturedStmt(); - PrintStmt(CS); - } + if (!ForceNoStmt && S->hasAssociatedStmt()) + PrintStmt(S->getInnermostCapturedStmt()->getCapturedStmt()); } void StmtPrinter::VisitOMPParallelDirective(OMPParallelDirective *Node) { - Indent() << "#pragma omp parallel "; + Indent() << "#pragma omp parallel"; PrintOMPExecutableDirective(Node); } void StmtPrinter::VisitOMPSimdDirective(OMPSimdDirective *Node) { - Indent() << "#pragma omp simd "; + Indent() << "#pragma omp simd"; PrintOMPExecutableDirective(Node); } void StmtPrinter::VisitOMPForDirective(OMPForDirective *Node) { - Indent() << "#pragma omp for "; + Indent() << "#pragma omp for"; PrintOMPExecutableDirective(Node); } void StmtPrinter::VisitOMPForSimdDirective(OMPForSimdDirective *Node) { - Indent() << "#pragma omp for simd "; + Indent() << "#pragma omp for simd"; PrintOMPExecutableDirective(Node); } void StmtPrinter::VisitOMPSectionsDirective(OMPSectionsDirective *Node) { - Indent() << "#pragma omp sections "; + Indent() << "#pragma omp sections"; PrintOMPExecutableDirective(Node); } @@ -1073,7 +1103,7 @@ void StmtPrinter::VisitOMPSectionDirective(OMPSectionDirective *Node) { } void StmtPrinter::VisitOMPSingleDirective(OMPSingleDirective *Node) { - Indent() << "#pragma omp single "; + Indent() << "#pragma omp single"; PrintOMPExecutableDirective(Node); } @@ -1089,29 +1119,28 @@ void StmtPrinter::VisitOMPCriticalDirective(OMPCriticalDirective *Node) { Node->getDirectiveName().printName(OS); OS << ")"; } - OS << " "; PrintOMPExecutableDirective(Node); } void StmtPrinter::VisitOMPParallelForDirective(OMPParallelForDirective *Node) { - Indent() << "#pragma omp parallel for "; + Indent() << "#pragma omp parallel for"; PrintOMPExecutableDirective(Node); } void StmtPrinter::VisitOMPParallelForSimdDirective( OMPParallelForSimdDirective *Node) { - Indent() << "#pragma omp parallel for simd "; + Indent() << "#pragma omp parallel for simd"; PrintOMPExecutableDirective(Node); } void StmtPrinter::VisitOMPParallelSectionsDirective( OMPParallelSectionsDirective *Node) { - Indent() << "#pragma omp parallel sections "; + Indent() << "#pragma omp parallel sections"; PrintOMPExecutableDirective(Node); } void StmtPrinter::VisitOMPTaskDirective(OMPTaskDirective *Node) { - Indent() << "#pragma omp task "; + Indent() << "#pragma omp task"; PrintOMPExecutableDirective(Node); } @@ -1131,61 +1160,61 @@ void StmtPrinter::VisitOMPTaskwaitDirective(OMPTaskwaitDirective *Node) { } void StmtPrinter::VisitOMPTaskgroupDirective(OMPTaskgroupDirective *Node) { - Indent() << "#pragma omp taskgroup "; + Indent() << "#pragma omp taskgroup"; PrintOMPExecutableDirective(Node); } void StmtPrinter::VisitOMPFlushDirective(OMPFlushDirective *Node) { - Indent() << "#pragma omp flush "; + Indent() << "#pragma omp flush"; PrintOMPExecutableDirective(Node); } void StmtPrinter::VisitOMPOrderedDirective(OMPOrderedDirective *Node) { - Indent() << "#pragma omp ordered "; - PrintOMPExecutableDirective(Node); + Indent() << "#pragma omp ordered"; + PrintOMPExecutableDirective(Node, Node->hasClausesOfKind<OMPDependClause>()); } void StmtPrinter::VisitOMPAtomicDirective(OMPAtomicDirective *Node) { - Indent() << "#pragma omp atomic "; + Indent() << "#pragma omp atomic"; PrintOMPExecutableDirective(Node); } void StmtPrinter::VisitOMPTargetDirective(OMPTargetDirective *Node) { - Indent() << "#pragma omp target "; + Indent() << "#pragma omp target"; PrintOMPExecutableDirective(Node); } void StmtPrinter::VisitOMPTargetDataDirective(OMPTargetDataDirective *Node) { - Indent() << "#pragma omp target data "; + Indent() << "#pragma omp target data"; PrintOMPExecutableDirective(Node); } void StmtPrinter::VisitOMPTargetEnterDataDirective( OMPTargetEnterDataDirective *Node) { - Indent() << "#pragma omp target enter data "; + Indent() << "#pragma omp target enter data"; PrintOMPExecutableDirective(Node, /*ForceNoStmt=*/true); } void StmtPrinter::VisitOMPTargetExitDataDirective( OMPTargetExitDataDirective *Node) { - Indent() << "#pragma omp target exit data "; + Indent() << "#pragma omp target exit data"; PrintOMPExecutableDirective(Node, /*ForceNoStmt=*/true); } void StmtPrinter::VisitOMPTargetParallelDirective( OMPTargetParallelDirective *Node) { - Indent() << "#pragma omp target parallel "; + Indent() << "#pragma omp target parallel"; PrintOMPExecutableDirective(Node); } void StmtPrinter::VisitOMPTargetParallelForDirective( OMPTargetParallelForDirective *Node) { - Indent() << "#pragma omp target parallel for "; + Indent() << "#pragma omp target parallel for"; PrintOMPExecutableDirective(Node); } void StmtPrinter::VisitOMPTeamsDirective(OMPTeamsDirective *Node) { - Indent() << "#pragma omp teams "; + Indent() << "#pragma omp teams"; PrintOMPExecutableDirective(Node); } @@ -1198,111 +1227,111 @@ void StmtPrinter::VisitOMPCancellationPointDirective( void StmtPrinter::VisitOMPCancelDirective(OMPCancelDirective *Node) { Indent() << "#pragma omp cancel " - << getOpenMPDirectiveName(Node->getCancelRegion()) << " "; + << getOpenMPDirectiveName(Node->getCancelRegion()); PrintOMPExecutableDirective(Node); } void StmtPrinter::VisitOMPTaskLoopDirective(OMPTaskLoopDirective *Node) { - Indent() << "#pragma omp taskloop "; + Indent() << "#pragma omp taskloop"; PrintOMPExecutableDirective(Node); } void StmtPrinter::VisitOMPTaskLoopSimdDirective( OMPTaskLoopSimdDirective *Node) { - Indent() << "#pragma omp taskloop simd "; + Indent() << "#pragma omp taskloop simd"; PrintOMPExecutableDirective(Node); } void StmtPrinter::VisitOMPDistributeDirective(OMPDistributeDirective *Node) { - Indent() << "#pragma omp distribute "; + Indent() << "#pragma omp distribute"; PrintOMPExecutableDirective(Node); } void StmtPrinter::VisitOMPTargetUpdateDirective( OMPTargetUpdateDirective *Node) { - Indent() << "#pragma omp target update "; + Indent() << "#pragma omp target update"; PrintOMPExecutableDirective(Node, /*ForceNoStmt=*/true); } void StmtPrinter::VisitOMPDistributeParallelForDirective( OMPDistributeParallelForDirective *Node) { - Indent() << "#pragma omp distribute parallel for "; + Indent() << "#pragma omp distribute parallel for"; PrintOMPExecutableDirective(Node); } void StmtPrinter::VisitOMPDistributeParallelForSimdDirective( OMPDistributeParallelForSimdDirective *Node) { - Indent() << "#pragma omp distribute parallel for simd "; + Indent() << "#pragma omp distribute parallel for simd"; PrintOMPExecutableDirective(Node); } void StmtPrinter::VisitOMPDistributeSimdDirective( OMPDistributeSimdDirective *Node) { - Indent() << "#pragma omp distribute simd "; + Indent() << "#pragma omp distribute simd"; PrintOMPExecutableDirective(Node); } void StmtPrinter::VisitOMPTargetParallelForSimdDirective( OMPTargetParallelForSimdDirective *Node) { - Indent() << "#pragma omp target parallel for simd "; + Indent() << "#pragma omp target parallel for simd"; PrintOMPExecutableDirective(Node); } void StmtPrinter::VisitOMPTargetSimdDirective(OMPTargetSimdDirective *Node) { - Indent() << "#pragma omp target simd "; + Indent() << "#pragma omp target simd"; PrintOMPExecutableDirective(Node); } void StmtPrinter::VisitOMPTeamsDistributeDirective( OMPTeamsDistributeDirective *Node) { - Indent() << "#pragma omp teams distribute "; + Indent() << "#pragma omp teams distribute"; PrintOMPExecutableDirective(Node); } void StmtPrinter::VisitOMPTeamsDistributeSimdDirective( OMPTeamsDistributeSimdDirective *Node) { - Indent() << "#pragma omp teams distribute simd "; + Indent() << "#pragma omp teams distribute simd"; PrintOMPExecutableDirective(Node); } void StmtPrinter::VisitOMPTeamsDistributeParallelForSimdDirective( OMPTeamsDistributeParallelForSimdDirective *Node) { - Indent() << "#pragma omp teams distribute parallel for simd "; + Indent() << "#pragma omp teams distribute parallel for simd"; PrintOMPExecutableDirective(Node); } void StmtPrinter::VisitOMPTeamsDistributeParallelForDirective( OMPTeamsDistributeParallelForDirective *Node) { - Indent() << "#pragma omp teams distribute parallel for "; + Indent() << "#pragma omp teams distribute parallel for"; PrintOMPExecutableDirective(Node); } void StmtPrinter::VisitOMPTargetTeamsDirective(OMPTargetTeamsDirective *Node) { - Indent() << "#pragma omp target teams "; + Indent() << "#pragma omp target teams"; PrintOMPExecutableDirective(Node); } void StmtPrinter::VisitOMPTargetTeamsDistributeDirective( OMPTargetTeamsDistributeDirective *Node) { - Indent() << "#pragma omp target teams distribute "; + Indent() << "#pragma omp target teams distribute"; PrintOMPExecutableDirective(Node); } void StmtPrinter::VisitOMPTargetTeamsDistributeParallelForDirective( OMPTargetTeamsDistributeParallelForDirective *Node) { - Indent() << "#pragma omp target teams distribute parallel for "; + Indent() << "#pragma omp target teams distribute parallel for"; PrintOMPExecutableDirective(Node); } void StmtPrinter::VisitOMPTargetTeamsDistributeParallelForSimdDirective( OMPTargetTeamsDistributeParallelForSimdDirective *Node) { - Indent() << "#pragma omp target teams distribute parallel for simd "; + Indent() << "#pragma omp target teams distribute parallel for simd"; PrintOMPExecutableDirective(Node); } void StmtPrinter::VisitOMPTargetTeamsDistributeSimdDirective( OMPTargetTeamsDistributeSimdDirective *Node) { - Indent() << "#pragma omp target teams distribute simd "; + Indent() << "#pragma omp target teams distribute simd"; PrintOMPExecutableDirective(Node); } @@ -1311,7 +1340,7 @@ void StmtPrinter::VisitOMPTargetTeamsDistributeSimdDirective( //===----------------------------------------------------------------------===// void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) { - if (auto *OCED = dyn_cast<OMPCapturedExprDecl>(Node->getDecl())) { + if (const auto *OCED = dyn_cast<OMPCapturedExprDecl>(Node->getDecl())) { OCED->getInit()->IgnoreImpCasts()->printPretty(OS, nullptr, Policy); return; } @@ -1347,8 +1376,7 @@ void StmtPrinter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node) { static bool isImplicitSelf(const Expr *E) { if (const auto *DRE = dyn_cast<DeclRefExpr>(E)) { - if (const ImplicitParamDecl *PD = - dyn_cast<ImplicitParamDecl>(DRE->getDecl())) { + if (const auto *PD = dyn_cast<ImplicitParamDecl>(DRE->getDecl())) { if (PD->getParameterKind() == ImplicitParamDecl::ObjCSelf && DRE->getLocStart().isInvalid()) return true; @@ -1378,14 +1406,17 @@ void StmtPrinter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) { OS << Node->getClassReceiver()->getName() << "."; } - if (Node->isImplicitProperty()) - Node->getImplicitPropertyGetter()->getSelector().print(OS); - else + if (Node->isImplicitProperty()) { + if (const auto *Getter = Node->getImplicitPropertyGetter()) + Getter->getSelector().print(OS); + else + OS << SelectorTable::getPropertyNameFromSetterSelector( + Node->getImplicitPropertySetter()->getSelector()); + } else OS << Node->getExplicitProperty()->getName(); } void StmtPrinter::VisitObjCSubscriptRefExpr(ObjCSubscriptRefExpr *Node) { - PrintExpr(Node->getBaseExpr()); OS << "["; PrintExpr(Node->getKeyExpr()); @@ -1498,6 +1529,28 @@ void StmtPrinter::VisitIntegerLiteral(IntegerLiteral *Node) { } } +void StmtPrinter::VisitFixedPointLiteral(FixedPointLiteral *Node) { + if (Policy.ConstantsAsWritten && printExprAsWritten(OS, Node, Context)) + return; + OS << Node->getValueAsString(/*Radix=*/10); + + switch (Node->getType()->getAs<BuiltinType>()->getKind()) { + default: llvm_unreachable("Unexpected type for fixed point literal!"); + case BuiltinType::ShortFract: OS << "hr"; break; + case BuiltinType::ShortAccum: OS << "hk"; break; + case BuiltinType::UShortFract: OS << "uhr"; break; + case BuiltinType::UShortAccum: OS << "uhk"; break; + case BuiltinType::Fract: OS << "r"; break; + case BuiltinType::Accum: OS << "k"; break; + case BuiltinType::UFract: OS << "ur"; break; + case BuiltinType::UAccum: OS << "uk"; break; + case BuiltinType::LongFract: OS << "lr"; break; + case BuiltinType::LongAccum: OS << "lk"; break; + case BuiltinType::ULongFract: OS << "ulr"; break; + case BuiltinType::ULongAccum: OS << "ulk"; break; + } +} + static void PrintFloatingLiteral(raw_ostream &OS, FloatingLiteral *Node, bool PrintSuffix) { SmallString<16> Str; @@ -1535,11 +1588,13 @@ void StmtPrinter::VisitImaginaryLiteral(ImaginaryLiteral *Node) { void StmtPrinter::VisitStringLiteral(StringLiteral *Str) { Str->outputString(OS); } + void StmtPrinter::VisitParenExpr(ParenExpr *Node) { OS << "("; PrintExpr(Node->getSubExpr()); OS << ")"; } + void StmtPrinter::VisitUnaryOperator(UnaryOperator *Node) { if (!Node->isPostfix()) { OS << UnaryOperator::getOpcodeStr(Node->getOpcode()); @@ -1695,7 +1750,7 @@ void StmtPrinter::VisitMemberExpr(MemberExpr *Node) { if (!Policy.SuppressImplicitBase || !isImplicitThis(Node->getBase())) { PrintExpr(Node->getBase()); - MemberExpr *ParentMember = dyn_cast<MemberExpr>(Node->getBase()); + auto *ParentMember = dyn_cast<MemberExpr>(Node->getBase()); FieldDecl *ParentDecl = ParentMember ? dyn_cast<FieldDecl>(ParentMember->getMemberDecl()) : nullptr; @@ -1704,7 +1759,7 @@ void StmtPrinter::VisitMemberExpr(MemberExpr *Node) { OS << (Node->isArrow() ? "->" : "."); } - if (FieldDecl *FD = dyn_cast<FieldDecl>(Node->getMemberDecl())) + if (auto *FD = dyn_cast<FieldDecl>(Node->getMemberDecl())) if (FD->isAnonymousStructOrUnion()) return; @@ -1716,6 +1771,7 @@ void StmtPrinter::VisitMemberExpr(MemberExpr *Node) { if (Node->hasExplicitTemplateArgs()) printTemplateArgumentList(OS, Node->template_arguments(), Policy); } + void StmtPrinter::VisitObjCIsaExpr(ObjCIsaExpr *Node) { PrintExpr(Node->getBase()); OS << (Node->isArrow() ? "->isa" : ".isa"); @@ -1726,32 +1782,38 @@ void StmtPrinter::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) { OS << "."; OS << Node->getAccessor().getName(); } + void StmtPrinter::VisitCStyleCastExpr(CStyleCastExpr *Node) { OS << '('; Node->getTypeAsWritten().print(OS, Policy); OS << ')'; PrintExpr(Node->getSubExpr()); } + void StmtPrinter::VisitCompoundLiteralExpr(CompoundLiteralExpr *Node) { OS << '('; Node->getType().print(OS, Policy); OS << ')'; PrintExpr(Node->getInitializer()); } + void StmtPrinter::VisitImplicitCastExpr(ImplicitCastExpr *Node) { // No need to print anything, simply forward to the subexpression. PrintExpr(Node->getSubExpr()); } + void StmtPrinter::VisitBinaryOperator(BinaryOperator *Node) { PrintExpr(Node->getLHS()); OS << " " << BinaryOperator::getOpcodeStr(Node->getOpcode()) << " "; PrintExpr(Node->getRHS()); } + void StmtPrinter::VisitCompoundAssignOperator(CompoundAssignOperator *Node) { PrintExpr(Node->getLHS()); OS << " " << BinaryOperator::getOpcodeStr(Node->getOpcode()) << " "; PrintExpr(Node->getRHS()); } + void StmtPrinter::VisitConditionalOperator(ConditionalOperator *Node) { PrintExpr(Node->getCond()); OS << " ? "; @@ -1768,6 +1830,7 @@ StmtPrinter::VisitBinaryConditionalOperator(BinaryConditionalOperator *Node) { OS << " ?: "; PrintExpr(Node->getFalseExpr()); } + void StmtPrinter::VisitAddrLabelExpr(AddrLabelExpr *Node) { OS << "&&" << Node->getLabel()->getName(); } @@ -2100,7 +2163,7 @@ void StmtPrinter::VisitUserDefinedLiteral(UserDefinedLiteral *Node) { OS << cast<StringLiteral>(Node->getArg(0)->IgnoreImpCasts())->getString(); break; case UserDefinedLiteral::LOK_Template: { - DeclRefExpr *DRE = cast<DeclRefExpr>(Node->getCallee()->IgnoreImpCasts()); + const auto *DRE = cast<DeclRefExpr>(Node->getCallee()->IgnoreImpCasts()); const TemplateArgumentList *Args = cast<FunctionDecl>(DRE->getDecl())->getTemplateSpecializationArgs(); assert(Args); @@ -2121,13 +2184,13 @@ void StmtPrinter::VisitUserDefinedLiteral(UserDefinedLiteral *Node) { } case UserDefinedLiteral::LOK_Integer: { // Print integer literal without suffix. - IntegerLiteral *Int = cast<IntegerLiteral>(Node->getCookedLiteral()); + const auto *Int = cast<IntegerLiteral>(Node->getCookedLiteral()); OS << Int->getValue().toString(10, /*isSigned*/false); break; } case UserDefinedLiteral::LOK_Floating: { // Print floating literal without suffix. - FloatingLiteral *Float = cast<FloatingLiteral>(Node->getCookedLiteral()); + auto *Float = cast<FloatingLiteral>(Node->getCookedLiteral()); PrintFloatingLiteral(OS, Float, /*PrintSuffix=*/false); break; } @@ -2240,9 +2303,11 @@ void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) { case LCK_This: OS << "this"; break; + case LCK_StarThis: OS << "*this"; break; + case LCK_ByRef: if (Node->getCaptureDefault() != LCD_ByRef || Node->isInitCapture(C)) OS << '&'; @@ -2252,6 +2317,7 @@ void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) { case LCK_ByCopy: OS << C->getCapturedVar()->getName(); break; + case LCK_VLAType: llvm_unreachable("VLA type in explicit captures."); } @@ -2265,7 +2331,7 @@ void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) { OS << " ("; CXXMethodDecl *Method = Node->getCallOperator(); NeedComma = false; - for (auto P : Method->parameters()) { + for (const auto *P : Method->parameters()) { if (NeedComma) { OS << ", "; } else { @@ -2284,8 +2350,7 @@ void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) { if (Node->isMutable()) OS << " mutable"; - const FunctionProtoType *Proto - = Method->getType()->getAs<FunctionProtoType>(); + auto *Proto = Method->getType()->getAs<FunctionProtoType>(); Proto->printExceptionSpecification(OS, Policy); // FIXME: Attributes @@ -2569,13 +2634,11 @@ void StmtPrinter::VisitCoawaitExpr(CoawaitExpr *S) { PrintExpr(S->getOperand()); } - void StmtPrinter::VisitDependentCoawaitExpr(DependentCoawaitExpr *S) { OS << "co_await "; PrintExpr(S->getOperand()); } - void StmtPrinter::VisitCoyieldExpr(CoyieldExpr *S) { OS << "co_yield "; PrintExpr(S->getOperand()); @@ -2708,7 +2771,7 @@ void StmtPrinter::VisitBlockExpr(BlockExpr *Node) { (*AI)->getType().print(OS, Policy, ParamStr); } - const FunctionProtoType *FT = cast<FunctionProtoType>(AFT); + const auto *FT = cast<FunctionProtoType>(AFT); if (FT->isVariadic()) { if (!BD->param_empty()) OS << ", "; OS << "..."; @@ -2755,4 +2818,4 @@ void Stmt::printPretty(raw_ostream &OS, PrinterHelper *Helper, //===----------------------------------------------------------------------===// // Implement virtual destructor. -PrinterHelper::~PrinterHelper() {} +PrinterHelper::~PrinterHelper() = default; diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index 00ef0da18bbb..791ec569cc41 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -38,37 +38,39 @@ namespace { void VisitStmt(const Stmt *S); + virtual void HandleStmtClass(Stmt::StmtClass SC) = 0; + #define STMT(Node, Base) void Visit##Node(const Node *S); #include "clang/AST/StmtNodes.inc" - /// \brief Visit a declaration that is referenced within an expression + /// Visit a declaration that is referenced within an expression /// or statement. virtual void VisitDecl(const Decl *D) = 0; - /// \brief Visit a type that is referenced within an expression or + /// Visit a type that is referenced within an expression or /// statement. virtual void VisitType(QualType T) = 0; - /// \brief Visit a name that occurs within an expression or statement. - virtual void VisitName(DeclarationName Name) = 0; + /// Visit a name that occurs within an expression or statement. + virtual void VisitName(DeclarationName Name, bool TreatAsDecl = false) = 0; - /// \brief Visit identifiers that are not in Decl's or Type's. + /// Visit identifiers that are not in Decl's or Type's. virtual void VisitIdentifierInfo(IdentifierInfo *II) = 0; - /// \brief Visit a nested-name-specifier that occurs within an expression + /// Visit a nested-name-specifier that occurs within an expression /// or statement. virtual void VisitNestedNameSpecifier(NestedNameSpecifier *NNS) = 0; - /// \brief Visit a template name that occurs within an expression or + /// Visit a template name that occurs within an expression or /// statement. virtual void VisitTemplateName(TemplateName Name) = 0; - /// \brief Visit template arguments that occur within an expression or + /// Visit template arguments that occur within an expression or /// statement. void VisitTemplateArguments(const TemplateArgumentLoc *Args, unsigned NumArgs); - /// \brief Visit a single template argument. + /// Visit a single template argument. void VisitTemplateArgument(const TemplateArgument &Arg); }; @@ -80,6 +82,10 @@ namespace { const ASTContext &Context, bool Canonical) : StmtProfiler(ID, Canonical), Context(Context) {} private: + void HandleStmtClass(Stmt::StmtClass SC) override { + ID.AddInteger(SC); + } + void VisitDecl(const Decl *D) override { ID.AddInteger(D ? D->getKind() : 0); @@ -134,7 +140,7 @@ namespace { ID.AddPointer(T.getAsOpaquePtr()); } - void VisitName(DeclarationName Name) override { + void VisitName(DeclarationName Name, bool /*TreatAsDecl*/) override { ID.AddPointer(Name.getAsOpaquePtr()); } @@ -163,11 +169,26 @@ namespace { : StmtProfiler(ID, false), Hash(Hash) {} private: + void HandleStmtClass(Stmt::StmtClass SC) override { + if (SC == Stmt::UnresolvedLookupExprClass) { + // Pretend that the name looked up is a Decl due to how templates + // handle some Decl lookups. + ID.AddInteger(Stmt::DeclRefExprClass); + } else { + ID.AddInteger(SC); + } + } + void VisitType(QualType T) override { Hash.AddQualType(T); } - void VisitName(DeclarationName Name) override { + void VisitName(DeclarationName Name, bool TreatAsDecl) override { + if (TreatAsDecl) { + // A Decl can be null, so each Decl is preceded by a boolean to + // store its nullness. Add a boolean here to match. + ID.AddBoolean(true); + } Hash.AddDeclarationName(Name); } void VisitIdentifierInfo(IdentifierInfo *II) override { @@ -196,7 +217,9 @@ namespace { void StmtProfiler::VisitStmt(const Stmt *S) { assert(S && "Requires non-null Stmt pointer"); - ID.AddInteger(S->getStmtClass()); + + HandleStmtClass(S->getStmtClass()); + for (const Stmt *SubStmt : S->children()) { if (SubStmt) Visit(SubStmt); @@ -382,7 +405,7 @@ StmtProfiler::VisitObjCAutoreleasePoolStmt(const ObjCAutoreleasePoolStmt *S) { namespace { class OMPClauseProfiler : public ConstOMPClauseVisitor<OMPClauseProfiler> { StmtProfiler *Profiler; - /// \brief Process clauses with list of variables. + /// Process clauses with list of variables. template <typename T> void VisitOMPClauseList(T *Node); @@ -966,8 +989,11 @@ void StmtProfiler::VisitDeclRefExpr(const DeclRefExpr *S) { if (!Canonical) VisitNestedNameSpecifier(S->getQualifier()); VisitDecl(S->getDecl()); - if (!Canonical) - VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs()); + if (!Canonical) { + ID.AddBoolean(S->hasExplicitTemplateArgs()); + if (S->hasExplicitTemplateArgs()) + VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs()); + } } void StmtProfiler::VisitPredefinedExpr(const PredefinedExpr *S) { @@ -981,6 +1007,12 @@ void StmtProfiler::VisitIntegerLiteral(const IntegerLiteral *S) { ID.AddInteger(S->getType()->castAs<BuiltinType>()->getKind()); } +void StmtProfiler::VisitFixedPointLiteral(const FixedPointLiteral *S) { + VisitExpr(S); + S->getValue().Profile(ID); + ID.AddInteger(S->getType()->castAs<BuiltinType>()->getKind()); +} + void StmtProfiler::VisitCharacterLiteral(const CharacterLiteral *S) { VisitExpr(S); ID.AddInteger(S->getKind()); @@ -1659,7 +1691,7 @@ StmtProfiler::VisitCXXPseudoDestructorExpr(const CXXPseudoDestructorExpr *S) { void StmtProfiler::VisitOverloadExpr(const OverloadExpr *S) { VisitExpr(S); VisitNestedNameSpecifier(S->getQualifier()); - VisitName(S->getName()); + VisitName(S->getName(), /*TreatAsDecl*/ true); ID.AddBoolean(S->hasExplicitTemplateArgs()); if (S->hasExplicitTemplateArgs()) VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs()); diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp index e81c11a77825..394e9f38bcfd 100644 --- a/lib/AST/TemplateBase.cpp +++ b/lib/AST/TemplateBase.cpp @@ -43,7 +43,7 @@ using namespace clang; -/// \brief Print a template integral argument value. +/// Print a template integral argument value. /// /// \param TemplArg the TemplateArgument instance to print. /// @@ -406,7 +406,7 @@ void TemplateArgument::print(const PrintingPolicy &Policy, } case Declaration: { - NamedDecl *ND = cast<NamedDecl>(getAsDecl()); + NamedDecl *ND = getAsDecl(); Out << '&'; if (ND->getDeclName()) { // FIXME: distinguish between pointer and reference args? diff --git a/lib/AST/TemplateName.cpp b/lib/AST/TemplateName.cpp index bd04fd8366b3..548468ed17cd 100644 --- a/lib/AST/TemplateName.cpp +++ b/lib/AST/TemplateName.cpp @@ -185,6 +185,11 @@ bool TemplateName::isInstantiationDependent() const { } bool TemplateName::containsUnexpandedParameterPack() const { + if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) { + if (QTN->getQualifier()->containsUnexpandedParameterPack()) + return true; + } + if (TemplateDecl *Template = getAsTemplateDecl()) { if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(Template)) diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 38f2a16fa16f..fad8c0d1c6b2 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -29,6 +29,7 @@ #include "clang/AST/TypeVisitor.h" #include "clang/Basic/AddressSpaces.h" #include "clang/Basic/ExceptionSpecificationType.h" +#include "clang/Basic/IdentifierTable.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/Linkage.h" @@ -87,6 +88,16 @@ const IdentifierInfo* QualType::getBaseTypeIdentifier() const { return nullptr; } +bool QualType::mayBeDynamicClass() const { + const auto *ClassDecl = getTypePtr()->getPointeeCXXRecordDecl(); + return ClassDecl && ClassDecl->mayBeDynamicClass(); +} + +bool QualType::mayBeNotDynamicClass() const { + const auto *ClassDecl = getTypePtr()->getPointeeCXXRecordDecl(); + return !ClassDecl || ClassDecl->mayBeNonDynamicClass(); +} + bool QualType::isConstant(QualType T, const ASTContext &Ctx) { if (T.isConstQualified()) return true; @@ -166,6 +177,27 @@ void DependentSizedArrayType::Profile(llvm::FoldingSetNodeID &ID, E->Profile(ID, Context, true); } +DependentVectorType::DependentVectorType( + const ASTContext &Context, QualType ElementType, QualType CanonType, + Expr *SizeExpr, SourceLocation Loc, VectorType::VectorKind VecKind) + : Type(DependentVector, CanonType, /*Dependent=*/true, + /*InstantiationDependent=*/true, + ElementType->isVariablyModifiedType(), + ElementType->containsUnexpandedParameterPack() || + (SizeExpr && SizeExpr->containsUnexpandedParameterPack())), + Context(Context), ElementType(ElementType), SizeExpr(SizeExpr), Loc(Loc) { + VectorTypeBits.VecKind = VecKind; +} + +void DependentVectorType::Profile(llvm::FoldingSetNodeID &ID, + const ASTContext &Context, + QualType ElementType, const Expr *SizeExpr, + VectorType::VectorKind VecKind) { + ID.AddPointer(ElementType.getAsOpaquePtr()); + ID.AddInteger(VecKind); + SizeExpr->Profile(ID, Context, true); +} + DependentSizedExtVectorType::DependentSizedExtVectorType(const ASTContext &Context, QualType ElementType, @@ -228,7 +260,7 @@ VectorType::VectorType(TypeClass tc, QualType vecType, unsigned nElements, /// This method should never be used when type qualifiers are meaningful. const Type *Type::getArrayElementTypeNoTypeQual() const { // If this is directly an array type, return it. - if (const ArrayType *ATy = dyn_cast<ArrayType>(this)) + if (const auto *ATy = dyn_cast<ArrayType>(this)) return ATy->getElementType().getTypePtr(); // If the canonical form of this type isn't the right kind, reject it. @@ -264,7 +296,7 @@ QualType Type::getLocallyUnqualifiedSingleStepDesugaredType() const { #define ABSTRACT_TYPE(Class, Parent) #define TYPE(Class, Parent) \ case Type::Class: { \ - const Class##Type *ty = cast<Class##Type>(this); \ + const auto *ty = cast<Class##Type>(this); \ if (!ty->isSugared()) return QualType(ty, 0); \ return ty->desugar(); \ } @@ -283,7 +315,7 @@ SplitQualType QualType::getSplitDesugaredType(QualType T) { #define ABSTRACT_TYPE(Class, Parent) #define TYPE(Class, Parent) \ case Type::Class: { \ - const Class##Type *Ty = cast<Class##Type>(CurTy); \ + const auto *Ty = cast<Class##Type>(CurTy); \ if (!Ty->isSugared()) \ return SplitQualType(Ty, Qs); \ Cur = Ty->desugar(); \ @@ -312,7 +344,7 @@ SplitQualType QualType::getSplitUnqualifiedTypeImpl(QualType type) { #define ABSTRACT_TYPE(Class, Parent) #define TYPE(Class, Parent) \ case Type::Class: { \ - const Class##Type *ty = cast<Class##Type>(split.Ty); \ + const auto *ty = cast<Class##Type>(split.Ty); \ if (!ty->isSugared()) goto done; \ next = ty->desugar(); \ break; \ @@ -335,23 +367,23 @@ SplitQualType QualType::getSplitUnqualifiedTypeImpl(QualType type) { QualType QualType::IgnoreParens(QualType T) { // FIXME: this seems inherently un-qualifiers-safe. - while (const ParenType *PT = T->getAs<ParenType>()) + while (const auto *PT = T->getAs<ParenType>()) T = PT->getInnerType(); return T; } -/// \brief This will check for a T (which should be a Type which can act as +/// This will check for a T (which should be a Type which can act as /// sugar, such as a TypedefType) by removing any existing sugar until it /// reaches a T or a non-sugared type. template<typename T> static const T *getAsSugar(const Type *Cur) { while (true) { - if (const T *Sugar = dyn_cast<T>(Cur)) + if (const auto *Sugar = dyn_cast<T>(Cur)) return Sugar; switch (Cur->getTypeClass()) { #define ABSTRACT_TYPE(Class, Parent) #define TYPE(Class, Parent) \ case Type::Class: { \ - const Class##Type *Ty = cast<Class##Type>(Cur); \ + const auto *Ty = cast<Class##Type>(Cur); \ if (!Ty->isSugared()) return 0; \ Cur = Ty->desugar().getTypePtr(); \ break; \ @@ -384,7 +416,7 @@ const Type *Type::getUnqualifiedDesugaredType() const { #define ABSTRACT_TYPE(Class, Parent) #define TYPE(Class, Parent) \ case Class: { \ - const Class##Type *Ty = cast<Class##Type>(Cur); \ + const auto *Ty = cast<Class##Type>(Cur); \ if (!Ty->isSugared()) return Cur; \ Cur = Ty->desugar().getTypePtr(); \ break; \ @@ -395,28 +427,31 @@ const Type *Type::getUnqualifiedDesugaredType() const { } bool Type::isClassType() const { - if (const RecordType *RT = getAs<RecordType>()) + if (const auto *RT = getAs<RecordType>()) return RT->getDecl()->isClass(); return false; } bool Type::isStructureType() const { - if (const RecordType *RT = getAs<RecordType>()) + if (const auto *RT = getAs<RecordType>()) return RT->getDecl()->isStruct(); return false; } + bool Type::isObjCBoxableRecordType() const { - if (const RecordType *RT = getAs<RecordType>()) + if (const auto *RT = getAs<RecordType>()) return RT->getDecl()->hasAttr<ObjCBoxableAttr>(); return false; } + bool Type::isInterfaceType() const { - if (const RecordType *RT = getAs<RecordType>()) + if (const auto *RT = getAs<RecordType>()) return RT->getDecl()->isInterface(); return false; } + bool Type::isStructureOrClassType() const { - if (const RecordType *RT = getAs<RecordType>()) { + if (const auto *RT = getAs<RecordType>()) { RecordDecl *RD = RT->getDecl(); return RD->isStruct() || RD->isClass() || RD->isInterface(); } @@ -424,19 +459,19 @@ bool Type::isStructureOrClassType() const { } bool Type::isVoidPointerType() const { - if (const PointerType *PT = getAs<PointerType>()) + if (const auto *PT = getAs<PointerType>()) return PT->getPointeeType()->isVoidType(); return false; } bool Type::isUnionType() const { - if (const RecordType *RT = getAs<RecordType>()) + if (const auto *RT = getAs<RecordType>()) return RT->getDecl()->isUnion(); return false; } bool Type::isComplexType() const { - if (const ComplexType *CT = dyn_cast<ComplexType>(CanonicalType)) + if (const auto *CT = dyn_cast<ComplexType>(CanonicalType)) return CT->getElementType()->isFloatingType(); return false; } @@ -446,38 +481,44 @@ bool Type::isComplexIntegerType() const { return getAsComplexIntegerType(); } +bool Type::isScopedEnumeralType() const { + if (const auto *ET = getAs<EnumType>()) + return ET->getDecl()->isScoped(); + return false; +} + const ComplexType *Type::getAsComplexIntegerType() const { - if (const ComplexType *Complex = getAs<ComplexType>()) + if (const auto *Complex = getAs<ComplexType>()) if (Complex->getElementType()->isIntegerType()) return Complex; return nullptr; } QualType Type::getPointeeType() const { - if (const PointerType *PT = getAs<PointerType>()) + if (const auto *PT = getAs<PointerType>()) return PT->getPointeeType(); - if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>()) + if (const auto *OPT = getAs<ObjCObjectPointerType>()) return OPT->getPointeeType(); - if (const BlockPointerType *BPT = getAs<BlockPointerType>()) + if (const auto *BPT = getAs<BlockPointerType>()) return BPT->getPointeeType(); - if (const ReferenceType *RT = getAs<ReferenceType>()) + if (const auto *RT = getAs<ReferenceType>()) return RT->getPointeeType(); - if (const MemberPointerType *MPT = getAs<MemberPointerType>()) + if (const auto *MPT = getAs<MemberPointerType>()) return MPT->getPointeeType(); - if (const DecayedType *DT = getAs<DecayedType>()) + if (const auto *DT = getAs<DecayedType>()) return DT->getPointeeType(); - return QualType(); + return {}; } const RecordType *Type::getAsStructureType() const { // If this is directly a structure type, return it. - if (const RecordType *RT = dyn_cast<RecordType>(this)) { + if (const auto *RT = dyn_cast<RecordType>(this)) { if (RT->getDecl()->isStruct()) return RT; } // If the canonical form of this type isn't the right kind, reject it. - if (const RecordType *RT = dyn_cast<RecordType>(CanonicalType)) { + if (const auto *RT = dyn_cast<RecordType>(CanonicalType)) { if (!RT->getDecl()->isStruct()) return nullptr; @@ -490,13 +531,13 @@ const RecordType *Type::getAsStructureType() const { const RecordType *Type::getAsUnionType() const { // If this is directly a union type, return it. - if (const RecordType *RT = dyn_cast<RecordType>(this)) { + if (const auto *RT = dyn_cast<RecordType>(this)) { if (RT->getDecl()->isUnion()) return RT; } // If the canonical form of this type isn't the right kind, reject it. - if (const RecordType *RT = dyn_cast<RecordType>(CanonicalType)) { + if (const auto *RT = dyn_cast<RecordType>(CanonicalType)) { if (!RT->getDecl()->isUnion()) return nullptr; @@ -512,7 +553,7 @@ bool Type::isObjCIdOrObjectKindOfType(const ASTContext &ctx, const ObjCObjectType *&bound) const { bound = nullptr; - const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>(); + const auto *OPT = getAs<ObjCObjectPointerType>(); if (!OPT) return false; @@ -535,7 +576,7 @@ bool Type::isObjCIdOrObjectKindOfType(const ASTContext &ctx, } bool Type::isObjCClassOrClassKindOfType() const { - const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>(); + const auto *OPT = getAs<ObjCObjectPointerType>(); if (!OPT) return false; @@ -560,7 +601,7 @@ bool Type::isObjCClassOrClassKindOfType() const { bool Type::isObjCInertUnsafeUnretainedType() const { const Type *cur = this; while (true) { - if (auto attributed = dyn_cast<AttributedType>(cur)) { + if (const auto attributed = dyn_cast<AttributedType>(cur)) { if (attributed->getAttrKind() == AttributedType::attr_objc_inert_unsafe_unretained) return true; @@ -622,7 +663,7 @@ bool ObjCObjectType::isSpecialized() const { return true; // Otherwise, check whether the base type is specialized. - if (auto objcObject = getBaseType()->getAs<ObjCObjectType>()) { + if (const auto objcObject = getBaseType()->getAs<ObjCObjectType>()) { // Terminate when we reach an interface type. if (isa<ObjCInterfaceType>(objcObject)) return false; @@ -640,7 +681,7 @@ ArrayRef<QualType> ObjCObjectType::getTypeArgs() const { return getTypeArgsAsWritten(); // Look at the base type, which might have type arguments. - if (auto objcObject = getBaseType()->getAs<ObjCObjectType>()) { + if (const auto objcObject = getBaseType()->getAs<ObjCObjectType>()) { // Terminate when we reach an interface type. if (isa<ObjCInterfaceType>(objcObject)) return {}; @@ -657,7 +698,7 @@ bool ObjCObjectType::isKindOfType() const { return true; // Look at the base type, which might have type arguments. - if (auto objcObject = getBaseType()->getAs<ObjCObjectType>()) { + if (const auto objcObject = getBaseType()->getAs<ObjCObjectType>()) { // Terminate when we reach an interface type. if (isa<ObjCInterfaceType>(objcObject)) return false; @@ -677,10 +718,8 @@ QualType ObjCObjectType::stripObjCKindOfTypeAndQuals( // Recursively strip __kindof. SplitQualType splitBaseType = getBaseType().split(); QualType baseType(splitBaseType.Ty, 0); - if (const ObjCObjectType *baseObj - = splitBaseType.Ty->getAs<ObjCObjectType>()) { + if (const auto *baseObj = splitBaseType.Ty->getAs<ObjCObjectType>()) baseType = baseObj->stripObjCKindOfTypeAndQuals(ctx); - } return ctx.getObjCObjectType(ctx.getQualifiedType(baseType, splitBaseType.Quals), @@ -733,7 +772,7 @@ public: QualType VisitComplexType(const ComplexType *T) { QualType elementType = recurse(T->getElementType()); if (elementType.isNull()) - return QualType(); + return {}; if (elementType.getAsOpaquePtr() == T->getElementType().getAsOpaquePtr()) return QualType(T, 0); @@ -744,7 +783,7 @@ public: QualType VisitPointerType(const PointerType *T) { QualType pointeeType = recurse(T->getPointeeType()); if (pointeeType.isNull()) - return QualType(); + return {}; if (pointeeType.getAsOpaquePtr() == T->getPointeeType().getAsOpaquePtr()) return QualType(T, 0); @@ -755,7 +794,7 @@ public: QualType VisitBlockPointerType(const BlockPointerType *T) { QualType pointeeType = recurse(T->getPointeeType()); if (pointeeType.isNull()) - return QualType(); + return {}; if (pointeeType.getAsOpaquePtr() == T->getPointeeType().getAsOpaquePtr()) return QualType(T, 0); @@ -766,7 +805,7 @@ public: QualType VisitLValueReferenceType(const LValueReferenceType *T) { QualType pointeeType = recurse(T->getPointeeTypeAsWritten()); if (pointeeType.isNull()) - return QualType(); + return {}; if (pointeeType.getAsOpaquePtr() == T->getPointeeTypeAsWritten().getAsOpaquePtr()) @@ -778,7 +817,7 @@ public: QualType VisitRValueReferenceType(const RValueReferenceType *T) { QualType pointeeType = recurse(T->getPointeeTypeAsWritten()); if (pointeeType.isNull()) - return QualType(); + return {}; if (pointeeType.getAsOpaquePtr() == T->getPointeeTypeAsWritten().getAsOpaquePtr()) @@ -790,7 +829,7 @@ public: QualType VisitMemberPointerType(const MemberPointerType *T) { QualType pointeeType = recurse(T->getPointeeType()); if (pointeeType.isNull()) - return QualType(); + return {}; if (pointeeType.getAsOpaquePtr() == T->getPointeeType().getAsOpaquePtr()) return QualType(T, 0); @@ -801,7 +840,7 @@ public: QualType VisitConstantArrayType(const ConstantArrayType *T) { QualType elementType = recurse(T->getElementType()); if (elementType.isNull()) - return QualType(); + return {}; if (elementType.getAsOpaquePtr() == T->getElementType().getAsOpaquePtr()) return QualType(T, 0); @@ -814,7 +853,7 @@ public: QualType VisitVariableArrayType(const VariableArrayType *T) { QualType elementType = recurse(T->getElementType()); if (elementType.isNull()) - return QualType(); + return {}; if (elementType.getAsOpaquePtr() == T->getElementType().getAsOpaquePtr()) return QualType(T, 0); @@ -828,7 +867,7 @@ public: QualType VisitIncompleteArrayType(const IncompleteArrayType *T) { QualType elementType = recurse(T->getElementType()); if (elementType.isNull()) - return QualType(); + return {}; if (elementType.getAsOpaquePtr() == T->getElementType().getAsOpaquePtr()) return QualType(T, 0); @@ -840,7 +879,7 @@ public: QualType VisitVectorType(const VectorType *T) { QualType elementType = recurse(T->getElementType()); if (elementType.isNull()) - return QualType(); + return {}; if (elementType.getAsOpaquePtr() == T->getElementType().getAsOpaquePtr()) return QualType(T, 0); @@ -852,7 +891,7 @@ public: QualType VisitExtVectorType(const ExtVectorType *T) { QualType elementType = recurse(T->getElementType()); if (elementType.isNull()) - return QualType(); + return {}; if (elementType.getAsOpaquePtr() == T->getElementType().getAsOpaquePtr()) return QualType(T, 0); @@ -863,7 +902,7 @@ public: QualType VisitFunctionNoProtoType(const FunctionNoProtoType *T) { QualType returnType = recurse(T->getReturnType()); if (returnType.isNull()) - return QualType(); + return {}; if (returnType.getAsOpaquePtr() == T->getReturnType().getAsOpaquePtr()) return QualType(T, 0); @@ -874,7 +913,7 @@ public: QualType VisitFunctionProtoType(const FunctionProtoType *T) { QualType returnType = recurse(T->getReturnType()); if (returnType.isNull()) - return QualType(); + return {}; // Transform parameter types. SmallVector<QualType, 4> paramTypes; @@ -882,7 +921,7 @@ public: for (auto paramType : T->getParamTypes()) { QualType newParamType = recurse(paramType); if (newParamType.isNull()) - return QualType(); + return {}; if (newParamType.getAsOpaquePtr() != paramType.getAsOpaquePtr()) paramChanged = true; @@ -898,10 +937,9 @@ public: for (auto exceptionType : info.ExceptionSpec.Exceptions) { QualType newExceptionType = recurse(exceptionType); if (newExceptionType.isNull()) - return QualType(); + return {}; - if (newExceptionType.getAsOpaquePtr() - != exceptionType.getAsOpaquePtr()) + if (newExceptionType.getAsOpaquePtr() != exceptionType.getAsOpaquePtr()) exceptionChanged = true; exceptionTypes.push_back(newExceptionType); @@ -923,7 +961,7 @@ public: QualType VisitParenType(const ParenType *T) { QualType innerType = recurse(T->getInnerType()); if (innerType.isNull()) - return QualType(); + return {}; if (innerType.getAsOpaquePtr() == T->getInnerType().getAsOpaquePtr()) return QualType(T, 0); @@ -937,11 +975,11 @@ public: QualType VisitAdjustedType(const AdjustedType *T) { QualType originalType = recurse(T->getOriginalType()); if (originalType.isNull()) - return QualType(); + return {}; QualType adjustedType = recurse(T->getAdjustedType()); if (adjustedType.isNull()) - return QualType(); + return {}; if (originalType.getAsOpaquePtr() == T->getOriginalType().getAsOpaquePtr() && @@ -954,7 +992,7 @@ public: QualType VisitDecayedType(const DecayedType *T) { QualType originalType = recurse(T->getOriginalType()); if (originalType.isNull()) - return QualType(); + return {}; if (originalType.getAsOpaquePtr() == T->getOriginalType().getAsOpaquePtr()) @@ -976,11 +1014,11 @@ public: QualType VisitAttributedType(const AttributedType *T) { QualType modifiedType = recurse(T->getModifiedType()); if (modifiedType.isNull()) - return QualType(); + return {}; QualType equivalentType = recurse(T->getEquivalentType()); if (equivalentType.isNull()) - return QualType(); + return {}; if (modifiedType.getAsOpaquePtr() == T->getModifiedType().getAsOpaquePtr() && @@ -995,7 +1033,7 @@ public: QualType VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T) { QualType replacementType = recurse(T->getReplacementType()); if (replacementType.isNull()) - return QualType(); + return {}; if (replacementType.getAsOpaquePtr() == T->getReplacementType().getAsOpaquePtr()) @@ -1014,7 +1052,7 @@ public: QualType deducedType = recurse(T->getDeducedType()); if (deducedType.isNull()) - return QualType(); + return {}; if (deducedType.getAsOpaquePtr() == T->getDeducedType().getAsOpaquePtr()) @@ -1030,7 +1068,7 @@ public: QualType VisitObjCObjectType(const ObjCObjectType *T) { QualType baseType = recurse(T->getBaseType()); if (baseType.isNull()) - return QualType(); + return {}; // Transform type arguments. bool typeArgChanged = false; @@ -1038,7 +1076,7 @@ public: for (auto typeArg : T->getTypeArgsAsWritten()) { QualType newTypeArg = recurse(typeArg); if (newTypeArg.isNull()) - return QualType(); + return {}; if (newTypeArg.getAsOpaquePtr() != typeArg.getAsOpaquePtr()) typeArgChanged = true; @@ -1061,7 +1099,7 @@ public: QualType VisitObjCObjectPointerType(const ObjCObjectPointerType *T) { QualType pointeeType = recurse(T->getPointeeType()); if (pointeeType.isNull()) - return QualType(); + return {}; if (pointeeType.getAsOpaquePtr() == T->getPointeeType().getAsOpaquePtr()) @@ -1073,7 +1111,7 @@ public: QualType VisitAtomicType(const AtomicType *T) { QualType valueType = recurse(T->getValueType()); if (valueType.isNull()) - return QualType(); + return {}; if (valueType.getAsOpaquePtr() == T->getValueType().getAsOpaquePtr()) @@ -1123,57 +1161,56 @@ QualType QualType::substObjCTypeArgs( // Replace an Objective-C type parameter reference with the corresponding // type argument. if (const auto *OTPTy = dyn_cast<ObjCTypeParamType>(splitType.Ty)) { - if (auto *typeParam = dyn_cast<ObjCTypeParamDecl>(OTPTy->getDecl())) { - // If we have type arguments, use them. - if (!typeArgs.empty()) { - QualType argType = typeArgs[typeParam->getIndex()]; - if (OTPTy->qual_empty()) - return ctx.getQualifiedType(argType, splitType.Quals); - - // Apply protocol lists if exists. - bool hasError; - SmallVector<ObjCProtocolDecl*, 8> protocolsVec; - protocolsVec.append(OTPTy->qual_begin(), - OTPTy->qual_end()); - ArrayRef<ObjCProtocolDecl *> protocolsToApply = protocolsVec; - QualType resultTy = ctx.applyObjCProtocolQualifiers(argType, - protocolsToApply, hasError, true/*allowOnPointerType*/); - - return ctx.getQualifiedType(resultTy, splitType.Quals); - } + ObjCTypeParamDecl *typeParam = OTPTy->getDecl(); + // If we have type arguments, use them. + if (!typeArgs.empty()) { + QualType argType = typeArgs[typeParam->getIndex()]; + if (OTPTy->qual_empty()) + return ctx.getQualifiedType(argType, splitType.Quals); + + // Apply protocol lists if exists. + bool hasError; + SmallVector<ObjCProtocolDecl*, 8> protocolsVec; + protocolsVec.append(OTPTy->qual_begin(), + OTPTy->qual_end()); + ArrayRef<ObjCProtocolDecl *> protocolsToApply = protocolsVec; + QualType resultTy = ctx.applyObjCProtocolQualifiers(argType, + protocolsToApply, hasError, true/*allowOnPointerType*/); + + return ctx.getQualifiedType(resultTy, splitType.Quals); + } - switch (context) { - case ObjCSubstitutionContext::Ordinary: - case ObjCSubstitutionContext::Parameter: - case ObjCSubstitutionContext::Superclass: - // Substitute the bound. + switch (context) { + case ObjCSubstitutionContext::Ordinary: + case ObjCSubstitutionContext::Parameter: + case ObjCSubstitutionContext::Superclass: + // Substitute the bound. + return ctx.getQualifiedType(typeParam->getUnderlyingType(), + splitType.Quals); + + case ObjCSubstitutionContext::Result: + case ObjCSubstitutionContext::Property: { + // Substitute the __kindof form of the underlying type. + const auto *objPtr = typeParam->getUnderlyingType() + ->castAs<ObjCObjectPointerType>(); + + // __kindof types, id, and Class don't need an additional + // __kindof. + if (objPtr->isKindOfType() || objPtr->isObjCIdOrClassType()) return ctx.getQualifiedType(typeParam->getUnderlyingType(), splitType.Quals); - case ObjCSubstitutionContext::Result: - case ObjCSubstitutionContext::Property: { - // Substitute the __kindof form of the underlying type. - const auto *objPtr = typeParam->getUnderlyingType() - ->castAs<ObjCObjectPointerType>(); - - // __kindof types, id, and Class don't need an additional - // __kindof. - if (objPtr->isKindOfType() || objPtr->isObjCIdOrClassType()) - return ctx.getQualifiedType(typeParam->getUnderlyingType(), - splitType.Quals); - - // Add __kindof. - const auto *obj = objPtr->getObjectType(); - QualType resultTy = ctx.getObjCObjectType(obj->getBaseType(), - obj->getTypeArgsAsWritten(), - obj->getProtocols(), - /*isKindOf=*/true); - - // Rebuild object pointer type. - resultTy = ctx.getObjCObjectPointerType(resultTy); - return ctx.getQualifiedType(resultTy, splitType.Quals); - } - } + // Add __kindof. + const auto *obj = objPtr->getObjectType(); + QualType resultTy = ctx.getObjCObjectType(obj->getBaseType(), + obj->getTypeArgsAsWritten(), + obj->getProtocols(), + /*isKindOf=*/true); + + // Rebuild object pointer type. + resultTy = ctx.getObjCObjectPointerType(resultTy); + return ctx.getQualifiedType(resultTy, splitType.Quals); + } } } @@ -1185,7 +1222,7 @@ QualType QualType::substObjCTypeArgs( typeArgs, ObjCSubstitutionContext::Result); if (returnType.isNull()) - return QualType(); + return {}; // Handle non-prototyped functions, which only substitute into the result // type. @@ -1210,7 +1247,7 @@ QualType QualType::substObjCTypeArgs( typeArgs, ObjCSubstitutionContext::Parameter); if (newParamType.isNull()) - return QualType(); + return {}; if (newParamType.getAsOpaquePtr() != paramType.getAsOpaquePtr()) paramChanged = true; @@ -1229,7 +1266,7 @@ QualType QualType::substObjCTypeArgs( typeArgs, ObjCSubstitutionContext::Ordinary); if (newExceptionType.isNull()) - return QualType(); + return {}; if (newExceptionType.getAsOpaquePtr() != exceptionType.getAsOpaquePtr()) @@ -1263,7 +1300,7 @@ QualType QualType::substObjCTypeArgs( ctx, typeArgs, ObjCSubstitutionContext::Ordinary); if (newTypeArg.isNull()) - return QualType(); + return {}; if (newTypeArg.getAsOpaquePtr() != typeArg.getAsOpaquePtr()) { // If we're substituting based on an unspecialized context type, @@ -1336,7 +1373,7 @@ QualType QualType::stripObjCKindOfType(const ASTContext &constCtx) const { } QualType QualType::getAtomicUnqualifiedType() const { - if (auto AT = getTypePtr()->getAs<AtomicType>()) + if (const auto AT = getTypePtr()->getAs<AtomicType>()) return AT->getValueType().getUnqualifiedType(); return getUnqualifiedType(); } @@ -1344,12 +1381,12 @@ QualType QualType::getAtomicUnqualifiedType() const { Optional<ArrayRef<QualType>> Type::getObjCSubstitutions( const DeclContext *dc) const { // Look through method scopes. - if (auto method = dyn_cast<ObjCMethodDecl>(dc)) + if (const auto method = dyn_cast<ObjCMethodDecl>(dc)) dc = method->getDeclContext(); // Find the class or category in which the type we're substituting // was declared. - const ObjCInterfaceDecl *dcClassDecl = dyn_cast<ObjCInterfaceDecl>(dc); + const auto *dcClassDecl = dyn_cast<ObjCInterfaceDecl>(dc); const ObjCCategoryDecl *dcCategoryDecl = nullptr; ObjCTypeParamList *dcTypeParams = nullptr; if (dcClassDecl) { @@ -1526,7 +1563,7 @@ const ObjCObjectType *Type::getAsObjCQualifiedInterfaceType() const { // There is no sugar for ObjCObjectType's, just return the canonical // type pointer if it is the right class. There is no typedef information to // return and these cannot be Address-space qualified. - if (const ObjCObjectType *T = getAs<ObjCObjectType>()) + if (const auto *T = getAs<ObjCObjectType>()) if (T->getNumProtocols() && T->getInterface()) return T; return nullptr; @@ -1539,7 +1576,7 @@ bool Type::isObjCQualifiedInterfaceType() const { const ObjCObjectPointerType *Type::getAsObjCQualifiedIdType() const { // There is no sugar for ObjCQualifiedIdType's, just return the canonical // type pointer if it is the right class. - if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>()) { + if (const auto *OPT = getAs<ObjCObjectPointerType>()) { if (OPT->isObjCQualifiedIdType()) return OPT; } @@ -1549,7 +1586,7 @@ const ObjCObjectPointerType *Type::getAsObjCQualifiedIdType() const { const ObjCObjectPointerType *Type::getAsObjCQualifiedClassType() const { // There is no sugar for ObjCQualifiedClassType's, just return the canonical // type pointer if it is the right class. - if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>()) { + if (const auto *OPT = getAs<ObjCObjectPointerType>()) { if (OPT->isObjCQualifiedClassType()) return OPT; } @@ -1557,7 +1594,7 @@ const ObjCObjectPointerType *Type::getAsObjCQualifiedClassType() const { } const ObjCObjectType *Type::getAsObjCInterfaceType() const { - if (const ObjCObjectType *OT = getAs<ObjCObjectType>()) { + if (const auto *OT = getAs<ObjCObjectType>()) { if (OT->getInterface()) return OT; } @@ -1565,7 +1602,7 @@ const ObjCObjectType *Type::getAsObjCInterfaceType() const { } const ObjCObjectPointerType *Type::getAsObjCInterfacePointerType() const { - if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>()) { + if (const auto *OPT = getAs<ObjCObjectPointerType>()) { if (OPT->getInterfaceType()) return OPT; } @@ -1574,14 +1611,14 @@ const ObjCObjectPointerType *Type::getAsObjCInterfacePointerType() const { const CXXRecordDecl *Type::getPointeeCXXRecordDecl() const { QualType PointeeType; - if (const PointerType *PT = getAs<PointerType>()) + if (const auto *PT = getAs<PointerType>()) PointeeType = PT->getPointeeType(); - else if (const ReferenceType *RT = getAs<ReferenceType>()) + else if (const auto *RT = getAs<ReferenceType>()) PointeeType = RT->getPointeeType(); else return nullptr; - if (const RecordType *RT = PointeeType->getAs<RecordType>()) + if (const auto *RT = PointeeType->getAs<RecordType>()) return dyn_cast<CXXRecordDecl>(RT->getDecl()); return nullptr; @@ -1593,7 +1630,7 @@ CXXRecordDecl *Type::getAsCXXRecordDecl() const { TagDecl *Type::getAsTagDecl() const { if (const auto *TT = getAs<TagType>()) - return cast<TagDecl>(TT->getDecl()); + return TT->getDecl(); if (const auto *Injected = getAs<InjectedClassNameType>()) return Injected->getDecl(); @@ -1694,13 +1731,13 @@ bool Type::hasAutoForTrailingReturnType() const { } bool Type::hasIntegerRepresentation() const { - if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType)) + if (const auto *VT = dyn_cast<VectorType>(CanonicalType)) return VT->getElementType()->isIntegerType(); else return isIntegerType(); } -/// \brief Determine whether this type is an integral type. +/// Determine whether this type is an integral type. /// /// This routine determines whether the given type is an integral type per /// C++ [basic.fundamental]p7. Although the C standard does not define the @@ -1720,20 +1757,20 @@ bool Type::hasIntegerRepresentation() const { /// /// \returns true if the type is considered an integral type, false otherwise. bool Type::isIntegralType(const ASTContext &Ctx) const { - if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType)) return BT->getKind() >= BuiltinType::Bool && BT->getKind() <= BuiltinType::Int128; // Complete enum types are integral in C. if (!Ctx.getLangOpts().CPlusPlus) - if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) + if (const auto *ET = dyn_cast<EnumType>(CanonicalType)) return ET->getDecl()->isComplete(); return false; } bool Type::isIntegralOrUnscopedEnumerationType() const { - if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType)) return BT->getKind() >= BuiltinType::Bool && BT->getKind() <= BuiltinType::Int128; @@ -1741,14 +1778,14 @@ bool Type::isIntegralOrUnscopedEnumerationType() const { // enumeration type in the sense required here. // C++0x: However, if the underlying type of the enum is fixed, it is // considered complete. - if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) + if (const auto *ET = dyn_cast<EnumType>(CanonicalType)) return ET->getDecl()->isComplete() && !ET->getDecl()->isScoped(); return false; } bool Type::isCharType() const { - if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType)) return BT->getKind() == BuiltinType::Char_U || BT->getKind() == BuiltinType::UChar || BT->getKind() == BuiltinType::Char_S || @@ -1757,34 +1794,41 @@ bool Type::isCharType() const { } bool Type::isWideCharType() const { - if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType)) return BT->getKind() == BuiltinType::WChar_S || BT->getKind() == BuiltinType::WChar_U; return false; } -bool Type::isChar16Type() const { +bool Type::isChar8Type() const { if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() == BuiltinType::Char8; + return false; +} + +bool Type::isChar16Type() const { + if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType)) return BT->getKind() == BuiltinType::Char16; return false; } bool Type::isChar32Type() const { - if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType)) return BT->getKind() == BuiltinType::Char32; return false; } -/// \brief Determine whether this type is any of the built-in character +/// Determine whether this type is any of the built-in character /// types. bool Type::isAnyCharacterType() const { - const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType); + const auto *BT = dyn_cast<BuiltinType>(CanonicalType); if (!BT) return false; switch (BT->getKind()) { default: return false; case BuiltinType::Char_U: case BuiltinType::UChar: case BuiltinType::WChar_U: + case BuiltinType::Char8: case BuiltinType::Char16: case BuiltinType::Char32: case BuiltinType::Char_S: @@ -1798,7 +1842,7 @@ bool Type::isAnyCharacterType() const { /// signed, according to C99 6.2.5p4 [char, signed char, short, int, long..], /// an enum decl which has a signed representation bool Type::isSignedIntegerType() const { - if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) { + if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType)) { return BT->getKind() >= BuiltinType::Char_S && BT->getKind() <= BuiltinType::Int128; } @@ -1814,12 +1858,12 @@ bool Type::isSignedIntegerType() const { } bool Type::isSignedIntegerOrEnumerationType() const { - if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) { + if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType)) { return BT->getKind() >= BuiltinType::Char_S && BT->getKind() <= BuiltinType::Int128; } - if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) { + if (const auto *ET = dyn_cast<EnumType>(CanonicalType)) { if (ET->getDecl()->isComplete()) return ET->getDecl()->getIntegerType()->isSignedIntegerType(); } @@ -1828,7 +1872,7 @@ bool Type::isSignedIntegerOrEnumerationType() const { } bool Type::hasSignedIntegerRepresentation() const { - if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType)) + if (const auto *VT = dyn_cast<VectorType>(CanonicalType)) return VT->getElementType()->isSignedIntegerOrEnumerationType(); else return isSignedIntegerOrEnumerationType(); @@ -1838,12 +1882,12 @@ bool Type::hasSignedIntegerRepresentation() const { /// unsigned, according to C99 6.2.5p6 [which returns true for _Bool], an enum /// decl which has an unsigned representation bool Type::isUnsignedIntegerType() const { - if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) { + if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType)) { return BT->getKind() >= BuiltinType::Bool && BT->getKind() <= BuiltinType::UInt128; } - if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) { + if (const auto *ET = dyn_cast<EnumType>(CanonicalType)) { // Incomplete enum types are not treated as integer types. // FIXME: In C++, enum types are never integer types. if (ET->getDecl()->isComplete() && !ET->getDecl()->isScoped()) @@ -1854,12 +1898,12 @@ bool Type::isUnsignedIntegerType() const { } bool Type::isUnsignedIntegerOrEnumerationType() const { - if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) { + if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType)) { return BT->getKind() >= BuiltinType::Bool && BT->getKind() <= BuiltinType::UInt128; } - if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) { + if (const auto *ET = dyn_cast<EnumType>(CanonicalType)) { if (ET->getDecl()->isComplete()) return ET->getDecl()->getIntegerType()->isUnsignedIntegerType(); } @@ -1868,48 +1912,48 @@ bool Type::isUnsignedIntegerOrEnumerationType() const { } bool Type::hasUnsignedIntegerRepresentation() const { - if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType)) + if (const auto *VT = dyn_cast<VectorType>(CanonicalType)) return VT->getElementType()->isUnsignedIntegerOrEnumerationType(); else return isUnsignedIntegerOrEnumerationType(); } bool Type::isFloatingType() const { - if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType)) return BT->getKind() >= BuiltinType::Half && BT->getKind() <= BuiltinType::Float128; - if (const ComplexType *CT = dyn_cast<ComplexType>(CanonicalType)) + if (const auto *CT = dyn_cast<ComplexType>(CanonicalType)) return CT->getElementType()->isFloatingType(); return false; } bool Type::hasFloatingRepresentation() const { - if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType)) + if (const auto *VT = dyn_cast<VectorType>(CanonicalType)) return VT->getElementType()->isFloatingType(); else return isFloatingType(); } bool Type::isRealFloatingType() const { - if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType)) return BT->isFloatingPoint(); return false; } bool Type::isRealType() const { - if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType)) return BT->getKind() >= BuiltinType::Bool && BT->getKind() <= BuiltinType::Float128; - if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) + if (const auto *ET = dyn_cast<EnumType>(CanonicalType)) return ET->getDecl()->isComplete() && !ET->getDecl()->isScoped(); return false; } bool Type::isArithmeticType() const { - if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType)) return BT->getKind() >= BuiltinType::Bool && BT->getKind() <= BuiltinType::Float128; - if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) + if (const auto *ET = dyn_cast<EnumType>(CanonicalType)) // GCC allows forward declaration of enum types (forbid by C99 6.7.2.3p2). // If a body isn't seen by the time we get here, return false. // @@ -1924,7 +1968,7 @@ Type::ScalarTypeKind Type::getScalarTypeKind() const { assert(isScalarType()); const Type *T = CanonicalType.getTypePtr(); - if (const BuiltinType *BT = dyn_cast<BuiltinType>(T)) { + if (const auto *BT = dyn_cast<BuiltinType>(T)) { if (BT->getKind() == BuiltinType::Bool) return STK_Bool; if (BT->getKind() == BuiltinType::NullPtr) return STK_CPointer; if (BT->isInteger()) return STK_Integral; @@ -1941,7 +1985,7 @@ Type::ScalarTypeKind Type::getScalarTypeKind() const { } else if (isa<EnumType>(T)) { assert(cast<EnumType>(T)->getDecl()->isComplete()); return STK_Integral; - } else if (const ComplexType *CT = dyn_cast<ComplexType>(T)) { + } else if (const auto *CT = dyn_cast<ComplexType>(T)) { if (CT->getElementType()->isRealFloatingType()) return STK_FloatingComplex; return STK_IntegralComplex; @@ -1950,7 +1994,7 @@ Type::ScalarTypeKind Type::getScalarTypeKind() const { llvm_unreachable("unknown scalar type"); } -/// \brief Determines whether the type is a C++ aggregate type or C +/// Determines whether the type is a C++ aggregate type or C /// aggregate or union type. /// /// An aggregate type is an array or a class type (struct, union, or @@ -1960,8 +2004,8 @@ Type::ScalarTypeKind Type::getScalarTypeKind() const { /// subsumes the notion of C aggregates (C99 6.2.5p21) because it also /// includes union types. bool Type::isAggregateType() const { - if (const RecordType *Record = dyn_cast<RecordType>(CanonicalType)) { - if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(Record->getDecl())) + if (const auto *Record = dyn_cast<RecordType>(CanonicalType)) { + if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>(Record->getDecl())) return ClassDecl->isAggregate(); return true; @@ -1997,12 +2041,7 @@ bool Type::isIncompleteType(NamedDecl **Def) const { EnumDecl *EnumD = cast<EnumType>(CanonicalType)->getDecl(); if (Def) *Def = EnumD; - - // An enumeration with fixed underlying type is complete (C++0x 7.2p3). - if (EnumD->isFixed()) - return false; - - return !EnumD->isCompleteDefinition(); + return !EnumD->isComplete(); } case Record: { // A tagged type (struct/union/enum/class) is incomplete if the decl is a @@ -2038,7 +2077,7 @@ bool Type::isIncompleteType(NamedDecl **Def) const { return false; // The inheritance attribute might only be present on the most recent // CXXRecordDecl, use that one. - RD = RD->getMostRecentDecl(); + RD = RD->getMostRecentNonInjectedDecl(); // Nothing interesting to do if the inheritance attribute is already set. if (RD->hasAttr<MSInheritanceAttr>()) return false; @@ -2105,8 +2144,8 @@ bool QualType::isCXX98PODType(const ASTContext &Context) const { return true; case Type::Record: - if (CXXRecordDecl *ClassDecl - = dyn_cast<CXXRecordDecl>(cast<RecordType>(CanonicalType)->getDecl())) + if (const auto *ClassDecl = + dyn_cast<CXXRecordDecl>(cast<RecordType>(CanonicalType)->getDecl())) return ClassDecl->isPOD(); // C struct/union is POD. @@ -2144,9 +2183,8 @@ bool QualType::isTrivialType(const ASTContext &Context) const { // As an extension, Clang treats vector types as Scalar types. if (CanonicalType->isScalarType() || CanonicalType->isVectorType()) return true; - if (const RecordType *RT = CanonicalType->getAs<RecordType>()) { - if (const CXXRecordDecl *ClassDecl = - dyn_cast<CXXRecordDecl>(RT->getDecl())) { + if (const auto *RT = CanonicalType->getAs<RecordType>()) { + if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) { // C++11 [class]p6: // A trivial class is a class that has a default constructor, // has no non-trivial default constructors, and is trivially @@ -2188,9 +2226,8 @@ bool QualType::isTriviallyCopyableType(const ASTContext &Context) const { if (CanonicalType->isScalarType() || CanonicalType->isVectorType()) return true; - if (const RecordType *RT = CanonicalType->getAs<RecordType>()) { - if (const CXXRecordDecl *ClassDecl = - dyn_cast<CXXRecordDecl>(RT->getDecl())) { + if (const auto *RT = CanonicalType->getAs<RecordType>()) { + if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) { if (!ClassDecl->isTriviallyCopyable()) return false; } @@ -2207,6 +2244,45 @@ bool QualType::isNonWeakInMRRWithObjCWeak(const ASTContext &Context) const { getObjCLifetime() != Qualifiers::OCL_Weak; } +QualType::PrimitiveDefaultInitializeKind +QualType::isNonTrivialToPrimitiveDefaultInitialize() const { + if (const auto *RT = + getTypePtr()->getBaseElementTypeUnsafe()->getAs<RecordType>()) + if (RT->getDecl()->isNonTrivialToPrimitiveDefaultInitialize()) + return PDIK_Struct; + + switch (getQualifiers().getObjCLifetime()) { + case Qualifiers::OCL_Strong: + return PDIK_ARCStrong; + case Qualifiers::OCL_Weak: + return PDIK_ARCWeak; + default: + return PDIK_Trivial; + } +} + +QualType::PrimitiveCopyKind QualType::isNonTrivialToPrimitiveCopy() const { + if (const auto *RT = + getTypePtr()->getBaseElementTypeUnsafe()->getAs<RecordType>()) + if (RT->getDecl()->isNonTrivialToPrimitiveCopy()) + return PCK_Struct; + + Qualifiers Qs = getQualifiers(); + switch (Qs.getObjCLifetime()) { + case Qualifiers::OCL_Strong: + return PCK_ARCStrong; + case Qualifiers::OCL_Weak: + return PCK_ARCWeak; + default: + return Qs.hasVolatile() ? PCK_VolatileTrivial : PCK_Trivial; + } +} + +QualType::PrimitiveCopyKind +QualType::isNonTrivialToPrimitiveDestructiveMove() const { + return isNonTrivialToPrimitiveCopy(); +} + bool Type::isLiteralType(const ASTContext &Ctx) const { if (isDependentType()) return false; @@ -2243,7 +2319,7 @@ bool Type::isLiteralType(const ASTContext &Ctx) const { if (BaseTy->isReferenceType()) return true; // -- a class type that has all of the following properties: - if (const RecordType *RT = BaseTy->getAs<RecordType>()) { + if (const auto *RT = BaseTy->getAs<RecordType>()) { // -- a trivial destructor, // -- every constructor call and full-expression in the // brace-or-equal-initializers for non-static data members (if any) @@ -2254,15 +2330,14 @@ bool Type::isLiteralType(const ASTContext &Ctx) const { // -- all non-static data members and base classes of literal types // // We resolve DR1361 by ignoring the second bullet. - if (const CXXRecordDecl *ClassDecl = - dyn_cast<CXXRecordDecl>(RT->getDecl())) + if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) return ClassDecl->isLiteral(); return true; } // We treat _Atomic T as a literal type if T is a literal type. - if (const AtomicType *AT = BaseTy->getAs<AtomicType>()) + if (const auto *AT = BaseTy->getAs<AtomicType>()) return AT->getValueType()->isLiteralType(Ctx); // If this type hasn't been deduced yet, then conservatively assume that @@ -2291,9 +2366,8 @@ bool Type::isStandardLayoutType() const { // As an extension, Clang treats vector types as Scalar types. if (BaseTy->isScalarType() || BaseTy->isVectorType()) return true; - if (const RecordType *RT = BaseTy->getAs<RecordType>()) { - if (const CXXRecordDecl *ClassDecl = - dyn_cast<CXXRecordDecl>(RT->getDecl())) + if (const auto *RT = BaseTy->getAs<RecordType>()) { + if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) if (!ClassDecl->isStandardLayout()) return false; @@ -2331,9 +2405,8 @@ bool QualType::isCXX11PODType(const ASTContext &Context) const { // As an extension, Clang treats vector types as Scalar types. if (BaseTy->isScalarType() || BaseTy->isVectorType()) return true; - if (const RecordType *RT = BaseTy->getAs<RecordType>()) { - if (const CXXRecordDecl *ClassDecl = - dyn_cast<CXXRecordDecl>(RT->getDecl())) { + if (const auto *RT = BaseTy->getAs<RecordType>()) { + if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) { // C++11 [class]p10: // A POD struct is a non-union class that is both a trivial class [...] if (!ClassDecl->isTrivial()) return false; @@ -2361,8 +2434,8 @@ bool QualType::isCXX11PODType(const ASTContext &Context) const { } bool Type::isAlignValT() const { - if (auto *ET = getAs<EnumType>()) { - auto *II = ET->getDecl()->getIdentifier(); + if (const auto *ET = getAs<EnumType>()) { + IdentifierInfo *II = ET->getDecl()->getIdentifier(); if (II && II->isStr("align_val_t") && ET->getDecl()->isInStdNamespace()) return true; } @@ -2370,8 +2443,8 @@ bool Type::isAlignValT() const { } bool Type::isStdByteType() const { - if (auto *ET = getAs<EnumType>()) { - auto *II = ET->getDecl()->getIdentifier(); + if (const auto *ET = getAs<EnumType>()) { + IdentifierInfo *II = ET->getDecl()->getIdentifier(); if (II && II->isStr("byte") && ET->getDecl()->isInStdNamespace()) return true; } @@ -2379,7 +2452,7 @@ bool Type::isStdByteType() const { } bool Type::isPromotableIntegerType() const { - if (const BuiltinType *BT = getAs<BuiltinType>()) + if (const auto *BT = getAs<BuiltinType>()) switch (BT->getKind()) { case BuiltinType::Bool: case BuiltinType::Char_S: @@ -2390,6 +2463,7 @@ bool Type::isPromotableIntegerType() const { case BuiltinType::UShort: case BuiltinType::WChar_S: case BuiltinType::WChar_U: + case BuiltinType::Char8: case BuiltinType::Char16: case BuiltinType::Char32: return true; @@ -2399,7 +2473,7 @@ bool Type::isPromotableIntegerType() const { // Enumerated types are promotable to their compatible integer types // (C99 6.3.1.1) a.k.a. its underlying type (C++ [conv.prom]p2). - if (const EnumType *ET = getAs<EnumType>()){ + if (const auto *ET = getAs<EnumType>()){ if (this->isDependentType() || ET->getDecl()->getPromotionType().isNull() || ET->getDecl()->isScoped()) return false; @@ -2506,7 +2580,7 @@ TypeWithKeyword::KeywordIsTagTypeKind(ElaboratedTypeKeyword Keyword) { StringRef TypeWithKeyword::getKeywordName(ElaboratedTypeKeyword Keyword) { switch (Keyword) { - case ETK_None: return ""; + case ETK_None: return {}; case ETK_Typename: return "typename"; case ETK_Class: return "class"; case ETK_Struct: return "struct"; @@ -2554,12 +2628,12 @@ DependentTemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID, bool Type::isElaboratedTypeSpecifier() const { ElaboratedTypeKeyword Keyword; - if (const ElaboratedType *Elab = dyn_cast<ElaboratedType>(this)) + if (const auto *Elab = dyn_cast<ElaboratedType>(this)) Keyword = Elab->getKeyword(); - else if (const DependentNameType *DepName = dyn_cast<DependentNameType>(this)) + else if (const auto *DepName = dyn_cast<DependentNameType>(this)) Keyword = DepName->getKeyword(); - else if (const DependentTemplateSpecializationType *DepTST = - dyn_cast<DependentTemplateSpecializationType>(this)) + else if (const auto *DepTST = + dyn_cast<DependentTemplateSpecializationType>(this)) Keyword = DepTST->getKeyword(); else return false; @@ -2619,6 +2693,54 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const { return "double"; case LongDouble: return "long double"; + case ShortAccum: + return "short _Accum"; + case Accum: + return "_Accum"; + case LongAccum: + return "long _Accum"; + case UShortAccum: + return "unsigned short _Accum"; + case UAccum: + return "unsigned _Accum"; + case ULongAccum: + return "unsigned long _Accum"; + case BuiltinType::ShortFract: + return "short _Fract"; + case BuiltinType::Fract: + return "_Fract"; + case BuiltinType::LongFract: + return "long _Fract"; + case BuiltinType::UShortFract: + return "unsigned short _Fract"; + case BuiltinType::UFract: + return "unsigned _Fract"; + case BuiltinType::ULongFract: + return "unsigned long _Fract"; + case BuiltinType::SatShortAccum: + return "_Sat short _Accum"; + case BuiltinType::SatAccum: + return "_Sat _Accum"; + case BuiltinType::SatLongAccum: + return "_Sat long _Accum"; + case BuiltinType::SatUShortAccum: + return "_Sat unsigned short _Accum"; + case BuiltinType::SatUAccum: + return "_Sat unsigned _Accum"; + case BuiltinType::SatULongAccum: + return "_Sat unsigned long _Accum"; + case BuiltinType::SatShortFract: + return "_Sat short _Fract"; + case BuiltinType::SatFract: + return "_Sat _Fract"; + case BuiltinType::SatLongFract: + return "_Sat long _Fract"; + case BuiltinType::SatUShortFract: + return "_Sat unsigned short _Fract"; + case BuiltinType::SatUFract: + return "_Sat unsigned _Fract"; + case BuiltinType::SatULongFract: + return "_Sat unsigned long _Fract"; case Float16: return "_Float16"; case Float128: @@ -2626,6 +2748,8 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const { case WChar_S: case WChar_U: return Policy.MSWChar ? "__wchar_t" : "wchar_t"; + case Char8: + return "char8_t"; case Char16: return "char16_t"; case Char32: @@ -2674,7 +2798,7 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const { } QualType QualType::getNonLValueExprType(const ASTContext &Context) const { - if (const ReferenceType *RefType = getTypePtr()->getAs<ReferenceType>()) + if (const auto *RefType = getTypePtr()->getAs<ReferenceType>()) return RefType->getPointeeType(); // C++0x [basic.lval]: @@ -2732,7 +2856,7 @@ FunctionProtoType::FunctionProtoType(QualType result, ArrayRef<QualType> params, FunctionTypeBits.RefQualifier = epi.RefQualifier; // Fill in the trailing argument array. - QualType *argSlot = reinterpret_cast<QualType*>(this+1); + auto *argSlot = reinterpret_cast<QualType *>(this+1); for (unsigned i = 0; i != NumParams; ++i) { if (params[i]->isDependentType()) setDependent(); @@ -2761,24 +2885,25 @@ FunctionProtoType::FunctionProtoType(QualType result, ArrayRef<QualType> params, exnSlot[I++] = ExceptionType; } - } else if (getExceptionSpecType() == EST_ComputedNoexcept) { + } else if (isComputedNoexcept(getExceptionSpecType())) { + assert(epi.ExceptionSpec.NoexceptExpr && "computed noexcept with no expr"); + assert((getExceptionSpecType() == EST_DependentNoexcept) == + epi.ExceptionSpec.NoexceptExpr->isValueDependent()); + // Store the noexcept expression and context. - Expr **noexSlot = reinterpret_cast<Expr **>(argSlot + NumParams); + auto **noexSlot = reinterpret_cast<Expr **>(argSlot + NumParams); *noexSlot = epi.ExceptionSpec.NoexceptExpr; - if (epi.ExceptionSpec.NoexceptExpr) { - if (epi.ExceptionSpec.NoexceptExpr->isValueDependent() || - epi.ExceptionSpec.NoexceptExpr->isInstantiationDependent()) - setInstantiationDependent(); + if (epi.ExceptionSpec.NoexceptExpr->isValueDependent() || + epi.ExceptionSpec.NoexceptExpr->isInstantiationDependent()) + setInstantiationDependent(); - if (epi.ExceptionSpec.NoexceptExpr->containsUnexpandedParameterPack()) - setContainsUnexpandedParameterPack(); - } + if (epi.ExceptionSpec.NoexceptExpr->containsUnexpandedParameterPack()) + setContainsUnexpandedParameterPack(); } else if (getExceptionSpecType() == EST_Uninstantiated) { // Store the function decl from which we will resolve our // exception specification. - FunctionDecl **slot = - reinterpret_cast<FunctionDecl **>(argSlot + NumParams); + auto **slot = reinterpret_cast<FunctionDecl **>(argSlot + NumParams); slot[0] = epi.ExceptionSpec.SourceDecl; slot[1] = epi.ExceptionSpec.SourceTemplate; // This exception specification doesn't make the type dependent, because @@ -2786,8 +2911,7 @@ FunctionProtoType::FunctionProtoType(QualType result, ArrayRef<QualType> params, } else if (getExceptionSpecType() == EST_Unevaluated) { // Store the function decl from which we will resolve our // exception specification. - FunctionDecl **slot = - reinterpret_cast<FunctionDecl **>(argSlot + NumParams); + auto **slot = reinterpret_cast<FunctionDecl **>(argSlot + NumParams); slot[0] = epi.ExceptionSpec.SourceDecl; } @@ -2795,7 +2919,7 @@ FunctionProtoType::FunctionProtoType(QualType result, ArrayRef<QualType> params, // then it's a dependent type. This only happens in C++17 onwards. if (isCanonicalUnqualified()) { if (getExceptionSpecType() == EST_Dynamic || - getExceptionSpecType() == EST_ComputedNoexcept) { + getExceptionSpecType() == EST_DependentNoexcept) { assert(hasDependentExceptionSpec() && "type should not be canonical"); setDependent(); } @@ -2805,7 +2929,7 @@ FunctionProtoType::FunctionProtoType(QualType result, ArrayRef<QualType> params, } if (epi.ExtParameterInfos) { - ExtParameterInfo *extParamInfos = + auto *extParamInfos = const_cast<ExtParameterInfo *>(getExtParameterInfosBuffer()); for (unsigned i = 0; i != NumParams; ++i) extParamInfos[i] = epi.ExtParameterInfos[i]; @@ -2833,52 +2957,36 @@ bool FunctionProtoType::hasInstantiationDependentExceptionSpec() const { return false; } -FunctionProtoType::NoexceptResult -FunctionProtoType::getNoexceptSpec(const ASTContext &ctx) const { - ExceptionSpecificationType est = getExceptionSpecType(); - if (est == EST_BasicNoexcept) - return NR_Nothrow; - - if (est != EST_ComputedNoexcept) - return NR_NoNoexcept; - - Expr *noexceptExpr = getNoexceptExpr(); - if (!noexceptExpr) - return NR_BadNoexcept; - if (noexceptExpr->isValueDependent()) - return NR_Dependent; - - llvm::APSInt value; - bool isICE = noexceptExpr->isIntegerConstantExpr(value, ctx, nullptr, - /*evaluated*/false); - (void)isICE; - assert(isICE && "AST should not contain bad noexcept expressions."); - - return value.getBoolValue() ? NR_Nothrow : NR_Throw; -} +CanThrowResult FunctionProtoType::canThrow() const { + switch (getExceptionSpecType()) { + case EST_Unparsed: + case EST_Unevaluated: + case EST_Uninstantiated: + llvm_unreachable("should not call this with unresolved exception specs"); -CanThrowResult FunctionProtoType::canThrow(const ASTContext &Ctx) const { - ExceptionSpecificationType EST = getExceptionSpecType(); - assert(EST != EST_Unevaluated && EST != EST_Uninstantiated); - if (EST == EST_DynamicNone || EST == EST_BasicNoexcept) + case EST_DynamicNone: + case EST_BasicNoexcept: + case EST_NoexceptTrue: return CT_Cannot; - if (EST == EST_Dynamic) { + case EST_None: + case EST_MSAny: + case EST_NoexceptFalse: + return CT_Can; + + case EST_Dynamic: // A dynamic exception specification is throwing unless every exception // type is an (unexpanded) pack expansion type. for (unsigned I = 0, N = NumExceptions; I != N; ++I) if (!getExceptionType(I)->getAs<PackExpansionType>()) return CT_Can; return CT_Dependent; - } - if (EST != EST_ComputedNoexcept) - return CT_Can; - - NoexceptResult NR = getNoexceptSpec(Ctx); - if (NR == NR_Dependent) + case EST_DependentNoexcept: return CT_Dependent; - return NR == NR_Nothrow ? CT_Cannot : CT_Can; + } + + llvm_unreachable("unexpected exception specification kind"); } bool FunctionProtoType::isTemplateVariadic() const { @@ -2928,8 +3036,7 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result, if (epi.ExceptionSpec.Type == EST_Dynamic) { for (QualType Ex : epi.ExceptionSpec.Exceptions) ID.AddPointer(Ex.getAsOpaquePtr()); - } else if (epi.ExceptionSpec.Type == EST_ComputedNoexcept && - epi.ExceptionSpec.NoexceptExpr) { + } else if (isComputedNoexcept(epi.ExceptionSpec.Type)) { epi.ExceptionSpec.NoexceptExpr->Profile(ID, Context, Canonical); } else if (epi.ExceptionSpec.Type == EST_Uninstantiated || epi.ExceptionSpec.Type == EST_Unevaluated) { @@ -3048,7 +3155,7 @@ bool RecordType::hasConstFields() const { if (FieldTy.isConstQualified()) return true; FieldTy = FieldTy.getCanonicalType(); - if (const RecordType *FieldRecTy = FieldTy->getAs<RecordType>()) + if (const auto *FieldRecTy = FieldTy->getAs<RecordType>()) if (FieldRecTy->hasConstFields()) return true; } @@ -3097,6 +3204,7 @@ bool AttributedType::isQualifier() const { case AttributedType::attr_uptr: case AttributedType::attr_objc_kindof: case AttributedType::attr_ns_returns_retained: + case AttributedType::attr_nocf_check: return false; } llvm_unreachable("bad attributed type kind"); @@ -3134,6 +3242,7 @@ bool AttributedType::isCallingConv() const { case attr_nullable: case attr_null_unspecified: case attr_objc_kindof: + case attr_nocf_check: return false; case attr_pcs: @@ -3229,8 +3338,7 @@ TemplateSpecializationType(TemplateName T, T.getKind() == TemplateName::SubstTemplateTemplateParmPack) && "Unexpected template name for TemplateSpecializationType"); - TemplateArgument *TemplateArgs - = reinterpret_cast<TemplateArgument *>(this + 1); + auto *TemplateArgs = reinterpret_cast<TemplateArgument *>(this + 1); for (const TemplateArgument &Arg : Args) { // Update instantiation-dependent and variably-modified bits. // If the canonical type exists and is non-dependent, the template @@ -3252,7 +3360,7 @@ TemplateSpecializationType(TemplateName T, // Store the aliased type if this is a type alias template specialization. if (TypeAlias) { - TemplateArgument *Begin = reinterpret_cast<TemplateArgument *>(this + 1); + auto *Begin = reinterpret_cast<TemplateArgument *>(this + 1); *reinterpret_cast<QualType*>(Begin + getNumArgs()) = AliasedType; } } @@ -3320,7 +3428,7 @@ void ObjCTypeParamType::Profile(llvm::FoldingSetNodeID &ID) { namespace { -/// \brief The cached properties of a type. +/// The cached properties of a type. class CachedProperties { Linkage L; bool local; @@ -3450,7 +3558,7 @@ static CachedProperties computeCachedProperties(const Type *T) { case Type::RValueReference: return Cache::get(cast<ReferenceType>(T)->getPointeeType()); case Type::MemberPointer: { - const MemberPointerType *MPT = cast<MemberPointerType>(T); + const auto *MPT = cast<MemberPointerType>(T); return merge(Cache::get(MPT->getClass()), Cache::get(MPT->getPointeeType())); } @@ -3464,7 +3572,7 @@ static CachedProperties computeCachedProperties(const Type *T) { case Type::FunctionNoProto: return Cache::get(cast<FunctionType>(T)->getReturnType()); case Type::FunctionProto: { - const FunctionProtoType *FPT = cast<FunctionProtoType>(T); + const auto *FPT = cast<FunctionProtoType>(T); CachedProperties result = Cache::get(FPT->getReturnType()); for (const auto &ai : FPT->param_types()) result = merge(result, Cache::get(ai)); @@ -3487,7 +3595,7 @@ static CachedProperties computeCachedProperties(const Type *T) { llvm_unreachable("unhandled type class"); } -/// \brief Determine the linkage of this type. +/// Determine the linkage of this type. Linkage Type::getLinkage() const { Cache::ensure(this); return TypeBits.getLinkage(); @@ -3534,7 +3642,7 @@ LinkageInfo LinkageComputer::computeTypeLinkageInfo(const Type *T) { case Type::RValueReference: return computeTypeLinkageInfo(cast<ReferenceType>(T)->getPointeeType()); case Type::MemberPointer: { - const MemberPointerType *MPT = cast<MemberPointerType>(T); + const auto *MPT = cast<MemberPointerType>(T); LinkageInfo LV = computeTypeLinkageInfo(MPT->getClass()); LV.merge(computeTypeLinkageInfo(MPT->getPointeeType())); return LV; @@ -3549,7 +3657,7 @@ LinkageInfo LinkageComputer::computeTypeLinkageInfo(const Type *T) { case Type::FunctionNoProto: return computeTypeLinkageInfo(cast<FunctionType>(T)->getReturnType()); case Type::FunctionProto: { - const FunctionProtoType *FPT = cast<FunctionProtoType>(T); + const auto *FPT = cast<FunctionProtoType>(T); LinkageInfo LV = computeTypeLinkageInfo(FPT->getReturnType()); for (const auto &ai : FPT->param_types()) LV.merge(computeTypeLinkageInfo(ai)); @@ -3702,6 +3810,7 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const { case Type::IncompleteArray: case Type::VariableArray: case Type::DependentSizedArray: + case Type::DependentVector: case Type::DependentSizedExtVector: case Type::Vector: case Type::ExtVector: @@ -3744,7 +3853,7 @@ Optional<NullabilityKind> AttributedType::stripOuterNullability(QualType &T) { } bool Type::isBlockCompatibleObjCPointerType(ASTContext &ctx) const { - const ObjCObjectPointerType *objcPtr = getAs<ObjCObjectPointerType>(); + const auto *objcPtr = getAs<ObjCObjectPointerType>(); if (!objcPtr) return false; @@ -3789,11 +3898,10 @@ bool Type::isObjCARCImplicitlyUnretainedType() const { const Type *canon = getCanonicalTypeInternal().getTypePtr(); // Walk down to the base type. We don't care about qualifiers for this. - while (const ArrayType *array = dyn_cast<ArrayType>(canon)) + while (const auto *array = dyn_cast<ArrayType>(canon)) canon = array->getElementType().getTypePtr(); - if (const ObjCObjectPointerType *opt - = dyn_cast<ObjCObjectPointerType>(canon)) { + if (const auto *opt = dyn_cast<ObjCObjectPointerType>(canon)) { // Class and Class<Protocol> don't require retention. if (opt->getObjectType()->isObjCClass()) return true; @@ -3805,7 +3913,7 @@ bool Type::isObjCARCImplicitlyUnretainedType() const { bool Type::isObjCNSObjectType() const { const Type *cur = this; while (true) { - if (const TypedefType *typedefType = dyn_cast<TypedefType>(cur)) + if (const auto *typedefType = dyn_cast<TypedefType>(cur)) return typedefType->getDecl()->hasAttr<ObjCNSObjectAttr>(); // Single-step desugar until we run out of sugar. @@ -3816,7 +3924,7 @@ bool Type::isObjCNSObjectType() const { } bool Type::isObjCIndependentClassType() const { - if (const TypedefType *typedefType = dyn_cast<TypedefType>(this)) + if (const auto *typedefType = dyn_cast<TypedefType>(this)) return typedefType->getDecl()->hasAttr<ObjCIndependentClassAttr>(); return false; } @@ -3830,11 +3938,11 @@ bool Type::isObjCRetainableType() const { bool Type::isObjCIndirectLifetimeType() const { if (isObjCLifetimeType()) return true; - if (const PointerType *OPT = getAs<PointerType>()) + if (const auto *OPT = getAs<PointerType>()) return OPT->getPointeeType()->isObjCIndirectLifetimeType(); - if (const ReferenceType *Ref = getAs<ReferenceType>()) + if (const auto *Ref = getAs<ReferenceType>()) return Ref->getPointeeType()->isObjCIndirectLifetimeType(); - if (const MemberPointerType *MemPtr = getAs<MemberPointerType>()) + if (const auto *MemPtr = getAs<MemberPointerType>()) return MemPtr->getPointeeType()->isObjCIndirectLifetimeType(); return false; } @@ -3848,15 +3956,15 @@ bool Type::isObjCLifetimeType() const { return type->isObjCRetainableType(); } -/// \brief Determine whether the given type T is a "bridgable" Objective-C type, +/// Determine whether the given type T is a "bridgable" Objective-C type, /// which is either an Objective-C object pointer type or an bool Type::isObjCARCBridgableType() const { return isObjCObjectPointerType() || isBlockPointerType(); } -/// \brief Determine whether the given type T is a "bridgeable" C type. +/// Determine whether the given type T is a "bridgeable" C type. bool Type::isCARCBridgableType() const { - const PointerType *Pointer = getAs<PointerType>(); + const auto *Pointer = getAs<PointerType>(); if (!Pointer) return false; @@ -3867,9 +3975,9 @@ bool Type::isCARCBridgableType() const { bool Type::hasSizedVLAType() const { if (!isVariablyModifiedType()) return false; - if (const PointerType *ptr = getAs<PointerType>()) + if (const auto *ptr = getAs<PointerType>()) return ptr->getPointeeType()->hasSizedVLAType(); - if (const ReferenceType *ref = getAs<ReferenceType>()) + if (const auto *ref = getAs<ReferenceType>()) return ref->getPointeeType()->hasSizedVLAType(); if (const ArrayType *arr = getAsArrayTypeUnsafe()) { if (isa<VariableArrayType>(arr) && @@ -3895,16 +4003,40 @@ QualType::DestructionKind QualType::isDestructedTypeImpl(QualType type) { return DK_objc_weak_lifetime; } - /// Currently, the only destruction kind we recognize is C++ objects - /// with non-trivial destructors. - const CXXRecordDecl *record = - type->getBaseElementTypeUnsafe()->getAsCXXRecordDecl(); - if (record && record->hasDefinition() && !record->hasTrivialDestructor()) - return DK_cxx_destructor; + if (const auto *RT = + type->getBaseElementTypeUnsafe()->getAs<RecordType>()) { + const RecordDecl *RD = RT->getDecl(); + if (const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) { + /// Check if this is a C++ object with a non-trivial destructor. + if (CXXRD->hasDefinition() && !CXXRD->hasTrivialDestructor()) + return DK_cxx_destructor; + } else { + /// Check if this is a C struct that is non-trivial to destroy or an array + /// that contains such a struct. + if (RD->isNonTrivialToPrimitiveDestroy()) + return DK_nontrivial_c_struct; + } + } return DK_none; } CXXRecordDecl *MemberPointerType::getMostRecentCXXRecordDecl() const { - return getClass()->getAsCXXRecordDecl()->getMostRecentDecl(); + return getClass()->getAsCXXRecordDecl()->getMostRecentNonInjectedDecl(); +} + +void clang::FixedPointValueToString(SmallVectorImpl<char> &Str, + const llvm::APSInt &Val, unsigned Scale, + unsigned Radix) { + llvm::APSInt ScaleVal = llvm::APSInt::getUnsigned(1ULL << Scale); + llvm::APSInt IntPart = Val / ScaleVal; + llvm::APSInt FractPart = Val % ScaleVal; + llvm::APSInt RadixInt = llvm::APSInt::getUnsigned(Radix); + + IntPart.toString(Str, Radix); + Str.push_back('.'); + do { + (FractPart * RadixInt / ScaleVal).toString(Str, Radix); + FractPart = (FractPart * RadixInt) % ScaleVal; + } while (FractPart.getExtValue()); } diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp index 0ac50b31acec..6fa76e14a590 100644 --- a/lib/AST/TypeLoc.cpp +++ b/lib/AST/TypeLoc.cpp @@ -68,7 +68,7 @@ public: } // namespace -/// \brief Returns the alignment of the type source info data block. +/// 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, nullptr)); @@ -88,7 +88,7 @@ public: } // namespace -/// \brief Returns the size of the type source info data block. +/// Returns the size of the type source info data block. unsigned TypeLoc::getFullDataSizeForType(QualType Ty) { unsigned Total = 0; TypeLoc TyLoc(Ty, nullptr); @@ -118,13 +118,13 @@ public: } // namespace -/// \brief Get the next TypeLoc pointed by this TypeLoc, e.g for "int*" the +/// Get the next TypeLoc pointed by this TypeLoc, e.g for "int*" the /// TypeLoc is a PointerLoc and next TypeLoc is for "int". TypeLoc TypeLoc::getNextTypeLocImpl(TypeLoc TL) { return NextLoc().Visit(TL); } -/// \brief Initializes a type location, and all of its children +/// Initializes a type location, and all of its children /// recursively, as if the entire tree had been written in the /// given location. void TypeLoc::initializeImpl(ASTContext &Context, TypeLoc TL, @@ -254,7 +254,7 @@ SourceLocation TypeLoc::getEndLoc() const { case RValueReference: case PackExpansion: if (!Last) - Last = Cur; + Last = Cur; break; case Qualified: case Elaborated: @@ -281,7 +281,7 @@ struct TSTChecker : public TypeLocVisitor<TSTChecker, bool> { } // namespace -/// \brief Determines if the given type loc corresponds to a +/// Determines if the given type loc corresponds to a /// TypeSpecTypeLoc. Since there is not actually a TypeSpecType in /// the type hierarchy, this is made somewhat complicated. /// @@ -317,6 +317,8 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const { case BuiltinType::Char_U: case BuiltinType::Char_S: return TST_char; + case BuiltinType::Char8: + return TST_char8; case BuiltinType::Char16: return TST_char16; case BuiltinType::Char32: @@ -342,6 +344,30 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const { case BuiltinType::LongDouble: case BuiltinType::Float16: case BuiltinType::Float128: + case BuiltinType::ShortAccum: + case BuiltinType::Accum: + case BuiltinType::LongAccum: + case BuiltinType::UShortAccum: + case BuiltinType::UAccum: + case BuiltinType::ULongAccum: + case BuiltinType::ShortFract: + case BuiltinType::Fract: + case BuiltinType::LongFract: + case BuiltinType::UShortFract: + case BuiltinType::UFract: + case BuiltinType::ULongFract: + case BuiltinType::SatShortAccum: + case BuiltinType::SatAccum: + case BuiltinType::SatLongAccum: + case BuiltinType::SatUShortAccum: + case BuiltinType::SatUAccum: + case BuiltinType::SatULongAccum: + case BuiltinType::SatShortFract: + case BuiltinType::SatFract: + case BuiltinType::SatLongFract: + case BuiltinType::SatUShortFract: + case BuiltinType::SatUFract: + case BuiltinType::SatULongFract: llvm_unreachable("Builtin type needs extra local data!"); // Fall through, if the impossible happens. diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index c28ada7dcb8b..c5e2244e26c5 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -1,4 +1,4 @@ -//===--- TypePrinter.cpp - Pretty-Print Clang Types -----------------------===// +//===- TypePrinter.cpp - Pretty-Print Clang Types -------------------------===// // // The LLVM Compiler Infrastructure // @@ -14,20 +14,40 @@ #include "clang/AST/PrettyPrinter.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" +#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/TemplateBase.h" +#include "clang/AST/TemplateName.h" #include "clang/AST/Type.h" +#include "clang/Basic/AddressSpaces.h" +#include "clang/Basic/ExceptionSpecificationType.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LLVM.h" #include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" +#include "clang/Basic/Specifiers.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallString.h" -#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/SaveAndRestore.h" #include "llvm/Support/raw_ostream.h" +#include <cassert> +#include <string> + using namespace clang; namespace { - /// \brief RAII object that enables printing of the ARC __strong lifetime + + /// RAII object that enables printing of the ARC __strong lifetime /// qualifier. class IncludeStrongLifetimeRAII { PrintingPolicy &Policy; @@ -35,7 +55,7 @@ namespace { public: explicit IncludeStrongLifetimeRAII(PrintingPolicy &Policy) - : Policy(Policy), Old(Policy.SuppressStrongLifetime) { + : Policy(Policy), Old(Policy.SuppressStrongLifetime) { if (!Policy.SuppressLifetimeQualifiers) Policy.SuppressStrongLifetime = false; } @@ -51,7 +71,7 @@ namespace { public: explicit ParamPolicyRAII(PrintingPolicy &Policy) - : Policy(Policy), Old(Policy.SuppressSpecifiers) { + : Policy(Policy), Old(Policy.SuppressSpecifiers) { Policy.SuppressSpecifiers = false; } @@ -82,13 +102,12 @@ namespace { class TypePrinter { PrintingPolicy Policy; unsigned Indentation; - bool HasEmptyPlaceHolder; - bool InsideCCAttribute; + bool HasEmptyPlaceHolder = false; + bool InsideCCAttribute = false; public: explicit TypePrinter(const PrintingPolicy &Policy, unsigned Indentation = 0) - : Policy(Policy), Indentation(Indentation), - HasEmptyPlaceHolder(false), InsideCCAttribute(false) { } + : Policy(Policy), Indentation(Indentation) {} void print(const Type *ty, Qualifiers qs, raw_ostream &OS, StringRef PlaceHolder); @@ -111,7 +130,8 @@ namespace { void print##CLASS##After(const CLASS##Type *T, raw_ostream &OS); #include "clang/AST/TypeNodes.def" }; -} + +} // namespace static void AppendTypeQualList(raw_ostream &OS, unsigned TypeQuals, bool HasRestrictKeyword) { @@ -169,10 +189,9 @@ bool TypePrinter::canPrefixQualifiers(const Type *T, bool CanPrefixQualifiers = false; NeedARCStrongQualifier = false; Type::TypeClass TC = T->getTypeClass(); - if (const AutoType *AT = dyn_cast<AutoType>(T)) + if (const auto *AT = dyn_cast<AutoType>(T)) TC = AT->desugar()->getTypeClass(); - if (const SubstTemplateTypeParmType *Subst - = dyn_cast<SubstTemplateTypeParmType>(T)) + if (const auto *Subst = dyn_cast<SubstTemplateTypeParmType>(T)) TC = Subst->getReplacementType()->getTypeClass(); switch (TC) { @@ -223,6 +242,7 @@ bool TypePrinter::canPrefixQualifiers(const Type *T, case Type::RValueReference: case Type::MemberPointer: case Type::DependentAddressSpace: + case Type::DependentVector: case Type::DependentSizedExtVector: case Type::Vector: case Type::ExtVector: @@ -245,14 +265,13 @@ void TypePrinter::printBefore(QualType T, raw_ostream &OS) { // If we have cv1 T, where T is substituted for cv2 U, only print cv1 - cv2 // at this level. Qualifiers Quals = Split.Quals; - if (const SubstTemplateTypeParmType *Subst = - dyn_cast<SubstTemplateTypeParmType>(Split.Ty)) + if (const auto *Subst = dyn_cast<SubstTemplateTypeParmType>(Split.Ty)) Quals -= QualType(Subst, 0).getQualifiers(); printBefore(Split.Ty, Quals, OS); } -/// \brief Prints the part of the type string before an identifier, e.g. for +/// Prints the part of the type string before an identifier, e.g. for /// "int foo[10]" it prints "int ". void TypePrinter::printBefore(const Type *T,Qualifiers Quals, raw_ostream &OS) { if (Policy.SuppressSpecifiers && T->isSpecifierType()) @@ -305,7 +324,7 @@ void TypePrinter::printAfter(QualType t, raw_ostream &OS) { printAfter(split.Ty, split.Quals, OS); } -/// \brief Prints the part of the type string after an identifier, e.g. for +/// Prints the part of the type string after an identifier, e.g. for /// "int foo[10]" it prints "[10]". void TypePrinter::printAfter(const Type *T, Qualifiers Quals, raw_ostream &OS) { switch (T->getTypeClass()) { @@ -321,12 +340,14 @@ void TypePrinter::printBuiltinBefore(const BuiltinType *T, raw_ostream &OS) { OS << T->getName(Policy); spaceBeforePlaceHolder(OS); } -void TypePrinter::printBuiltinAfter(const BuiltinType *T, raw_ostream &OS) { } + +void TypePrinter::printBuiltinAfter(const BuiltinType *T, raw_ostream &OS) {} void TypePrinter::printComplexBefore(const ComplexType *T, raw_ostream &OS) { OS << "_Complex "; printBefore(T->getElementType(), OS); } + void TypePrinter::printComplexAfter(const ComplexType *T, raw_ostream &OS) { printAfter(T->getElementType(), OS); } @@ -341,6 +362,7 @@ void TypePrinter::printPointerBefore(const PointerType *T, raw_ostream &OS) { OS << '('; OS << '*'; } + void TypePrinter::printPointerAfter(const PointerType *T, raw_ostream &OS) { IncludeStrongLifetimeRAII Strong(Policy); SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false); @@ -357,54 +379,69 @@ void TypePrinter::printBlockPointerBefore(const BlockPointerType *T, printBefore(T->getPointeeType(), OS); OS << '^'; } + void TypePrinter::printBlockPointerAfter(const BlockPointerType *T, raw_ostream &OS) { SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false); printAfter(T->getPointeeType(), OS); } +// When printing a reference, the referenced type might also be a reference. +// If so, we want to skip that before printing the inner type. +static QualType skipTopLevelReferences(QualType T) { + if (auto *Ref = T->getAs<ReferenceType>()) + return skipTopLevelReferences(Ref->getPointeeTypeAsWritten()); + return T; +} + void TypePrinter::printLValueReferenceBefore(const LValueReferenceType *T, raw_ostream &OS) { IncludeStrongLifetimeRAII Strong(Policy); SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false); - printBefore(T->getPointeeTypeAsWritten(), OS); + QualType Inner = skipTopLevelReferences(T->getPointeeTypeAsWritten()); + printBefore(Inner, OS); // Handle things like 'int (&A)[4];' correctly. // FIXME: this should include vectors, but vectors use attributes I guess. - if (isa<ArrayType>(T->getPointeeTypeAsWritten())) + if (isa<ArrayType>(Inner)) OS << '('; OS << '&'; } + void TypePrinter::printLValueReferenceAfter(const LValueReferenceType *T, raw_ostream &OS) { IncludeStrongLifetimeRAII Strong(Policy); SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false); + QualType Inner = skipTopLevelReferences(T->getPointeeTypeAsWritten()); // Handle things like 'int (&A)[4];' correctly. // FIXME: this should include vectors, but vectors use attributes I guess. - if (isa<ArrayType>(T->getPointeeTypeAsWritten())) + if (isa<ArrayType>(Inner)) OS << ')'; - printAfter(T->getPointeeTypeAsWritten(), OS); + printAfter(Inner, OS); } void TypePrinter::printRValueReferenceBefore(const RValueReferenceType *T, raw_ostream &OS) { IncludeStrongLifetimeRAII Strong(Policy); SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false); - printBefore(T->getPointeeTypeAsWritten(), OS); + QualType Inner = skipTopLevelReferences(T->getPointeeTypeAsWritten()); + printBefore(Inner, OS); // Handle things like 'int (&&A)[4];' correctly. // FIXME: this should include vectors, but vectors use attributes I guess. - if (isa<ArrayType>(T->getPointeeTypeAsWritten())) + if (isa<ArrayType>(Inner)) OS << '('; OS << "&&"; } + void TypePrinter::printRValueReferenceAfter(const RValueReferenceType *T, raw_ostream &OS) { IncludeStrongLifetimeRAII Strong(Policy); SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false); + QualType Inner = skipTopLevelReferences(T->getPointeeTypeAsWritten()); // Handle things like 'int (&&A)[4];' correctly. // FIXME: this should include vectors, but vectors use attributes I guess. - if (isa<ArrayType>(T->getPointeeTypeAsWritten())) + if (isa<ArrayType>(Inner)) OS << ')'; - printAfter(T->getPointeeTypeAsWritten(), OS); + printAfter(Inner, OS); } void TypePrinter::printMemberPointerBefore(const MemberPointerType *T, @@ -423,6 +460,7 @@ void TypePrinter::printMemberPointerBefore(const MemberPointerType *T, OS << "::*"; } + void TypePrinter::printMemberPointerAfter(const MemberPointerType *T, raw_ostream &OS) { IncludeStrongLifetimeRAII Strong(Policy); @@ -440,6 +478,7 @@ void TypePrinter::printConstantArrayBefore(const ConstantArrayType *T, SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false); printBefore(T->getElementType(), OS); } + void TypePrinter::printConstantArrayAfter(const ConstantArrayType *T, raw_ostream &OS) { OS << '['; @@ -462,6 +501,7 @@ void TypePrinter::printIncompleteArrayBefore(const IncompleteArrayType *T, SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false); printBefore(T->getElementType(), OS); } + void TypePrinter::printIncompleteArrayAfter(const IncompleteArrayType *T, raw_ostream &OS) { OS << "[]"; @@ -474,6 +514,7 @@ void TypePrinter::printVariableArrayBefore(const VariableArrayType *T, SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false); printBefore(T->getElementType(), OS); } + void TypePrinter::printVariableArrayAfter(const VariableArrayType *T, raw_ostream &OS) { OS << '['; @@ -499,6 +540,7 @@ void TypePrinter::printAdjustedBefore(const AdjustedType *T, raw_ostream &OS) { // invisible. printBefore(T->getAdjustedType(), OS); } + void TypePrinter::printAdjustedAfter(const AdjustedType *T, raw_ostream &OS) { printAfter(T->getAdjustedType(), OS); } @@ -507,6 +549,7 @@ void TypePrinter::printDecayedBefore(const DecayedType *T, raw_ostream &OS) { // Print as though it's a pointer. printAdjustedBefore(T, OS); } + void TypePrinter::printDecayedAfter(const DecayedType *T, raw_ostream &OS) { printAdjustedAfter(T, OS); } @@ -518,6 +561,7 @@ void TypePrinter::printDependentSizedArrayBefore( SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false); printBefore(T->getElementType(), OS); } + void TypePrinter::printDependentSizedArrayAfter( const DependentSizedArrayType *T, raw_ostream &OS) { @@ -532,6 +576,7 @@ void TypePrinter::printDependentAddressSpaceBefore( const DependentAddressSpaceType *T, raw_ostream &OS) { printBefore(T->getPointeeType(), OS); } + void TypePrinter::printDependentAddressSpaceAfter( const DependentAddressSpaceType *T, raw_ostream &OS) { OS << " __attribute__((address_space("; @@ -546,6 +591,7 @@ void TypePrinter::printDependentSizedExtVectorBefore( raw_ostream &OS) { printBefore(T->getElementType(), OS); } + void TypePrinter::printDependentSizedExtVectorAfter( const DependentSizedExtVectorType *T, raw_ostream &OS) { @@ -592,14 +638,64 @@ void TypePrinter::printVectorBefore(const VectorType *T, raw_ostream &OS) { } } } + void TypePrinter::printVectorAfter(const VectorType *T, raw_ostream &OS) { printAfter(T->getElementType(), OS); -} +} + +void TypePrinter::printDependentVectorBefore( + const DependentVectorType *T, raw_ostream &OS) { + switch (T->getVectorKind()) { + case VectorType::AltiVecPixel: + OS << "__vector __pixel "; + break; + case VectorType::AltiVecBool: + OS << "__vector __bool "; + printBefore(T->getElementType(), OS); + break; + case VectorType::AltiVecVector: + OS << "__vector "; + printBefore(T->getElementType(), OS); + break; + case VectorType::NeonVector: + OS << "__attribute__((neon_vector_type("; + if (T->getSizeExpr()) + T->getSizeExpr()->printPretty(OS, nullptr, Policy); + OS << "))) "; + printBefore(T->getElementType(), OS); + break; + case VectorType::NeonPolyVector: + OS << "__attribute__((neon_polyvector_type("; + if (T->getSizeExpr()) + T->getSizeExpr()->printPretty(OS, nullptr, Policy); + OS << "))) "; + printBefore(T->getElementType(), OS); + break; + case VectorType::GenericVector: { + // FIXME: We prefer to print the size directly here, but have no way + // to get the size of the type. + OS << "__attribute__((__vector_size__("; + if (T->getSizeExpr()) + T->getSizeExpr()->printPretty(OS, nullptr, Policy); + OS << " * sizeof("; + print(T->getElementType(), OS, StringRef()); + OS << ")))) "; + printBefore(T->getElementType(), OS); + break; + } + } +} + +void TypePrinter::printDependentVectorAfter( + const DependentVectorType *T, raw_ostream &OS) { + printAfter(T->getElementType(), OS); +} void TypePrinter::printExtVectorBefore(const ExtVectorType *T, raw_ostream &OS) { printBefore(T->getElementType(), OS); } + void TypePrinter::printExtVectorAfter(const ExtVectorType *T, raw_ostream &OS) { printAfter(T->getElementType(), OS); OS << " __attribute__((ext_vector_type("; @@ -611,7 +707,6 @@ void FunctionProtoType::printExceptionSpecification(raw_ostream &OS, const PrintingPolicy &Policy) const { - if (hasDynamicExceptionSpec()) { OS << " throw("; if (getExceptionSpecType() == EST_MSAny) @@ -626,7 +721,9 @@ FunctionProtoType::printExceptionSpecification(raw_ostream &OS, OS << ')'; } else if (isNoexceptExceptionSpec(getExceptionSpecType())) { OS << " noexcept"; - if (getExceptionSpecType() == EST_ComputedNoexcept) { + // FIXME:Is it useful to print out the expression for a non-dependent + // noexcept specification? + if (isComputedNoexcept(getExceptionSpecType())) { OS << '('; if (getNoexceptExpr()) getNoexceptExpr()->printPretty(OS, nullptr, Policy); @@ -650,7 +747,7 @@ void TypePrinter::printFunctionProtoBefore(const FunctionProtoType *T, } } -llvm::StringRef clang::getParameterABISpelling(ParameterABI ABI) { +StringRef clang::getParameterABISpelling(ParameterABI ABI) { switch (ABI) { case ParameterABI::Ordinary: llvm_unreachable("asking for spelling of ordinary parameter ABI"); @@ -801,6 +898,8 @@ void TypePrinter::printFunctionAfter(const FunctionType::ExtInfo &Info, << Info.getRegParm() << ")))"; if (Info.getNoCallerSavedRegs()) OS << " __attribute__((no_caller_saved_registers))"; + if (Info.getNoCfCheck()) + OS << " __attribute__((nocf_check))"; } void TypePrinter::printFunctionNoProtoBefore(const FunctionNoProtoType *T, @@ -811,6 +910,7 @@ void TypePrinter::printFunctionNoProtoBefore(const FunctionNoProtoType *T, if (!PrevPHIsEmpty.get()) OS << '('; } + void TypePrinter::printFunctionNoProtoAfter(const FunctionNoProtoType *T, raw_ostream &OS) { // If needed for precedence reasons, wrap the inner part in grouping parens. @@ -840,13 +940,15 @@ void TypePrinter::printUnresolvedUsingBefore(const UnresolvedUsingType *T, raw_ostream &OS) { printTypeSpec(T->getDecl(), OS); } + void TypePrinter::printUnresolvedUsingAfter(const UnresolvedUsingType *T, - raw_ostream &OS) { } + raw_ostream &OS) {} void TypePrinter::printTypedefBefore(const TypedefType *T, raw_ostream &OS) { printTypeSpec(T->getDecl(), OS); } -void TypePrinter::printTypedefAfter(const TypedefType *T, raw_ostream &OS) { } + +void TypePrinter::printTypedefAfter(const TypedefType *T, raw_ostream &OS) {} void TypePrinter::printTypeOfExprBefore(const TypeOfExprType *T, raw_ostream &OS) { @@ -855,8 +957,9 @@ void TypePrinter::printTypeOfExprBefore(const TypeOfExprType *T, T->getUnderlyingExpr()->printPretty(OS, nullptr, Policy); spaceBeforePlaceHolder(OS); } + void TypePrinter::printTypeOfExprAfter(const TypeOfExprType *T, - raw_ostream &OS) { } + raw_ostream &OS) {} void TypePrinter::printTypeOfBefore(const TypeOfType *T, raw_ostream &OS) { OS << "typeof("; @@ -864,7 +967,8 @@ void TypePrinter::printTypeOfBefore(const TypeOfType *T, raw_ostream &OS) { OS << ')'; spaceBeforePlaceHolder(OS); } -void TypePrinter::printTypeOfAfter(const TypeOfType *T, raw_ostream &OS) { } + +void TypePrinter::printTypeOfAfter(const TypeOfType *T, raw_ostream &OS) {} void TypePrinter::printDecltypeBefore(const DecltypeType *T, raw_ostream &OS) { OS << "decltype("; @@ -873,7 +977,8 @@ void TypePrinter::printDecltypeBefore(const DecltypeType *T, raw_ostream &OS) { OS << ')'; spaceBeforePlaceHolder(OS); } -void TypePrinter::printDecltypeAfter(const DecltypeType *T, raw_ostream &OS) { } + +void TypePrinter::printDecltypeAfter(const DecltypeType *T, raw_ostream &OS) {} void TypePrinter::printUnaryTransformBefore(const UnaryTransformType *T, raw_ostream &OS) { @@ -890,6 +995,7 @@ void TypePrinter::printUnaryTransformBefore(const UnaryTransformType *T, printBefore(T->getBaseType(), OS); } + void TypePrinter::printUnaryTransformAfter(const UnaryTransformType *T, raw_ostream &OS) { IncludeStrongLifetimeRAII Strong(Policy); @@ -915,6 +1021,7 @@ void TypePrinter::printAutoBefore(const AutoType *T, raw_ostream &OS) { spaceBeforePlaceHolder(OS); } } + void TypePrinter::printAutoAfter(const AutoType *T, raw_ostream &OS) { // If the type has been deduced, do not print 'auto'. if (!T->getDeducedType().isNull()) @@ -932,6 +1039,7 @@ void TypePrinter::printDeducedTemplateSpecializationBefore( spaceBeforePlaceHolder(OS); } } + void TypePrinter::printDeducedTemplateSpecializationAfter( const DeducedTemplateSpecializationType *T, raw_ostream &OS) { // If the type has been deduced, print the deduced type. @@ -947,7 +1055,8 @@ void TypePrinter::printAtomicBefore(const AtomicType *T, raw_ostream &OS) { OS << ')'; spaceBeforePlaceHolder(OS); } -void TypePrinter::printAtomicAfter(const AtomicType *T, raw_ostream &OS) { } + +void TypePrinter::printAtomicAfter(const AtomicType *T, raw_ostream &OS) {} void TypePrinter::printPipeBefore(const PipeType *T, raw_ostream &OS) { IncludeStrongLifetimeRAII Strong(Policy); @@ -961,15 +1070,15 @@ void TypePrinter::printPipeBefore(const PipeType *T, raw_ostream &OS) { spaceBeforePlaceHolder(OS); } -void TypePrinter::printPipeAfter(const PipeType *T, raw_ostream &OS) { -} +void TypePrinter::printPipeAfter(const PipeType *T, raw_ostream &OS) {} + /// Appends the given scope to the end of a string. void TypePrinter::AppendScope(DeclContext *DC, raw_ostream &OS) { if (DC->isTranslationUnit()) return; if (DC->isFunctionOrMethod()) return; AppendScope(DC->getParent(), OS); - if (NamespaceDecl *NS = dyn_cast<NamespaceDecl>(DC)) { + if (const auto *NS = dyn_cast<NamespaceDecl>(DC)) { if (Policy.SuppressUnwrittenScope && (NS->isAnonymousNamespace() || NS->isInline())) return; @@ -977,14 +1086,13 @@ void TypePrinter::AppendScope(DeclContext *DC, raw_ostream &OS) { OS << NS->getName() << "::"; else OS << "(anonymous namespace)::"; - } else if (ClassTemplateSpecializationDecl *Spec - = dyn_cast<ClassTemplateSpecializationDecl>(DC)) { + } else if (const auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(DC)) { IncludeStrongLifetimeRAII Strong(Policy); OS << Spec->getIdentifier()->getName(); const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); printTemplateArgumentList(OS, TemplateArgs.asArray(), Policy); OS << "::"; - } else if (TagDecl *Tag = dyn_cast<TagDecl>(DC)) { + } else if (const auto *Tag = dyn_cast<TagDecl>(DC)) { if (TypedefNameDecl *Typedef = Tag->getTypedefNameForAnonDecl()) OS << Typedef->getIdentifier()->getName() << "::"; else if (Tag->getIdentifier()) @@ -1057,8 +1165,7 @@ void TypePrinter::printTag(TagDecl *D, raw_ostream &OS) { // If this is a class template specialization, print the template // arguments. - if (ClassTemplateSpecializationDecl *Spec - = dyn_cast<ClassTemplateSpecializationDecl>(D)) { + if (const auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(D)) { ArrayRef<TemplateArgument> Args; if (TypeSourceInfo *TAW = Spec->getTypeAsWritten()) { const TemplateSpecializationType *TST = @@ -1078,12 +1185,14 @@ void TypePrinter::printTag(TagDecl *D, raw_ostream &OS) { void TypePrinter::printRecordBefore(const RecordType *T, raw_ostream &OS) { printTag(T->getDecl(), OS); } -void TypePrinter::printRecordAfter(const RecordType *T, raw_ostream &OS) { } + +void TypePrinter::printRecordAfter(const RecordType *T, raw_ostream &OS) {} void TypePrinter::printEnumBefore(const EnumType *T, raw_ostream &OS) { printTag(T->getDecl(), OS); } -void TypePrinter::printEnumAfter(const EnumType *T, raw_ostream &OS) { } + +void TypePrinter::printEnumAfter(const EnumType *T, raw_ostream &OS) {} void TypePrinter::printTemplateTypeParmBefore(const TemplateTypeParmType *T, raw_ostream &OS) { @@ -1093,8 +1202,9 @@ void TypePrinter::printTemplateTypeParmBefore(const TemplateTypeParmType *T, OS << "type-parameter-" << T->getDepth() << '-' << T->getIndex(); spaceBeforePlaceHolder(OS); } + void TypePrinter::printTemplateTypeParmAfter(const TemplateTypeParmType *T, - raw_ostream &OS) { } + raw_ostream &OS) {} void TypePrinter::printSubstTemplateTypeParmBefore( const SubstTemplateTypeParmType *T, @@ -1102,6 +1212,7 @@ void TypePrinter::printSubstTemplateTypeParmBefore( IncludeStrongLifetimeRAII Strong(Policy); printBefore(T->getReplacementType(), OS); } + void TypePrinter::printSubstTemplateTypeParmAfter( const SubstTemplateTypeParmType *T, raw_ostream &OS) { @@ -1115,6 +1226,7 @@ void TypePrinter::printSubstTemplateTypeParmPackBefore( IncludeStrongLifetimeRAII Strong(Policy); printTemplateTypeParmBefore(T->getReplacedParameter(), OS); } + void TypePrinter::printSubstTemplateTypeParmPackAfter( const SubstTemplateTypeParmPackType *T, raw_ostream &OS) { @@ -1131,26 +1243,39 @@ void TypePrinter::printTemplateSpecializationBefore( printTemplateArgumentList(OS, T->template_arguments(), Policy); spaceBeforePlaceHolder(OS); } + void TypePrinter::printTemplateSpecializationAfter( const TemplateSpecializationType *T, - raw_ostream &OS) { } + raw_ostream &OS) {} void TypePrinter::printInjectedClassNameBefore(const InjectedClassNameType *T, raw_ostream &OS) { printTemplateSpecializationBefore(T->getInjectedTST(), OS); } + void TypePrinter::printInjectedClassNameAfter(const InjectedClassNameType *T, - raw_ostream &OS) { } + raw_ostream &OS) {} void TypePrinter::printElaboratedBefore(const ElaboratedType *T, raw_ostream &OS) { + if (Policy.IncludeTagDefinition && T->getOwnedTagDecl()) { + TagDecl *OwnedTagDecl = T->getOwnedTagDecl(); + assert(OwnedTagDecl->getTypeForDecl() == T->getNamedType().getTypePtr() && + "OwnedTagDecl expected to be a declaration for the type"); + PrintingPolicy SubPolicy = Policy; + SubPolicy.IncludeTagDefinition = false; + OwnedTagDecl->print(OS, SubPolicy, Indentation); + spaceBeforePlaceHolder(OS); + return; + } + // The tag definition will take care of these. if (!Policy.IncludeTagDefinition) { OS << TypeWithKeyword::getKeywordName(T->getKeyword()); if (T->getKeyword() != ETK_None) OS << " "; - NestedNameSpecifier* Qualifier = T->getQualifier(); + NestedNameSpecifier *Qualifier = T->getQualifier(); if (Qualifier) Qualifier->print(OS, Policy); } @@ -1158,8 +1283,11 @@ void TypePrinter::printElaboratedBefore(const ElaboratedType *T, ElaboratedTypePolicyRAII PolicyRAII(Policy); printBefore(T->getNamedType(), OS); } + void TypePrinter::printElaboratedAfter(const ElaboratedType *T, raw_ostream &OS) { + if (Policy.IncludeTagDefinition && T->getOwnedTagDecl()) + return; ElaboratedTypePolicyRAII PolicyRAII(Policy); printAfter(T->getNamedType(), OS); } @@ -1171,6 +1299,7 @@ void TypePrinter::printParenBefore(const ParenType *T, raw_ostream &OS) { } else printBefore(T->getInnerType(), OS); } + void TypePrinter::printParenAfter(const ParenType *T, raw_ostream &OS) { if (!HasEmptyPlaceHolder && !isa<FunctionType>(T->getInnerType())) { OS << ')'; @@ -1190,8 +1319,9 @@ void TypePrinter::printDependentNameBefore(const DependentNameType *T, OS << T->getIdentifier()->getName(); spaceBeforePlaceHolder(OS); } + void TypePrinter::printDependentNameAfter(const DependentNameType *T, - raw_ostream &OS) { } + raw_ostream &OS) {} void TypePrinter::printDependentTemplateSpecializationBefore( const DependentTemplateSpecializationType *T, raw_ostream &OS) { @@ -1209,12 +1339,13 @@ void TypePrinter::printDependentTemplateSpecializationBefore( } void TypePrinter::printDependentTemplateSpecializationAfter( - const DependentTemplateSpecializationType *T, raw_ostream &OS) { } + const DependentTemplateSpecializationType *T, raw_ostream &OS) {} void TypePrinter::printPackExpansionBefore(const PackExpansionType *T, raw_ostream &OS) { printBefore(T->getPattern(), OS); } + void TypePrinter::printPackExpansionAfter(const PackExpansionType *T, raw_ostream &OS) { printAfter(T->getPattern(), OS); @@ -1323,9 +1454,9 @@ void TypePrinter::printAttributedAfter(const AttributedType *T, OS << ')'; break; - case AttributedType::attr_vector_size: { + case AttributedType::attr_vector_size: OS << "__vector_size__("; - if (const VectorType *vector =T->getEquivalentType()->getAs<VectorType>()) { + if (const auto *vector = T->getEquivalentType()->getAs<VectorType>()) { OS << vector->getNumElements(); OS << " * sizeof("; print(vector->getElementType(), OS, StringRef()); @@ -1333,7 +1464,6 @@ void TypePrinter::printAttributedAfter(const AttributedType *T, } OS << ')'; break; - } case AttributedType::attr_neon_vector_type: case AttributedType::attr_neon_polyvector_type: { @@ -1341,7 +1471,7 @@ void TypePrinter::printAttributedAfter(const AttributedType *T, OS << "neon_vector_type("; else OS << "neon_polyvector_type("; - const VectorType *vector = T->getEquivalentType()->getAs<VectorType>(); + const auto *vector = T->getEquivalentType()->getAs<VectorType>(); OS << vector->getNumElements(); OS << ')'; break; @@ -1396,7 +1526,7 @@ void TypePrinter::printAttributedAfter(const AttributedType *T, // 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_nocf_check: OS << "nocf_check"; break; case AttributedType::attr_cdecl: OS << "cdecl"; break; case AttributedType::attr_fastcall: OS << "fastcall"; break; case AttributedType::attr_stdcall: OS << "stdcall"; break; @@ -1418,10 +1548,12 @@ void TypePrinter::printAttributedAfter(const AttributedType *T, OS << ')'; break; } + case AttributedType::attr_inteloclbicc: OS << "inteloclbicc"; break; case AttributedType::attr_preserve_most: OS << "preserve_most"; break; + case AttributedType::attr_preserve_all: OS << "preserve_all"; break; @@ -1434,8 +1566,9 @@ void TypePrinter::printObjCInterfaceBefore(const ObjCInterfaceType *T, OS << T->getDecl()->getName(); spaceBeforePlaceHolder(OS); } + void TypePrinter::printObjCInterfaceAfter(const ObjCInterfaceType *T, - raw_ostream &OS) { } + raw_ostream &OS) {} void TypePrinter::printObjCTypeParamBefore(const ObjCTypeParamType *T, raw_ostream &OS) { @@ -1457,7 +1590,7 @@ void TypePrinter::printObjCTypeParamBefore(const ObjCTypeParamType *T, } void TypePrinter::printObjCTypeParamAfter(const ObjCTypeParamType *T, - raw_ostream &OS) { } + raw_ostream &OS) {} void TypePrinter::printObjCObjectBefore(const ObjCObjectType *T, raw_ostream &OS) { @@ -1499,6 +1632,7 @@ void TypePrinter::printObjCObjectBefore(const ObjCObjectType *T, spaceBeforePlaceHolder(OS); } + void TypePrinter::printObjCObjectAfter(const ObjCObjectType *T, raw_ostream &OS) { if (T->qual_empty() && T->isUnspecializedAsWritten() && @@ -1520,7 +1654,7 @@ void TypePrinter::printObjCObjectPointerBefore(const ObjCObjectPointerType *T, } void TypePrinter::printObjCObjectPointerAfter(const ObjCObjectPointerType *T, - raw_ostream &OS) { } + raw_ostream &OS) {} static const TemplateArgument &getArgument(const TemplateArgument &A) { return A; } diff --git a/lib/AST/VTableBuilder.cpp b/lib/AST/VTableBuilder.cpp index 347c516ef6a5..0a3da024f147 100644 --- a/lib/AST/VTableBuilder.cpp +++ b/lib/AST/VTableBuilder.cpp @@ -2105,8 +2105,8 @@ void ItaniumVTableBuilder::dumpLayout(raw_ostream &Out) { const CXXMethodDecl *MD = I.second; ThunkInfoVectorTy ThunksVector = Thunks[MD]; - std::sort(ThunksVector.begin(), ThunksVector.end(), - [](const ThunkInfo &LHS, const ThunkInfo &RHS) { + llvm::sort(ThunksVector.begin(), ThunksVector.end(), + [](const ThunkInfo &LHS, const ThunkInfo &RHS) { assert(LHS.Method == nullptr && RHS.Method == nullptr); return std::tie(LHS.This, LHS.Return) < std::tie(RHS.This, RHS.Return); }); @@ -2206,9 +2206,9 @@ VTableLayout::VTableLayout(ArrayRef<size_t> VTableIndices, else this->VTableIndices = OwningArrayRef<size_t>(VTableIndices); - std::sort(this->VTableThunks.begin(), this->VTableThunks.end(), - [](const VTableLayout::VTableThunkTy &LHS, - const VTableLayout::VTableThunkTy &RHS) { + llvm::sort(this->VTableThunks.begin(), this->VTableThunks.end(), + [](const VTableLayout::VTableThunkTy &LHS, + const VTableLayout::VTableThunkTy &RHS) { assert((LHS.first != RHS.first || LHS.second == RHS.second) && "Different thunks should have unique indices!"); return LHS.first < RHS.first; @@ -2223,6 +2223,7 @@ ItaniumVTableContext::ItaniumVTableContext(ASTContext &Context) ItaniumVTableContext::~ItaniumVTableContext() {} uint64_t ItaniumVTableContext::getMethodVTableIndex(GlobalDecl GD) { + GD = GD.getCanonicalDecl(); MethodVTableIndicesTy::iterator I = MethodVTableIndices.find(GD); if (I != MethodVTableIndices.end()) return I->second; @@ -2367,8 +2368,6 @@ namespace { class VFTableBuilder { public: - typedef MicrosoftVTableContext::MethodVFTableLocation MethodVFTableLocation; - typedef llvm::DenseMap<GlobalDecl, MethodVFTableLocation> MethodVFTableLocationsTy; @@ -2398,7 +2397,7 @@ private: MethodVFTableLocationsTy MethodVFTableLocations; - /// \brief Does this class have an RTTI component? + /// Does this class have an RTTI component? bool HasRTTIComponent = false; /// MethodInfo - Contains information about a method in a vtable. @@ -2505,6 +2504,8 @@ private: for (const auto &I : MethodInfoMap) { const CXXMethodDecl *MD = I.first; const MethodInfo &MI = I.second; + assert(MD == MD->getCanonicalDecl()); + // Skip the methods that the MostDerivedClass didn't override // and the entries shadowed by return adjusting thunks. if (MD->getParent() != MostDerivedClass || MI.Shadowed) @@ -2997,7 +2998,7 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth, } // In case we need a return adjustment, we'll add a new slot for - // the overrider. Mark the overriden method as shadowed by the new slot. + // the overrider. Mark the overridden method as shadowed by the new slot. OverriddenMethodInfo.Shadowed = true; // Force a special name mangling for a return-adjusting thunk @@ -3344,8 +3345,8 @@ static bool rebucketPaths(VPtrInfoVector &Paths) { PathsSorted.reserve(Paths.size()); for (auto& P : Paths) PathsSorted.push_back(*P); - std::sort(PathsSorted.begin(), PathsSorted.end(), - [](const VPtrInfo &LHS, const VPtrInfo &RHS) { + llvm::sort(PathsSorted.begin(), PathsSorted.end(), + [](const VPtrInfo &LHS, const VPtrInfo &RHS) { return LHS.MangledPath < RHS.MangledPath; }); bool Changed = false; @@ -3544,6 +3545,18 @@ static void computeFullPathsForVFTables(ASTContext &Context, } } +static bool vfptrIsEarlierInMDC(const ASTRecordLayout &Layout, + const MethodVFTableLocation &LHS, + const MethodVFTableLocation &RHS) { + CharUnits L = LHS.VFPtrOffset; + CharUnits R = RHS.VFPtrOffset; + if (LHS.VBase) + L += Layout.getVBaseClassOffset(LHS.VBase); + if (RHS.VBase) + R += Layout.getVBaseClassOffset(RHS.VBase); + return L < R; +} + void MicrosoftVTableContext::computeVTableRelatedInformation( const CXXRecordDecl *RD) { assert(RD->isDynamicClass()); @@ -3555,14 +3568,14 @@ void MicrosoftVTableContext::computeVTableRelatedInformation( const VTableLayout::AddressPointsMapTy EmptyAddressPointsMap; { - VPtrInfoVector VFPtrs; - computeVTablePaths(/*ForVBTables=*/false, RD, VFPtrs); - computeFullPathsForVFTables(Context, RD, VFPtrs); + auto VFPtrs = llvm::make_unique<VPtrInfoVector>(); + computeVTablePaths(/*ForVBTables=*/false, RD, *VFPtrs); + computeFullPathsForVFTables(Context, RD, *VFPtrs); VFPtrLocations[RD] = std::move(VFPtrs); } MethodVFTableLocationsTy NewMethodLocations; - for (const std::unique_ptr<VPtrInfo> &VFPtr : VFPtrLocations[RD]) { + for (const std::unique_ptr<VPtrInfo> &VFPtr : *VFPtrLocations[RD]) { VFTableBuilder Builder(*this, RD, *VFPtr); VFTableIdTy id(RD, VFPtr->FullOffsetInMDC); @@ -3574,12 +3587,15 @@ void MicrosoftVTableContext::computeVTableRelatedInformation( EmptyAddressPointsMap); Thunks.insert(Builder.thunks_begin(), Builder.thunks_end()); + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); for (const auto &Loc : Builder.vtable_locations()) { - GlobalDecl GD = Loc.first; - MethodVFTableLocation NewLoc = Loc.second; - auto M = NewMethodLocations.find(GD); - if (M == NewMethodLocations.end() || NewLoc < M->second) - NewMethodLocations[GD] = NewLoc; + auto Insert = NewMethodLocations.insert(Loc); + if (!Insert.second) { + const MethodVFTableLocation &NewLoc = Loc.second; + MethodVFTableLocation &OldLoc = Insert.first->second; + if (vfptrIsEarlierInMDC(Layout, NewLoc, OldLoc)) + OldLoc = NewLoc; + } } } @@ -3704,7 +3720,7 @@ MicrosoftVTableContext::getVFPtrOffsets(const CXXRecordDecl *RD) { computeVTableRelatedInformation(RD); assert(VFPtrLocations.count(RD) && "Couldn't find vfptr locations"); - return VFPtrLocations[RD]; + return *VFPtrLocations[RD]; } const VTableLayout & @@ -3717,13 +3733,15 @@ MicrosoftVTableContext::getVFTableLayout(const CXXRecordDecl *RD, return *VFTableLayouts[id]; } -const MicrosoftVTableContext::MethodVFTableLocation & +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); + GD = GD.getCanonicalDecl(); + MethodVFTableLocationsTy::iterator I = MethodVFTableLocations.find(GD); if (I != MethodVFTableLocations.end()) return I->second; |