diff options
Diffstat (limited to 'clang/lib/AST')
74 files changed, 2873 insertions, 2772 deletions
diff --git a/clang/lib/AST/APValue.cpp b/clang/lib/AST/APValue.cpp index ee3dc84..2d62209 100644 --- a/clang/lib/AST/APValue.cpp +++ b/clang/lib/AST/APValue.cpp @@ -902,8 +902,9 @@ void APValue::printPretty(raw_ostream &Out, const PrintingPolicy &Policy, } case APValue::Struct: { Out << '{'; - const RecordDecl *RD = Ty->castAs<RecordType>()->getDecl(); bool First = true; + const RecordDecl *RD = + Ty->castAs<RecordType>()->getOriginalDecl()->getDefinitionOrSelf(); if (unsigned N = getStructNumBases()) { const CXXRecordDecl *CD = cast<CXXRecordDecl>(RD); CXXRecordDecl::base_class_const_iterator BI = CD->bases_begin(); diff --git a/clang/lib/AST/ASTConcept.cpp b/clang/lib/AST/ASTConcept.cpp index 2243ac0..d658890 100644 --- a/clang/lib/AST/ASTConcept.cpp +++ b/clang/lib/AST/ASTConcept.cpp @@ -14,6 +14,7 @@ #include "clang/AST/ASTConcept.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ExprConcepts.h" +#include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/PrettyPrinter.h" #include "llvm/ADT/StringExtras.h" @@ -92,10 +93,16 @@ ConceptReference::Create(const ASTContext &C, NestedNameSpecifierLoc NNS, FoundDecl, NamedConcept, ArgsAsWritten); } +SourceLocation ConceptReference::getBeginLoc() const { + // Note that if the qualifier is null the template KW must also be null. + if (auto QualifierLoc = getNestedNameSpecifierLoc()) + return QualifierLoc.getBeginLoc(); + return getConceptNameInfo().getBeginLoc(); +} + void ConceptReference::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy) const { - if (NestedNameSpec) - NestedNameSpec.getNestedNameSpecifier()->print(OS, Policy); + NestedNameSpec.getNestedNameSpecifier().print(OS, Policy); ConceptName.printName(OS, Policy); if (hasExplicitTemplateArgs()) { OS << "<"; diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 3a16111..95dd426 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -654,7 +654,7 @@ comments::FullComment *ASTContext::getCommentForDecl( // does not have one of its own. QualType QT = TD->getUnderlyingType(); if (const auto *TT = QT->getAs<TagType>()) - if (const Decl *TD = TT->getDecl()) + if (const Decl *TD = TT->getOriginalDecl()) if (comments::FullComment *FC = getCommentForDecl(TD, PP)) return cloneFullComment(FC, D); } @@ -1933,10 +1933,12 @@ TypeInfoChars 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 auto *RT = T->getAs<RecordType>(); - RT && !RT->getDecl()->isInvalidDecl()) { - const ASTRecordLayout &layout = getASTRecordLayout(RT->getDecl()); - Info.Width = layout.getDataSize(); + if (const auto *RT = T->getAs<RecordType>()) { + const auto *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); + if (!RD->isInvalidDecl()) { + const ASTRecordLayout &layout = getASTRecordLayout(RD); + Info.Width = layout.getDataSize(); + } } } @@ -2003,8 +2005,9 @@ bool ASTContext::isPromotableIntegerType(QualType T) 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 auto *ET = T->getAs<EnumType>()) { - if (T->isDependentType() || ET->getDecl()->getPromotionType().isNull() || - ET->getDecl()->isScoped()) + const EnumDecl *ED = ET->getOriginalDecl()->getDefinitionOrSelf(); + if (T->isDependentType() || ED->getPromotionType().isNull() || + ED->isScoped()) return false; return true; @@ -2040,8 +2043,8 @@ unsigned ASTContext::getTypeAlignIfKnown(QualType T, return Align; // Otherwise, see if the declaration of the type had an attribute. - if (const auto *TT = T->getAs<TagType>()) - return TT->getDecl()->getMaxAlignment(); + if (const auto *TD = T->getAsTagDecl()) + return TD->getMaxAlignment(); return 0; } @@ -2472,15 +2475,16 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { case Type::Record: case Type::Enum: { const auto *TT = cast<TagType>(T); + const TagDecl *TD = TT->getOriginalDecl()->getDefinitionOrSelf(); - if (TT->getDecl()->isInvalidDecl()) { + if (TD->isInvalidDecl()) { Width = 8; Align = 8; break; } - if (const auto *ET = dyn_cast<EnumType>(TT)) { - const EnumDecl *ED = ET->getDecl(); + if (isa<EnumType>(TT)) { + const EnumDecl *ED = cast<EnumDecl>(TD); TypeInfo Info = getTypeInfo(ED->getIntegerType()->getUnqualifiedDesugaredType()); if (unsigned AttrAlign = ED->getMaxAlignment()) { @@ -2490,8 +2494,7 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { return Info; } - const auto *RT = cast<RecordType>(TT); - const RecordDecl *RD = RT->getDecl(); + const auto *RD = cast<RecordDecl>(TD); const ASTRecordLayout &Layout = getASTRecordLayout(RD); Width = toBits(Layout.getSize()); Align = toBits(Layout.getAlignment()); @@ -2543,9 +2546,6 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { break; } - case Type::Elaborated: - return getTypeInfo(cast<ElaboratedType>(T)->getNamedType().getTypePtr()); - case Type::Attributed: return getTypeInfo( cast<AttributedType>(T)->getEquivalentType().getTypePtr()); @@ -2619,8 +2619,7 @@ unsigned ASTContext::getTypeUnadjustedAlign(const Type *T) const { unsigned UnadjustedAlign; if (const auto *RT = T->getAs<RecordType>()) { - const RecordDecl *RD = RT->getDecl(); - const ASTRecordLayout &Layout = getASTRecordLayout(RD); + const ASTRecordLayout &Layout = getASTRecordLayout(RT->getOriginalDecl()); UnadjustedAlign = toBits(Layout.getUnadjustedAlignment()); } else if (const auto *ObjCI = T->getAs<ObjCInterfaceType>()) { const ASTRecordLayout &Layout = getASTObjCInterfaceLayout(ObjCI->getDecl()); @@ -2696,7 +2695,7 @@ unsigned ASTContext::getPreferredTypeAlign(const Type *T) const { return ABIAlign; if (const auto *RT = T->getAs<RecordType>()) { - const RecordDecl *RD = RT->getDecl(); + const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); // When used as part of a typedef, or together with a 'packed' attribute, // the 'aligned' attribute can be used to decrease alignment. Note that the @@ -2719,7 +2718,10 @@ unsigned ASTContext::getPreferredTypeAlign(const Type *T) const { if (const auto *CT = T->getAs<ComplexType>()) T = CT->getElementType().getTypePtr(); if (const auto *ET = T->getAs<EnumType>()) - T = ET->getDecl()->getIntegerType().getTypePtr(); + T = ET->getOriginalDecl() + ->getDefinitionOrSelf() + ->getIntegerType() + .getTypePtr(); if (T->isSpecificBuiltinType(BuiltinType::Double) || T->isSpecificBuiltinType(BuiltinType::LongLong) || T->isSpecificBuiltinType(BuiltinType::ULongLong) || @@ -2851,7 +2853,8 @@ static bool unionHasUniqueObjectRepresentations(const ASTContext &Context, const RecordDecl *RD, bool CheckIfTriviallyCopyable) { assert(RD->isUnion() && "Must be union type"); - CharUnits UnionSize = Context.getTypeSizeInChars(RD->getTypeForDecl()); + CharUnits UnionSize = + Context.getTypeSizeInChars(Context.getCanonicalTagType(RD)); for (const auto *Field : RD->fields()) { if (!Context.hasUniqueObjectRepresentations(Field->getType(), @@ -3045,7 +3048,8 @@ bool ASTContext::hasUniqueObjectRepresentations( return !ABI->getMemberPointerInfo(MPT).HasPadding; if (Ty->isRecordType()) { - const RecordDecl *Record = Ty->castAs<RecordType>()->getDecl(); + const RecordDecl *Record = + Ty->castAs<RecordType>()->getOriginalDecl()->getDefinitionOrSelf(); if (Record->isInvalidDecl()) return false; @@ -3418,7 +3422,10 @@ static void encodeTypeForFunctionPointerAuth(const ASTContext &Ctx, // type, or an unsigned integer type. // // So we have to treat enum types as integers. - QualType UnderlyingType = cast<EnumType>(T)->getDecl()->getIntegerType(); + QualType UnderlyingType = cast<EnumType>(T) + ->getOriginalDecl() + ->getDefinitionOrSelf() + ->getIntegerType(); return encodeTypeForFunctionPointerAuth( Ctx, OS, UnderlyingType.isNull() ? Ctx.IntTy : UnderlyingType); } @@ -3456,7 +3463,7 @@ static void encodeTypeForFunctionPointerAuth(const ASTContext &Ctx, OS << "M"; const auto *MPT = T->castAs<MemberPointerType>(); encodeTypeForFunctionPointerAuth( - Ctx, OS, QualType(MPT->getQualifier()->getAsType(), 0)); + Ctx, OS, QualType(MPT->getQualifier().getAsType(), 0)); encodeTypeForFunctionPointerAuth(Ctx, OS, MPT->getPointeeType()); return; } @@ -3562,7 +3569,8 @@ static void encodeTypeForFunctionPointerAuth(const ASTContext &Ctx, llvm_unreachable("should never get here"); } case Type::Record: { - const RecordDecl *RD = T->castAs<RecordType>()->getDecl(); + const RecordDecl *RD = + T->castAs<RecordType>()->getOriginalDecl()->getDefinitionOrSelf(); const IdentifierInfo *II = RD->getIdentifier(); // In C++, an immediate typedef of an anonymous struct or union @@ -3740,12 +3748,6 @@ ASTContext::adjustType(QualType Orig, adjustType(BTFT->getWrappedType(), Adjust)); } - case Type::Elaborated: { - const auto *ET = cast<ElaboratedType>(Orig); - return getElaboratedType(ET->getKeyword(), ET->getQualifier(), - adjustType(ET->getNamedType(), Adjust)); - } - case Type::Paren: return getParenType( adjustType(cast<ParenType>(Orig)->getInnerType(), Adjust)); @@ -4163,14 +4165,13 @@ QualType ASTContext::getRValueReferenceType(QualType T) const { } QualType ASTContext::getMemberPointerType(QualType T, - NestedNameSpecifier *Qualifier, + NestedNameSpecifier Qualifier, const CXXRecordDecl *Cls) const { if (!Qualifier) { assert(Cls && "At least one of Qualifier or Cls must be provided"); - Qualifier = NestedNameSpecifier::Create(*this, /*Prefix=*/nullptr, - getTypeDeclType(Cls).getTypePtr()); + Qualifier = NestedNameSpecifier(getCanonicalTagType(Cls).getTypePtr()); } else if (!Cls) { - Cls = Qualifier->getAsRecordDecl(); + Cls = Qualifier.getAsRecordDecl(); } // Unique pointers, to guarantee there is only one pointer of a particular // structure. @@ -4182,12 +4183,11 @@ QualType ASTContext::getMemberPointerType(QualType T, MemberPointerTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(PT, 0); - NestedNameSpecifier *CanonicalQualifier = [&] { + NestedNameSpecifier CanonicalQualifier = [&] { if (!Cls) - return getCanonicalNestedNameSpecifier(Qualifier); - NestedNameSpecifier *R = NestedNameSpecifier::Create( - *this, /*Prefix=*/nullptr, Cls->getCanonicalDecl()->getTypeForDecl()); - assert(R == getCanonicalNestedNameSpecifier(R)); + return Qualifier.getCanonical(); + NestedNameSpecifier R(getCanonicalTagType(Cls).getTypePtr()); + assert(R.isCanonical()); return R; }(); // If the pointee or class type isn't canonical, this won't be a canonical @@ -5245,7 +5245,6 @@ ASTContext::getPredefinedSugarType(PredefinedSugarType::Kind KD) const { } llvm_unreachable("unexpected kind"); }; - auto *New = new (*this, alignof(PredefinedSugarType)) PredefinedSugarType(KD, &Idents.get(PredefinedSugarType::getName(KD)), getCanonicalType(*this, static_cast<Kind>(KD))); @@ -5254,153 +5253,297 @@ ASTContext::getPredefinedSugarType(PredefinedSugarType::Kind KD) const { return QualType(New, 0); } -#ifndef NDEBUG -static bool NeedsInjectedClassNameType(const RecordDecl *D) { - if (!isa<CXXRecordDecl>(D)) return false; - const auto *RD = cast<CXXRecordDecl>(D); - if (isa<ClassTemplatePartialSpecializationDecl>(RD)) - return true; - if (RD->getDescribedClassTemplate() && - !isa<ClassTemplateSpecializationDecl>(RD)) - return true; - return false; -} -#endif +QualType ASTContext::getTypeDeclType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, + const TypeDecl *Decl) const { + if (auto *Tag = dyn_cast<TagDecl>(Decl)) + return getTagType(Keyword, Qualifier, Tag, + /*OwnsTag=*/false); + if (auto *Typedef = dyn_cast<TypedefNameDecl>(Decl)) + return getTypedefType(Keyword, Qualifier, Typedef); + if (auto *UD = dyn_cast<UnresolvedUsingTypenameDecl>(Decl)) + return getUnresolvedUsingType(Keyword, Qualifier, UD); -/// getInjectedClassNameType - Return the unique reference to the -/// injected class name type for the specified templated declaration. -QualType ASTContext::getInjectedClassNameType(CXXRecordDecl *Decl, - QualType TST) const { - assert(NeedsInjectedClassNameType(Decl)); - if (Decl->TypeForDecl) { - assert(isa<InjectedClassNameType>(Decl->TypeForDecl)); - } else if (CXXRecordDecl *PrevDecl = Decl->getPreviousDecl()) { - assert(PrevDecl->TypeForDecl && "previous declaration has no type"); - Decl->TypeForDecl = PrevDecl->TypeForDecl; - assert(isa<InjectedClassNameType>(Decl->TypeForDecl)); - } else { - Type *newType = new (*this, alignof(InjectedClassNameType)) - InjectedClassNameType(Decl, TST); - Decl->TypeForDecl = newType; - Types.push_back(newType); - } + assert(Keyword == ElaboratedTypeKeyword::None); + assert(!Qualifier); return QualType(Decl->TypeForDecl, 0); } -/// getTypeDeclType - Return the unique reference to the type for the -/// specified type declaration. -QualType ASTContext::getTypeDeclTypeSlow(const TypeDecl *Decl) const { - assert(Decl && "Passed null for Decl param"); - assert(!Decl->TypeForDecl && "TypeForDecl present in slow case"); - - if (const auto *Typedef = dyn_cast<TypedefNameDecl>(Decl)) - return getTypedefType(Typedef); - - assert(!isa<TemplateTypeParmDecl>(Decl) && - "Template type parameter types are always available."); - - 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 auto *Enum = dyn_cast<EnumDecl>(Decl)) { - assert(Enum->isFirstDecl() && "enum has previous declaration"); - return getEnumType(Enum); - } else if (const auto *Using = dyn_cast<UnresolvedUsingTypenameDecl>(Decl)) { - return getUnresolvedUsingType(Using); - } else - llvm_unreachable("TypeDecl without a type?"); - +CanQualType ASTContext::getCanonicalTypeDeclType(const TypeDecl *TD) const { + if (auto *Tag = dyn_cast<TagDecl>(TD)) + return getCanonicalTagType(Tag); + if (auto *TN = dyn_cast<TypedefNameDecl>(TD)) + return getCanonicalType(TN->getUnderlyingType()); + if (const auto *UD = dyn_cast<UnresolvedUsingTypenameDecl>(TD)) + return getCanonicalUnresolvedUsingType(UD); + assert(TD->TypeForDecl); + return TD->TypeForDecl->getCanonicalTypeUnqualified(); +} + +QualType ASTContext::getTypeDeclType(const TypeDecl *Decl) const { + if (const auto *TD = dyn_cast<TagDecl>(Decl)) + return getCanonicalTagType(TD); + if (const auto *TD = dyn_cast<TypedefNameDecl>(Decl); + isa_and_nonnull<TypedefDecl, TypeAliasDecl>(TD)) + return getTypedefType(ElaboratedTypeKeyword::None, + /*Qualifier=*/std::nullopt, TD); + if (const auto *Using = dyn_cast<UnresolvedUsingTypenameDecl>(Decl)) + return getCanonicalUnresolvedUsingType(Using); + + assert(Decl->TypeForDecl); return QualType(Decl->TypeForDecl, 0); } /// getTypedefType - Return the unique reference to the type for the /// specified typedef name decl. -QualType ASTContext::getTypedefType(const TypedefNameDecl *Decl, - QualType Underlying) const { - if (!Decl->TypeForDecl) { - if (Underlying.isNull()) - Underlying = Decl->getUnderlyingType(); - auto *NewType = new (*this, alignof(TypedefType)) TypedefType( - Type::Typedef, Decl, Underlying, /*HasTypeDifferentFromDecl=*/false); - Decl->TypeForDecl = NewType; +QualType +ASTContext::getTypedefType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, + const TypedefNameDecl *Decl, QualType UnderlyingType, + std::optional<bool> TypeMatchesDeclOrNone) const { + if (!TypeMatchesDeclOrNone) { + QualType DeclUnderlyingType = Decl->getUnderlyingType(); + assert(!DeclUnderlyingType.isNull()); + if (UnderlyingType.isNull()) + UnderlyingType = DeclUnderlyingType; + else + assert(hasSameType(UnderlyingType, DeclUnderlyingType)); + TypeMatchesDeclOrNone = UnderlyingType == DeclUnderlyingType; + } else { + // FIXME: This is a workaround for a serialization cycle: assume the decl + // underlying type is not available; don't touch it. + assert(!UnderlyingType.isNull()); + } + + if (Keyword == ElaboratedTypeKeyword::None && !Qualifier && + *TypeMatchesDeclOrNone) { + if (Decl->TypeForDecl) + return QualType(Decl->TypeForDecl, 0); + + auto *NewType = new (*this, alignof(TypedefType)) + TypedefType(Type::Typedef, Keyword, Qualifier, Decl, UnderlyingType, + !*TypeMatchesDeclOrNone); + Types.push_back(NewType); + Decl->TypeForDecl = NewType; return QualType(NewType, 0); } - if (Underlying.isNull() || Decl->getUnderlyingType() == Underlying) - return QualType(Decl->TypeForDecl, 0); - assert(hasSameType(Decl->getUnderlyingType(), Underlying)); llvm::FoldingSetNodeID ID; - TypedefType::Profile(ID, Decl, Underlying); + TypedefType::Profile(ID, Keyword, Qualifier, Decl, UnderlyingType); void *InsertPos = nullptr; - if (TypedefType *T = TypedefTypes.FindNodeOrInsertPos(ID, InsertPos)) { - assert(!T->typeMatchesDecl() && - "non-divergent case should be handled with TypeDecl"); - return QualType(T, 0); - } + if (FoldingSetPlaceholder<TypedefType> *Placeholder = + TypedefTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(Placeholder->getType(), 0); - void *Mem = Allocate(TypedefType::totalSizeToAlloc<QualType>(true), - alignof(TypedefType)); - auto *NewType = new (Mem) TypedefType(Type::Typedef, Decl, Underlying, - /*HasTypeDifferentFromDecl=*/true); - TypedefTypes.InsertNode(NewType, InsertPos); + void *Mem = + Allocate(TypedefType::totalSizeToAlloc<FoldingSetPlaceholder<TypedefType>, + NestedNameSpecifier, QualType>( + 1, !!Qualifier, !*TypeMatchesDeclOrNone), + alignof(TypedefType)); + auto *NewType = + new (Mem) TypedefType(Type::Typedef, Keyword, Qualifier, Decl, + UnderlyingType, !*TypeMatchesDeclOrNone); + auto *Placeholder = new (NewType->getFoldingSetPlaceholder()) + FoldingSetPlaceholder<TypedefType>(); + TypedefTypes.InsertNode(Placeholder, InsertPos); Types.push_back(NewType); return QualType(NewType, 0); } -QualType ASTContext::getUsingType(const UsingShadowDecl *Found, - QualType Underlying) const { +QualType ASTContext::getUsingType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, + const UsingShadowDecl *D, + QualType UnderlyingType) const { + // FIXME: This is expensive to compute every time! + if (UnderlyingType.isNull()) { + const auto *UD = cast<UsingDecl>(D->getIntroducer()); + UnderlyingType = + getTypeDeclType(UD->hasTypename() ? ElaboratedTypeKeyword::Typename + : ElaboratedTypeKeyword::None, + UD->getQualifier(), cast<TypeDecl>(D->getTargetDecl())); + } + llvm::FoldingSetNodeID ID; - UsingType::Profile(ID, Found, Underlying); + UsingType::Profile(ID, Keyword, Qualifier, D, UnderlyingType); void *InsertPos = nullptr; - if (UsingType *T = UsingTypes.FindNodeOrInsertPos(ID, InsertPos)) + if (const UsingType *T = UsingTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(T, 0); - const Type *TypeForDecl = - cast<TypeDecl>(Found->getTargetDecl())->getTypeForDecl(); + assert(!UnderlyingType.hasLocalQualifiers()); - assert(!Underlying.hasLocalQualifiers()); - QualType Canon = Underlying->getCanonicalTypeInternal(); - assert(TypeForDecl->getCanonicalTypeInternal() == Canon); + assert( + hasSameType(getCanonicalTypeDeclType(cast<TypeDecl>(D->getTargetDecl())), + UnderlyingType)); - if (Underlying.getTypePtr() == TypeForDecl) - Underlying = QualType(); void *Mem = - Allocate(UsingType::totalSizeToAlloc<QualType>(!Underlying.isNull()), + Allocate(UsingType::totalSizeToAlloc<NestedNameSpecifier>(!!Qualifier), alignof(UsingType)); - UsingType *NewType = new (Mem) UsingType(Found, Underlying, Canon); - Types.push_back(NewType); - UsingTypes.InsertNode(NewType, InsertPos); - return QualType(NewType, 0); + UsingType *T = new (Mem) UsingType(Keyword, Qualifier, D, UnderlyingType); + Types.push_back(T); + UsingTypes.InsertNode(T, InsertPos); + return QualType(T, 0); } -QualType ASTContext::getRecordType(const RecordDecl *Decl) const { - if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0); +TagType *ASTContext::getTagTypeInternal(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, + const TagDecl *TD, bool OwnsTag, + bool IsInjected, + const Type *CanonicalType, + bool WithFoldingSetNode) const { + auto [TC, Size] = [&] { + switch (TD->getDeclKind()) { + case Decl::Enum: + static_assert(alignof(EnumType) == alignof(TagType)); + return std::make_tuple(Type::Enum, sizeof(EnumType)); + case Decl::ClassTemplatePartialSpecialization: + case Decl::ClassTemplateSpecialization: + case Decl::CXXRecord: + static_assert(alignof(RecordType) == alignof(TagType)); + static_assert(alignof(InjectedClassNameType) == alignof(TagType)); + if (cast<CXXRecordDecl>(TD)->hasInjectedClassType()) + return std::make_tuple(Type::InjectedClassName, + sizeof(InjectedClassNameType)); + [[fallthrough]]; + case Decl::Record: + return std::make_tuple(Type::Record, sizeof(RecordType)); + default: + llvm_unreachable("unexpected decl kind"); + } + }(); - if (const RecordDecl *PrevDecl = Decl->getPreviousDecl()) - if (PrevDecl->TypeForDecl) - return QualType(Decl->TypeForDecl = PrevDecl->TypeForDecl, 0); + if (Qualifier) { + static_assert(alignof(NestedNameSpecifier) <= alignof(TagType)); + Size = llvm::alignTo(Size, alignof(NestedNameSpecifier)) + + sizeof(NestedNameSpecifier); + } + void *Mem; + if (WithFoldingSetNode) { + // FIXME: It would be more profitable to tail allocate the folding set node + // from the type, instead of the other way around, due to the greater + // alignment requirements of the type. But this makes it harder to deal with + // the different type node sizes. This would require either uniquing from + // different folding sets, or having the folding setaccept a + // contextual parameter which is not fixed at construction. + Mem = Allocate( + sizeof(TagTypeFoldingSetPlaceholder) + + TagTypeFoldingSetPlaceholder::getOffset() + Size, + std::max(alignof(TagTypeFoldingSetPlaceholder), alignof(TagType))); + auto *T = new (Mem) TagTypeFoldingSetPlaceholder(); + Mem = T->getTagType(); + } else { + Mem = Allocate(Size, alignof(TagType)); + } + + auto *T = [&, TC = TC]() -> TagType * { + switch (TC) { + case Type::Enum: { + assert(isa<EnumDecl>(TD)); + auto *T = new (Mem) EnumType(TC, Keyword, Qualifier, TD, OwnsTag, + IsInjected, CanonicalType); + assert(reinterpret_cast<void *>(T) == + reinterpret_cast<void *>(static_cast<TagType *>(T)) && + "TagType must be the first base of EnumType"); + return T; + } + case Type::Record: { + assert(isa<RecordDecl>(TD)); + auto *T = new (Mem) RecordType(TC, Keyword, Qualifier, TD, OwnsTag, + IsInjected, CanonicalType); + assert(reinterpret_cast<void *>(T) == + reinterpret_cast<void *>(static_cast<TagType *>(T)) && + "TagType must be the first base of RecordType"); + return T; + } + case Type::InjectedClassName: { + auto *T = new (Mem) InjectedClassNameType(Keyword, Qualifier, TD, + IsInjected, CanonicalType); + assert(reinterpret_cast<void *>(T) == + reinterpret_cast<void *>(static_cast<TagType *>(T)) && + "TagType must be the first base of InjectedClassNameType"); + return T; + } + default: + llvm_unreachable("unexpected type class"); + } + }(); + assert(T->getKeyword() == Keyword); + assert(T->getQualifier() == Qualifier); + assert(T->getOriginalDecl() == TD); + assert(T->isInjected() == IsInjected); + assert(T->isTagOwned() == OwnsTag); + assert((T->isCanonicalUnqualified() + ? QualType() + : T->getCanonicalTypeInternal()) == QualType(CanonicalType, 0)); + Types.push_back(T); + return T; +} - auto *newType = new (*this, alignof(RecordType)) RecordType(Decl); - Decl->TypeForDecl = newType; - Types.push_back(newType); - return QualType(newType, 0); +static bool getNonInjectedClassName(const TagDecl *&TD) { + if (const auto *RD = dyn_cast<CXXRecordDecl>(TD); + RD && RD->isInjectedClassName()) { + TD = cast<TagDecl>(RD->getDeclContext()); + return true; + } + return false; } -QualType ASTContext::getEnumType(const EnumDecl *Decl) const { - if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0); +CanQualType ASTContext::getCanonicalTagType(const TagDecl *TD) const { + ::getNonInjectedClassName(TD); + TD = TD->getCanonicalDecl(); + if (TD->TypeForDecl) + return TD->TypeForDecl->getCanonicalTypeUnqualified(); + + const Type *CanonicalType = getTagTypeInternal( + ElaboratedTypeKeyword::None, + /*Qualifier=*/std::nullopt, TD, + /*OwnsTag=*/false, /*IsInjected=*/false, /*CanonicalType=*/nullptr, + /*WithFoldingSetNode=*/false); + TD->TypeForDecl = CanonicalType; + return CanQualType::CreateUnsafe(QualType(CanonicalType, 0)); +} + +QualType ASTContext::getTagType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, + const TagDecl *TD, bool OwnsTag) const { + ElaboratedTypeKeyword PreferredKeyword = + getLangOpts().CPlusPlus + ? ElaboratedTypeKeyword::None + : KeywordHelpers::getKeywordForTagTypeKind(TD->getTagKind()); + + if (Keyword == PreferredKeyword && !Qualifier && !OwnsTag) { + if (const Type *T = TD->TypeForDecl; T && !T->isCanonicalUnqualified()) + return QualType(T, 0); + + bool IsInjected = ::getNonInjectedClassName(TD); + const Type *CanonicalType = getCanonicalTagType(TD).getTypePtr(); + const Type *T = + getTagTypeInternal(Keyword, + /*Qualifier=*/std::nullopt, TD, + /*OwnsTag=*/false, IsInjected, CanonicalType, + /*WithFoldingSetNode=*/false); + TD->TypeForDecl = T; + return QualType(T, 0); + } + + bool IsInjected = ::getNonInjectedClassName(TD); - if (const EnumDecl *PrevDecl = Decl->getPreviousDecl()) - if (PrevDecl->TypeForDecl) - return QualType(Decl->TypeForDecl = PrevDecl->TypeForDecl, 0); + llvm::FoldingSetNodeID ID; + TagTypeFoldingSetPlaceholder::Profile(ID, Keyword, Qualifier, TD, OwnsTag, + IsInjected); - auto *newType = new (*this, alignof(EnumType)) EnumType(Decl); - Decl->TypeForDecl = newType; - Types.push_back(newType); - return QualType(newType, 0); + void *InsertPos = nullptr; + if (TagTypeFoldingSetPlaceholder *T = + TagTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(T->getTagType(), 0); + + const Type *CanonicalType = getCanonicalTagType(TD).getTypePtr(); + TagType *T = getTagTypeInternal(Keyword, Qualifier, TD, OwnsTag, IsInjected, + CanonicalType, /*WithFoldingSetNode=*/true); + TagTypes.InsertNode(TagTypeFoldingSetPlaceholder::fromTagType(T), InsertPos); + return QualType(T, 0); } bool ASTContext::computeBestEnumTypes(bool IsPacked, unsigned NumNegativeBits, @@ -5495,21 +5638,69 @@ bool ASTContext::isRepresentableIntegerValue(llvm::APSInt &Value, QualType T) { return Value.getSignificantBits() <= BitWidth; } -QualType ASTContext::getUnresolvedUsingType( - const UnresolvedUsingTypenameDecl *Decl) const { - if (Decl->TypeForDecl) - return QualType(Decl->TypeForDecl, 0); +UnresolvedUsingType *ASTContext::getUnresolvedUsingTypeInternal( + ElaboratedTypeKeyword Keyword, NestedNameSpecifier Qualifier, + const UnresolvedUsingTypenameDecl *D, void *InsertPos, + const Type *CanonicalType) const { + void *Mem = Allocate( + UnresolvedUsingType::totalSizeToAlloc< + FoldingSetPlaceholder<UnresolvedUsingType>, NestedNameSpecifier>( + !!InsertPos, !!Qualifier), + alignof(UnresolvedUsingType)); + auto *T = new (Mem) UnresolvedUsingType(Keyword, Qualifier, D, CanonicalType); + if (InsertPos) { + auto *Placeholder = new (T->getFoldingSetPlaceholder()) + FoldingSetPlaceholder<TypedefType>(); + TypedefTypes.InsertNode(Placeholder, InsertPos); + } + Types.push_back(T); + return T; +} - if (const UnresolvedUsingTypenameDecl *CanonicalDecl = - Decl->getCanonicalDecl()) - if (CanonicalDecl->TypeForDecl) - return QualType(Decl->TypeForDecl = CanonicalDecl->TypeForDecl, 0); +CanQualType ASTContext::getCanonicalUnresolvedUsingType( + const UnresolvedUsingTypenameDecl *D) const { + D = D->getCanonicalDecl(); + if (D->TypeForDecl) + return D->TypeForDecl->getCanonicalTypeUnqualified(); - Type *newType = - new (*this, alignof(UnresolvedUsingType)) UnresolvedUsingType(Decl); - Decl->TypeForDecl = newType; - Types.push_back(newType); - return QualType(newType, 0); + const Type *CanonicalType = getUnresolvedUsingTypeInternal( + ElaboratedTypeKeyword::None, + /*Qualifier=*/std::nullopt, D, + /*InsertPos=*/nullptr, /*CanonicalType=*/nullptr); + D->TypeForDecl = CanonicalType; + return CanQualType::CreateUnsafe(QualType(CanonicalType, 0)); +} + +QualType +ASTContext::getUnresolvedUsingType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, + const UnresolvedUsingTypenameDecl *D) const { + if (Keyword == ElaboratedTypeKeyword::None && !Qualifier) { + if (const Type *T = D->TypeForDecl; T && !T->isCanonicalUnqualified()) + return QualType(T, 0); + + const Type *CanonicalType = getCanonicalUnresolvedUsingType(D).getTypePtr(); + const Type *T = + getUnresolvedUsingTypeInternal(ElaboratedTypeKeyword::None, + /*Qualifier=*/std::nullopt, D, + /*InsertPos=*/nullptr, CanonicalType); + D->TypeForDecl = T; + return QualType(T, 0); + } + + llvm::FoldingSetNodeID ID; + UnresolvedUsingType::Profile(ID, Keyword, Qualifier, D); + + void *InsertPos = nullptr; + if (FoldingSetPlaceholder<UnresolvedUsingType> *Placeholder = + UnresolvedUsingTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(Placeholder->getType(), 0); + assert(InsertPos); + + const Type *CanonicalType = getCanonicalUnresolvedUsingType(D).getTypePtr(); + const Type *T = getUnresolvedUsingTypeInternal(Keyword, Qualifier, D, + InsertPos, CanonicalType); + return QualType(T, 0); } QualType ASTContext::getAttributedType(attr::Kind attrKind, @@ -5729,34 +5920,32 @@ QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index, } TypeSourceInfo *ASTContext::getTemplateSpecializationTypeInfo( + ElaboratedTypeKeyword Keyword, SourceLocation ElaboratedKeywordLoc, + NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKeywordLoc, TemplateName Name, SourceLocation NameLoc, const TemplateArgumentListInfo &SpecifiedArgs, ArrayRef<TemplateArgument> CanonicalArgs, QualType Underlying) const { - QualType TST = getTemplateSpecializationType(Name, SpecifiedArgs.arguments(), - CanonicalArgs, Underlying); + QualType TST = getTemplateSpecializationType( + Keyword, Name, SpecifiedArgs.arguments(), CanonicalArgs, Underlying); TypeSourceInfo *DI = CreateTypeSourceInfo(TST); - TemplateSpecializationTypeLoc TL = - DI->getTypeLoc().castAs<TemplateSpecializationTypeLoc>(); - TL.setTemplateKeywordLoc(SourceLocation()); - TL.setTemplateNameLoc(NameLoc); - TL.setLAngleLoc(SpecifiedArgs.getLAngleLoc()); - TL.setRAngleLoc(SpecifiedArgs.getRAngleLoc()); - for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) - TL.setArgLocInfo(i, SpecifiedArgs[i].getLocInfo()); + DI->getTypeLoc().castAs<TemplateSpecializationTypeLoc>().set( + ElaboratedKeywordLoc, QualifierLoc, TemplateKeywordLoc, NameLoc, + SpecifiedArgs); return DI; } QualType ASTContext::getTemplateSpecializationType( - TemplateName Template, ArrayRef<TemplateArgumentLoc> SpecifiedArgs, + ElaboratedTypeKeyword Keyword, TemplateName Template, + ArrayRef<TemplateArgumentLoc> SpecifiedArgs, ArrayRef<TemplateArgument> CanonicalArgs, QualType Underlying) const { SmallVector<TemplateArgument, 4> SpecifiedArgVec; SpecifiedArgVec.reserve(SpecifiedArgs.size()); for (const TemplateArgumentLoc &Arg : SpecifiedArgs) SpecifiedArgVec.push_back(Arg.getArgument()); - return getTemplateSpecializationType(Template, SpecifiedArgVec, CanonicalArgs, - Underlying); + return getTemplateSpecializationType(Keyword, Template, SpecifiedArgVec, + CanonicalArgs, Underlying); } [[maybe_unused]] static bool @@ -5787,7 +5976,8 @@ QualType ASTContext::getCanonicalTemplateSpecializationType( sizeof(TemplateArgument) * Args.size(), alignof(TemplateSpecializationType)); auto *Spec = new (Mem) - TemplateSpecializationType(Template, /*IsAlias=*/false, Args, QualType()); + TemplateSpecializationType(ElaboratedTypeKeyword::None, Template, + /*IsAlias=*/false, Args, QualType()); assert(Spec->isDependentType() && "canonical template specialization must be dependent"); Types.push_back(Spec); @@ -5796,7 +5986,8 @@ QualType ASTContext::getCanonicalTemplateSpecializationType( } QualType ASTContext::getTemplateSpecializationType( - TemplateName Template, ArrayRef<TemplateArgument> SpecifiedArgs, + ElaboratedTypeKeyword Keyword, TemplateName Template, + ArrayRef<TemplateArgument> SpecifiedArgs, ArrayRef<TemplateArgument> CanonicalArgs, QualType Underlying) const { assert(!Template.getUnderlying().getAsDependentTemplateName() && "No dependent template names here!"); @@ -5806,7 +5997,8 @@ QualType ASTContext::getTemplateSpecializationType( if (Underlying.isNull()) { TemplateName CanonTemplate = getCanonicalTemplateName(Template, /*IgnoreDeduced=*/true); - bool NonCanonical = Template != CanonTemplate; + bool NonCanonical = + Template != CanonTemplate || Keyword != ElaboratedTypeKeyword::None; SmallVector<TemplateArgument, 4> CanonArgsVec; if (CanonicalArgs.empty()) { CanonArgsVec = SmallVector<TemplateArgument, 4>(SpecifiedArgs); @@ -5837,42 +6029,12 @@ QualType ASTContext::getTemplateSpecializationType( sizeof(TemplateArgument) * SpecifiedArgs.size() + (IsTypeAlias ? sizeof(QualType) : 0), alignof(TemplateSpecializationType)); - auto *Spec = new (Mem) TemplateSpecializationType(Template, IsTypeAlias, - SpecifiedArgs, Underlying); + auto *Spec = new (Mem) TemplateSpecializationType( + Keyword, Template, IsTypeAlias, SpecifiedArgs, Underlying); Types.push_back(Spec); return QualType(Spec, 0); } -QualType ASTContext::getElaboratedType(ElaboratedTypeKeyword Keyword, - NestedNameSpecifier *NNS, - QualType NamedType, - TagDecl *OwnedTagDecl) const { - llvm::FoldingSetNodeID ID; - ElaboratedType::Profile(ID, Keyword, NNS, NamedType, OwnedTagDecl); - - void *InsertPos = nullptr; - ElaboratedType *T = ElaboratedTypes.FindNodeOrInsertPos(ID, InsertPos); - if (T) - return QualType(T, 0); - - QualType Canon = NamedType; - if (!Canon.isCanonical()) { - Canon = getCanonicalType(NamedType); - ElaboratedType *CheckT = ElaboratedTypes.FindNodeOrInsertPos(ID, InsertPos); - assert(!CheckT && "Elaborated canonical type broken"); - (void)CheckT; - } - - void *Mem = - Allocate(ElaboratedType::totalSizeToAlloc<TagDecl *>(!!OwnedTagDecl), - alignof(ElaboratedType)); - T = new (Mem) ElaboratedType(Keyword, NNS, NamedType, Canon, OwnedTagDecl); - - Types.push_back(T); - ElaboratedTypes.InsertNode(T, InsertPos); - return QualType(T, 0); -} - QualType ASTContext::getParenType(QualType InnerType) const { llvm::FoldingSetNodeID ID; @@ -5935,7 +6097,7 @@ getCanonicalElaboratedTypeKeyword(ElaboratedTypeKeyword Keyword) { } QualType ASTContext::getDependentNameType(ElaboratedTypeKeyword Keyword, - NestedNameSpecifier *NNS, + NestedNameSpecifier NNS, const IdentifierInfo *Name) const { llvm::FoldingSetNodeID ID; DependentNameType::Profile(ID, Keyword, NNS, Name); @@ -5947,7 +6109,7 @@ QualType ASTContext::getDependentNameType(ElaboratedTypeKeyword Keyword, ElaboratedTypeKeyword CanonKeyword = getCanonicalElaboratedTypeKeyword(Keyword); - NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS); + NestedNameSpecifier CanonNNS = NNS.getCanonical(); QualType Canon; if (CanonKeyword != Keyword || CanonNNS != NNS) { @@ -5985,13 +6147,13 @@ QualType ASTContext::getDependentTemplateSpecializationType( T_iter != DependentTemplateSpecializationTypes.end()) return QualType(T_iter->getSecond(), 0); - NestedNameSpecifier *NNS = Name.getQualifier(); + NestedNameSpecifier NNS = Name.getQualifier(); QualType Canon; if (!IsCanonical) { ElaboratedTypeKeyword CanonKeyword = getCanonicalElaboratedTypeKeyword(Keyword); - NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS); + NestedNameSpecifier CanonNNS = NNS.getCanonical(); bool AnyNonCanonArgs = false; auto CanonArgs = ::getCanonicalTemplateArguments(*this, Args, AnyNonCanonArgs); @@ -6006,7 +6168,7 @@ QualType ASTContext::getDependentTemplateSpecializationType( } else { assert(Keyword == getCanonicalElaboratedTypeKeyword(Keyword)); assert(Name.hasTemplateKeyword()); - assert(NNS == getCanonicalNestedNameSpecifier(NNS)); + assert(NNS.isCanonical()); #ifndef NDEBUG for (const auto &Arg : Args) assert(Arg.structurallyEquals(getCanonicalTemplateArgument(Arg))); @@ -6062,7 +6224,8 @@ TemplateArgument ASTContext::getInjectedTemplateArg(NamedDecl *Param) const { } else { auto *TTP = cast<TemplateTemplateParmDecl>(Param); TemplateName Name = getQualifiedTemplateName( - nullptr, /*TemplateKeyword=*/false, TemplateName(TTP)); + /*Qualifier=*/std::nullopt, /*TemplateKeyword=*/false, + TemplateName(TTP)); if (TTP->isParameterPack()) Arg = TemplateArgument(Name, /*NumExpansions=*/std::nullopt); else @@ -6334,11 +6497,11 @@ void ASTContext::adjustObjCTypeParamBoundType(const ObjCTypeParamDecl *Orig, ObjCTypeParamDecl *New) const { New->setTypeSourceInfo(getTrivialTypeSourceInfo(Orig->getUnderlyingType())); // Update TypeForDecl after updating TypeSourceInfo. - auto NewTypeParamTy = cast<ObjCTypeParamType>(New->getTypeForDecl()); + auto *NewTypeParamTy = cast<ObjCTypeParamType>(New->TypeForDecl); SmallVector<ObjCProtocolDecl *, 8> protocols; protocols.append(NewTypeParamTy->qual_begin(), NewTypeParamTy->qual_end()); QualType UpdatedTy = getObjCTypeParamType(New, protocols); - New->setTypeForDecl(UpdatedTy.getTypePtr()); + New->TypeForDecl = UpdatedTy.getTypePtr(); } /// ObjCObjectAdoptsQTypeProtocols - Checks that protocols in IC's @@ -6737,20 +6900,20 @@ QualType ASTContext::getUnconstrainedType(QualType T) const { } QualType ASTContext::getDeducedTemplateSpecializationTypeInternal( - TemplateName Template, QualType DeducedType, bool IsDependent, - QualType Canon) const { + ElaboratedTypeKeyword Keyword, TemplateName Template, QualType DeducedType, + bool IsDependent, QualType Canon) const { // Look in the folding set for an existing type. void *InsertPos = nullptr; llvm::FoldingSetNodeID ID; - DeducedTemplateSpecializationType::Profile(ID, Template, DeducedType, + DeducedTemplateSpecializationType::Profile(ID, Keyword, Template, DeducedType, IsDependent); if (DeducedTemplateSpecializationType *DTST = DeducedTemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(DTST, 0); auto *DTST = new (*this, alignof(DeducedTemplateSpecializationType)) - DeducedTemplateSpecializationType(Template, DeducedType, IsDependent, - Canon); + DeducedTemplateSpecializationType(Keyword, Template, DeducedType, + IsDependent, Canon); #ifndef NDEBUG llvm::FoldingSetNodeID TempID; @@ -6766,14 +6929,20 @@ QualType ASTContext::getDeducedTemplateSpecializationTypeInternal( /// which has been deduced to the given type, or to the canonical undeduced /// such type, or the canonical deduced-but-dependent such type. QualType ASTContext::getDeducedTemplateSpecializationType( - TemplateName Template, QualType DeducedType, bool IsDependent) const { - QualType Canon = DeducedType.isNull() - ? getDeducedTemplateSpecializationTypeInternal( - getCanonicalTemplateName(Template), QualType(), - IsDependent, QualType()) - : DeducedType.getCanonicalType(); - return getDeducedTemplateSpecializationTypeInternal(Template, DeducedType, - IsDependent, Canon); + ElaboratedTypeKeyword Keyword, TemplateName Template, QualType DeducedType, + bool IsDependent) const { + // FIXME: This could save an extra hash table lookup if it handled all the + // parameters already being canonical. + // FIXME: Can this be formed from a DependentTemplateName, such that the + // keyword should be part of the canonical type? + QualType Canon = + DeducedType.isNull() + ? getDeducedTemplateSpecializationTypeInternal( + ElaboratedTypeKeyword::None, getCanonicalTemplateName(Template), + QualType(), IsDependent, QualType()) + : DeducedType.getCanonicalType(); + return getDeducedTemplateSpecializationTypeInternal( + Keyword, Template, DeducedType, IsDependent, Canon); } /// getAtomicType - Return the uniqued reference to the atomic type for @@ -6823,15 +6992,6 @@ QualType ASTContext::getAutoRRefDeductType() const { return AutoRRefDeductTy; } -/// getTagDeclType - Return the unique reference to the type for the -/// specified TagDecl (struct/union/class/enum) decl. -QualType ASTContext::getTagDeclType(const TagDecl *Decl) const { - assert(Decl); - // FIXME: What is the design on getTagDeclType when it requires casting - // away const? mutable? - return getTypeDeclType(const_cast<TagDecl*>(Decl)); -} - /// getSizeType - Return the unique type for "size_t" (C99 7.17), the result /// of the sizeof operator (C99 6.5.3.4p4). The value is target dependent and /// needs to agree with the definition in <stddef.h>. @@ -7053,8 +7213,8 @@ bool ASTContext::UnwrapSimilarTypes(QualType &T1, QualType &T2, *RD2 = T2MPType->getMostRecentCXXRecordDecl(); RD1 != RD2 && RD1->getCanonicalDecl() != RD2->getCanonicalDecl()) return false; - if (getCanonicalNestedNameSpecifier(T1MPType->getQualifier()) != - getCanonicalNestedNameSpecifier(T2MPType->getQualifier())) + if (T1MPType->getQualifier().getCanonical() != + T2MPType->getQualifier().getCanonical()) return false; T1 = T1MPType->getPointeeType(); T2 = T2MPType->getPointeeType(); @@ -7211,9 +7371,8 @@ TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name, case TemplateName::DependentTemplate: { DependentTemplateName *DTN = Name.getAsDependentTemplateName(); assert(DTN && "Non-dependent template names must refer to template decls."); - NestedNameSpecifier *Qualifier = DTN->getQualifier(); - NestedNameSpecifier *CanonQualifier = - getCanonicalNestedNameSpecifier(Qualifier); + NestedNameSpecifier Qualifier = DTN->getQualifier(); + NestedNameSpecifier CanonQualifier = Qualifier.getCanonical(); if (Qualifier != CanonQualifier || !DTN->hasTemplateKeyword()) return getDependentTemplateName({CanonQualifier, DTN->getName(), /*HasTemplateKeyword=*/true}); @@ -7430,38 +7589,40 @@ bool ASTContext::isSameDefaultTemplateArgument(const NamedDecl *X, return hasSameTemplateName(TAX.getAsTemplate(), TAY.getAsTemplate()); } -static bool isSameQualifier(const NestedNameSpecifier *X, - const NestedNameSpecifier *Y) { - if (X->getKind() != Y->getKind()) +static bool isSameQualifier(const NestedNameSpecifier X, + const NestedNameSpecifier Y) { + if (X == Y) + return true; + if (!X || !Y) + return false; + + auto Kind = X.getKind(); + if (Kind != Y.getKind()) return false; // FIXME: For namespaces and types, we're permitted to check that the entity // is named via the same tokens. We should probably do so. - switch (X->getKind()) { - case NestedNameSpecifier::Identifier: - if (X->getAsIdentifier() != Y->getAsIdentifier()) - return false; - break; - case NestedNameSpecifier::Namespace: - if (!declaresSameEntity(X->getAsNamespace(), Y->getAsNamespace())) + switch (Kind) { + case NestedNameSpecifier::Kind::Namespace: { + auto [NamespaceX, PrefixX] = X.getAsNamespaceAndPrefix(); + auto [NamespaceY, PrefixY] = Y.getAsNamespaceAndPrefix(); + if (!declaresSameEntity(NamespaceX->getNamespace(), + NamespaceY->getNamespace())) return false; - break; - case NestedNameSpecifier::TypeSpec: - if (X->getAsType()->getCanonicalTypeInternal() != - Y->getAsType()->getCanonicalTypeInternal()) + return isSameQualifier(PrefixX, PrefixY); + } + case NestedNameSpecifier::Kind::Type: { + const auto *TX = X.getAsType(), *TY = Y.getAsType(); + if (TX->getCanonicalTypeInternal() != TY->getCanonicalTypeInternal()) return false; - break; - case NestedNameSpecifier::Global: - case NestedNameSpecifier::Super: + return isSameQualifier(TX->getPrefix(), TY->getPrefix()); + } + case NestedNameSpecifier::Kind::Null: + case NestedNameSpecifier::Kind::Global: + case NestedNameSpecifier::Kind::MicrosoftSuper: return true; } - - // Recurse into earlier portion of NNS, if any. - auto *PX = X->getPrefix(); - auto *PY = Y->getPrefix(); - if (PX && PY) - return isSameQualifier(PX, PY); - return !PX && !PY; + llvm_unreachable("unhandled qualifier kind"); } static bool hasSameCudaAttrs(const FunctionDecl *A, const FunctionDecl *B) { @@ -7854,63 +8015,6 @@ bool ASTContext::isSameTemplateArgument(const TemplateArgument &Arg1, llvm_unreachable("Unhandled template argument kind"); } -NestedNameSpecifier * -ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const { - if (!NNS) - return nullptr; - - switch (NNS->getKind()) { - case NestedNameSpecifier::Identifier: - // Canonicalize the prefix but keep the identifier the same. - return NestedNameSpecifier::Create(*this, - getCanonicalNestedNameSpecifier(NNS->getPrefix()), - NNS->getAsIdentifier()); - - case NestedNameSpecifier::Namespace: - // A namespace is canonical; build a nested-name-specifier with - // this namespace and no prefix. - return NestedNameSpecifier::Create( - *this, nullptr, NNS->getAsNamespace()->getNamespace()->getFirstDecl()); - - // The difference between TypeSpec and TypeSpecWithTemplate is that the - // latter will have the 'template' keyword when printed. - case NestedNameSpecifier::TypeSpec: { - const Type *T = getCanonicalType(NNS->getAsType()); - - // If we have some kind of dependent-named type (e.g., "typename T::type"), - // break it apart into its prefix and identifier, then reconsititute those - // as the canonical nested-name-specifier. This is required to canonicalize - // a dependent nested-name-specifier involving typedefs of dependent-name - // types, e.g., - // typedef typename T::type T1; - // typedef typename T1::type T2; - if (const auto *DNT = T->getAs<DependentNameType>()) - return NestedNameSpecifier::Create(*this, DNT->getQualifier(), - DNT->getIdentifier()); - if (const auto *DTST = T->getAs<DependentTemplateSpecializationType>()) { - const DependentTemplateStorage &DTN = DTST->getDependentTemplateName(); - QualType NewT = getDependentTemplateSpecializationType( - ElaboratedTypeKeyword::None, - {/*NNS=*/nullptr, DTN.getName(), /*HasTemplateKeyword=*/true}, - DTST->template_arguments(), /*IsCanonical=*/true); - assert(NewT.isCanonical()); - NestedNameSpecifier *Prefix = DTN.getQualifier(); - if (!Prefix) - Prefix = getCanonicalNestedNameSpecifier(NNS->getPrefix()); - return NestedNameSpecifier::Create(*this, Prefix, NewT.getTypePtr()); - } - return NestedNameSpecifier::Create(*this, nullptr, T); - } - - case NestedNameSpecifier::Global: - case NestedNameSpecifier::Super: - // The global specifier and __super specifer are canonical and unique. - return NNS; - } - - llvm_unreachable("Invalid NestedNameSpecifier::Kind!"); -} - const ArrayType *ASTContext::getAsArrayType(QualType T) const { // Handle the non-qualified case efficiently. if (!T.hasLocalQualifiers()) { @@ -8229,7 +8333,7 @@ QualType ASTContext::getPromotedIntegerType(QualType Promotable) const { assert(!Promotable.isNull()); assert(isPromotableIntegerType(Promotable)); if (const auto *ET = Promotable->getAs<EnumType>()) - return ET->getDecl()->getPromotionType(); + return ET->getOriginalDecl()->getDefinitionOrSelf()->getPromotionType(); if (const auto *BT = Promotable->getAs<BuiltinType>()) { // C++ [conv.prom]: A prvalue of type char16_t, char32_t, or wchar_t @@ -8288,8 +8392,9 @@ Qualifiers::ObjCLifetime ASTContext::getInnerObjCOwnership(QualType T) const { static const Type *getIntegerTypeForEnum(const EnumType *ET) { // Incomplete enum types are not treated as integer types. // FIXME: In C++, enum types are never integer types. - if (ET->getDecl()->isComplete() && !ET->getDecl()->isScoped()) - return ET->getDecl()->getIntegerType().getTypePtr(); + const EnumDecl *ED = ET->getOriginalDecl()->getDefinitionOrSelf(); + if (ED->isComplete() && !ED->isScoped()) + return ED->getIntegerType().getTypePtr(); return nullptr; } @@ -8418,7 +8523,7 @@ TypedefDecl *ASTContext::getCFConstantStringDecl() const { CFConstantStringTagDecl->completeDefinition(); // This type is designed to be compatible with NSConstantString, but cannot // use the same name, since NSConstantString is an interface. - auto tagType = getTagDeclType(CFConstantStringTagDecl); + CanQualType tagType = getCanonicalTagType(CFConstantStringTagDecl); CFConstantStringTypeDecl = buildImplicitTypedef(tagType, "__NSConstantString"); @@ -8433,14 +8538,15 @@ RecordDecl *ASTContext::getCFConstantStringTagDecl() const { // getCFConstantStringType - Return the type used for constant CFStrings. QualType ASTContext::getCFConstantStringType() const { - return getTypedefType(getCFConstantStringDecl()); + return getTypedefType(ElaboratedTypeKeyword::None, /*Qualifier=*/std::nullopt, + getCFConstantStringDecl()); } QualType ASTContext::getObjCSuperType() const { if (ObjCSuperType.isNull()) { RecordDecl *ObjCSuperTypeDecl = buildImplicitRecord("objc_super"); getTranslationUnitDecl()->addDecl(ObjCSuperTypeDecl); - ObjCSuperType = getTagDeclType(ObjCSuperTypeDecl); + ObjCSuperType = getCanonicalTagType(ObjCSuperTypeDecl); } return ObjCSuperType; } @@ -8449,12 +8555,12 @@ void ASTContext::setCFConstantStringType(QualType T) { const auto *TD = T->castAs<TypedefType>(); CFConstantStringTypeDecl = cast<TypedefDecl>(TD->getDecl()); const auto *TagType = TD->castAs<RecordType>(); - CFConstantStringTagDecl = TagType->getDecl(); + CFConstantStringTagDecl = TagType->getOriginalDecl()->getDefinitionOrSelf(); } QualType ASTContext::getBlockDescriptorType() const { if (BlockDescriptorType) - return getTagDeclType(BlockDescriptorType); + return getCanonicalTagType(BlockDescriptorType); RecordDecl *RD; // FIXME: Needs the FlagAppleBlock bit. @@ -8484,12 +8590,12 @@ QualType ASTContext::getBlockDescriptorType() const { BlockDescriptorType = RD; - return getTagDeclType(BlockDescriptorType); + return getCanonicalTagType(BlockDescriptorType); } QualType ASTContext::getBlockDescriptorExtendedType() const { if (BlockDescriptorExtendedType) - return getTagDeclType(BlockDescriptorExtendedType); + return getCanonicalTagType(BlockDescriptorExtendedType); RecordDecl *RD; // FIXME: Needs the FlagAppleBlock bit. @@ -8523,7 +8629,7 @@ QualType ASTContext::getBlockDescriptorExtendedType() const { RD->completeDefinition(); BlockDescriptorExtendedType = RD; - return getTagDeclType(BlockDescriptorExtendedType); + return getCanonicalTagType(BlockDescriptorExtendedType); } OpenCLTypeKind ASTContext::getOpenCLTypeKind(const Type *T) const { @@ -9161,7 +9267,7 @@ static char getObjCEncodingForPrimitiveType(const ASTContext *C, } static char ObjCEncodingForEnumType(const ASTContext *C, const EnumType *ET) { - EnumDecl *Enum = ET->getDecl(); + EnumDecl *Enum = ET->getOriginalDecl()->getDefinitionOrSelf(); // The encoding of an non-fixed enum type is always 'i', regardless of size. if (!Enum->isFixed()) @@ -9330,13 +9436,14 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S, return; } } else if (const auto *RTy = PointeeTy->getAs<RecordType>()) { + const IdentifierInfo *II = RTy->getOriginalDecl()->getIdentifier(); // GCC binary compat: Need to convert "struct objc_class *" to "#". - if (RTy->getDecl()->getIdentifier() == &Idents.get("objc_class")) { + if (II == &Idents.get("objc_class")) { S += '#'; return; } // GCC binary compat: Need to convert "struct objc_object *" to "@". - if (RTy->getDecl()->getIdentifier() == &Idents.get("objc_object")) { + if (II == &Idents.get("objc_object")) { S += '@'; return; } @@ -9401,7 +9508,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S, return; case Type::Record: { - RecordDecl *RDecl = cast<RecordType>(CT)->getDecl(); + RecordDecl *RDecl = cast<RecordType>(CT)->getOriginalDecl(); S += RDecl->isUnion() ? '(' : '{'; // Anonymous structures print as '?' if (const IdentifierInfo *II = RDecl->getIdentifier()) { @@ -9900,7 +10007,7 @@ CreateAArch64ABIBuiltinVaListDecl(const ASTContext *Context) { } VaListTagDecl->completeDefinition(); Context->VaListTagDecl = VaListTagDecl; - QualType VaListTagType = Context->getRecordType(VaListTagDecl); + CanQualType VaListTagType = Context->getCanonicalTagType(VaListTagDecl); // } __builtin_va_list; return Context->buildImplicitTypedef(VaListTagType, "__builtin_va_list"); @@ -9952,14 +10059,15 @@ static TypedefDecl *CreatePowerABIBuiltinVaListDecl(const ASTContext *Context) { } VaListTagDecl->completeDefinition(); Context->VaListTagDecl = VaListTagDecl; - QualType VaListTagType = Context->getRecordType(VaListTagDecl); + CanQualType VaListTagType = Context->getCanonicalTagType(VaListTagDecl); // } __va_list_tag; TypedefDecl *VaListTagTypedefDecl = Context->buildImplicitTypedef(VaListTagType, "__va_list_tag"); QualType VaListTagTypedefType = - Context->getTypedefType(VaListTagTypedefDecl); + Context->getTypedefType(ElaboratedTypeKeyword::None, + /*Qualifier=*/std::nullopt, VaListTagTypedefDecl); // typedef __va_list_tag __builtin_va_list[1]; llvm::APInt Size(Context->getTypeSize(Context->getSizeType()), 1); @@ -10011,7 +10119,7 @@ CreateX86_64ABIBuiltinVaListDecl(const ASTContext *Context) { } VaListTagDecl->completeDefinition(); Context->VaListTagDecl = VaListTagDecl; - QualType VaListTagType = Context->getRecordType(VaListTagDecl); + CanQualType VaListTagType = Context->getCanonicalTagType(VaListTagDecl); // }; @@ -10059,7 +10167,7 @@ CreateAAPCSABIBuiltinVaListDecl(const ASTContext *Context) { Context->VaListTagDecl = VaListDecl; // typedef struct __va_list __builtin_va_list; - QualType T = Context->getRecordType(VaListDecl); + CanQualType T = Context->getCanonicalTagType(VaListDecl); return Context->buildImplicitTypedef(T, "__builtin_va_list"); } @@ -10106,7 +10214,7 @@ CreateSystemZBuiltinVaListDecl(const ASTContext *Context) { } VaListTagDecl->completeDefinition(); Context->VaListTagDecl = VaListTagDecl; - QualType VaListTagType = Context->getRecordType(VaListTagDecl); + CanQualType VaListTagType = Context->getCanonicalTagType(VaListTagDecl); // }; @@ -10153,13 +10261,15 @@ static TypedefDecl *CreateHexagonBuiltinVaListDecl(const ASTContext *Context) { } VaListTagDecl->completeDefinition(); Context->VaListTagDecl = VaListTagDecl; - QualType VaListTagType = Context->getRecordType(VaListTagDecl); + CanQualType VaListTagType = Context->getCanonicalTagType(VaListTagDecl); // } __va_list_tag; TypedefDecl *VaListTagTypedefDecl = Context->buildImplicitTypedef(VaListTagType, "__va_list_tag"); - QualType VaListTagTypedefType = Context->getTypedefType(VaListTagTypedefDecl); + QualType VaListTagTypedefType = + Context->getTypedefType(ElaboratedTypeKeyword::None, + /*Qualifier=*/std::nullopt, VaListTagTypedefDecl); // typedef __va_list_tag __builtin_va_list[1]; llvm::APInt Size(Context->getTypeSize(Context->getSizeType()), 1); @@ -10197,7 +10307,7 @@ CreateXtensaABIBuiltinVaListDecl(const ASTContext *Context) { } VaListTagDecl->completeDefinition(); Context->VaListTagDecl = VaListTagDecl; - QualType VaListTagType = Context->getRecordType(VaListTagDecl); + CanQualType VaListTagType = Context->getCanonicalTagType(VaListTagDecl); // } __va_list_tag; TypedefDecl *VaListTagTypedefDecl = @@ -10311,7 +10421,7 @@ TemplateName ASTContext::getAssumedTemplateName(DeclarationName Name) const { /// Retrieve the template name that represents a qualified /// template name such as \c std::vector. -TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS, +TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier Qualifier, bool TemplateKeyword, TemplateName Template) const { assert(Template.getKind() == TemplateName::Template || @@ -10319,14 +10429,14 @@ TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS, // FIXME: Canonicalization? llvm::FoldingSetNodeID ID; - QualifiedTemplateName::Profile(ID, NNS, TemplateKeyword, Template); + QualifiedTemplateName::Profile(ID, Qualifier, TemplateKeyword, Template); void *InsertPos = nullptr; QualifiedTemplateName *QTN = - QualifiedTemplateNames.FindNodeOrInsertPos(ID, InsertPos); + QualifiedTemplateNames.FindNodeOrInsertPos(ID, InsertPos); if (!QTN) { QTN = new (*this, alignof(QualifiedTemplateName)) - QualifiedTemplateName(NNS, TemplateKeyword, Template); + QualifiedTemplateName(Qualifier, TemplateKeyword, Template); QualifiedTemplateNames.InsertNode(QTN, InsertPos); } @@ -11296,7 +11406,7 @@ QualType ASTContext::mergeTransparentUnionType(QualType T, QualType SubType, bool OfBlockPointer, bool Unqualified) { if (const RecordType *UT = T->getAsUnionType()) { - RecordDecl *UD = UT->getDecl(); + RecordDecl *UD = UT->getOriginalDecl()->getMostRecentDecl(); if (UD->hasAttr<TransparentUnionAttr>()) { for (const auto *I : UD->fields()) { QualType ET = I->getType().getUnqualifiedType(); @@ -11528,7 +11638,8 @@ 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 auto *Enum = paramTy->getAs<EnumType>()) { - paramTy = Enum->getDecl()->getIntegerType(); + paramTy = + Enum->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); if (paramTy.isNull()) return {}; } @@ -11560,7 +11671,8 @@ static QualType mergeEnumWithInteger(ASTContext &Context, const EnumType *ET, // a signed integer type, or an unsigned integer type. // Compatibility is based on the underlying type, not the promotion // type. - QualType underlyingType = ET->getDecl()->getIntegerType(); + QualType underlyingType = + ET->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); if (underlyingType.isNull()) return {}; if (Context.hasSameType(underlyingType, other)) @@ -12119,7 +12231,7 @@ QualType ASTContext::mergeObjCGCQualifiers(QualType LHS, QualType RHS) { unsigned ASTContext::getIntWidth(QualType T) const { if (const auto *ET = T->getAs<EnumType>()) - T = ET->getDecl()->getIntegerType(); + T = ET->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); if (T->isBooleanType()) return 1; if (const auto *EIT = T->getAs<BitIntType>()) @@ -12145,7 +12257,7 @@ QualType ASTContext::getCorrespondingUnsignedType(QualType T) const { // For enums, get the underlying integer type of the enum, and let the general // integer type signchanging code handle it. if (const auto *ETy = T->getAs<EnumType>()) - T = ETy->getDecl()->getIntegerType(); + T = ETy->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); switch (T->castAs<BuiltinType>()->getKind()) { case BuiltinType::Char_U: @@ -12219,7 +12331,7 @@ QualType ASTContext::getCorrespondingSignedType(QualType T) const { // For enums, get the underlying integer type of the enum, and let the general // integer type signchanging code handle it. if (const auto *ETy = T->getAs<EnumType>()) - T = ETy->getDecl()->getIntegerType(); + T = ETy->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); switch (T->castAs<BuiltinType>()->getKind()) { case BuiltinType::Char_S: @@ -13573,7 +13685,7 @@ static T *getCommonDeclChecked(T *X, T *Y) { const_cast<Decl *>(cast<Decl>(Y)))); } -static TemplateName getCommonTemplateName(ASTContext &Ctx, TemplateName X, +static TemplateName getCommonTemplateName(const ASTContext &Ctx, TemplateName X, TemplateName Y, bool IgnoreDeduced = false) { if (X.getAsVoidPointer() == Y.getAsVoidPointer()) @@ -13588,7 +13700,7 @@ static TemplateName getCommonTemplateName(ASTContext &Ctx, TemplateName X, return CX; } -static TemplateName getCommonTemplateNameChecked(ASTContext &Ctx, +static TemplateName getCommonTemplateNameChecked(const ASTContext &Ctx, TemplateName X, TemplateName Y, bool IgnoreDeduced) { TemplateName R = getCommonTemplateName(Ctx, X, Y, IgnoreDeduced); @@ -13596,7 +13708,7 @@ static TemplateName getCommonTemplateNameChecked(ASTContext &Ctx, return R; } -static auto getCommonTypes(ASTContext &Ctx, ArrayRef<QualType> Xs, +static auto getCommonTypes(const ASTContext &Ctx, ArrayRef<QualType> Xs, ArrayRef<QualType> Ys, bool Unqualified = false) { assert(Xs.size() == Ys.size()); SmallVector<QualType, 8> Rs(Xs.size()); @@ -13611,7 +13723,7 @@ static SourceLocation getCommonAttrLoc(const T *X, const T *Y) { : SourceLocation(); } -static TemplateArgument getCommonTemplateArgument(ASTContext &Ctx, +static TemplateArgument getCommonTemplateArgument(const ASTContext &Ctx, const TemplateArgument &X, const TemplateArgument &Y) { if (X.getKind() != Y.getKind()) @@ -13657,7 +13769,7 @@ static TemplateArgument getCommonTemplateArgument(ASTContext &Ctx, } } -static bool getCommonTemplateArguments(ASTContext &Ctx, +static bool getCommonTemplateArguments(const ASTContext &Ctx, SmallVectorImpl<TemplateArgument> &R, ArrayRef<TemplateArgument> Xs, ArrayRef<TemplateArgument> Ys) { @@ -13672,7 +13784,7 @@ static bool getCommonTemplateArguments(ASTContext &Ctx, return false; } -static auto getCommonTemplateArguments(ASTContext &Ctx, +static auto getCommonTemplateArguments(const ASTContext &Ctx, ArrayRef<TemplateArgument> Xs, ArrayRef<TemplateArgument> Ys) { SmallVector<TemplateArgument, 8> R; @@ -13683,163 +13795,101 @@ static auto getCommonTemplateArguments(ASTContext &Ctx, } template <class T> -static ElaboratedTypeKeyword getCommonTypeKeyword(const T *X, const T *Y) { - return X->getKeyword() == Y->getKeyword() ? X->getKeyword() - : ElaboratedTypeKeyword::None; +static ElaboratedTypeKeyword getCommonTypeKeyword(const T *X, const T *Y, + bool IsSame) { + ElaboratedTypeKeyword KX = X->getKeyword(), KY = Y->getKeyword(); + if (KX == KY) + return KX; + KX = getCanonicalElaboratedTypeKeyword(KX); + assert(!IsSame || KX == getCanonicalElaboratedTypeKeyword(KY)); + return KX; } /// Returns a NestedNameSpecifier which has only the common sugar /// present in both NNS1 and NNS2. -static NestedNameSpecifier *getCommonNNS(ASTContext &Ctx, - NestedNameSpecifier *NNS1, - NestedNameSpecifier *NNS2, - bool IsSame) { +static NestedNameSpecifier getCommonNNS(const ASTContext &Ctx, + NestedNameSpecifier NNS1, + NestedNameSpecifier NNS2, bool IsSame) { // If they are identical, all sugar is common. if (NNS1 == NNS2) return NNS1; - // IsSame implies both NNSes are equivalent. - NestedNameSpecifier *Canon = Ctx.getCanonicalNestedNameSpecifier(NNS1); - if (Canon != Ctx.getCanonicalNestedNameSpecifier(NNS2)) { + // IsSame implies both Qualifiers are equivalent. + NestedNameSpecifier Canon = NNS1.getCanonical(); + if (Canon != NNS2.getCanonical()) { assert(!IsSame && "Should be the same NestedNameSpecifier"); // If they are not the same, there is nothing to unify. - // FIXME: It would be useful here if we could represent a canonically - // empty NNS, which is not identical to an empty-as-written NNS. - return nullptr; + return std::nullopt; } - NestedNameSpecifier *R = nullptr; - NestedNameSpecifier::SpecifierKind K1 = NNS1->getKind(), K2 = NNS2->getKind(); - switch (K1) { - case NestedNameSpecifier::SpecifierKind::Identifier: { - assert(K2 == NestedNameSpecifier::SpecifierKind::Identifier); - IdentifierInfo *II = NNS1->getAsIdentifier(); - assert(II == NNS2->getAsIdentifier()); - // For an identifier, the prefixes are significant, so they must be the - // same. - NestedNameSpecifier *P = ::getCommonNNS(Ctx, NNS1->getPrefix(), - NNS2->getPrefix(), /*IsSame=*/true); - R = NestedNameSpecifier::Create(Ctx, P, II); - break; - } - case NestedNameSpecifier::SpecifierKind::Namespace: { - assert(K2 == NestedNameSpecifier::SpecifierKind::Namespace); - // The prefixes for namespaces are not significant, its declaration - // identifies it uniquely. - NestedNameSpecifier *P = - ::getCommonNNS(Ctx, NNS1->getPrefix(), NNS2->getPrefix(), - /*IsSame=*/false); - NamespaceBaseDecl *Namespace1 = NNS1->getAsNamespace(), - *Namespace2 = NNS2->getAsNamespace(); + NestedNameSpecifier R = std::nullopt; + NestedNameSpecifier::Kind Kind = NNS1.getKind(); + assert(Kind == NNS2.getKind()); + switch (Kind) { + case NestedNameSpecifier::Kind::Namespace: { + auto [Namespace1, Prefix1] = NNS1.getAsNamespaceAndPrefix(); + auto [Namespace2, Prefix2] = NNS2.getAsNamespaceAndPrefix(); auto Kind = Namespace1->getKind(); if (Kind != Namespace2->getKind() || (Kind == Decl::NamespaceAlias && !declaresSameEntity(Namespace1, Namespace2))) { - R = NestedNameSpecifier::Create( - Ctx, P, + R = NestedNameSpecifier( + Ctx, ::getCommonDeclChecked(Namespace1->getNamespace(), - Namespace2->getNamespace())); + Namespace2->getNamespace()), + /*Prefix=*/std::nullopt); break; } - R = NestedNameSpecifier::Create( - Ctx, P, ::getCommonDeclChecked(Namespace1, Namespace2)); + // The prefixes for namespaces are not significant, its declaration + // identifies it uniquely. + NestedNameSpecifier Prefix = ::getCommonNNS(Ctx, Prefix1, Prefix2, + /*IsSame=*/false); + R = NestedNameSpecifier(Ctx, ::getCommonDeclChecked(Namespace1, Namespace2), + Prefix); break; } - case NestedNameSpecifier::SpecifierKind::TypeSpec: { - // FIXME: See comment below, on Super case. - if (K2 == NestedNameSpecifier::SpecifierKind::Super) - return Ctx.getCanonicalNestedNameSpecifier(NNS1); - - assert(K2 == NestedNameSpecifier::SpecifierKind::TypeSpec); - - const Type *T1 = NNS1->getAsType(), *T2 = NNS2->getAsType(); - if (T1 == T2) { - // If the types are indentical, then only the prefixes differ. - // A well-formed NNS never has these types, as they have - // special normalized forms. - assert((!isa<DependentNameType, ElaboratedType>(T1))); - // Only for a DependentTemplateSpecializationType the prefix - // is actually significant. A DependentName, which would be another - // plausible case, cannot occur here, as explained above. - bool IsSame = isa<DependentTemplateSpecializationType>(T1); - NestedNameSpecifier *P = - ::getCommonNNS(Ctx, NNS1->getPrefix(), NNS2->getPrefix(), IsSame); - R = NestedNameSpecifier::Create(Ctx, P, T1); - break; - } - // TODO: Try to salvage the original prefix. - // If getCommonSugaredType removed any top level sugar, the original prefix - // is not applicable anymore. + case NestedNameSpecifier::Kind::Type: { + const Type *T1 = NNS1.getAsType(), *T2 = NNS2.getAsType(); const Type *T = Ctx.getCommonSugaredType(QualType(T1, 0), QualType(T2, 0), /*Unqualified=*/true) .getTypePtr(); - - // A NestedNameSpecifier has special normalization rules for certain types. - switch (T->getTypeClass()) { - case Type::Elaborated: { - // An ElaboratedType is stripped off, it's Qualifier becomes the prefix. - auto *ET = cast<ElaboratedType>(T); - R = NestedNameSpecifier::Create(Ctx, ET->getQualifier(), - ET->getNamedType().getTypePtr()); - break; - } - case Type::DependentName: { - // A DependentName is turned into an Identifier NNS. - auto *DN = cast<DependentNameType>(T); - R = NestedNameSpecifier::Create(Ctx, DN->getQualifier(), - DN->getIdentifier()); - break; - } - case Type::DependentTemplateSpecialization: { - // A DependentTemplateSpecializationType loses it's Qualifier, which - // is turned into the prefix. - auto *DTST = cast<DependentTemplateSpecializationType>(T); - const DependentTemplateStorage &DTN = DTST->getDependentTemplateName(); - DependentTemplateStorage NewDTN(/*Qualifier=*/nullptr, DTN.getName(), - DTN.hasTemplateKeyword()); - T = Ctx.getDependentTemplateSpecializationType(DTST->getKeyword(), NewDTN, - DTST->template_arguments()) - .getTypePtr(); - R = NestedNameSpecifier::Create(Ctx, DTN.getQualifier(), T); - break; - } - default: - R = NestedNameSpecifier::Create(Ctx, /*Prefix=*/nullptr, T); - break; - } + R = NestedNameSpecifier(T); break; } - case NestedNameSpecifier::SpecifierKind::Super: + case NestedNameSpecifier::Kind::MicrosoftSuper: { // FIXME: Can __super even be used with data members? // If it's only usable in functions, we will never see it here, // unless we save the qualifiers used in function types. // In that case, it might be possible NNS2 is a type, // in which case we should degrade the result to // a CXXRecordType. - return Ctx.getCanonicalNestedNameSpecifier(NNS1); - case NestedNameSpecifier::SpecifierKind::Global: - // The global NNS is a singleton. - assert(K2 == NestedNameSpecifier::SpecifierKind::Global && - "Global NNS cannot be equivalent to any other kind"); - llvm_unreachable("Global NestedNameSpecifiers did not compare equal"); - } - assert(Ctx.getCanonicalNestedNameSpecifier(R) == Canon); + R = NestedNameSpecifier(getCommonDeclChecked(NNS1.getAsMicrosoftSuper(), + NNS2.getAsMicrosoftSuper())); + break; + } + case NestedNameSpecifier::Kind::Null: + case NestedNameSpecifier::Kind::Global: + // These are singletons. + llvm_unreachable("singletons did not compare equal"); + } + assert(R.getCanonical() == Canon); return R; } template <class T> -static NestedNameSpecifier *getCommonQualifier(ASTContext &Ctx, const T *X, - const T *Y, bool IsSame) { +static NestedNameSpecifier getCommonQualifier(const ASTContext &Ctx, const T *X, + const T *Y, bool IsSame) { return ::getCommonNNS(Ctx, X->getQualifier(), Y->getQualifier(), IsSame); } template <class T> -static QualType getCommonElementType(ASTContext &Ctx, const T *X, const T *Y) { +static QualType getCommonElementType(const ASTContext &Ctx, const T *X, + const T *Y) { return Ctx.getCommonSugaredType(X->getElementType(), Y->getElementType()); } template <class T> -static QualType getCommonArrayElementType(ASTContext &Ctx, const T *X, +static QualType getCommonArrayElementType(const ASTContext &Ctx, const T *X, Qualifiers &QX, const T *Y, Qualifiers &QY) { QualType EX = X->getElementType(), EY = Y->getElementType(); @@ -13856,11 +13906,13 @@ static QualType getCommonArrayElementType(ASTContext &Ctx, const T *X, } template <class T> -static QualType getCommonPointeeType(ASTContext &Ctx, const T *X, const T *Y) { +static QualType getCommonPointeeType(const ASTContext &Ctx, const T *X, + const T *Y) { return Ctx.getCommonSugaredType(X->getPointeeType(), Y->getPointeeType()); } -template <class T> static auto *getCommonSizeExpr(ASTContext &Ctx, T *X, T *Y) { +template <class T> +static auto *getCommonSizeExpr(const ASTContext &Ctx, T *X, T *Y) { assert(Ctx.hasSameExpr(X->getSizeExpr(), Y->getSizeExpr())); return X->getSizeExpr(); } @@ -13880,8 +13932,9 @@ static auto getCommonIndexTypeCVRQualifiers(const ArrayType *X, // each type (in a canonical sense) only once, in the order they appear // from X to Y. If they occur in both X and Y, the result will contain // the common sugared type between them. -static void mergeTypeLists(ASTContext &Ctx, SmallVectorImpl<QualType> &Out, - ArrayRef<QualType> X, ArrayRef<QualType> Y) { +static void mergeTypeLists(const ASTContext &Ctx, + SmallVectorImpl<QualType> &Out, ArrayRef<QualType> X, + ArrayRef<QualType> Y) { llvm::DenseMap<QualType, unsigned> Found; for (auto Ts : {X, Y}) { for (QualType T : Ts) { @@ -13900,7 +13953,7 @@ FunctionProtoType::ExceptionSpecInfo ASTContext::mergeExceptionSpecs(FunctionProtoType::ExceptionSpecInfo ESI1, FunctionProtoType::ExceptionSpecInfo ESI2, SmallVectorImpl<QualType> &ExceptionTypeStorage, - bool AcceptDependent) { + bool AcceptDependent) const { ExceptionSpecificationType EST1 = ESI1.Type, EST2 = ESI2.Type; // If either of them can throw anything, that is the result. @@ -13964,7 +14017,7 @@ ASTContext::mergeExceptionSpecs(FunctionProtoType::ExceptionSpecInfo ESI1, llvm_unreachable("invalid ExceptionSpecificationType"); } -static QualType getCommonNonSugarTypeNode(ASTContext &Ctx, const Type *X, +static QualType getCommonNonSugarTypeNode(const ASTContext &Ctx, const Type *X, Qualifiers &QX, const Type *Y, Qualifiers &QY) { Type::TypeClass TC = X->getTypeClass(); @@ -13982,10 +14035,8 @@ static QualType getCommonNonSugarTypeNode(ASTContext &Ctx, const Type *X, SUGAR_FREE_TYPE(Builtin) SUGAR_FREE_TYPE(DeducedTemplateSpecialization) SUGAR_FREE_TYPE(DependentBitInt) - SUGAR_FREE_TYPE(Enum) SUGAR_FREE_TYPE(BitInt) SUGAR_FREE_TYPE(ObjCInterface) - SUGAR_FREE_TYPE(Record) SUGAR_FREE_TYPE(SubstTemplateTypeParmPack) SUGAR_FREE_TYPE(UnresolvedUsing) SUGAR_FREE_TYPE(HLSLAttributedResource) @@ -14203,13 +14254,15 @@ static QualType getCommonNonSugarTypeNode(ASTContext &Ctx, const Type *X, getCommonElementType(Ctx, VX, VY), getCommonSizeExpr(Ctx, VX, VY), getCommonAttrLoc(VX, VY), VX->getVectorKind()); } + case Type::Enum: + case Type::Record: case Type::InjectedClassName: { - const auto *IX = cast<InjectedClassNameType>(X), - *IY = cast<InjectedClassNameType>(Y); - return Ctx.getInjectedClassNameType( - getCommonDeclChecked(IX->getDecl(), IY->getDecl()), - Ctx.getCommonSugaredType(IX->getInjectedSpecializationType(), - IY->getInjectedSpecializationType())); + const auto *TX = cast<TagType>(X), *TY = cast<TagType>(Y); + return Ctx.getTagType( + ::getCommonTypeKeyword(TX, TY, /*IsSame=*/false), + ::getCommonQualifier(Ctx, TX, TY, /*IsSame=*/false), + ::getCommonDeclChecked(TX->getOriginalDecl(), TY->getOriginalDecl()), + /*OwnedTag=*/false); } case Type::TemplateSpecialization: { const auto *TX = cast<TemplateSpecializationType>(X), @@ -14217,6 +14270,7 @@ static QualType getCommonNonSugarTypeNode(ASTContext &Ctx, const Type *X, auto As = getCommonTemplateArguments(Ctx, TX->template_arguments(), TY->template_arguments()); return Ctx.getTemplateSpecializationType( + getCommonTypeKeyword(TX, TY, /*IsSame=*/false), ::getCommonTemplateNameChecked(Ctx, TX->getTemplateName(), TY->getTemplateName(), /*IgnoreDeduced=*/true), @@ -14244,7 +14298,7 @@ static QualType getCommonNonSugarTypeNode(ASTContext &Ctx, const Type *X, *NY = cast<DependentNameType>(Y); assert(NX->getIdentifier() == NY->getIdentifier()); return Ctx.getDependentNameType( - getCommonTypeKeyword(NX, NY), + getCommonTypeKeyword(NX, NY, /*IsSame=*/true), getCommonQualifier(Ctx, NX, NY, /*IsSame=*/true), NX->getIdentifier()); } case Type::DependentTemplateSpecialization: { @@ -14260,7 +14314,7 @@ static QualType getCommonNonSugarTypeNode(ASTContext &Ctx, const Type *X, /*IsSame=*/true), SX.getName(), SX.hasTemplateKeyword() || SY.hasTemplateKeyword()); return Ctx.getDependentTemplateSpecializationType( - getCommonTypeKeyword(TX, TY), Name, As); + getCommonTypeKeyword(TX, TY, /*IsSame=*/true), Name, As); } case Type::UnaryTransform: { const auto *TX = cast<UnaryTransformType>(X), @@ -14301,7 +14355,7 @@ static QualType getCommonNonSugarTypeNode(ASTContext &Ctx, const Type *X, llvm_unreachable("Unknown Type Class"); } -static QualType getCommonSugarTypeNode(ASTContext &Ctx, const Type *X, +static QualType getCommonSugarTypeNode(const ASTContext &Ctx, const Type *X, const Type *Y, SplitQualType Underlying) { Type::TypeClass TC = X->getTypeClass(); @@ -14413,15 +14467,6 @@ static QualType getCommonSugarTypeNode(ASTContext &Ctx, const Type *X, case Type::DeducedTemplateSpecialization: // FIXME: Try to merge these. return QualType(); - - case Type::Elaborated: { - const auto *EX = cast<ElaboratedType>(X), *EY = cast<ElaboratedType>(Y); - return Ctx.getElaboratedType( - ::getCommonTypeKeyword(EX, EY), - ::getCommonQualifier(Ctx, EX, EY, /*IsSame=*/false), - Ctx.getQualifiedType(Underlying), - ::getCommonDecl(EX->getOwnedTagDecl(), EY->getOwnedTagDecl())); - } case Type::MacroQualified: { const auto *MX = cast<MacroQualifiedType>(X), *MY = cast<MacroQualifiedType>(Y); @@ -14465,16 +14510,19 @@ static QualType getCommonSugarTypeNode(ASTContext &Ctx, const Type *X, if (getCommonTemplateArguments(Ctx, As, TX->template_arguments(), TY->template_arguments())) return QualType(); - return Ctx.getTemplateSpecializationType(CTN, As, - /*CanonicalArgs=*/{}, - Ctx.getQualifiedType(Underlying)); + return Ctx.getTemplateSpecializationType( + getCommonTypeKeyword(TX, TY, /*IsSame=*/false), CTN, As, + /*CanonicalArgs=*/{}, Ctx.getQualifiedType(Underlying)); } case Type::Typedef: { const auto *TX = cast<TypedefType>(X), *TY = cast<TypedefType>(Y); const TypedefNameDecl *CD = ::getCommonDecl(TX->getDecl(), TY->getDecl()); if (!CD) return QualType(); - return Ctx.getTypedefType(CD, Ctx.getQualifiedType(Underlying)); + return Ctx.getTypedefType( + ::getCommonTypeKeyword(TX, TY, /*IsSame=*/false), + ::getCommonQualifier(Ctx, TX, TY, /*IsSame=*/false), CD, + Ctx.getQualifiedType(Underlying)); } case Type::TypeOf: { // The common sugar between two typeof expressions, where one is @@ -14505,11 +14553,12 @@ static QualType getCommonSugarTypeNode(ASTContext &Ctx, const Type *X, } case Type::Using: { const auto *UX = cast<UsingType>(X), *UY = cast<UsingType>(Y); - const UsingShadowDecl *CD = - ::getCommonDecl(UX->getFoundDecl(), UY->getFoundDecl()); + const UsingShadowDecl *CD = ::getCommonDecl(UX->getDecl(), UY->getDecl()); if (!CD) return QualType(); - return Ctx.getUsingType(CD, Ctx.getQualifiedType(Underlying)); + return Ctx.getUsingType(::getCommonTypeKeyword(UX, UY, /*IsSame=*/false), + ::getCommonQualifier(Ctx, UX, UY, /*IsSame=*/false), + CD, Ctx.getQualifiedType(Underlying)); } case Type::MemberPointer: { const auto *PX = cast<MemberPointerType>(X), @@ -14568,7 +14617,7 @@ static auto unwrapSugar(SplitQualType &T, Qualifiers &QTotal) { } QualType ASTContext::getCommonSugaredType(QualType X, QualType Y, - bool Unqualified) { + bool Unqualified) const { assert(Unqualified ? hasSameUnqualifiedType(X, Y) : hasSameType(X, Y)); if (X == Y) return X; diff --git a/clang/lib/AST/ASTDiagnostic.cpp b/clang/lib/AST/ASTDiagnostic.cpp index 2ef0c31..d7fd411 100644 --- a/clang/lib/AST/ASTDiagnostic.cpp +++ b/clang/lib/AST/ASTDiagnostic.cpp @@ -36,11 +36,6 @@ QualType clang::desugarForDiagnostic(ASTContext &Context, QualType QT, while (true) { const Type *Ty = QC.strip(QT); - // Don't aka just because we saw an elaborated type... - if (const ElaboratedType *ET = dyn_cast<ElaboratedType>(Ty)) { - QT = ET->desugar(); - continue; - } // ... or a using type ... if (const UsingType *UT = dyn_cast<UsingType>(Ty)) { QT = UT->desugar(); @@ -130,7 +125,8 @@ QualType clang::desugarForDiagnostic(ASTContext &Context, QualType QT, if (DesugarArgument) { ShouldAKA = true; QT = Context.getTemplateSpecializationType( - TST->getTemplateName(), Args, /*CanonicalArgs=*/{}, QT); + TST->getKeyword(), TST->getTemplateName(), Args, + /*CanonicalArgs=*/{}, QT); } break; } @@ -200,7 +196,8 @@ break; \ // Don't desugar through the primary typedef of an anonymous type. if (const TagType *UTT = Underlying->getAs<TagType>()) if (const TypedefType *QTT = dyn_cast<TypedefType>(QT)) - if (UTT->getDecl()->getTypedefNameForAnonDecl() == QTT->getDecl()) + if (UTT->getOriginalDecl()->getTypedefNameForAnonDecl() == + QTT->getDecl()) break; // Record that we actually looked through an opaque type here. @@ -461,13 +458,12 @@ void clang::FormatASTNodeDiagnosticArgument( ND->getNameForDiagnostic(OS, Context.getPrintingPolicy(), Qualified); break; } - case DiagnosticsEngine::ak_nestednamespec: { - NestedNameSpecifier *NNS = reinterpret_cast<NestedNameSpecifier*>(Val); - NNS->print(OS, Context.getPrintingPolicy(), + case DiagnosticsEngine::ak_nestednamespec: + NestedNameSpecifier::getFromVoidPointer(reinterpret_cast<void *>(Val)) + .print(OS, Context.getPrintingPolicy(), /*ResolveTemplateArguments=*/false, /*PrintFinalScopeResOp=*/false); break; - } case DiagnosticsEngine::ak_declcontext: { DeclContext *DC = reinterpret_cast<DeclContext *> (Val); assert(DC && "Should never have a null declaration context"); @@ -484,9 +480,8 @@ void clang::FormatASTNodeDiagnosticArgument( } else if (isLambdaCallOperator(DC)) { OS << "lambda expression"; } else if (TypeDecl *Type = dyn_cast<TypeDecl>(DC)) { - OS << ConvertTypeToDiagnosticString(Context, - Context.getTypeDeclType(Type), - PrevArgs, QualTypeVals); + OS << ConvertTypeToDiagnosticString( + Context, Context.getTypeDeclType(Type), PrevArgs, QualTypeVals); } else { assert(isa<NamedDecl>(DC) && "Expected a NamedDecl"); NamedDecl *ND = cast<NamedDecl>(DC); @@ -1158,12 +1153,13 @@ class TemplateDiff { return nullptr; const ClassTemplateSpecializationDecl *CTSD = - dyn_cast<ClassTemplateSpecializationDecl>(RT->getDecl()); + dyn_cast<ClassTemplateSpecializationDecl>(RT->getOriginalDecl()); if (!CTSD) return nullptr; Ty = Context.getTemplateSpecializationType( + ElaboratedTypeKeyword::None, TemplateName(CTSD->getSpecializedTemplate()), CTSD->getTemplateArgs().asArray(), /*CanonicalArgs=*/{}, Ty.getLocalUnqualifiedType().getCanonicalType()); @@ -1743,25 +1739,10 @@ class TemplateDiff { std::string FromTypeStr = FromType.isNull() ? "(no argument)" : FromType.getAsString(Policy); - std::string ToTypeStr = ToType.isNull() ? "(no argument)" - : ToType.getAsString(Policy); - // Print without ElaboratedType sugar if it is better. + std::string ToTypeStr = + ToType.isNull() ? "(no argument)" : ToType.getAsString(Policy); // TODO: merge this with other aka printing above. if (FromTypeStr == ToTypeStr) { - const auto *FromElTy = dyn_cast<ElaboratedType>(FromType), - *ToElTy = dyn_cast<ElaboratedType>(ToType); - if (FromElTy || ToElTy) { - std::string FromNamedTypeStr = - FromElTy ? FromElTy->getNamedType().getAsString(Policy) - : FromTypeStr; - std::string ToNamedTypeStr = - ToElTy ? ToElTy->getNamedType().getAsString(Policy) : ToTypeStr; - if (FromNamedTypeStr != ToNamedTypeStr) { - FromTypeStr = FromNamedTypeStr; - ToTypeStr = ToNamedTypeStr; - goto PrintTypes; - } - } // Switch to canonical typename if it is better. std::string FromCanTypeStr = FromType.getCanonicalType().getAsString(Policy); @@ -1772,8 +1753,8 @@ class TemplateDiff { } } - PrintTypes: - if (PrintTree) OS << '['; + if (PrintTree) + OS << '['; OS << (FromDefault ? "(default) " : ""); Bold(); OS << FromTypeStr; diff --git a/clang/lib/AST/ASTDumper.cpp b/clang/lib/AST/ASTDumper.cpp index 5e4487e..8e651a0 100644 --- a/clang/lib/AST/ASTDumper.cpp +++ b/clang/lib/AST/ASTDumper.cpp @@ -117,7 +117,9 @@ void ASTDumper::dumpTemplateDeclSpecialization(const SpecializationDecl *D, // FIXME: The redecls() range sometimes has elements of a less-specific // type. (In particular, ClassTemplateSpecializationDecl::redecls() gives // us TagDecls, and should give CXXRecordDecls). - auto *Redecl = cast<SpecializationDecl>(RedeclWithBadType); + auto *Redecl = dyn_cast<SpecializationDecl>(RedeclWithBadType); + if (!Redecl) + continue; switch (Redecl->getTemplateSpecializationKind()) { case TSK_ExplicitInstantiationDeclaration: case TSK_ExplicitInstantiationDefinition: diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 8e2927b..315ead9 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -949,8 +949,10 @@ ASTNodeImporter::import(const TemplateArgumentLoc &TALoc) { else return TSIOrErr.takeError(); } else { - auto ToTemplateQualifierLocOrErr = - import(FromInfo.getTemplateQualifierLoc()); + auto ToTemplateKWLocOrErr = import(FromInfo.getTemplateKwLoc()); + if (!ToTemplateKWLocOrErr) + return ToTemplateKWLocOrErr.takeError(); + auto ToTemplateQualifierLocOrErr = import(TALoc.getTemplateQualifierLoc()); if (!ToTemplateQualifierLocOrErr) return ToTemplateQualifierLocOrErr.takeError(); auto ToTemplateNameLocOrErr = import(FromInfo.getTemplateNameLoc()); @@ -961,8 +963,9 @@ ASTNodeImporter::import(const TemplateArgumentLoc &TALoc) { if (!ToTemplateEllipsisLocOrErr) return ToTemplateEllipsisLocOrErr.takeError(); ToInfo = TemplateArgumentLocInfo( - Importer.getToContext(), *ToTemplateQualifierLocOrErr, - *ToTemplateNameLocOrErr, *ToTemplateEllipsisLocOrErr); + Importer.getToContext(), *ToTemplateKWLocOrErr, + *ToTemplateQualifierLocOrErr, *ToTemplateNameLocOrErr, + *ToTemplateEllipsisLocOrErr); } return TemplateArgumentLoc(Arg, ToInfo); @@ -1597,13 +1600,15 @@ ASTNodeImporter::VisitFunctionProtoType(const FunctionProtoType *T) { ExpectedType ASTNodeImporter::VisitUnresolvedUsingType( const UnresolvedUsingType *T) { Error Err = Error::success(); - auto ToD = importChecked(Err, T->getDecl()); - auto ToPrevD = importChecked(Err, T->getDecl()->getPreviousDecl()); + auto ToQualifier = importChecked(Err, T->getQualifier()); + auto *ToD = importChecked(Err, T->getDecl()); if (Err) return std::move(Err); - return Importer.getToContext().getTypeDeclType( - ToD, cast_or_null<TypeDecl>(ToPrevD)); + if (T->isCanonicalUnqualified()) + return Importer.getToContext().getCanonicalUnresolvedUsingType(ToD); + return Importer.getToContext().getUnresolvedUsingType(T->getKeyword(), + ToQualifier, ToD); } ExpectedType ASTNodeImporter::VisitParenType(const ParenType *T) { @@ -1631,15 +1636,17 @@ ExpectedType ASTNodeImporter::VisitTypedefType(const TypedefType *T) { if (!ToDeclOrErr) return ToDeclOrErr.takeError(); - TypedefNameDecl *ToDecl = *ToDeclOrErr; - if (ToDecl->getTypeForDecl()) - return QualType(ToDecl->getTypeForDecl(), 0); + auto ToQualifierOrErr = import(T->getQualifier()); + if (!ToQualifierOrErr) + return ToQualifierOrErr.takeError(); - ExpectedType ToUnderlyingTypeOrErr = import(T->desugar()); + ExpectedType ToUnderlyingTypeOrErr = + T->typeMatchesDecl() ? QualType() : import(T->desugar()); if (!ToUnderlyingTypeOrErr) return ToUnderlyingTypeOrErr.takeError(); - return Importer.getToContext().getTypedefType(ToDecl, *ToUnderlyingTypeOrErr); + return Importer.getToContext().getTypedefType( + T->getKeyword(), *ToQualifierOrErr, *ToDeclOrErr, *ToUnderlyingTypeOrErr); } ExpectedType ASTNodeImporter::VisitTypeOfExprType(const TypeOfExprType *T) { @@ -1658,14 +1665,14 @@ ExpectedType ASTNodeImporter::VisitTypeOfType(const TypeOfType *T) { } ExpectedType ASTNodeImporter::VisitUsingType(const UsingType *T) { - Expected<UsingShadowDecl *> FoundOrErr = import(T->getFoundDecl()); - if (!FoundOrErr) - return FoundOrErr.takeError(); - Expected<QualType> UnderlyingOrErr = import(T->getUnderlyingType()); - if (!UnderlyingOrErr) - return UnderlyingOrErr.takeError(); - - return Importer.getToContext().getUsingType(*FoundOrErr, *UnderlyingOrErr); + Error Err = Error::success(); + auto ToQualifier = importChecked(Err, T->getQualifier()); + auto *ToD = importChecked(Err, T->getDecl()); + QualType ToT = importChecked(Err, T->desugar()); + if (Err) + return std::move(Err); + return Importer.getToContext().getUsingType(T->getKeyword(), ToQualifier, ToD, + ToT); } ExpectedType ASTNodeImporter::VisitDecltypeType(const DecltypeType *T) { @@ -1728,36 +1735,37 @@ ExpectedType ASTNodeImporter::VisitDeducedTemplateSpecializationType( return ToDeducedTypeOrErr.takeError(); return Importer.getToContext().getDeducedTemplateSpecializationType( - *ToTemplateNameOrErr, *ToDeducedTypeOrErr, T->isDependentType()); + T->getKeyword(), *ToTemplateNameOrErr, *ToDeducedTypeOrErr, + T->isDependentType()); } -ExpectedType ASTNodeImporter::VisitInjectedClassNameType( - const InjectedClassNameType *T) { - Expected<CXXRecordDecl *> ToDeclOrErr = import(T->getDecl()); +ExpectedType ASTNodeImporter::VisitTagType(const TagType *T) { + Expected<TagDecl *> ToDeclOrErr = import(T->getOriginalDecl()); if (!ToDeclOrErr) return ToDeclOrErr.takeError(); - // The InjectedClassNameType is created in VisitRecordDecl when the - // T->getDecl() is imported. Here we can return the existing type. - const Type *Ty = (*ToDeclOrErr)->getTypeForDecl(); - assert(isa_and_nonnull<InjectedClassNameType>(Ty)); - return QualType(Ty, 0); -} + if (T->isCanonicalUnqualified()) + return Importer.getToContext().getCanonicalTagType(*ToDeclOrErr); -ExpectedType ASTNodeImporter::VisitRecordType(const RecordType *T) { - Expected<RecordDecl *> ToDeclOrErr = import(T->getDecl()); - if (!ToDeclOrErr) - return ToDeclOrErr.takeError(); + auto ToQualifierOrErr = import(T->getQualifier()); + if (!ToQualifierOrErr) + return ToQualifierOrErr.takeError(); - return Importer.getToContext().getTagDeclType(*ToDeclOrErr); + return Importer.getToContext().getTagType(T->getKeyword(), *ToQualifierOrErr, + *ToDeclOrErr, T->isTagOwned()); } ExpectedType ASTNodeImporter::VisitEnumType(const EnumType *T) { - Expected<EnumDecl *> ToDeclOrErr = import(T->getDecl()); - if (!ToDeclOrErr) - return ToDeclOrErr.takeError(); + return VisitTagType(T); +} + +ExpectedType ASTNodeImporter::VisitRecordType(const RecordType *T) { + return VisitTagType(T); +} - return Importer.getToContext().getTagDeclType(*ToDeclOrErr); +ExpectedType +ASTNodeImporter::VisitInjectedClassNameType(const InjectedClassNameType *T) { + return VisitTagType(T); } ExpectedType ASTNodeImporter::VisitAttributedType(const AttributedType *T) { @@ -1850,27 +1858,8 @@ ExpectedType ASTNodeImporter::VisitTemplateSpecializationType( if (!ToUnderlyingOrErr) return ToUnderlyingOrErr.takeError(); return Importer.getToContext().getTemplateSpecializationType( - *ToTemplateOrErr, ToTemplateArgs, {}, *ToUnderlyingOrErr); -} - -ExpectedType ASTNodeImporter::VisitElaboratedType(const ElaboratedType *T) { - // Note: the qualifier in an ElaboratedType is optional. - auto ToQualifierOrErr = import(T->getQualifier()); - if (!ToQualifierOrErr) - return ToQualifierOrErr.takeError(); - - ExpectedType ToNamedTypeOrErr = import(T->getNamedType()); - if (!ToNamedTypeOrErr) - return ToNamedTypeOrErr.takeError(); - - Expected<TagDecl *> ToOwnedTagDeclOrErr = import(T->getOwnedTagDecl()); - if (!ToOwnedTagDeclOrErr) - return ToOwnedTagDeclOrErr.takeError(); - - return Importer.getToContext().getElaboratedType(T->getKeyword(), - *ToQualifierOrErr, - *ToNamedTypeOrErr, - *ToOwnedTagDeclOrErr); + T->getKeyword(), *ToTemplateOrErr, ToTemplateArgs, {}, + *ToUnderlyingOrErr); } ExpectedType @@ -2168,7 +2157,7 @@ Error ASTNodeImporter::ImportDeclParts( const Type *LeafT = getLeafPointeeType(P->getType().getCanonicalType().getTypePtr()); auto *RT = dyn_cast<RecordType>(LeafT); - if (RT && RT->getDecl() == D) { + if (RT && RT->getOriginalDecl() == D) { Importer.FromDiag(D->getLocation(), diag::err_unsupported_ast_node) << D->getDeclKindName(); return make_error<ASTImportError>(ASTImportError::UnsupportedConstruct); @@ -2421,8 +2410,8 @@ Error ASTNodeImporter::ImportFieldDeclDefinition(const FieldDecl *From, const RecordType *RecordTo = ToType->getAs<RecordType>(); if (RecordFrom && RecordTo) { - FromRecordDecl = RecordFrom->getDecl(); - ToRecordDecl = RecordTo->getDecl(); + FromRecordDecl = RecordFrom->getOriginalDecl(); + ToRecordDecl = RecordTo->getOriginalDecl(); } } @@ -2643,7 +2632,7 @@ Error ASTNodeImporter::ImportDefinition( return Err; ExpectedType ToTypeOrErr = - import(Importer.getFromContext().getTypeDeclType(From)); + import(QualType(Importer.getFromContext().getCanonicalTagType(From))); if (!ToTypeOrErr) return ToTypeOrErr.takeError(); @@ -3218,7 +3207,7 @@ ExpectedDecl ASTNodeImporter::VisitEnumDecl(EnumDecl *D) { if (auto *Typedef = dyn_cast<TypedefNameDecl>(FoundDecl)) { if (const auto *Tag = Typedef->getUnderlyingType()->getAs<TagType>()) - FoundDecl = Tag->getDecl(); + FoundDecl = Tag->getOriginalDecl(); } if (auto *FoundEnum = dyn_cast<EnumDecl>(FoundDecl)) { @@ -3349,7 +3338,7 @@ ExpectedDecl ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { Decl *Found = FoundDecl; if (auto *Typedef = dyn_cast<TypedefNameDecl>(Found)) { if (const auto *Tag = Typedef->getUnderlyingType()->getAs<TagType>()) - Found = Tag->getDecl(); + Found = Tag->getOriginalDecl(); } if (auto *FoundRecord = dyn_cast<RecordDecl>(Found)) { @@ -3428,17 +3417,6 @@ ExpectedDecl ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { return CDeclOrErr.takeError(); Numbering.ContextDecl = *CDeclOrErr; D2CXX->setLambdaNumbering(Numbering); - } else if (DCXX->isInjectedClassName()) { - // We have to be careful to do a similar dance to the one in - // Sema::ActOnStartCXXMemberDeclarations - const bool DelayTypeCreation = true; - if (GetImportedOrCreateDecl( - D2CXX, D, Importer.getToContext(), D->getTagKind(), DC, - *BeginLocOrErr, Loc, Name.getAsIdentifierInfo(), - cast_or_null<CXXRecordDecl>(PrevDecl), DelayTypeCreation)) - return D2CXX; - Importer.getToContext().getTypeDeclType( - D2CXX, dyn_cast<CXXRecordDecl>(DC)); } else { if (GetImportedOrCreateDecl(D2CXX, D, Importer.getToContext(), D->getTagKind(), DC, *BeginLocOrErr, Loc, @@ -3458,51 +3436,6 @@ ExpectedDecl ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { if (Error Err = importInto(ToDescribed, FromDescribed)) return std::move(Err); D2CXX->setDescribedClassTemplate(ToDescribed); - if (!DCXX->isInjectedClassName() && !IsFriendTemplate) { - // 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). - CXXRecordDecl *Injected = nullptr; - for (NamedDecl *Found : D2CXX->noload_lookup(Name)) { - auto *Record = dyn_cast<CXXRecordDecl>(Found); - if (Record && Record->isInjectedClassName()) { - Injected = Record; - break; - } - } - // Create an injected type for the whole redecl chain. - // The chain may contain an already existing injected type at the start, - // if yes this should be reused. We must ensure that only one type - // object exists for the injected type (including the injected record - // declaration), ASTContext does not check it. - SmallVector<Decl *, 2> Redecls = - getCanonicalForwardRedeclChain(D2CXX); - const Type *FrontTy = - cast<CXXRecordDecl>(Redecls.front())->getTypeForDecl(); - QualType InjSpec; - if (auto *InjTy = FrontTy->getAs<InjectedClassNameType>()) - InjSpec = InjTy->getInjectedSpecializationType(); - else - InjSpec = ToDescribed->getInjectedClassNameSpecialization(); - for (auto *R : Redecls) { - auto *RI = cast<CXXRecordDecl>(R); - if (R != Redecls.front() || - !isa<InjectedClassNameType>(RI->getTypeForDecl())) - RI->setTypeForDecl(nullptr); - // This function tries to get the injected type from getTypeForDecl, - // then from the previous declaration if possible. If not, it creates - // a new type. - Importer.getToContext().getInjectedClassNameType(RI, InjSpec); - } - // Set the new type for the injected decl too. - if (Injected) { - Injected->setTypeForDecl(nullptr); - // This function will copy the injected type from D2CXX into Injected. - // The injected decl does not have a previous decl to copy from. - Importer.getToContext().getTypeDeclType(Injected, D2CXX); - } - } } else if (MemberSpecializationInfo *MemberInfo = DCXX->getMemberSpecializationInfo()) { TemplateSpecializationKind SK = @@ -3826,11 +3759,12 @@ public: } std::optional<bool> VisitTagType(const TagType *T) { - if (auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(T->getDecl())) + if (auto *Spec = + dyn_cast<ClassTemplateSpecializationDecl>(T->getOriginalDecl())) for (const auto &Arg : Spec->getTemplateArgs().asArray()) if (checkTemplateArgument(Arg)) return true; - return isAncestorDeclContextOf(ParentDC, T->getDecl()); + return isAncestorDeclContextOf(ParentDC, T->getOriginalDecl()); } std::optional<bool> VisitPointerType(const PointerType *T) { @@ -3842,17 +3776,11 @@ public: } std::optional<bool> VisitTypedefType(const TypedefType *T) { - const TypedefNameDecl *TD = T->getDecl(); - assert(TD); - return isAncestorDeclContextOf(ParentDC, TD); + return isAncestorDeclContextOf(ParentDC, T->getDecl()); } std::optional<bool> VisitUsingType(const UsingType *T) { - if (T->getFoundDecl() && - isAncestorDeclContextOf(ParentDC, T->getFoundDecl())) - return true; - - return {}; + return isAncestorDeclContextOf(ParentDC, T->getDecl()); } std::optional<bool> @@ -6521,16 +6449,10 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl( // Create the specialization. ClassTemplateSpecializationDecl *D2 = nullptr; if (PartialSpec) { - QualType CanonInjType; - if (Error Err = importInto( - CanonInjType, PartialSpec->getInjectedSpecializationType())) - return std::move(Err); - CanonInjType = CanonInjType.getCanonicalType(); - if (GetImportedOrCreateDecl<ClassTemplatePartialSpecializationDecl>( D2, D, Importer.getToContext(), D->getTagKind(), DC, *BeginLocOrErr, *IdLocOrErr, ToTPList, ClassTemplate, ArrayRef(TemplateArgs), - CanonInjType, + /*CanonInjectedTST=*/CanQualType(), cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl))) return D2; @@ -10050,46 +9972,34 @@ Expected<Stmt *> ASTImporter::Import(Stmt *FromS) { return ToSOrErr; } -Expected<NestedNameSpecifier *> -ASTImporter::Import(NestedNameSpecifier *FromNNS) { - if (!FromNNS) - return nullptr; - - NestedNameSpecifier *Prefix = nullptr; - if (Error Err = importInto(Prefix, FromNNS->getPrefix())) - return std::move(Err); - - switch (FromNNS->getKind()) { - case NestedNameSpecifier::Identifier: - assert(FromNNS->getAsIdentifier() && "NNS should contain identifier."); - return NestedNameSpecifier::Create(ToContext, Prefix, - Import(FromNNS->getAsIdentifier())); - - case NestedNameSpecifier::Namespace: - if (ExpectedDecl NSOrErr = Import(FromNNS->getAsNamespace())) { - return NestedNameSpecifier::Create(ToContext, Prefix, - cast<NamespaceBaseDecl>(*NSOrErr)); - } else +Expected<NestedNameSpecifier> ASTImporter::Import(NestedNameSpecifier FromNNS) { + switch (FromNNS.getKind()) { + case NestedNameSpecifier::Kind::Null: + case NestedNameSpecifier::Kind::Global: + return FromNNS; + case NestedNameSpecifier::Kind::Namespace: { + auto [Namespace, Prefix] = FromNNS.getAsNamespaceAndPrefix(); + auto NSOrErr = Import(Namespace); + if (!NSOrErr) return NSOrErr.takeError(); - - case NestedNameSpecifier::Global: - return NestedNameSpecifier::GlobalSpecifier(ToContext); - - case NestedNameSpecifier::Super: - if (ExpectedDecl RDOrErr = Import(FromNNS->getAsRecordDecl())) - return NestedNameSpecifier::SuperSpecifier(ToContext, - cast<CXXRecordDecl>(*RDOrErr)); + auto PrefixOrErr = Import(Prefix); + if (!PrefixOrErr) + return PrefixOrErr.takeError(); + return NestedNameSpecifier(ToContext, cast<NamespaceBaseDecl>(*NSOrErr), + *PrefixOrErr); + } + case NestedNameSpecifier::Kind::MicrosoftSuper: + if (ExpectedDecl RDOrErr = Import(FromNNS.getAsMicrosoftSuper())) + return NestedNameSpecifier(cast<CXXRecordDecl>(*RDOrErr)); else return RDOrErr.takeError(); - - case NestedNameSpecifier::TypeSpec: - if (ExpectedTypePtr TyOrErr = Import(FromNNS->getAsType())) { - return NestedNameSpecifier::Create(ToContext, Prefix, *TyOrErr); + case NestedNameSpecifier::Kind::Type: + if (ExpectedTypePtr TyOrErr = Import(FromNNS.getAsType())) { + return NestedNameSpecifier(*TyOrErr); } else { return TyOrErr.takeError(); } } - llvm_unreachable("Invalid nested name specifier kind"); } @@ -10103,64 +10013,62 @@ ASTImporter::Import(NestedNameSpecifierLoc FromNNS) { // serialization in reverse order. while (NNS) { NestedNames.push_back(NNS); - NNS = NNS.getPrefix(); + NNS = NNS.getAsNamespaceAndPrefix().Prefix; } NestedNameSpecifierLocBuilder Builder; while (!NestedNames.empty()) { NNS = NestedNames.pop_back_val(); - NestedNameSpecifier *Spec = nullptr; + NestedNameSpecifier Spec = std::nullopt; if (Error Err = importInto(Spec, NNS.getNestedNameSpecifier())) return std::move(Err); - NestedNameSpecifier::SpecifierKind Kind = Spec->getKind(); + NestedNameSpecifier::Kind Kind = Spec.getKind(); SourceLocation ToLocalBeginLoc, ToLocalEndLoc; - if (Kind != NestedNameSpecifier::Super) { + if (Kind != NestedNameSpecifier::Kind::MicrosoftSuper) { if (Error Err = importInto(ToLocalBeginLoc, NNS.getLocalBeginLoc())) return std::move(Err); - if (Kind != NestedNameSpecifier::Global) + if (Kind != NestedNameSpecifier::Kind::Global) if (Error Err = importInto(ToLocalEndLoc, NNS.getLocalEndLoc())) return std::move(Err); } switch (Kind) { - case NestedNameSpecifier::Identifier: - Builder.Extend(getToContext(), Spec->getAsIdentifier(), ToLocalBeginLoc, - ToLocalEndLoc); - break; - - case NestedNameSpecifier::Namespace: - Builder.Extend(getToContext(), Spec->getAsNamespace(), ToLocalBeginLoc, - ToLocalEndLoc); + case NestedNameSpecifier::Kind::Namespace: + Builder.Extend(getToContext(), Spec.getAsNamespaceAndPrefix().Namespace, + ToLocalBeginLoc, ToLocalEndLoc); break; - case NestedNameSpecifier::TypeSpec: { + case NestedNameSpecifier::Kind::Type: { SourceLocation ToTLoc; - if (Error Err = importInto(ToTLoc, NNS.getTypeLoc().getBeginLoc())) + if (Error Err = importInto(ToTLoc, NNS.castAsTypeLoc().getBeginLoc())) return std::move(Err); TypeSourceInfo *TSI = getToContext().getTrivialTypeSourceInfo( - QualType(Spec->getAsType(), 0), ToTLoc); - Builder.Extend(getToContext(), TSI->getTypeLoc(), ToLocalEndLoc); + QualType(Spec.getAsType(), 0), ToTLoc); + Builder.Make(getToContext(), TSI->getTypeLoc(), ToLocalEndLoc); break; } - case NestedNameSpecifier::Global: + case NestedNameSpecifier::Kind::Global: Builder.MakeGlobal(getToContext(), ToLocalBeginLoc); break; - case NestedNameSpecifier::Super: { + case NestedNameSpecifier::Kind::MicrosoftSuper: { auto ToSourceRangeOrErr = Import(NNS.getSourceRange()); if (!ToSourceRangeOrErr) return ToSourceRangeOrErr.takeError(); - Builder.MakeSuper(getToContext(), Spec->getAsRecordDecl(), - ToSourceRangeOrErr->getBegin(), - ToSourceRangeOrErr->getEnd()); + Builder.MakeMicrosoftSuper(getToContext(), Spec.getAsMicrosoftSuper(), + ToSourceRangeOrErr->getBegin(), + ToSourceRangeOrErr->getEnd()); + break; + } + case NestedNameSpecifier::Kind::Null: + llvm_unreachable("unexpected null nested name specifier"); } - } } return Builder.getWithLocInContext(getToContext()); @@ -10740,7 +10648,7 @@ ASTNodeImporter::ImportAPValue(const APValue &FromValue) { if (Err) return std::move(Err); if (auto *RD = dyn_cast<CXXRecordDecl>(FromDecl)) - FromElemTy = Importer.FromContext.getRecordType(RD); + FromElemTy = Importer.FromContext.getCanonicalTagType(RD); else FromElemTy = cast<ValueDecl>(FromDecl)->getType(); ToPath[LoopIdx] = APValue::LValuePathEntry(APValue::BaseOrMemberType( diff --git a/clang/lib/AST/ASTImporterLookupTable.cpp b/clang/lib/AST/ASTImporterLookupTable.cpp index 4ed3198..29c3af1 100644 --- a/clang/lib/AST/ASTImporterLookupTable.cpp +++ b/clang/lib/AST/ASTImporterLookupTable.cpp @@ -49,8 +49,6 @@ struct Builder : RecursiveASTVisitor<Builder> { bool VisitFriendDecl(FriendDecl *D) { if (D->getFriendType()) { QualType Ty = D->getFriendType()->getType(); - if (isa<ElaboratedType>(Ty)) - Ty = cast<ElaboratedType>(Ty)->getNamedType(); // A FriendDecl with a dependent type (e.g. ClassTemplateSpecialization) // always has that decl as child node. // However, there are non-dependent cases which does not have the @@ -64,13 +62,15 @@ struct Builder : RecursiveASTVisitor<Builder> { dyn_cast<SubstTemplateTypeParmType>(Ty)) { if (SubstTy->getAsCXXRecordDecl()) LT.add(SubstTy->getAsCXXRecordDecl()); - } else if (isa<TypedefType>(Ty)) { - // We do not put friend typedefs to the lookup table because - // ASTImporter does not organize typedefs into redecl chains. - } else if (isa<UsingType>(Ty)) { - // Similar to TypedefType, not putting into lookup table. } else { - llvm_unreachable("Unhandled type of friend class"); + if (isa<TypedefType>(Ty)) { + // We do not put friend typedefs to the lookup table because + // ASTImporter does not organize typedefs into redecl chains. + } else if (isa<UsingType>(Ty)) { + // Similar to TypedefType, not putting into lookup table. + } else { + llvm_unreachable("Unhandled type of friend class"); + } } } } diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp index 0e2023f..096bc6c 100644 --- a/clang/lib/AST/ASTStructuralEquivalence.cpp +++ b/clang/lib/AST/ASTStructuralEquivalence.cpp @@ -110,8 +110,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, const TemplateArgumentLoc &Arg1, const TemplateArgumentLoc &Arg2); static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, - NestedNameSpecifier *NNS1, - NestedNameSpecifier *NNS2); + NestedNameSpecifier NNS1, + NestedNameSpecifier NNS2); static bool IsStructurallyEquivalent(const IdentifierInfo *Name1, const IdentifierInfo *Name2); @@ -579,35 +579,30 @@ static bool IsStructurallyEquivalent(const IdentifierInfo *Name1, /// Determine whether two nested-name-specifiers are equivalent. static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, - NestedNameSpecifier *NNS1, - NestedNameSpecifier *NNS2) { - if (NNS1->getKind() != NNS2->getKind()) - return false; - - NestedNameSpecifier *Prefix1 = NNS1->getPrefix(), - *Prefix2 = NNS2->getPrefix(); - if ((bool)Prefix1 != (bool)Prefix2) - return false; - - if (Prefix1) - if (!IsStructurallyEquivalent(Context, Prefix1, Prefix2)) - return false; - - switch (NNS1->getKind()) { - case NestedNameSpecifier::Identifier: - return IsStructurallyEquivalent(NNS1->getAsIdentifier(), - NNS2->getAsIdentifier()); - case NestedNameSpecifier::Namespace: - return IsStructurallyEquivalent(Context, NNS1->getAsNamespace(), - NNS2->getAsNamespace()); - case NestedNameSpecifier::TypeSpec: - return IsStructurallyEquivalent(Context, QualType(NNS1->getAsType(), 0), - QualType(NNS2->getAsType(), 0)); - case NestedNameSpecifier::Global: + NestedNameSpecifier NNS1, + NestedNameSpecifier NNS2) { + auto Kind = NNS1.getKind(); + if (Kind != NNS2.getKind()) + return false; + switch (Kind) { + case NestedNameSpecifier::Kind::Null: + case NestedNameSpecifier::Kind::Global: return true; - case NestedNameSpecifier::Super: - return IsStructurallyEquivalent(Context, NNS1->getAsRecordDecl(), - NNS2->getAsRecordDecl()); + case NestedNameSpecifier::Kind::Namespace: { + auto [Namespace1, Prefix1] = NNS1.getAsNamespaceAndPrefix(); + auto [Namespace2, Prefix2] = NNS2.getAsNamespaceAndPrefix(); + if (!IsStructurallyEquivalent(Context, + const_cast<NamespaceBaseDecl *>(Namespace1), + const_cast<NamespaceBaseDecl *>(Namespace2))) + return false; + return IsStructurallyEquivalent(Context, Prefix1, Prefix2); + } + case NestedNameSpecifier::Kind::Type: + return IsStructurallyEquivalent(Context, QualType(NNS1.getAsType(), 0), + QualType(NNS2.getAsType(), 0)); + case NestedNameSpecifier::Kind::MicrosoftSuper: + return IsStructurallyEquivalent(Context, NNS1.getAsMicrosoftSuper(), + NNS2.getAsMicrosoftSuper()); } return false; } @@ -615,9 +610,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, const DependentTemplateStorage &S1, const DependentTemplateStorage &S2) { - if (NestedNameSpecifier *NNS1 = S1.getQualifier(), *NNS2 = S2.getQualifier(); - !NNS1 != !NNS2 || - (NNS1 && !IsStructurallyEquivalent(Context, NNS1, NNS2))) + if (!IsStructurallyEquivalent(Context, S1.getQualifier(), S2.getQualifier())) return false; IdentifierOrOverloadedOperator IO1 = S1.getName(), IO2 = S2.getName(); @@ -885,10 +878,10 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, // Treat the enumeration as its underlying type and use the builtin type // class comparison. if (T1->getTypeClass() == Type::Enum) { - T1 = T1->getAs<EnumType>()->getDecl()->getIntegerType(); + T1 = T1->getAs<EnumType>()->getOriginalDecl()->getIntegerType(); assert(T2->isBuiltinType() && !T1.isNull()); // Sanity check } else if (T2->getTypeClass() == Type::Enum) { - T2 = T2->getAs<EnumType>()->getDecl()->getIntegerType(); + T2 = T2->getAs<EnumType>()->getOriginalDecl()->getIntegerType(); assert(T1->isBuiltinType() && !T2.isNull()); // Sanity check } TC = Type::Builtin; @@ -1206,23 +1199,35 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, return false; break; - case Type::Using: - if (!IsStructurallyEquivalent(Context, cast<UsingType>(T1)->getFoundDecl(), - cast<UsingType>(T2)->getFoundDecl())) + case Type::Using: { + auto *U1 = cast<UsingType>(T1), *U2 = cast<UsingType>(T2); + if (U1->getKeyword() != U2->getKeyword()) return false; - if (!IsStructurallyEquivalent(Context, - cast<UsingType>(T1)->getUnderlyingType(), - cast<UsingType>(T2)->getUnderlyingType())) + if (!IsStructurallyEquivalent(Context, U1->getQualifier(), + U2->getQualifier())) + return false; + if (!IsStructurallyEquivalent(Context, U1->getDecl(), U2->getDecl())) + return false; + if (!IsStructurallyEquivalent(Context, U1->desugar(), U2->desugar())) return false; break; - - case Type::Typedef: - if (!IsStructurallyEquivalent(Context, cast<TypedefType>(T1)->getDecl(), - cast<TypedefType>(T2)->getDecl()) || - !IsStructurallyEquivalent(Context, cast<TypedefType>(T1)->desugar(), - cast<TypedefType>(T2)->desugar())) + } + case Type::Typedef: { + auto *U1 = cast<TypedefType>(T1), *U2 = cast<TypedefType>(T2); + if (U1->getKeyword() != U2->getKeyword()) + return false; + if (!IsStructurallyEquivalent(Context, U1->getQualifier(), + U2->getQualifier())) + return false; + if (!IsStructurallyEquivalent(Context, U1->getDecl(), U2->getDecl())) + return false; + if (U1->typeMatchesDecl() != U2->typeMatchesDecl()) + return false; + if (!U1->typeMatchesDecl() && + !IsStructurallyEquivalent(Context, U1->desugar(), U2->desugar())) return false; break; + } case Type::TypeOfExpr: if (!IsStructurallyEquivalent( @@ -1286,10 +1291,20 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, case Type::Record: case Type::Enum: - if (!IsStructurallyEquivalent(Context, cast<TagType>(T1)->getDecl(), - cast<TagType>(T2)->getDecl())) + case Type::InjectedClassName: { + const auto *TT1 = cast<TagType>(T1), *TT2 = cast<TagType>(T2); + if (TT1->getKeyword() != TT2->getKeyword()) + return false; + if (TT1->isTagOwned() != TT2->isTagOwned()) + return false; + if (!IsStructurallyEquivalent(Context, TT1->getQualifier(), + TT2->getQualifier())) + return false; + if (!IsStructurallyEquivalent(Context, TT1->getOriginalDecl(), + TT2->getOriginalDecl())) return false; break; + } case Type::TemplateTypeParm: { const auto *Parm1 = cast<TemplateTypeParmType>(T1); @@ -1348,33 +1363,6 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, break; } - case Type::Elaborated: { - const auto *Elab1 = cast<ElaboratedType>(T1); - const auto *Elab2 = cast<ElaboratedType>(T2); - // CHECKME: what if a keyword is ElaboratedTypeKeyword::None or - // ElaboratedTypeKeyword::Typename - // ? - if (Elab1->getKeyword() != Elab2->getKeyword()) - return false; - if (!IsStructurallyEquivalent(Context, Elab1->getQualifier(), - Elab2->getQualifier())) - return false; - if (!IsStructurallyEquivalent(Context, Elab1->getNamedType(), - Elab2->getNamedType())) - return false; - break; - } - - case Type::InjectedClassName: { - const auto *Inj1 = cast<InjectedClassNameType>(T1); - const auto *Inj2 = cast<InjectedClassNameType>(T2); - if (!IsStructurallyEquivalent(Context, - Inj1->getInjectedSpecializationType(), - Inj2->getInjectedSpecializationType())) - return false; - break; - } - case Type::DependentName: { const auto *Typename1 = cast<DependentNameType>(T1); const auto *Typename2 = cast<DependentNameType>(T2); @@ -1549,8 +1537,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, // types if (Field1->isAnonymousStructOrUnion() && Field2->isAnonymousStructOrUnion()) { - RecordDecl *D1 = Field1->getType()->castAs<RecordType>()->getDecl(); - RecordDecl *D2 = Field2->getType()->castAs<RecordType>()->getDecl(); + RecordDecl *D1 = Field1->getType()->castAs<RecordType>()->getOriginalDecl(); + RecordDecl *D2 = Field2->getType()->castAs<RecordType>()->getOriginalDecl(); return IsStructurallyEquivalent(Context, D1, D2); } @@ -1628,7 +1616,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, FieldDecl *Field1, FieldDecl *Field2) { const auto *Owner2 = cast<RecordDecl>(Field2->getDeclContext()); return IsStructurallyEquivalent(Context, Field1, Field2, - Context.ToCtx.getTypeDeclType(Owner2)); + Context.ToCtx.getCanonicalTagType(Owner2)); } /// Determine structural equivalence of two methods. @@ -1801,7 +1789,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (Context.Complain) { Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic( diag::err_odr_tag_type_inconsistent)) - << Context.ToCtx.getTypeDeclType(D2) + << Context.ToCtx.getCanonicalTagType(D2) << (&Context.FromCtx != &Context.ToCtx); Context.Diag1(D1->getLocation(), diag::note_odr_tag_kind_here) << D1->getDeclName() << (unsigned)D1->getTagKind(); @@ -1903,7 +1891,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic( diag::err_odr_tag_type_inconsistent)) - << Context.ToCtx.getTypeDeclType(D2) + << Context.ToCtx.getCanonicalTagType(D2) << (&Context.FromCtx != &Context.ToCtx); Context.Diag2(D2->getLocation(), diag::note_odr_number_of_bases) << D2CXX->getNumBases(); @@ -1924,7 +1912,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic( diag::err_odr_tag_type_inconsistent)) - << Context.ToCtx.getTypeDeclType(D2) + << Context.ToCtx.getCanonicalTagType(D2) << (&Context.FromCtx != &Context.ToCtx); Context.Diag2(Base2->getBeginLoc(), diag::note_odr_base) << Base2->getType() << Base2->getSourceRange(); @@ -1940,7 +1928,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic( diag::err_odr_tag_type_inconsistent)) - << Context.ToCtx.getTypeDeclType(D2) + << Context.ToCtx.getCanonicalTagType(D2) << (&Context.FromCtx != &Context.ToCtx); Context.Diag2(Base2->getBeginLoc(), diag::note_odr_virtual_base) << Base2->isVirtual() << Base2->getSourceRange(); @@ -1962,7 +1950,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic( diag::err_odr_tag_type_inconsistent)) - << Context.ToCtx.getTypeDeclType(D2CXX) + << Context.ToCtx.getCanonicalTagType(D2CXX) << (&Context.FromCtx != &Context.ToCtx); Context.Diag1((*Friend1)->getFriendLoc(), diag::note_odr_friend); Context.Diag2(D2->getLocation(), diag::note_odr_missing_friend); @@ -1975,7 +1963,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic( diag::err_odr_tag_type_inconsistent)) - << Context.ToCtx.getTypeDeclType(D2CXX) + << Context.ToCtx.getCanonicalTagType(D2CXX) << (&Context.FromCtx != &Context.ToCtx); Context.Diag1((*Friend1)->getFriendLoc(), diag::note_odr_friend); Context.Diag2((*Friend2)->getFriendLoc(), diag::note_odr_friend); @@ -1989,7 +1977,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic( diag::err_odr_tag_type_inconsistent)) - << Context.ToCtx.getTypeDeclType(D2) + << Context.ToCtx.getCanonicalTagType(D2) << (&Context.FromCtx != &Context.ToCtx); Context.Diag2((*Friend2)->getFriendLoc(), diag::note_odr_friend); Context.Diag1(D1->getLocation(), diag::note_odr_missing_friend); @@ -2001,7 +1989,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic( diag::err_odr_tag_type_inconsistent)) - << Context.ToCtx.getTypeDeclType(D2) + << Context.ToCtx.getCanonicalTagType(D2) << (&Context.FromCtx != &Context.ToCtx); const CXXBaseSpecifier *Base1 = D1CXX->bases_begin(); Context.Diag1(Base1->getBeginLoc(), diag::note_odr_base) @@ -2013,7 +2001,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, } // Check the fields for consistency. - QualType D2Type = Context.ToCtx.getTypeDeclType(D2); + CanQualType D2Type = Context.ToCtx.getCanonicalTagType(D2); RecordDecl::field_iterator Field2 = D2->field_begin(), Field2End = D2->field_end(); for (RecordDecl::field_iterator Field1 = D1->field_begin(), @@ -2024,7 +2012,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic( diag::err_odr_tag_type_inconsistent)) - << Context.ToCtx.getTypeDeclType(D2) + << Context.ToCtx.getCanonicalTagType(D2) << (&Context.FromCtx != &Context.ToCtx); Context.Diag1(Field1->getLocation(), diag::note_odr_field) << Field1->getDeclName() << Field1->getType(); @@ -2041,7 +2029,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (Context.Complain) { Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic( diag::err_odr_tag_type_inconsistent)) - << Context.ToCtx.getTypeDeclType(D2) + << Context.ToCtx.getCanonicalTagType(D2) << (&Context.FromCtx != &Context.ToCtx); Context.Diag2(Field2->getLocation(), diag::note_odr_field) << Field2->getDeclName() << Field2->getType(); @@ -2101,7 +2089,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic( diag::err_odr_tag_type_inconsistent)) - << Context.ToCtx.getTypeDeclType(D2) + << Context.ToCtx.getCanonicalTagType(D2) << (&Context.FromCtx != &Context.ToCtx); Context.Diag1(D1->getLocation(), D1->isFixed() @@ -2124,7 +2112,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic( diag::err_odr_tag_type_inconsistent)) - << Context.ToCtx.getTypeDeclType(D2) + << Context.ToCtx.getCanonicalTagType(D2) << (&Context.FromCtx != &Context.ToCtx); Context.Diag2(D2->getLocation(), diag::note_odr_incompatible_fixed_underlying_type) @@ -2162,7 +2150,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic( diag::err_odr_tag_type_inconsistent)) - << Context.ToCtx.getTypeDeclType(D2) + << Context.ToCtx.getCanonicalTagType(D2) << (&Context.FromCtx != &Context.ToCtx); Context.Diag1((*EC1)->getLocation(), diag::note_odr_enumerator) << (*EC1)->getDeclName() << toString((*EC1)->getInitVal(), 10); @@ -2180,7 +2168,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic( diag::err_odr_tag_type_inconsistent)) - << Context.ToCtx.getTypeDeclType(D2) + << Context.ToCtx.getCanonicalTagType(D2) << (&Context.FromCtx != &Context.ToCtx); Context.Diag2((*EC2)->getLocation(), diag::note_odr_enumerator) << (*EC2)->getDeclName() << toString((*EC2)->getInitVal(), 10); @@ -2198,7 +2186,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (Context.Complain) { Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic( diag::err_odr_tag_type_inconsistent)) - << Context.ToCtx.getTypeDeclType(D2) + << Context.ToCtx.getCanonicalTagType(D2) << (&Context.FromCtx != &Context.ToCtx); Context.Diag2((*EC2)->getLocation(), diag::note_odr_enumerator) << (*EC2)->getDeclName() << toString((*EC2)->getInitVal(), 10); @@ -2595,7 +2583,7 @@ DiagnosticBuilder StructuralEquivalenceContext::Diag2(SourceLocation Loc, UnsignedOrNone StructuralEquivalenceContext::findUntaggedStructOrUnionIndex(RecordDecl *Anon) { ASTContext &Context = Anon->getASTContext(); - QualType AnonTy = Context.getRecordType(Anon); + CanQualType AnonTy = Context.getCanonicalTagType(Anon); const auto *Owner = dyn_cast<RecordDecl>(Anon->getDeclContext()); if (!Owner) @@ -2617,12 +2605,8 @@ 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(); + const RecordDecl *RecDecl = RecType->getOriginalDecl(); if (RecDecl->getDeclContext() == Owner && !RecDecl->getIdentifier()) { if (Context.hasSameType(FieldType, AnonTy)) break; diff --git a/clang/lib/AST/ASTTypeTraits.cpp b/clang/lib/AST/ASTTypeTraits.cpp index 99916f5..d2f7fdb 100644 --- a/clang/lib/AST/ASTTypeTraits.cpp +++ b/clang/lib/AST/ASTTypeTraits.cpp @@ -194,8 +194,8 @@ void DynTypedNode::print(llvm::raw_ostream &OS, else if (const NestedNameSpecifier *NNS = get<NestedNameSpecifier>()) NNS->print(OS, PP); else if (const NestedNameSpecifierLoc *NNSL = get<NestedNameSpecifierLoc>()) { - if (const NestedNameSpecifier *NNS = NNSL->getNestedNameSpecifier()) - NNS->print(OS, PP); + if (NestedNameSpecifier NNS = NNSL->getNestedNameSpecifier()) + NNS.print(OS, PP); else OS << "(empty NestedNameSpecifierLoc)"; } else if (const QualType *QT = get<QualType>()) @@ -234,13 +234,39 @@ void DynTypedNode::dump(llvm::raw_ostream &OS, OS << "Unable to dump values of type " << NodeKind.asStringRef() << "\n"; } -SourceRange DynTypedNode::getSourceRange() const { +SourceRange DynTypedNode::getSourceRange(bool IncludeQualifier) const { if (const CXXCtorInitializer *CCI = get<CXXCtorInitializer>()) return CCI->getSourceRange(); if (const NestedNameSpecifierLoc *NNSL = get<NestedNameSpecifierLoc>()) return NNSL->getSourceRange(); - if (const TypeLoc *TL = get<TypeLoc>()) - return TL->getSourceRange(); + if (const TypeLoc *TL = get<TypeLoc>()) { + if (IncludeQualifier) + return TL->getSourceRange(); + switch (TL->getTypeLocClass()) { + case TypeLoc::DependentName: + return TL->castAs<DependentNameTypeLoc>().getNameLoc(); + case TypeLoc::TemplateSpecialization: { + auto T = TL->castAs<TemplateSpecializationTypeLoc>(); + return SourceRange(T.getTemplateNameLoc(), T.getEndLoc()); + } + case TypeLoc::DependentTemplateSpecialization: { + auto T = TL->castAs<DependentTemplateSpecializationTypeLoc>(); + return SourceRange(T.getTemplateNameLoc(), T.getEndLoc()); + } + case TypeLoc::Enum: + case TypeLoc::Record: + case TypeLoc::InjectedClassName: + return TL->castAs<TagTypeLoc>().getNameLoc(); + case TypeLoc::Typedef: + return TL->castAs<TypedefTypeLoc>().getNameLoc(); + case TypeLoc::UnresolvedUsing: + return TL->castAs<UnresolvedUsingTypeLoc>().getNameLoc(); + case TypeLoc::Using: + return TL->castAs<UsingTypeLoc>().getNameLoc(); + default: + return TL->getSourceRange(); + } + } if (const Decl *D = get<Decl>()) return D->getSourceRange(); if (const Stmt *S = get<Stmt>()) diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index 4ab4dee..f131ac1 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -553,9 +553,10 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) { // Possibly diagnose casts to enum types if the target type does not // have a fixed size. if (Ctx.getLangOpts().CPlusPlus && CE->getType()->isEnumeralType()) { - if (const auto *ET = CE->getType().getCanonicalType()->castAs<EnumType>(); - !ET->getDecl()->isFixed()) { - if (!this->emitCheckEnumValue(*FromT, ET->getDecl(), CE)) + const auto *ET = CE->getType().getCanonicalType()->castAs<EnumType>(); + const auto *ED = ET->getOriginalDecl()->getDefinitionOrSelf(); + if (!ED->isFixed()) { + if (!this->emitCheckEnumValue(*FromT, ED, CE)) return false; } } @@ -666,8 +667,8 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) { } case CK_VectorSplat: { - assert(!classify(CE->getType())); - assert(classify(SubExpr->getType())); + assert(!canClassify(CE->getType())); + assert(canClassify(SubExpr->getType())); assert(CE->getType()->isVectorType()); if (!Initializing) { @@ -2063,16 +2064,13 @@ bool Compiler<Emitter>::visitCallArgs(ArrayRef<const Expr *> Args, const FunctionDecl *FuncDecl, bool Activate) { assert(VarScope->getKind() == ScopeKind::Call); - bool HasNonNullAttr = false; llvm::BitVector NonNullArgs; - if (FuncDecl && FuncDecl->hasAttr<NonNullAttr>()) { - HasNonNullAttr = true; + if (FuncDecl && FuncDecl->hasAttr<NonNullAttr>()) NonNullArgs = collectNonNullArgs(FuncDecl, Args); - } unsigned ArgIndex = 0; for (const Expr *Arg : Args) { - if (OptPrimType T = classify(Arg)) { + if (canClassify(Arg)) { if (!this->visit(Arg)) return false; } else { @@ -2094,7 +2092,7 @@ bool Compiler<Emitter>::visitCallArgs(ArrayRef<const Expr *> Args, return false; } - if (HasNonNullAttr && NonNullArgs[ArgIndex]) { + if (!NonNullArgs.empty() && NonNullArgs[ArgIndex]) { PrimType ArgT = classify(Arg).value_or(PT_Ptr); if (ArgT == PT_Ptr) { if (!this->emitCheckNonNullArg(ArgT, Arg)) @@ -3157,7 +3155,7 @@ bool Compiler<Emitter>::VisitCXXNoexceptExpr(const CXXNoexceptExpr *E) { template <class Emitter> bool Compiler<Emitter>::VisitCXXConstructExpr(const CXXConstructExpr *E) { QualType T = E->getType(); - assert(!classify(T)); + assert(!canClassify(T)); if (T->isRecordType()) { const CXXConstructorDecl *Ctor = E->getConstructor(); @@ -4152,7 +4150,7 @@ template <class Emitter> bool Compiler<Emitter>::visit(const Expr *E) { // Create local variable to hold the return value. if (!E->isGLValue() && !E->getType()->isAnyComplexType() && - !classify(E->getType())) { + !canClassify(E->getType())) { std::optional<unsigned> LocalIndex = allocateLocal(E); if (!LocalIndex) return false; @@ -4172,7 +4170,7 @@ template <class Emitter> bool Compiler<Emitter>::visit(const Expr *E) { template <class Emitter> bool Compiler<Emitter>::visitInitializer(const Expr *E) { - assert(!classify(E->getType())); + assert(!canClassify(E->getType())); OptionScope<Emitter> Scope(this, /*NewDiscardResult=*/false, /*NewInitializing=*/true); @@ -4379,7 +4377,7 @@ bool Compiler<Emitter>::visitZeroArrayInitializer(QualType T, const Expr *E) { template <class Emitter> bool Compiler<Emitter>::visitAssignment(const Expr *LHS, const Expr *RHS, const Expr *E) { - if (!classify(E->getType())) + if (!canClassify(E->getType())) return false; if (!this->visit(RHS)) @@ -4592,7 +4590,7 @@ const RecordType *Compiler<Emitter>::getRecordTy(QualType Ty) { template <class Emitter> Record *Compiler<Emitter>::getRecord(QualType Ty) { if (const auto *RecordTy = getRecordTy(Ty)) - return getRecord(RecordTy->getDecl()); + return getRecord(RecordTy->getOriginalDecl()->getDefinitionOrSelf()); return nullptr; } @@ -5997,6 +5995,23 @@ bool Compiler<Emitter>::checkLiteralType(const Expr *E) { return this->emitCheckLiteralType(E->getType().getTypePtr(), E); } +static bool initNeedsOverridenLoc(const CXXCtorInitializer *Init) { + const Expr *InitExpr = Init->getInit(); + + if (!Init->isWritten() && !Init->isInClassMemberInitializer() && + !isa<CXXConstructExpr>(InitExpr)) + return true; + + if (const auto *CE = dyn_cast<CXXConstructExpr>(InitExpr)) { + const CXXConstructorDecl *Ctor = CE->getConstructor(); + if (Ctor->isDefaulted() && Ctor->isCopyOrMoveConstructor() && + Ctor->isTrivial()) + return true; + } + + return false; +} + template <class Emitter> bool Compiler<Emitter>::compileConstructor(const CXXConstructorDecl *Ctor) { assert(!ReturnType); @@ -6071,10 +6086,7 @@ bool Compiler<Emitter>::compileConstructor(const CXXConstructorDecl *Ctor) { const Record::Field *F = R->getField(Member); LocOverrideScope<Emitter> LOS(this, SourceInfo{}, - !Init->isWritten() && - !Init->isInClassMemberInitializer() && - (!isa<CXXConstructExpr>(InitExpr) || - Member->isAnonymousStructOrUnion())); + initNeedsOverridenLoc(Init)); if (!emitFieldInitializer(F, F->Offset, InitExpr, IsUnion)) return false; } else if (const Type *Base = Init->getBaseClass()) { @@ -6104,10 +6116,7 @@ bool Compiler<Emitter>::compileConstructor(const CXXConstructorDecl *Ctor) { return false; } else if (const IndirectFieldDecl *IFD = Init->getIndirectMember()) { LocOverrideScope<Emitter> LOS(this, SourceInfo{}, - !Init->isWritten() && - !Init->isInClassMemberInitializer() && - !isa<CXXConstructExpr>(InitExpr)); - + initNeedsOverridenLoc(Init)); assert(IFD->getChainingSize() >= 2); unsigned NestedFieldOffset = 0; @@ -7131,10 +7140,6 @@ bool Compiler<Emitter>::emitDestruction(const Descriptor *Desc, assert(!Desc->isPrimitive()); assert(!Desc->isPrimitiveArray()); - // Can happen if the decl is invalid. - if (Desc->isDummy()) - return true; - // Arrays. if (Desc->isArray()) { const Descriptor *ElemDesc = Desc->ElemDesc; diff --git a/clang/lib/AST/ByteCode/Compiler.h b/clang/lib/AST/ByteCode/Compiler.h index ee8327d..d72ffa1 100644 --- a/clang/lib/AST/ByteCode/Compiler.h +++ b/clang/lib/AST/ByteCode/Compiler.h @@ -256,6 +256,8 @@ protected: OptPrimType classify(const Expr *E) const { return Ctx.classify(E); } OptPrimType classify(QualType Ty) const { return Ctx.classify(Ty); } + bool canClassify(const Expr *E) const { return Ctx.canClassify(E); } + bool canClassify(QualType T) const { return Ctx.canClassify(T); } /// Classifies a known primitive type. PrimType classifyPrim(QualType Ty) const { diff --git a/clang/lib/AST/ByteCode/Context.cpp b/clang/lib/AST/ByteCode/Context.cpp index f7f528c..6343b2a 100644 --- a/clang/lib/AST/ByteCode/Context.cpp +++ b/clang/lib/AST/ByteCode/Context.cpp @@ -365,7 +365,7 @@ OptPrimType Context::classify(QualType T) const { } if (const auto *ET = T->getAs<EnumType>()) { - const auto *D = ET->getDecl(); + const auto *D = ET->getOriginalDecl()->getDefinitionOrSelf(); if (!D->isComplete()) return std::nullopt; return classify(D->getIntegerType()); @@ -501,7 +501,7 @@ const Function *Context::getOrCreateFunction(const FunctionDecl *FuncDecl) { // elsewhere in the code. QualType Ty = FuncDecl->getReturnType(); bool HasRVO = false; - if (!Ty->isVoidType() && !classify(Ty)) { + if (!Ty->isVoidType() && !canClassify(Ty)) { HasRVO = true; ParamTypes.push_back(PT_Ptr); ParamOffsets.push_back(ParamOffset); diff --git a/clang/lib/AST/ByteCode/Context.h b/clang/lib/AST/ByteCode/Context.h index 1c084ac..a6d90bb 100644 --- a/clang/lib/AST/ByteCode/Context.h +++ b/clang/lib/AST/ByteCode/Context.h @@ -93,6 +93,25 @@ public: return classify(E->getType()); } + bool canClassify(QualType T) { + if (const auto *BT = dyn_cast<BuiltinType>(T)) { + if (BT->isInteger() || BT->isFloatingPoint()) + return true; + if (BT->getKind() == BuiltinType::Bool) + return true; + } + + if (T->isArrayType() || T->isRecordType() || T->isAnyComplexType() || + T->isVectorType()) + return false; + return classify(T) != std::nullopt; + } + bool canClassify(const Expr *E) { + if (E->isGLValue()) + return true; + return canClassify(E->getType()); + } + const CXXMethodDecl * getOverridingFunction(const CXXRecordDecl *DynamicDecl, const CXXRecordDecl *StaticDecl, diff --git a/clang/lib/AST/ByteCode/Descriptor.cpp b/clang/lib/AST/ByteCode/Descriptor.cpp index 7403e90..234fa2c 100644 --- a/clang/lib/AST/ByteCode/Descriptor.cpp +++ b/clang/lib/AST/ByteCode/Descriptor.cpp @@ -153,28 +153,6 @@ static void dtorArrayDesc(Block *B, std::byte *Ptr, const Descriptor *D) { } } -static void moveArrayDesc(Block *B, std::byte *Src, std::byte *Dst, - const Descriptor *D) { - const unsigned NumElems = D->getNumElems(); - const unsigned ElemSize = - D->ElemDesc->getAllocSize() + sizeof(InlineDescriptor); - - unsigned ElemOffset = 0; - for (unsigned I = 0; I < NumElems; ++I, ElemOffset += ElemSize) { - auto *SrcPtr = Src + ElemOffset; - auto *DstPtr = Dst + ElemOffset; - - auto *SrcDesc = reinterpret_cast<InlineDescriptor *>(SrcPtr); - auto *SrcElemLoc = reinterpret_cast<std::byte *>(SrcDesc + 1); - auto *DstDesc = reinterpret_cast<InlineDescriptor *>(DstPtr); - auto *DstElemLoc = reinterpret_cast<std::byte *>(DstDesc + 1); - - *DstDesc = *SrcDesc; - if (auto Fn = D->ElemDesc->MoveFn) - Fn(B, SrcElemLoc, DstElemLoc, D->ElemDesc); - } -} - static void initField(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable, bool IsVolatile, bool IsActive, bool IsUnionField, bool InUnion, const Descriptor *D, unsigned FieldOffset) { @@ -268,45 +246,6 @@ static void dtorRecord(Block *B, std::byte *Ptr, const Descriptor *D) { destroyBase(B, Ptr, F.Desc, F.Offset); } -static void moveRecord(Block *B, std::byte *Src, std::byte *Dst, - const Descriptor *D) { - assert(D); - assert(D->ElemRecord); - - // FIXME: Code duplication. - for (const auto &F : D->ElemRecord->fields()) { - auto FieldOffset = F.Offset; - const auto *SrcDesc = - reinterpret_cast<const InlineDescriptor *>(Src + FieldOffset) - 1; - auto *DestDesc = - reinterpret_cast<InlineDescriptor *>(Dst + FieldOffset) - 1; - std::memcpy(DestDesc, SrcDesc, sizeof(InlineDescriptor)); - - if (auto Fn = F.Desc->MoveFn) - Fn(B, Src + FieldOffset, Dst + FieldOffset, F.Desc); - } - - for (const auto &Base : D->ElemRecord->bases()) { - auto BaseOffset = Base.Offset; - const auto *SrcDesc = - reinterpret_cast<const InlineDescriptor *>(Src + BaseOffset) - 1; - auto *DestDesc = reinterpret_cast<InlineDescriptor *>(Dst + BaseOffset) - 1; - std::memcpy(DestDesc, SrcDesc, sizeof(InlineDescriptor)); - - if (auto Fn = Base.Desc->MoveFn) - Fn(B, Src + BaseOffset, Dst + BaseOffset, Base.Desc); - } - - for (const auto &VBase : D->ElemRecord->virtual_bases()) { - auto VBaseOffset = VBase.Offset; - const auto *SrcDesc = - reinterpret_cast<const InlineDescriptor *>(Src + VBaseOffset) - 1; - auto *DestDesc = - reinterpret_cast<InlineDescriptor *>(Dst + VBaseOffset) - 1; - std::memcpy(DestDesc, SrcDesc, sizeof(InlineDescriptor)); - } -} - static BlockCtorFn getCtorPrim(PrimType Type) { // Floating types are special. They are primitives, but need their // constructor called. @@ -337,18 +276,6 @@ static BlockDtorFn getDtorPrim(PrimType Type) { COMPOSITE_TYPE_SWITCH(Type, return dtorTy<T>, return nullptr); } -static BlockMoveFn getMovePrim(PrimType Type) { - if (Type == PT_Float) - return moveTy<PrimConv<PT_Float>::T>; - if (Type == PT_IntAP) - return moveTy<PrimConv<PT_IntAP>::T>; - if (Type == PT_IntAPS) - return moveTy<PrimConv<PT_IntAPS>::T>; - if (Type == PT_MemberPtr) - return moveTy<PrimConv<PT_MemberPtr>::T>; - COMPOSITE_TYPE_SWITCH(Type, return moveTy<T>, return nullptr); -} - static BlockCtorFn getCtorArrayPrim(PrimType Type) { TYPE_SWITCH(Type, return ctorArrayTy<T>); llvm_unreachable("unknown Expr"); @@ -359,11 +286,6 @@ static BlockDtorFn getDtorArrayPrim(PrimType Type) { llvm_unreachable("unknown Expr"); } -static BlockMoveFn getMoveArrayPrim(PrimType Type) { - TYPE_SWITCH(Type, return moveArrayTy<T>); - llvm_unreachable("unknown Expr"); -} - /// Primitives. Descriptor::Descriptor(const DeclTy &D, const Type *SourceTy, PrimType Type, MetadataSize MD, bool IsConst, bool IsTemporary, @@ -372,7 +294,7 @@ Descriptor::Descriptor(const DeclTy &D, const Type *SourceTy, PrimType Type, MDSize(MD.value_or(0)), AllocSize(align(Size + MDSize)), PrimT(Type), IsConst(IsConst), IsMutable(IsMutable), IsTemporary(IsTemporary), IsVolatile(IsVolatile), CtorFn(getCtorPrim(Type)), - DtorFn(getDtorPrim(Type)), MoveFn(getMovePrim(Type)) { + DtorFn(getDtorPrim(Type)) { assert(AllocSize >= Size); assert(Source && "Missing source"); } @@ -386,7 +308,7 @@ Descriptor::Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD, AllocSize(align(MDSize) + align(Size) + sizeof(InitMapPtr)), PrimT(Type), IsConst(IsConst), IsMutable(IsMutable), IsTemporary(IsTemporary), IsArray(true), CtorFn(getCtorArrayPrim(Type)), - DtorFn(getDtorArrayPrim(Type)), MoveFn(getMoveArrayPrim(Type)) { + DtorFn(getDtorArrayPrim(Type)) { assert(Source && "Missing source"); assert(NumElems <= (MaxArrayElemBytes / ElemSize)); } @@ -399,7 +321,7 @@ Descriptor::Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD, AllocSize(MDSize + sizeof(InitMapPtr) + alignof(void *)), PrimT(Type), IsConst(IsConst), IsMutable(false), IsTemporary(IsTemporary), IsArray(true), CtorFn(getCtorArrayPrim(Type)), - DtorFn(getDtorArrayPrim(Type)), MoveFn(getMoveArrayPrim(Type)) { + DtorFn(getDtorArrayPrim(Type)) { assert(Source && "Missing source"); } @@ -414,7 +336,7 @@ Descriptor::Descriptor(const DeclTy &D, const Type *SourceTy, AllocSize(std::max<size_t>(alignof(void *), Size) + MDSize), ElemDesc(Elem), IsConst(IsConst), IsMutable(IsMutable), IsTemporary(IsTemporary), IsArray(true), CtorFn(ctorArrayDesc), - DtorFn(dtorArrayDesc), MoveFn(moveArrayDesc) { + DtorFn(dtorArrayDesc) { assert(Source && "Missing source"); } @@ -425,7 +347,7 @@ Descriptor::Descriptor(const DeclTy &D, const Descriptor *Elem, MetadataSize MD, Size(UnknownSizeMark), MDSize(MD.value_or(0)), AllocSize(MDSize + alignof(void *)), ElemDesc(Elem), IsConst(true), IsMutable(false), IsTemporary(IsTemporary), IsArray(true), - CtorFn(ctorArrayDesc), DtorFn(dtorArrayDesc), MoveFn(moveArrayDesc) { + CtorFn(ctorArrayDesc), DtorFn(dtorArrayDesc) { assert(Source && "Missing source"); } @@ -437,7 +359,7 @@ Descriptor::Descriptor(const DeclTy &D, const Record *R, MetadataSize MD, Size(ElemSize), MDSize(MD.value_or(0)), AllocSize(Size + MDSize), ElemRecord(R), IsConst(IsConst), IsMutable(IsMutable), IsTemporary(IsTemporary), IsVolatile(IsVolatile), CtorFn(ctorRecord), - DtorFn(dtorRecord), MoveFn(moveRecord) { + DtorFn(dtorRecord) { assert(Source && "Missing source"); } @@ -445,7 +367,7 @@ Descriptor::Descriptor(const DeclTy &D, const Record *R, MetadataSize MD, Descriptor::Descriptor(const DeclTy &D, MetadataSize MD) : Source(D), ElemSize(1), Size(1), MDSize(MD.value_or(0)), AllocSize(MDSize), ElemRecord(nullptr), IsConst(true), IsMutable(false), - IsTemporary(false), IsDummy(true) { + IsTemporary(false) { assert(Source && "Missing source"); } @@ -455,12 +377,14 @@ QualType Descriptor::getType() const { if (const auto *D = asValueDecl()) return D->getType(); if (const auto *T = dyn_cast_if_present<TypeDecl>(asDecl())) - return QualType(T->getTypeForDecl(), 0); + return T->getASTContext().getTypeDeclType(T); // The Source sometimes has a different type than the once // we really save. Try to consult the Record first. - if (isRecord()) - return QualType(ElemRecord->getDecl()->getTypeForDecl(), 0); + if (isRecord()) { + const RecordDecl *RD = ElemRecord->getDecl(); + return RD->getASTContext().getCanonicalTagType(RD); + } if (const auto *E = asExpr()) return E->getType(); llvm_unreachable("Invalid descriptor type"); @@ -531,7 +455,7 @@ SourceInfo Descriptor::getLoc() const { } bool Descriptor::hasTrivialDtor() const { - if (isPrimitive() || isPrimitiveArray() || isDummy()) + if (isPrimitive() || isPrimitiveArray()) return true; if (isRecord()) { @@ -540,8 +464,9 @@ bool Descriptor::hasTrivialDtor() const { return !Dtor || Dtor->isTrivial(); } + if (!ElemDesc) + return true; // Composite arrays. - assert(ElemDesc); return ElemDesc->hasTrivialDtor(); } diff --git a/clang/lib/AST/ByteCode/Descriptor.h b/clang/lib/AST/ByteCode/Descriptor.h index 4c925f6..4a808c0 100644 --- a/clang/lib/AST/ByteCode/Descriptor.h +++ b/clang/lib/AST/ByteCode/Descriptor.h @@ -41,14 +41,6 @@ using BlockCtorFn = void (*)(Block *Storage, std::byte *FieldPtr, bool IsConst, using BlockDtorFn = void (*)(Block *Storage, std::byte *FieldPtr, const Descriptor *FieldDesc); -/// Invoked when a block with pointers referencing it goes out of scope. Such -/// blocks are persisted: the move function copies all inline descriptors and -/// non-trivial fields, as existing pointers might need to reference those -/// descriptors. Data is not copied since it cannot be legally read. -using BlockMoveFn = void (*)(Block *Storage, std::byte *SrcFieldPtr, - std::byte *DstFieldPtr, - const Descriptor *FieldDesc); - enum class GlobalInitState { Initialized, NoInitializer, @@ -174,14 +166,11 @@ public: const bool IsVolatile = false; /// Flag indicating if the block is an array. const bool IsArray = false; - /// Flag indicating if this is a dummy descriptor. - bool IsDummy = false; bool IsConstexprUnknown = false; /// Storage management methods. const BlockCtorFn CtorFn = nullptr; const BlockDtorFn DtorFn = nullptr; - const BlockMoveFn MoveFn = nullptr; /// Allocates a descriptor for a primitive. Descriptor(const DeclTy &D, const Type *SourceTy, PrimType Type, @@ -212,9 +201,6 @@ public: /// Allocates a dummy descriptor. Descriptor(const DeclTy &D, MetadataSize MD = std::nullopt); - /// Make this descriptor a dummy descriptor. - void makeDummy() { IsDummy = true; } - QualType getType() const; QualType getElemQualType() const; QualType getDataType(const ASTContext &Ctx) const; @@ -282,8 +268,6 @@ public: bool isRecord() const { return !IsArray && ElemRecord; } /// Checks if the descriptor is of a union. bool isUnion() const; - /// Checks if this is a dummy descriptor. - bool isDummy() const { return IsDummy; } /// Whether variables of this descriptor need their destructor called or not. bool hasTrivialDtor() const; diff --git a/clang/lib/AST/ByteCode/Disasm.cpp b/clang/lib/AST/ByteCode/Disasm.cpp index 5049a65..8eb785d 100644 --- a/clang/lib/AST/ByteCode/Disasm.cpp +++ b/clang/lib/AST/ByteCode/Disasm.cpp @@ -338,7 +338,7 @@ LLVM_DUMP_METHOD void Program::dump(llvm::raw_ostream &OS) const { } OS << "\n"; - if (GP.isInitialized() && Desc->isPrimitive() && !Desc->isDummy()) { + if (GP.isInitialized() && Desc->isPrimitive() && !G->block()->isDummy()) { OS << " "; { ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_CYAN, false}); @@ -394,8 +394,6 @@ LLVM_DUMP_METHOD void Descriptor::dump(llvm::raw_ostream &OS) const { else if (isUnknownSizeArray()) OS << " unknown-size-array"; - if (isDummy()) - OS << " dummy"; if (IsConstexprUnknown) OS << " constexpr-unknown"; } @@ -541,11 +539,12 @@ LLVM_DUMP_METHOD void Block::dump(llvm::raw_ostream &OS) const { else OS << "-\n"; OS << " Pointers: " << NPointers << "\n"; - OS << " Dead: " << IsDead << "\n"; + OS << " Dead: " << isDead() << "\n"; OS << " Static: " << IsStatic << "\n"; - OS << " Extern: " << IsExtern << "\n"; + OS << " Extern: " << isExtern() << "\n"; OS << " Initialized: " << IsInitialized << "\n"; - OS << " Weak: " << IsWeak << "\n"; + OS << " Weak: " << isWeak() << "\n"; + OS << " Dummy: " << isDummy() << '\n'; OS << " Dynamic: " << IsDynamic << "\n"; } diff --git a/clang/lib/AST/ByteCode/DynamicAllocator.cpp b/clang/lib/AST/ByteCode/DynamicAllocator.cpp index 9b8b664..2d62ce7 100644 --- a/clang/lib/AST/ByteCode/DynamicAllocator.cpp +++ b/clang/lib/AST/ByteCode/DynamicAllocator.cpp @@ -13,25 +13,6 @@ using namespace clang; using namespace clang::interp; -// FIXME: There is a peculiar problem with the way we track pointers -// to blocks and the way we allocate dynamic memory. -// -// When we have code like this: -// while (true) { -// char *buffer = new char[1024]; -// delete[] buffer; -// } -// -// We have a local variable 'buffer' pointing to the heap allocated memory. -// When deallocating the memory via delete[], that local variable still -// points to the memory, which means we will create a DeadBlock for it and move -// it over to that block, essentially duplicating the allocation. Moving -// the data is also slow. -// -// However, when we actually try to access the allocation after it has been -// freed, we need the block to still exist (alive or dead) so we can tell -// that it's a dynamic allocation. - DynamicAllocator::~DynamicAllocator() { cleanup(); } void DynamicAllocator::cleanup() { @@ -42,8 +23,11 @@ void DynamicAllocator::cleanup() { for (auto &Iter : AllocationSites) { auto &AllocSite = Iter.second; for (auto &Alloc : AllocSite.Allocations) { - Block *B = reinterpret_cast<Block *>(Alloc.Memory.get()); + Block *B = Alloc.block(); + assert(!B->isDead()); + assert(B->isInitialized()); B->invokeDtor(); + if (B->hasPointers()) { while (B->Pointers) { Pointer *Next = B->Pointers->asBlockPointer().Next; @@ -89,6 +73,12 @@ Block *DynamicAllocator::allocate(const Descriptor *D, unsigned EvalID, assert(D); assert(D->asExpr()); + // Garbage collection. Remove all dead allocations that don't have pointers to + // them anymore. + llvm::erase_if(DeadAllocations, [](Allocation &Alloc) -> bool { + return !Alloc.block()->hasPointers(); + }); + auto Memory = std::make_unique<std::byte[]>(sizeof(Block) + D->getAllocSize()); auto *B = new (Memory.get()) Block(EvalID, D, /*isStatic=*/false); @@ -128,23 +118,39 @@ bool DynamicAllocator::deallocate(const Expr *Source, return false; auto &Site = It->second; - assert(Site.size() > 0); + assert(!Site.empty()); // Find the Block to delete. - auto AllocIt = llvm::find_if(Site.Allocations, [&](const Allocation &A) { - const Block *B = reinterpret_cast<const Block *>(A.Memory.get()); - return BlockToDelete == B; + auto *AllocIt = llvm::find_if(Site.Allocations, [&](const Allocation &A) { + return BlockToDelete == A.block(); }); assert(AllocIt != Site.Allocations.end()); - Block *B = reinterpret_cast<Block *>(AllocIt->Memory.get()); + Block *B = AllocIt->block(); + assert(B->isInitialized()); + assert(!B->isDead()); B->invokeDtor(); - S.deallocate(B); - Site.Allocations.erase(AllocIt); + // Almost all our dynamic allocations have a pointer pointing to them + // when we deallocate them, since otherwise we can't call delete() at all. + // This means that we would usually need to create DeadBlocks for all of them. + // To work around that, we instead mark them as dead without moving the data + // over to a DeadBlock and simply keep the block in a separate DeadAllocations + // list. + if (B->hasPointers()) { + B->AccessFlags |= Block::DeadFlag; + DeadAllocations.push_back(std::move(*AllocIt)); + Site.Allocations.erase(AllocIt); + + if (Site.size() == 0) + AllocationSites.erase(It); + return true; + } - if (Site.size() == 0) + // Get rid of the allocation altogether. + Site.Allocations.erase(AllocIt); + if (Site.empty()) AllocationSites.erase(It); return true; diff --git a/clang/lib/AST/ByteCode/DynamicAllocator.h b/clang/lib/AST/ByteCode/DynamicAllocator.h index cff09bf..31d0e58 100644 --- a/clang/lib/AST/ByteCode/DynamicAllocator.h +++ b/clang/lib/AST/ByteCode/DynamicAllocator.h @@ -43,6 +43,7 @@ private: std::unique_ptr<std::byte[]> Memory; Allocation(std::unique_ptr<std::byte[]> Memory) : Memory(std::move(Memory)) {} + Block *block() const { return reinterpret_cast<Block *>(Memory.get()); } }; struct AllocationSite { @@ -55,6 +56,7 @@ private: } size_t size() const { return Allocations.size(); } + bool empty() const { return Allocations.empty(); } }; public: @@ -65,8 +67,6 @@ public: void cleanup(); - unsigned getNumAllocations() const { return AllocationSites.size(); } - /// Allocate ONE element of the given descriptor. Block *allocate(const Descriptor *D, unsigned EvalID, Form AllocForm); /// Allocate \p NumElements primitive elements of the given type. @@ -96,8 +96,13 @@ public: return llvm::make_range(AllocationSites.begin(), AllocationSites.end()); } + bool hasAllocations() const { return !AllocationSites.empty(); } + private: llvm::DenseMap<const Expr *, AllocationSite> AllocationSites; + // Allocations that have already been deallocated but had pointers + // to them. + llvm::SmallVector<Allocation> DeadAllocations; using PoolAllocTy = llvm::BumpPtrAllocator; PoolAllocTy DescAllocator; diff --git a/clang/lib/AST/ByteCode/EvalEmitter.cpp b/clang/lib/AST/ByteCode/EvalEmitter.cpp index 976b7c0..68f46c1 100644 --- a/clang/lib/AST/ByteCode/EvalEmitter.cpp +++ b/clang/lib/AST/ByteCode/EvalEmitter.cpp @@ -98,10 +98,7 @@ bool EvalEmitter::interpretCall(const FunctionDecl *FD, const Expr *E) { this->Params.insert({PD, {0, false}}); } - if (!this->visit(E)) - return false; - PrimType T = Ctx.classify(E).value_or(PT_Ptr); - return this->emitPop(T, E); + return this->visitExpr(E, /*DestroyToplevelScope=*/false); } void EvalEmitter::emitLabel(LabelTy Label) { CurrentLabel = Label; } @@ -292,7 +289,7 @@ bool EvalEmitter::emitGetLocal(uint32_t I, const SourceInfo &Info) { Block *B = getLocal(I); - if (!CheckLocalLoad(S, OpPC, Pointer(B))) + if (!CheckLocalLoad(S, OpPC, B)) return false; S.Stk.push<T>(*reinterpret_cast<T *>(B->data())); diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index eb4e480..73507d2 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -211,25 +211,26 @@ static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC, S.Note(VD->getLocation(), diag::note_declared_at); } -static bool CheckTemporary(InterpState &S, CodePtr OpPC, const Pointer &Ptr, +static bool CheckTemporary(InterpState &S, CodePtr OpPC, const Block *B, AccessKinds AK) { - if (auto ID = Ptr.getDeclID()) { - if (!Ptr.isStaticTemporary()) + if (B->getDeclID()) { + if (!(B->isStatic() && B->isTemporary())) return true; const auto *MTE = dyn_cast_if_present<MaterializeTemporaryExpr>( - Ptr.getDeclDesc()->asExpr()); + B->getDescriptor()->asExpr()); if (!MTE) return true; // FIXME(perf): Since we do this check on every Load from a static // temporary, it might make sense to cache the value of the // isUsableInConstantExpressions call. - if (!MTE->isUsableInConstantExpressions(S.getASTContext()) && - Ptr.block()->getEvalID() != S.Ctx.getEvalID()) { + if (B->getEvalID() != S.Ctx.getEvalID() && + !MTE->isUsableInConstantExpressions(S.getASTContext())) { const SourceInfo &E = S.Current->getSource(OpPC); S.FFDiag(E, diag::note_constexpr_access_static_temporary, 1) << AK; - S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here); + S.Note(B->getDescriptor()->getLocation(), + diag::note_constexpr_temporary_here); return false; } } @@ -517,7 +518,7 @@ bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr, bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK) { - if (!Ptr.isOnePastEnd()) + if (!Ptr.isOnePastEnd() && !Ptr.isZeroSizeArray()) return true; if (S.getLangOpts().CPlusPlus) { const SourceInfo &Loc = S.Current->getSource(OpPC); @@ -658,17 +659,19 @@ static bool CheckVolatile(InterpState &S, CodePtr OpPC, const Pointer &Ptr, return false; } -bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, - AccessKinds AK) { +bool DiagnoseUninitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, + AccessKinds AK) { assert(Ptr.isLive()); + assert(!Ptr.isInitialized()); + return DiagnoseUninitialized(S, OpPC, Ptr.isExtern(), Ptr.getDeclDesc(), AK); +} - if (Ptr.isInitialized()) - return true; - - if (Ptr.isExtern() && S.checkingPotentialConstantExpression()) +bool DiagnoseUninitialized(InterpState &S, CodePtr OpPC, bool Extern, + const Descriptor *Desc, AccessKinds AK) { + if (Extern && S.checkingPotentialConstantExpression()) return false; - if (const auto *VD = Ptr.getDeclDesc()->asVarDecl(); + if (const auto *VD = Desc->asVarDecl(); VD && (VD->isConstexpr() || VD->hasGlobalStorage())) { if (VD == S.EvaluatingDecl && @@ -703,9 +706,9 @@ bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, return false; } -static bool CheckLifetime(InterpState &S, CodePtr OpPC, const Pointer &Ptr, +static bool CheckLifetime(InterpState &S, CodePtr OpPC, Lifetime LT, AccessKinds AK) { - if (Ptr.getLifetime() == Lifetime::Started) + if (LT == Lifetime::Started) return true; if (!S.checkingPotentialConstantExpression()) { @@ -715,11 +718,11 @@ static bool CheckLifetime(InterpState &S, CodePtr OpPC, const Pointer &Ptr, return false; } -static bool CheckWeak(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { - if (!Ptr.isWeak()) +static bool CheckWeak(InterpState &S, CodePtr OpPC, const Block *B) { + if (!B->isWeak()) return true; - const auto *VD = Ptr.getDeclDesc()->asVarDecl(); + const auto *VD = B->getDescriptor()->asVarDecl(); assert(VD); S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_var_init_weak) << VD; @@ -732,57 +735,100 @@ static bool CheckWeak(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { // ones removed that are impossible on primitive global values. // For example, since those can't be members of structs, they also can't // be mutable. -bool CheckGlobalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { - if (!CheckExtern(S, OpPC, Ptr)) - return false; - if (!CheckConstant(S, OpPC, Ptr)) - return false; - if (!CheckDummy(S, OpPC, Ptr, AK_Read)) - return false; - if (!CheckInitialized(S, OpPC, Ptr, AK_Read)) - return false; - if (!CheckTemporary(S, OpPC, Ptr, AK_Read)) +bool CheckGlobalLoad(InterpState &S, CodePtr OpPC, const Block *B) { + const auto &Desc = + *reinterpret_cast<const GlobalInlineDescriptor *>(B->rawData()); + if (!B->isAccessible()) { + if (!CheckExtern(S, OpPC, Pointer(const_cast<Block *>(B)))) + return false; + if (!CheckDummy(S, OpPC, B, AK_Read)) + return false; + return CheckWeak(S, OpPC, B); + } + + if (!CheckConstant(S, OpPC, B->getDescriptor())) return false; - if (!CheckWeak(S, OpPC, Ptr)) + if (Desc.InitState != GlobalInitState::Initialized) + return DiagnoseUninitialized(S, OpPC, B->isExtern(), B->getDescriptor(), + AK_Read); + if (!CheckTemporary(S, OpPC, B, AK_Read)) return false; - if (!CheckVolatile(S, OpPC, Ptr, AK_Read)) + if (B->getDescriptor()->IsVolatile) { + if (!S.getLangOpts().CPlusPlus) + return Invalid(S, OpPC); + + const ValueDecl *D = B->getDescriptor()->asValueDecl(); + S.FFDiag(S.Current->getLocation(OpPC), + diag::note_constexpr_access_volatile_obj, 1) + << AK_Read << 1 << D; + S.Note(D->getLocation(), diag::note_constexpr_volatile_here) << 1; return false; + } return true; } // Similarly, for local loads. -bool CheckLocalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { - if (!CheckLifetime(S, OpPC, Ptr, AK_Read)) - return false; - if (!CheckInitialized(S, OpPC, Ptr, AK_Read)) - return false; - if (!CheckVolatile(S, OpPC, Ptr, AK_Read)) +bool CheckLocalLoad(InterpState &S, CodePtr OpPC, const Block *B) { + assert(!B->isExtern()); + const auto &Desc = *reinterpret_cast<const InlineDescriptor *>(B->rawData()); + if (!CheckLifetime(S, OpPC, Desc.LifeState, AK_Read)) + return false; + if (!Desc.IsInitialized) + return DiagnoseUninitialized(S, OpPC, /*Extern=*/false, B->getDescriptor(), + AK_Read); + if (B->getDescriptor()->IsVolatile) { + if (!S.getLangOpts().CPlusPlus) + return Invalid(S, OpPC); + + const ValueDecl *D = B->getDescriptor()->asValueDecl(); + S.FFDiag(S.Current->getLocation(OpPC), + diag::note_constexpr_access_volatile_obj, 1) + << AK_Read << 1 << D; + S.Note(D->getLocation(), diag::note_constexpr_volatile_here) << 1; return false; + } return true; } bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK) { - if (!CheckLive(S, OpPC, Ptr, AK)) - return false; - if (!CheckExtern(S, OpPC, Ptr)) + if (!Ptr.isBlockPointer()) { + if (Ptr.isZero()) { + const auto &Src = S.Current->getSource(OpPC); + + if (Ptr.isField()) + S.FFDiag(Src, diag::note_constexpr_null_subobject) << CSK_Field; + else + S.FFDiag(Src, diag::note_constexpr_access_null) << AK; + } return false; + } + + // Block pointers are the only ones we can actually read from. + if (!Ptr.block()->isAccessible()) { + if (!CheckLive(S, OpPC, Ptr, AK)) + return false; + if (!CheckExtern(S, OpPC, Ptr)) + return false; + if (!CheckDummy(S, OpPC, Ptr.block(), AK)) + return false; + if (!CheckWeak(S, OpPC, Ptr.block())) + return false; + } + if (!CheckConstant(S, OpPC, Ptr)) return false; - if (!CheckDummy(S, OpPC, Ptr, AK)) - return false; if (!CheckRange(S, OpPC, Ptr, AK)) return false; if (!CheckActive(S, OpPC, Ptr, AK)) return false; - if (!CheckLifetime(S, OpPC, Ptr, AK)) - return false; - if (!CheckInitialized(S, OpPC, Ptr, AK)) - return false; - if (!CheckTemporary(S, OpPC, Ptr, AK)) + if (!CheckLifetime(S, OpPC, Ptr.getLifetime(), AK)) return false; - if (!CheckWeak(S, OpPC, Ptr)) + if (!Ptr.isInitialized()) + return DiagnoseUninitialized(S, OpPC, Ptr, AK); + if (!CheckTemporary(S, OpPC, Ptr.block(), AK)) return false; + if (!CheckMutable(S, OpPC, Ptr)) return false; if (!CheckVolatile(S, OpPC, Ptr, AK)) @@ -793,26 +839,39 @@ bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr, /// This is not used by any of the opcodes directly. It's used by /// EvalEmitter to do the final lvalue-to-rvalue conversion. bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { - if (!CheckLive(S, OpPC, Ptr, AK_Read)) + if (!Ptr.isBlockPointer()) { + if (Ptr.isZero()) { + const auto &Src = S.Current->getSource(OpPC); + + if (Ptr.isField()) + S.FFDiag(Src, diag::note_constexpr_null_subobject) << CSK_Field; + else + S.FFDiag(Src, diag::note_constexpr_access_null) << AK_Read; + } return false; + } + + assert(Ptr.isBlockPointer()); + if (!Ptr.block()->isAccessible()) { + if (!CheckLive(S, OpPC, Ptr, AK_Read)) + return false; + if (!CheckExtern(S, OpPC, Ptr)) + return false; + if (!CheckDummy(S, OpPC, Ptr.block(), AK_Read)) + return false; + return CheckWeak(S, OpPC, Ptr.block()); + } + if (!CheckConstant(S, OpPC, Ptr)) return false; - if (!CheckDummy(S, OpPC, Ptr, AK_Read)) - return false; - if (!CheckExtern(S, OpPC, Ptr)) - return false; - if (!CheckRange(S, OpPC, Ptr, AK_Read)) - return false; if (!CheckActive(S, OpPC, Ptr, AK_Read)) return false; - if (!CheckLifetime(S, OpPC, Ptr, AK_Read)) + if (!CheckLifetime(S, OpPC, Ptr.getLifetime(), AK_Read)) return false; - if (!CheckInitialized(S, OpPC, Ptr, AK_Read)) - return false; - if (!CheckTemporary(S, OpPC, Ptr, AK_Read)) - return false; - if (!CheckWeak(S, OpPC, Ptr)) + if (!Ptr.isInitialized()) + return DiagnoseUninitialized(S, OpPC, Ptr, AK_Read); + if (!CheckTemporary(S, OpPC, Ptr.block(), AK_Read)) return false; if (!CheckMutable(S, OpPC, Ptr)) return false; @@ -820,11 +879,15 @@ bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { } bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { - if (!CheckLive(S, OpPC, Ptr, AK_Assign)) - return false; - if (!CheckDummy(S, OpPC, Ptr, AK_Assign)) + if (!Ptr.isBlockPointer()) return false; - if (!CheckLifetime(S, OpPC, Ptr, AK_Assign)) + + if (!Ptr.block()->isAccessible()) { + if (!CheckLive(S, OpPC, Ptr, AK_Assign)) + return false; + return CheckDummy(S, OpPC, Ptr.block(), AK_Assign); + } + if (!CheckLifetime(S, OpPC, Ptr.getLifetime(), AK_Assign)) return false; if (!CheckExtern(S, OpPC, Ptr)) return false; @@ -1098,13 +1161,11 @@ bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR) { return diagnoseUnknownDecl(S, OpPC, D); } -bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr, - AccessKinds AK) { - if (!Ptr.isDummy()) +bool CheckDummy(InterpState &S, CodePtr OpPC, const Block *B, AccessKinds AK) { + if (!B->isDummy()) return true; - const Descriptor *Desc = Ptr.getDeclDesc(); - const ValueDecl *D = Desc->asValueDecl(); + const ValueDecl *D = B->getDescriptor()->asValueDecl(); if (!D) return false; @@ -1426,7 +1487,7 @@ static bool checkConstructor(InterpState &S, CodePtr OpPC, const Function *Func, bool CheckDestructor(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { if (!CheckLive(S, OpPC, Ptr, AK_Destroy)) return false; - if (!CheckTemporary(S, OpPC, Ptr, AK_Destroy)) + if (!CheckTemporary(S, OpPC, Ptr.block(), AK_Destroy)) return false; if (!CheckRange(S, OpPC, Ptr, AK_Destroy)) return false; @@ -1620,8 +1681,17 @@ bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func, const auto *StaticDecl = cast<CXXRecordDecl>(Func->getParentDecl()); const auto *InitialFunction = cast<CXXMethodDecl>(Callee); - const CXXMethodDecl *Overrider = S.getContext().getOverridingFunction( - DynamicDecl, StaticDecl, InitialFunction); + const CXXMethodDecl *Overrider; + + if (StaticDecl != DynamicDecl) { + if (!DynamicDecl->isDerivedFrom(StaticDecl)) + return false; + Overrider = S.getContext().getOverridingFunction(DynamicDecl, StaticDecl, + InitialFunction); + + } else { + Overrider = InitialFunction; + } if (Overrider != InitialFunction) { // DR1872: An instantiated virtual constexpr function can't be called in a @@ -1749,7 +1819,7 @@ static void startLifetimeRecurse(const Pointer &Ptr) { bool StartLifetime(InterpState &S, CodePtr OpPC) { const auto &Ptr = S.Stk.peek<Pointer>(); - if (!CheckDummy(S, OpPC, Ptr, AK_Destroy)) + if (Ptr.isBlockPointer() && !CheckDummy(S, OpPC, Ptr.block(), AK_Destroy)) return false; startLifetimeRecurse(Ptr.narrow()); return true; @@ -1780,7 +1850,7 @@ static void endLifetimeRecurse(const Pointer &Ptr) { /// Ends the lifetime of the peek'd pointer. bool EndLifetime(InterpState &S, CodePtr OpPC) { const auto &Ptr = S.Stk.peek<Pointer>(); - if (!CheckDummy(S, OpPC, Ptr, AK_Destroy)) + if (Ptr.isBlockPointer() && !CheckDummy(S, OpPC, Ptr.block(), AK_Destroy)) return false; endLifetimeRecurse(Ptr.narrow()); return true; @@ -1789,7 +1859,7 @@ bool EndLifetime(InterpState &S, CodePtr OpPC) { /// Ends the lifetime of the pop'd pointer. bool EndLifetimePop(InterpState &S, CodePtr OpPC) { const auto &Ptr = S.Stk.pop<Pointer>(); - if (!CheckDummy(S, OpPC, Ptr, AK_Destroy)) + if (Ptr.isBlockPointer() && !CheckDummy(S, OpPC, Ptr.block(), AK_Destroy)) return false; endLifetimeRecurse(Ptr.narrow()); return true; @@ -1802,26 +1872,32 @@ bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E, if (Ptr.inUnion() && Ptr.getBase().getRecord()->isUnion()) Ptr.activate(); + if (!Ptr.isBlockPointer()) + return false; + // Similar to CheckStore(), but with the additional CheckTemporary() call and // the AccessKinds are different. - if (!CheckTemporary(S, OpPC, Ptr, AK_Construct)) - return false; - if (!CheckLive(S, OpPC, Ptr, AK_Construct)) - return false; - if (!CheckDummy(S, OpPC, Ptr, AK_Construct)) + + if (!Ptr.block()->isAccessible()) { + if (!CheckExtern(S, OpPC, Ptr)) + return false; + if (!CheckLive(S, OpPC, Ptr, AK_Construct)) + return false; + return CheckDummy(S, OpPC, Ptr.block(), AK_Construct); + } + if (!CheckTemporary(S, OpPC, Ptr.block(), AK_Construct)) return false; // CheckLifetime for this and all base pointers. for (Pointer P = Ptr;;) { - if (!CheckLifetime(S, OpPC, P, AK_Construct)) + if (!CheckLifetime(S, OpPC, P.getLifetime(), AK_Construct)) return false; if (P.isRoot()) break; P = P.getBase(); } - if (!CheckExtern(S, OpPC, Ptr)) - return false; + if (!CheckRange(S, OpPC, Ptr, AK_Construct)) return false; if (!CheckGlobal(S, OpPC, Ptr)) @@ -2011,7 +2087,7 @@ bool GetTypeidPtr(InterpState &S, CodePtr OpPC, const Type *TypeInfoType) { return false; // Pick the most-derived type. - const Type *T = P.getDeclPtr().getType().getTypePtr(); + CanQualType T = P.getDeclPtr().getType()->getCanonicalTypeUnqualified(); // ... unless we're currently constructing this object. // FIXME: We have a similar check to this in more places. if (S.Current->getFunction()) { @@ -2019,14 +2095,14 @@ bool GetTypeidPtr(InterpState &S, CodePtr OpPC, const Type *TypeInfoType) { if (const Function *Func = Frame->getFunction(); Func && (Func->isConstructor() || Func->isDestructor()) && P.block() == Frame->getThis().block()) { - T = Func->getParentDecl()->getTypeForDecl(); + T = S.getContext().getASTContext().getCanonicalTagType( + Func->getParentDecl()); break; } } } - S.Stk.push<Pointer>(T->getCanonicalTypeUnqualified().getTypePtr(), - TypeInfoType); + S.Stk.push<Pointer>(T->getTypePtr(), TypeInfoType); return true; } diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h index 8a28106..75901e5 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -51,8 +51,7 @@ bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK); /// Checks if a pointer is a dummy pointer. -bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr, - AccessKinds AK); +bool CheckDummy(InterpState &S, CodePtr OpPC, const Block *B, AccessKinds AK); /// Checks if a pointer is null. bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr, @@ -89,11 +88,14 @@ bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK = AK_Read); bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr); -bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, - AccessKinds AK); +bool DiagnoseUninitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, + AccessKinds AK); +bool DiagnoseUninitialized(InterpState &S, CodePtr OpPC, bool Extern, + const Descriptor *Desc, AccessKinds AK); + /// Checks a direct load of a primitive value from a global or local variable. -bool CheckGlobalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr); -bool CheckLocalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr); +bool CheckGlobalLoad(InterpState &S, CodePtr OpPC, const Block *B); +bool CheckLocalLoad(InterpState &S, CodePtr OpPC, const Block *B); /// Checks if a value can be stored in a block. bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr); @@ -1351,10 +1353,10 @@ inline bool ConstFloat(InterpState &S, CodePtr OpPC, const Floating &F) { template <PrimType Name, class T = typename PrimConv<Name>::T> bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I) { - const Pointer &Ptr = S.Current->getLocalPointer(I); - if (!CheckLocalLoad(S, OpPC, Ptr)) + const Block *B = S.Current->getLocalBlock(I); + if (!CheckLocalLoad(S, OpPC, B)) return false; - S.Stk.push<T>(Ptr.deref<T>()); + S.Stk.push<T>(B->deref<T>()); return true; } @@ -1465,22 +1467,26 @@ bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I) { template <PrimType Name, class T = typename PrimConv<Name>::T> bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) { - const Pointer &Ptr = S.P.getPtrGlobal(I); + const Block *B = S.P.getGlobal(I); - if (!CheckGlobalLoad(S, OpPC, Ptr)) + if (!CheckGlobalLoad(S, OpPC, B)) return false; - S.Stk.push<T>(Ptr.deref<T>()); + S.Stk.push<T>(B->deref<T>()); return true; } /// Same as GetGlobal, but without the checks. template <PrimType Name, class T = typename PrimConv<Name>::T> bool GetGlobalUnchecked(InterpState &S, CodePtr OpPC, uint32_t I) { - const Pointer &Ptr = S.P.getPtrGlobal(I); - if (!CheckInitialized(S, OpPC, Ptr, AK_Read)) - return false; - S.Stk.push<T>(Ptr.deref<T>()); + const Block *B = S.P.getGlobal(I); + const auto &Desc = + *reinterpret_cast<const GlobalInlineDescriptor *>(B->rawData()); + if (Desc.InitState != GlobalInitState::Initialized) + return DiagnoseUninitialized(S, OpPC, B->isExtern(), B->getDescriptor(), + AK_Read); + + S.Stk.push<T>(B->deref<T>()); return true; } @@ -1764,10 +1770,7 @@ inline bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off, const Record *TargetRecord = Ptr.atFieldSub(Off).getRecord(); assert(TargetRecord); - if (TargetRecord->getDecl() - ->getTypeForDecl() - ->getAsCXXRecordDecl() - ->getCanonicalDecl() != + if (TargetRecord->getDecl()->getCanonicalDecl() != TargetType->getAsCXXRecordDecl()->getCanonicalDecl()) { QualType MostDerivedType = Ptr.getDeclDesc()->getType(); S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_invalid_downcast) @@ -2351,8 +2354,8 @@ static inline bool IncDecPtrHelper(InterpState &S, CodePtr OpPC, static inline bool IncPtr(InterpState &S, CodePtr OpPC) { const Pointer &Ptr = S.Stk.pop<Pointer>(); - if (!CheckInitialized(S, OpPC, Ptr, AK_Increment)) - return false; + if (!Ptr.isInitialized()) + return DiagnoseUninitialized(S, OpPC, Ptr, AK_Increment); return IncDecPtrHelper<ArithOp::Add>(S, OpPC, Ptr); } @@ -2360,8 +2363,8 @@ static inline bool IncPtr(InterpState &S, CodePtr OpPC) { static inline bool DecPtr(InterpState &S, CodePtr OpPC) { const Pointer &Ptr = S.Stk.pop<Pointer>(); - if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement)) - return false; + if (!Ptr.isInitialized()) + return DiagnoseUninitialized(S, OpPC, Ptr, AK_Decrement); return IncDecPtrHelper<ArithOp::Sub>(S, OpPC, Ptr); } @@ -3195,6 +3198,9 @@ inline bool GetMemberPtr(InterpState &S, CodePtr OpPC, const ValueDecl *D) { inline bool GetMemberPtrBase(InterpState &S, CodePtr OpPC) { const auto &MP = S.Stk.pop<MemberPointer>(); + if (!MP.isBaseCastPossible()) + return false; + S.Stk.push<Pointer>(MP.getBase()); return true; } diff --git a/clang/lib/AST/ByteCode/InterpBlock.cpp b/clang/lib/AST/ByteCode/InterpBlock.cpp index 963b54e..69221d8 100644 --- a/clang/lib/AST/ByteCode/InterpBlock.cpp +++ b/clang/lib/AST/ByteCode/InterpBlock.cpp @@ -64,7 +64,7 @@ void Block::removePointer(Pointer *P) { } void Block::cleanup() { - if (Pointers == nullptr && IsDead) + if (Pointers == nullptr && !IsDynamic && isDead()) (reinterpret_cast<DeadBlock *>(this + 1) - 1)->free(); } @@ -113,8 +113,8 @@ bool Block::hasPointer(const Pointer *P) const { #endif DeadBlock::DeadBlock(DeadBlock *&Root, Block *Blk) - : Root(Root), B(~0u, Blk->Desc, Blk->IsStatic, Blk->IsExtern, Blk->IsWeak, - /*isDead=*/true) { + : Root(Root), B(~0u, Blk->Desc, Blk->isExtern(), Blk->IsStatic, + Blk->isWeak(), Blk->isDummy(), /*IsDead=*/true) { // Add the block to the chain of dead blocks. if (Root) Root->Prev = this; @@ -133,8 +133,7 @@ DeadBlock::DeadBlock(DeadBlock *&Root, Block *Blk) } void DeadBlock::free() { - if (B.IsInitialized) - B.invokeDtor(); + assert(!B.isInitialized()); if (Prev) Prev->Next = Next; diff --git a/clang/lib/AST/ByteCode/InterpBlock.h b/clang/lib/AST/ByteCode/InterpBlock.h index 5162223..7ded1e8 100644 --- a/clang/lib/AST/ByteCode/InterpBlock.h +++ b/clang/lib/AST/ByteCode/InterpBlock.h @@ -42,21 +42,32 @@ enum PrimType : unsigned; /// the data size and the metadata size. /// class Block final { +private: + static constexpr uint8_t ExternFlag = 1 << 0; + static constexpr uint8_t DeadFlag = 1 << 1; + static constexpr uint8_t WeakFlag = 1 << 2; + static constexpr uint8_t DummyFlag = 1 << 3; + public: /// Creates a new block. Block(unsigned EvalID, const std::optional<unsigned> &DeclID, const Descriptor *Desc, bool IsStatic = false, bool IsExtern = false, - bool IsWeak = false) - : EvalID(EvalID), DeclID(DeclID), IsStatic(IsStatic), IsExtern(IsExtern), - IsDynamic(false), IsWeak(IsWeak), Desc(Desc) { + bool IsWeak = false, bool IsDummy = false) + : Desc(Desc), DeclID(DeclID), EvalID(EvalID), IsStatic(IsStatic) { assert(Desc); + AccessFlags |= (ExternFlag * IsExtern); + AccessFlags |= (WeakFlag * IsWeak); + AccessFlags |= (DummyFlag * IsDummy); } Block(unsigned EvalID, const Descriptor *Desc, bool IsStatic = false, - bool IsExtern = false, bool IsWeak = false) - : EvalID(EvalID), DeclID((unsigned)-1), IsStatic(IsStatic), - IsExtern(IsExtern), IsDynamic(false), IsWeak(IsWeak), Desc(Desc) { + bool IsExtern = false, bool IsWeak = false, bool IsDummy = false) + : Desc(Desc), DeclID((unsigned)-1), EvalID(EvalID), IsStatic(IsStatic), + IsDynamic(false) { assert(Desc); + AccessFlags |= (ExternFlag * IsExtern); + AccessFlags |= (WeakFlag * IsWeak); + AccessFlags |= (DummyFlag * IsDummy); } /// Returns the block's descriptor. @@ -64,13 +75,15 @@ public: /// Checks if the block has any live pointers. bool hasPointers() const { return Pointers; } /// Checks if the block is extern. - bool isExtern() const { return IsExtern; } + bool isExtern() const { return AccessFlags & ExternFlag; } /// Checks if the block has static storage duration. bool isStatic() const { return IsStatic; } /// Checks if the block is temporary. bool isTemporary() const { return Desc->IsTemporary; } - bool isWeak() const { return IsWeak; } + bool isWeak() const { return AccessFlags & WeakFlag; } bool isDynamic() const { return IsDynamic; } + bool isDummy() const { return AccessFlags & DummyFlag; } + bool isDead() const { return AccessFlags & DeadFlag; } /// Returns the size of the block. unsigned getSize() const { return Desc->getAllocSize(); } /// Returns the declaration ID. @@ -103,6 +116,10 @@ public: return reinterpret_cast<const std::byte *>(this) + sizeof(Block); } + template <typename T> T deref() const { + return *reinterpret_cast<const T *>(data()); + } + /// Invokes the constructor. void invokeCtor() { assert(!IsInitialized); @@ -126,6 +143,8 @@ public: void dump() const { dump(llvm::errs()); } void dump(llvm::raw_ostream &OS) const; + bool isAccessible() const { return AccessFlags == 0; } + private: friend class Pointer; friend class DeadBlock; @@ -133,10 +152,13 @@ private: friend class DynamicAllocator; Block(unsigned EvalID, const Descriptor *Desc, bool IsExtern, bool IsStatic, - bool IsWeak, bool IsDead) - : EvalID(EvalID), IsStatic(IsStatic), IsExtern(IsExtern), IsDead(true), - IsDynamic(false), IsWeak(IsWeak), Desc(Desc) { + bool IsWeak, bool IsDummy, bool IsDead) + : Desc(Desc), EvalID(EvalID), IsStatic(IsStatic) { assert(Desc); + AccessFlags |= (ExternFlag * IsExtern); + AccessFlags |= (DeadFlag * IsDead); + AccessFlags |= (WeakFlag * IsWeak); + AccessFlags |= (DummyFlag * IsDummy); } /// Deletes a dead block at the end of its lifetime. @@ -150,27 +172,23 @@ private: bool hasPointer(const Pointer *P) const; #endif - const unsigned EvalID = ~0u; + /// Pointer to the stack slot descriptor. + const Descriptor *Desc; /// Start of the chain of pointers. Pointer *Pointers = nullptr; /// Unique identifier of the declaration. std::optional<unsigned> DeclID; + const unsigned EvalID = ~0u; /// Flag indicating if the block has static storage duration. bool IsStatic = false; - /// Flag indicating if the block is an extern. - bool IsExtern = false; - /// Flag indicating if the pointer is dead. This is only ever - /// set once, when converting the Block to a DeadBlock. - bool IsDead = false; /// Flag indicating if the block contents have been initialized /// via invokeCtor. bool IsInitialized = false; /// Flag indicating if this block has been allocated via dynamic /// memory allocation (e.g. malloc). bool IsDynamic = false; - bool IsWeak = false; - /// Pointer to the stack slot descriptor. - const Descriptor *Desc; + /// AccessFlags containing IsExtern, IsDead, IsWeak, and IsDummy bits. + uint8_t AccessFlags = 0; }; /// Descriptor for a dead block. diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index f908d02..14f6929 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -276,7 +276,7 @@ static bool interp__builtin_strlen(InterpState &S, CodePtr OpPC, if (!CheckLive(S, OpPC, StrPtr, AK_Read)) return false; - if (!CheckDummy(S, OpPC, StrPtr, AK_Read)) + if (!CheckDummy(S, OpPC, StrPtr.block(), AK_Read)) return false; assert(StrPtr.getFieldDesc()->isPrimitiveArray()); @@ -1544,8 +1544,7 @@ static bool interp__builtin_operator_new(InterpState &S, CodePtr OpPC, // Composite arrays if (IsArray) { const Descriptor *Desc = - S.P.createDescriptor(NewCall, ElemType.getTypePtr(), - IsArray ? std::nullopt : Descriptor::InlineDescMD); + S.P.createDescriptor(NewCall, ElemType.getTypePtr(), std::nullopt); Block *B = Allocator.allocate(Desc, NumElems.getZExtValue(), S.Ctx.getEvalID(), DynamicAllocator::Form::Operator); @@ -1558,9 +1557,8 @@ static bool interp__builtin_operator_new(InterpState &S, CodePtr OpPC, QualType AllocType = S.getASTContext().getConstantArrayType( ElemType, NumElems, nullptr, ArraySizeModifier::Normal, 0); - const Descriptor *Desc = - S.P.createDescriptor(NewCall, AllocType.getTypePtr(), - IsArray ? std::nullopt : Descriptor::InlineDescMD); + const Descriptor *Desc = S.P.createDescriptor(NewCall, AllocType.getTypePtr(), + Descriptor::InlineDescMD); Block *B = Allocator.allocate(Desc, S.getContext().getEvalID(), DynamicAllocator::Form::Operator); assert(B); @@ -1785,6 +1783,13 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC, return false; QualType DestElemType = getElemType(DestPtr); + if (DestElemType->isIncompleteType()) { + S.FFDiag(S.Current->getSource(OpPC), + diag::note_constexpr_ltor_incomplete_type) + << DestElemType; + return false; + } + size_t RemainingDestElems; if (DestPtr.getFieldDesc()->isArray()) { RemainingDestElems = DestPtr.isUnknownSizeArray() @@ -2232,7 +2237,7 @@ static bool interp__builtin_is_within_lifetime(InterpState &S, CodePtr OpPC, return false; if (!CheckMutable(S, OpPC, Ptr)) return false; - if (!CheckDummy(S, OpPC, Ptr, AK_Read)) + if (!CheckDummy(S, OpPC, Ptr.block(), AK_Read)) return false; } @@ -2754,7 +2759,7 @@ bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E, const RecordType *RT = CurrentType->getAs<RecordType>(); if (!RT) return false; - const RecordDecl *RD = RT->getDecl(); + const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); if (RD->isInvalidDecl()) return false; const ASTRecordLayout &RL = S.getASTContext().getASTRecordLayout(RD); @@ -2787,7 +2792,7 @@ bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E, const RecordType *RT = CurrentType->getAs<RecordType>(); if (!RT) return false; - const RecordDecl *RD = RT->getDecl(); + const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); if (RD->isInvalidDecl()) return false; const ASTRecordLayout &RL = S.getASTContext().getASTRecordLayout(RD); @@ -2799,7 +2804,8 @@ bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E, return false; // Add the offset to the base. - Result += RL.getBaseClassOffset(cast<CXXRecordDecl>(BaseRT->getDecl())); + Result += RL.getBaseClassOffset(cast<CXXRecordDecl>( + BaseRT->getOriginalDecl()->getDefinitionOrSelf())); break; } case OffsetOfNode::Identifier: diff --git a/clang/lib/AST/ByteCode/InterpFrame.cpp b/clang/lib/AST/ByteCode/InterpFrame.cpp index 14f99c7..18400b10 100644 --- a/clang/lib/AST/ByteCode/InterpFrame.cpp +++ b/clang/lib/AST/ByteCode/InterpFrame.cpp @@ -133,6 +133,11 @@ static bool shouldSkipInBacktrace(const Function *F) { MD && MD->getParent()->isAnonymousStructOrUnion()) return true; + if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(FD); + Ctor && Ctor->isDefaulted() && Ctor->isTrivial() && + Ctor->isCopyOrMoveConstructor() && Ctor->inits().empty()) + return true; + return false; } @@ -164,7 +169,7 @@ void InterpFrame::describe(llvm::raw_ostream &OS) const { } else if (const auto *M = dyn_cast<CXXMethodDecl>(F)) { print(OS, This, S.getASTContext(), S.getASTContext().getLValueReferenceType( - S.getASTContext().getRecordType(M->getParent()))); + S.getASTContext().getCanonicalTagType(M->getParent()))); OS << "."; } } @@ -226,6 +231,10 @@ Pointer InterpFrame::getLocalPointer(unsigned Offset) const { return Pointer(localBlock(Offset)); } +Block *InterpFrame::getLocalBlock(unsigned Offset) const { + return localBlock(Offset); +} + Pointer InterpFrame::getParamPointer(unsigned Off) { // Return the block if it was created previously. if (auto Pt = Params.find(Off); Pt != Params.end()) diff --git a/clang/lib/AST/ByteCode/InterpFrame.h b/clang/lib/AST/ByteCode/InterpFrame.h index cfebe93..4be5391 100644 --- a/clang/lib/AST/ByteCode/InterpFrame.h +++ b/clang/lib/AST/ByteCode/InterpFrame.h @@ -86,6 +86,7 @@ public: /// Returns a pointer to a local variables. Pointer getLocalPointer(unsigned Offset) const; + Block *getLocalBlock(unsigned Offset) const; /// Returns the value of an argument. template <typename T> const T &getParam(unsigned Offset) const { diff --git a/clang/lib/AST/ByteCode/InterpState.cpp b/clang/lib/AST/ByteCode/InterpState.cpp index a06b125..b5f0f9a 100644 --- a/clang/lib/AST/ByteCode/InterpState.cpp +++ b/clang/lib/AST/ByteCode/InterpState.cpp @@ -76,8 +76,9 @@ bool InterpState::reportOverflow(const Expr *E, const llvm::APSInt &Value) { void InterpState::deallocate(Block *B) { assert(B); - const Descriptor *Desc = B->getDescriptor(); - assert(Desc); + assert(!B->isDynamic()); + assert(!B->isStatic()); + assert(!B->isDead()); // The block might have a pointer saved in a field in its data // that points to the block itself. We call the dtor first, @@ -87,6 +88,7 @@ void InterpState::deallocate(Block *B) { if (B->IsInitialized) B->invokeDtor(); + assert(!B->isInitialized()); if (B->hasPointers()) { size_t Size = B->getSize(); // Allocate a new block, transferring over pointers. @@ -95,24 +97,20 @@ void InterpState::deallocate(Block *B) { auto *D = new (Memory) DeadBlock(DeadBlocks, B); // Since the block doesn't hold any actual data anymore, we can just // memcpy() everything over. - std::memcpy(D->rawData(), B->rawData(), Desc->getAllocSize()); - D->B.IsInitialized = B->IsInitialized; - - // We moved the contents over to the DeadBlock. - B->IsInitialized = false; + std::memcpy(D->rawData(), B->rawData(), Size); + D->B.IsInitialized = false; } } bool InterpState::maybeDiagnoseDanglingAllocations() { - bool NoAllocationsLeft = (Alloc.getNumAllocations() == 0); + bool NoAllocationsLeft = !Alloc.hasAllocations(); if (!checkingPotentialConstantExpression()) { - for (const auto &It : Alloc.allocation_sites()) { - assert(It.second.size() > 0); + for (const auto &[Source, Site] : Alloc.allocation_sites()) { + assert(!Site.empty()); - const Expr *Source = It.first; CCEDiag(Source->getExprLoc(), diag::note_constexpr_memory_leak) - << (It.second.size() - 1) << Source->getSourceRange(); + << (Site.size() - 1) << Source->getSourceRange(); } } // Keep evaluating before C++20, since the CXXNewExpr wasn't valid there diff --git a/clang/lib/AST/ByteCode/MemberPointer.h b/clang/lib/AST/ByteCode/MemberPointer.h index b17ce25..8dd75ca 100644 --- a/clang/lib/AST/ByteCode/MemberPointer.h +++ b/clang/lib/AST/ByteCode/MemberPointer.h @@ -51,6 +51,12 @@ public: FunctionPointer toFunctionPointer(const Context &Ctx) const; + bool isBaseCastPossible() const { + if (PtrOffset < 0) + return true; + return static_cast<uint64_t>(PtrOffset) <= Base.getByteOffset(); + } + Pointer getBase() const { if (PtrOffset < 0) return Base.atField(-PtrOffset); diff --git a/clang/lib/AST/ByteCode/Pointer.cpp b/clang/lib/AST/ByteCode/Pointer.cpp index dec2088..4d70ae5 100644 --- a/clang/lib/AST/ByteCode/Pointer.cpp +++ b/clang/lib/AST/ByteCode/Pointer.cpp @@ -689,7 +689,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx, assert(Record && "Missing record descriptor"); bool Ok = true; - if (RT->getDecl()->isUnion()) { + if (RT->getOriginalDecl()->isUnion()) { const FieldDecl *ActiveField = nullptr; APValue Value; for (const auto &F : Record->fields()) { @@ -728,14 +728,15 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx, for (unsigned I = 0; I < NB; ++I) { const Record::Base *BD = Record->getBase(I); - QualType BaseTy = Ctx.getASTContext().getRecordType(BD->Decl); + QualType BaseTy = Ctx.getASTContext().getCanonicalTagType(BD->Decl); const Pointer &BP = Ptr.atField(BD->Offset); Ok &= Composite(BaseTy, BP, R.getStructBase(I)); } for (unsigned I = 0; I < NV; ++I) { const Record::Base *VD = Record->getVirtualBase(I); - QualType VirtBaseTy = Ctx.getASTContext().getRecordType(VD->Decl); + QualType VirtBaseTy = + Ctx.getASTContext().getCanonicalTagType(VD->Decl); const Pointer &VP = Ptr.atField(VD->Offset); Ok &= Composite(VirtBaseTy, VP, R.getStructBase(NB + I)); } diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h index 5bafc5b..94c83a0 100644 --- a/clang/lib/AST/ByteCode/Pointer.h +++ b/clang/lib/AST/ByteCode/Pointer.h @@ -282,7 +282,7 @@ public: bool isLive() const { if (!isBlockPointer()) return true; - return asBlockPointer().Pointee && !asBlockPointer().Pointee->IsDead; + return asBlockPointer().Pointee && !asBlockPointer().Pointee->isDead(); } /// Checks if the item is a field in an object. bool isField() const { @@ -568,10 +568,9 @@ public: if (!isBlockPointer()) return false; - if (!asBlockPointer().Pointee) - return false; - - return getDeclDesc()->isDummy(); + if (const Block *Pointee = asBlockPointer().Pointee) + return Pointee->isDummy(); + return false; } /// Checks if an object or a subfield is mutable. diff --git a/clang/lib/AST/ByteCode/Program.cpp b/clang/lib/AST/ByteCode/Program.cpp index 4daa4ab..2843b32 100644 --- a/clang/lib/AST/ByteCode/Program.cpp +++ b/clang/lib/AST/ByteCode/Program.cpp @@ -180,17 +180,15 @@ unsigned Program::getOrCreateDummy(const DeclTy &D) { Desc = allocateDescriptor(D); assert(Desc); - Desc->makeDummy(); - - assert(Desc->isDummy()); // Allocate a block for storage. unsigned I = Globals.size(); auto *G = new (Allocator, Desc->getAllocSize()) Global(Ctx.getEvalID(), getCurrentDecl(), Desc, /*IsStatic=*/true, - /*IsExtern=*/false, IsWeak); + /*IsExtern=*/false, IsWeak, /*IsDummy=*/true); G->block()->invokeCtor(); + assert(G->block()->isDummy()); Globals.push_back(G); DummyVariables[D.getOpaqueValue()] = I; @@ -325,7 +323,7 @@ Record *Program::getOrCreateRecord(const RecordDecl *RD) { const auto *RT = Spec.getType()->getAs<RecordType>(); if (!RT) return nullptr; - const RecordDecl *BD = RT->getDecl(); + const RecordDecl *BD = RT->getOriginalDecl()->getDefinitionOrSelf(); const Record *BR = getOrCreateRecord(BD); const Descriptor *Desc = GetBaseDesc(BD, BR); @@ -342,7 +340,7 @@ Record *Program::getOrCreateRecord(const RecordDecl *RD) { if (!RT) return nullptr; - const RecordDecl *BD = RT->getDecl(); + const RecordDecl *BD = RT->getOriginalDecl()->getDefinitionOrSelf(); const Record *BR = getOrCreateRecord(BD); const Descriptor *Desc = GetBaseDesc(BD, BR); @@ -399,7 +397,8 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty, // Classes and structures. if (const auto *RT = Ty->getAs<RecordType>()) { - if (const auto *Record = getOrCreateRecord(RT->getDecl())) + if (const auto *Record = + getOrCreateRecord(RT->getOriginalDecl()->getDefinitionOrSelf())) return allocateDescriptor(D, Record, MDSize, IsConst, IsTemporary, IsMutable, IsVolatile); return allocateDescriptor(D, MDSize); diff --git a/clang/lib/AST/ByteCode/Record.cpp b/clang/lib/AST/ByteCode/Record.cpp index 1d4ac71..a7934cc 100644 --- a/clang/lib/AST/ByteCode/Record.cpp +++ b/clang/lib/AST/ByteCode/Record.cpp @@ -51,7 +51,7 @@ const Record::Base *Record::getBase(const RecordDecl *FD) const { const Record::Base *Record::getBase(QualType T) const { if (auto *RT = T->getAs<RecordType>()) { - const RecordDecl *RD = RT->getDecl(); + const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); return BaseMap.lookup(RD); } return nullptr; diff --git a/clang/lib/AST/CXXInheritance.cpp b/clang/lib/AST/CXXInheritance.cpp index f037616..e4b77ed 100644 --- a/clang/lib/AST/CXXInheritance.cpp +++ b/clang/lib/AST/CXXInheritance.cpp @@ -132,8 +132,8 @@ bool CXXRecordDecl::forallBases(ForallBasesCallback BaseMatches) const { if (!Ty) return false; - CXXRecordDecl *Base = - cast_if_present<CXXRecordDecl>(Ty->getDecl()->getDefinition()); + CXXRecordDecl *Base = cast_if_present<CXXRecordDecl>( + Ty->getOriginalDecl()->getDefinition()); if (!Base || (Base->isDependentContext() && !Base->isCurrentInstantiation(Record))) { @@ -256,7 +256,8 @@ bool CXXBasePaths::lookupInBases(ASTContext &Context, BaseSpec.getType()->getAs<TemplateSpecializationType>(); if (!TST) { if (auto *RT = BaseSpec.getType()->getAs<RecordType>()) - BaseRecord = cast<CXXRecordDecl>(RT->getDecl()); + BaseRecord = cast<CXXRecordDecl>(RT->getOriginalDecl()) + ->getDefinitionOrSelf(); } else { TemplateName TN = TST->getTemplateName(); if (auto *TD = @@ -336,7 +337,8 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback BaseMatches, CXXRecordDecl *VBase = nullptr; if (const RecordType *Record = PE.Base->getType()->getAs<RecordType>()) - VBase = cast<CXXRecordDecl>(Record->getDecl()); + VBase = cast<CXXRecordDecl>(Record->getOriginalDecl()) + ->getDefinitionOrSelf(); if (!VBase) break; @@ -348,7 +350,8 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback BaseMatches, CXXRecordDecl *HidingClass = nullptr; if (const RecordType *Record = HidingP.back().Base->getType()->getAs<RecordType>()) - HidingClass = cast<CXXRecordDecl>(Record->getDecl()); + HidingClass = cast<CXXRecordDecl>(Record->getOriginalDecl()) + ->getDefinitionOrSelf(); if (!HidingClass) break; @@ -468,7 +471,8 @@ void FinalOverriderCollector::Collect(const CXXRecordDecl *RD, for (const auto &Base : RD->bases()) { if (const RecordType *RT = Base.getType()->getAs<RecordType>()) { - const CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(RT->getDecl()); + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(RT->getOriginalDecl())->getDefinitionOrSelf(); if (!BaseDecl->isPolymorphic()) continue; diff --git a/clang/lib/AST/Comment.cpp b/clang/lib/AST/Comment.cpp index cd73d27..37e21c3 100644 --- a/clang/lib/AST/Comment.cpp +++ b/clang/lib/AST/Comment.cpp @@ -147,8 +147,6 @@ static TypeLoc lookThroughTypedefOrTypeAliasLocs(TypeLoc &SrcTL) { return BlockPointerTL.getPointeeLoc().getUnqualifiedLoc(); if (MemberPointerTypeLoc MemberPointerTL = TL.getAs<MemberPointerTypeLoc>()) return MemberPointerTL.getPointeeLoc().getUnqualifiedLoc(); - if (ElaboratedTypeLoc ETL = TL.getAs<ElaboratedTypeLoc>()) - return ETL.getNamedTypeLoc(); return TL; } diff --git a/clang/lib/AST/CommentParser.cpp b/clang/lib/AST/CommentParser.cpp index e61846d..2e5821a 100644 --- a/clang/lib/AST/CommentParser.cpp +++ b/clang/lib/AST/CommentParser.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "clang/AST/CommentParser.h" +#include "clang/AST/Comment.h" #include "clang/AST/CommentCommandTraits.h" #include "clang/AST/CommentSema.h" #include "clang/Basic/CharInfo.h" @@ -569,6 +570,8 @@ BlockCommandComment *Parser::parseBlockCommand() { InlineCommandComment *Parser::parseInlineCommand() { assert(Tok.is(tok::backslash_command) || Tok.is(tok::at_command)); + CommandMarkerKind CMK = + Tok.is(tok::backslash_command) ? CMK_Backslash : CMK_At; const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID()); const Token CommandTok = Tok; @@ -580,7 +583,7 @@ InlineCommandComment *Parser::parseInlineCommand() { InlineCommandComment *IC = S.actOnInlineCommand( CommandTok.getLocation(), CommandTok.getEndLocation(), - CommandTok.getCommandID(), Args); + CommandTok.getCommandID(), CMK, Args); if (Args.size() < Info->NumArgs) { Diag(CommandTok.getEndLocation().getLocWithOffset(1), diff --git a/clang/lib/AST/CommentSema.cpp b/clang/lib/AST/CommentSema.cpp index 88520d7..649fba9 100644 --- a/clang/lib/AST/CommentSema.cpp +++ b/clang/lib/AST/CommentSema.cpp @@ -363,12 +363,13 @@ void Sema::actOnTParamCommandFinish(TParamCommandComment *Command, InlineCommandComment * Sema::actOnInlineCommand(SourceLocation CommandLocBegin, SourceLocation CommandLocEnd, unsigned CommandID, + CommandMarkerKind CommandMarker, ArrayRef<Comment::Argument> Args) { StringRef CommandName = Traits.getCommandInfo(CommandID)->Name; - return new (Allocator) - InlineCommandComment(CommandLocBegin, CommandLocEnd, CommandID, - getInlineCommandRenderKind(CommandName), Args); + return new (Allocator) InlineCommandComment( + CommandLocBegin, CommandLocEnd, CommandID, + getInlineCommandRenderKind(CommandName), CommandMarker, Args); } InlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin, @@ -905,17 +906,9 @@ bool Sema::isClassOrStructOrTagTypedefDecl() { if (isClassOrStructDeclImpl(ThisDeclInfo->CurrentDecl)) return true; - if (auto *ThisTypedefDecl = dyn_cast<TypedefDecl>(ThisDeclInfo->CurrentDecl)) { - auto UnderlyingType = ThisTypedefDecl->getUnderlyingType(); - if (auto ThisElaboratedType = dyn_cast<ElaboratedType>(UnderlyingType)) { - auto DesugaredType = ThisElaboratedType->desugar(); - if (auto *DesugaredTypePtr = DesugaredType.getTypePtrOrNull()) { - if (auto *ThisRecordType = dyn_cast<RecordType>(DesugaredTypePtr)) { - return isClassOrStructDeclImpl(ThisRecordType->getAsRecordDecl()); - } - } - } - } + if (auto *ThisTypedefDecl = dyn_cast<TypedefDecl>(ThisDeclInfo->CurrentDecl)) + if (auto *D = ThisTypedefDecl->getUnderlyingType()->getAsRecordDecl()) + return isClassOrStructDeclImpl(D); return false; } diff --git a/clang/lib/AST/ComparisonCategories.cpp b/clang/lib/AST/ComparisonCategories.cpp index 2824410..0c7a7f4 100644 --- a/clang/lib/AST/ComparisonCategories.cpp +++ b/clang/lib/AST/ComparisonCategories.cpp @@ -166,7 +166,7 @@ const ComparisonCategoryInfo &ComparisonCategories::getInfoForType(QualType Ty) QualType ComparisonCategoryInfo::getType() const { assert(Record); - return QualType(Record->getTypeForDecl(), 0); + return Record->getASTContext().getCanonicalTagType(Record); } StringRef ComparisonCategories::getCategoryString(ComparisonCategoryType Kind) { diff --git a/clang/lib/AST/ComputeDependence.cpp b/clang/lib/AST/ComputeDependence.cpp index 87334d9..e0cf0de 100644 --- a/clang/lib/AST/ComputeDependence.cpp +++ b/clang/lib/AST/ComputeDependence.cpp @@ -500,9 +500,8 @@ ExprDependence clang::computeDependence(OMPIteratorExpr *E) { ExprDependence clang::computeDependence(DeclRefExpr *E, const ASTContext &Ctx) { auto Deps = ExprDependence::None; - if (auto *NNS = E->getQualifier()) - Deps |= toExprDependence(NNS->getDependence() & - ~NestedNameSpecifierDependence::Dependent); + Deps |= toExprDependence(E->getQualifier().getDependence() & + ~NestedNameSpecifierDependence::Dependent); if (auto *FirstArg = E->getTemplateArgs()) { unsigned NumArgs = E->getNumTemplateArgs(); @@ -673,9 +672,8 @@ ExprDependence clang::computeDependence(MemberExpr *E) { auto D = E->getBase()->getDependence(); D |= getDependenceInExpr(E->getMemberNameInfo()); - if (auto *NNS = E->getQualifier()) - D |= toExprDependence(NNS->getDependence() & - ~NestedNameSpecifierDependence::Dependent); + D |= toExprDependence(E->getQualifier().getDependence() & + ~NestedNameSpecifierDependence::Dependent); for (const auto &A : E->template_arguments()) D |= toExprDependence(A.getArgument().getDependence()); @@ -783,9 +781,8 @@ ExprDependence clang::computeDependence(CXXPseudoDestructorExpr *E) { if (auto *ST = E->getScopeTypeInfo()) D |= turnTypeToValueDependence( toExprDependenceAsWritten(ST->getType()->getDependence())); - if (auto *Q = E->getQualifier()) - D |= toExprDependence(Q->getDependence() & - ~NestedNameSpecifierDependence::Dependent); + D |= toExprDependence(E->getQualifier().getDependence() & + ~NestedNameSpecifierDependence::Dependent); return D; } @@ -801,9 +798,8 @@ clang::computeDependence(OverloadExpr *E, bool KnownDependent, if (KnownContainsUnexpandedParameterPack) Deps |= ExprDependence::UnexpandedPack; Deps |= getDependenceInExpr(E->getNameInfo()); - if (auto *Q = E->getQualifier()) - Deps |= toExprDependence(Q->getDependence() & - ~NestedNameSpecifierDependence::Dependent); + Deps |= toExprDependence(E->getQualifier().getDependence() & + ~NestedNameSpecifierDependence::Dependent); for (auto *D : E->decls()) { if (D->getDeclContext()->isDependentContext() || isa<UnresolvedUsingValueDecl>(D) || isa<TemplateTemplateParmDecl>(D)) @@ -820,8 +816,7 @@ clang::computeDependence(OverloadExpr *E, bool KnownDependent, ExprDependence clang::computeDependence(DependentScopeDeclRefExpr *E) { auto D = ExprDependence::TypeValue; D |= getDependenceInExpr(E->getNameInfo()); - if (auto *Q = E->getQualifier()) - D |= toExprDependence(Q->getDependence()); + D |= toExprDependence(E->getQualifier().getDependence()); for (const auto &A : E->template_arguments()) D |= toExprDependence(A.getArgument().getDependence()); return D; @@ -872,8 +867,7 @@ ExprDependence clang::computeDependence(CXXDependentScopeMemberExpr *E) { auto D = ExprDependence::TypeValueInstantiation; if (!E->isImplicitAccess()) D |= E->getBase()->getDependence(); - if (auto *Q = E->getQualifier()) - D |= toExprDependence(Q->getDependence()); + D |= toExprDependence(E->getQualifier().getDependence()); D |= getDependenceInExpr(E->getMemberNameInfo()); for (const auto &A : E->template_arguments()) D |= toExprDependence(A.getArgument().getDependence()); diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 5471f31..12fe551 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -1693,9 +1693,9 @@ void NamedDecl::printQualifiedName(raw_ostream &OS, return; } printNestedNameSpecifier(OS, P); - if (getDeclName()) - OS << *this; - else { + if (getDeclName()) { + printName(OS, P); + } else { // Give the printName override a chance to pick a different name before we // fall back to "(anonymous)". SmallString<64> NameBuffer; @@ -1883,18 +1883,13 @@ bool NamedDecl::declarationReplaces(const NamedDecl *OldD, // Using declarations can be replaced if they import the same name from the // same context. - if (const auto *UD = dyn_cast<UsingDecl>(this)) { - ASTContext &Context = getASTContext(); - return Context.getCanonicalNestedNameSpecifier(UD->getQualifier()) == - Context.getCanonicalNestedNameSpecifier( - cast<UsingDecl>(OldD)->getQualifier()); - } - if (const auto *UUVD = dyn_cast<UnresolvedUsingValueDecl>(this)) { - ASTContext &Context = getASTContext(); - return Context.getCanonicalNestedNameSpecifier(UUVD->getQualifier()) == - Context.getCanonicalNestedNameSpecifier( - cast<UnresolvedUsingValueDecl>(OldD)->getQualifier()); - } + if (const auto *UD = dyn_cast<UsingDecl>(this)) + return UD->getQualifier().getCanonical() == + + cast<UsingDecl>(OldD)->getQualifier().getCanonical(); + if (const auto *UUVD = dyn_cast<UnresolvedUsingValueDecl>(this)) + return UUVD->getQualifier().getCanonical() == + cast<UnresolvedUsingValueDecl>(OldD)->getQualifier().getCanonical(); if (isRedeclarable(getKind())) { if (getCanonicalDecl() != OldD->getCanonicalDecl()) @@ -2864,7 +2859,8 @@ VarDecl::needsDestruction(const ASTContext &Ctx) const { bool VarDecl::hasFlexibleArrayInit(const ASTContext &Ctx) const { assert(hasInit() && "Expect initializer to check for flexible array init"); auto *Ty = getType()->getAs<RecordType>(); - if (!Ty || !Ty->getDecl()->hasFlexibleArrayMember()) + if (!Ty || + !Ty->getOriginalDecl()->getDefinitionOrSelf()->hasFlexibleArrayMember()) return false; auto *List = dyn_cast<InitListExpr>(getInit()->IgnoreParens()); if (!List) @@ -2879,7 +2875,10 @@ bool VarDecl::hasFlexibleArrayInit(const ASTContext &Ctx) const { CharUnits VarDecl::getFlexibleArrayInitChars(const ASTContext &Ctx) const { assert(hasInit() && "Expect initializer to check for flexible array init"); auto *Ty = getType()->getAs<RecordType>(); - if (!Ty || !Ty->getDecl()->hasFlexibleArrayMember()) + if (!Ty) + return CharUnits::Zero(); + const RecordDecl *RD = Ty->getOriginalDecl()->getDefinitionOrSelf(); + if (!Ty || !RD->hasFlexibleArrayMember()) return CharUnits::Zero(); auto *List = dyn_cast<InitListExpr>(getInit()->IgnoreParens()); if (!List || List->getNumInits() == 0) @@ -2889,7 +2888,7 @@ CharUnits VarDecl::getFlexibleArrayInitChars(const ASTContext &Ctx) const { if (!InitTy) return CharUnits::Zero(); CharUnits FlexibleArraySize = Ctx.getTypeSizeInChars(InitTy); - const ASTRecordLayout &RL = Ctx.getASTRecordLayout(Ty->getDecl()); + const ASTRecordLayout &RL = Ctx.getASTRecordLayout(RD); CharUnits FlexibleArrayOffset = Ctx.toCharUnitsFromBits(RL.getFieldOffset(RL.getFieldCount() - 1)); if (FlexibleArrayOffset + FlexibleArraySize < RL.getSize()) @@ -2991,7 +2990,10 @@ bool ParmVarDecl::isDestroyedInCallee() const { // FIXME: isParamDestroyedInCallee() should probably imply // isDestructedType() const auto *RT = getType()->getAs<RecordType>(); - if (RT && RT->getDecl()->isParamDestroyedInCallee() && + if (RT && + RT->getOriginalDecl() + ->getDefinitionOrSelf() + ->isParamDestroyedInCallee() && getType().isDestructedType()) return true; @@ -3502,7 +3504,7 @@ bool FunctionDecl::isUsableAsGlobalAllocationFunctionInConstantEvaluation( while (const auto *TD = T->getAs<TypedefType>()) T = TD->getDecl()->getUnderlyingType(); const IdentifierInfo *II = - T->castAs<EnumType>()->getDecl()->getIdentifier(); + T->castAs<EnumType>()->getOriginalDecl()->getIdentifier(); if (II && II->isStr("__hot_cold_t")) Consume(); } @@ -4653,7 +4655,7 @@ bool FieldDecl::isAnonymousStructOrUnion() const { return false; if (const auto *Record = getType()->getAs<RecordType>()) - return Record->getDecl()->isAnonymousStructOrUnion(); + return Record->getOriginalDecl()->isAnonymousStructOrUnion(); return false; } @@ -4713,7 +4715,7 @@ bool FieldDecl::isZeroSize(const ASTContext &Ctx) const { const auto *RT = getType()->getAs<RecordType>(); if (!RT) return false; - const RecordDecl *RD = RT->getDecl()->getDefinition(); + const RecordDecl *RD = RT->getOriginalDecl()->getDefinition(); if (!RD) { assert(isInvalidDecl() && "valid field has incomplete type"); return false; @@ -4836,10 +4838,6 @@ TagDecl *TagDecl::getCanonicalDecl() { return getFirstDecl(); } void TagDecl::setTypedefNameForAnonDecl(TypedefNameDecl *TDD) { TypedefNameDeclOrQualifier = TDD; - if (const Type *T = getTypeForDecl()) { - (void)T; - assert(T->isLinkageValid()); - } assert(isLinkageValid()); } @@ -4867,25 +4865,16 @@ void TagDecl::completeDefinition() { } TagDecl *TagDecl::getDefinition() const { - if (isCompleteDefinition()) + if (isCompleteDefinition() || isBeingDefined()) return const_cast<TagDecl *>(this); - // If it's possible for us to have an out-of-date definition, check now. - if (mayHaveOutOfDateDef()) { - if (IdentifierInfo *II = getIdentifier()) { - if (II->isOutOfDate()) { - updateOutOfDate(*II); - } - } - } - if (const auto *CXXRD = dyn_cast<CXXRecordDecl>(this)) return CXXRD->getDefinition(); - for (auto *R : redecls()) - if (R->isCompleteDefinition()) + for (TagDecl *R : + redecl_range(redecl_iterator(getNextRedeclaration()), redecl_iterator())) + if (R->isCompleteDefinition() || R->isBeingDefined()) return R; - return nullptr; } @@ -4919,7 +4908,7 @@ void TagDecl::printName(raw_ostream &OS, const PrintingPolicy &Policy) const { // is already printed as part of the type. PrintingPolicy Copy(Policy); Copy.SuppressScope = true; - getASTContext().getTagDeclType(this).print(OS, Copy); + QualType(getASTContext().getCanonicalTagType(this)).print(OS, Copy); return; } // Otherwise, do the normal printing. @@ -4963,19 +4952,13 @@ EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC, IdentifierInfo *Id, EnumDecl *PrevDecl, bool IsScoped, bool IsScopedUsingClassTag, bool IsFixed) { - auto *Enum = new (C, DC) EnumDecl(C, DC, StartLoc, IdLoc, Id, PrevDecl, - IsScoped, IsScopedUsingClassTag, IsFixed); - Enum->setMayHaveOutOfDateDef(C.getLangOpts().Modules); - C.getTypeDeclType(Enum, PrevDecl); - return Enum; + return new (C, DC) EnumDecl(C, DC, StartLoc, IdLoc, Id, PrevDecl, IsScoped, + IsScopedUsingClassTag, IsFixed); } EnumDecl *EnumDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { - EnumDecl *Enum = - new (C, ID) EnumDecl(C, nullptr, SourceLocation(), SourceLocation(), - nullptr, nullptr, false, false, false); - Enum->setMayHaveOutOfDateDef(C.getLangOpts().Modules); - return Enum; + return new (C, ID) EnumDecl(C, nullptr, SourceLocation(), SourceLocation(), + nullptr, nullptr, false, false, false); } SourceRange EnumDecl::getIntegerTypeRange() const { @@ -5035,7 +5018,7 @@ EnumDecl *EnumDecl::getTemplateInstantiationPattern() const { EnumDecl *ED = getInstantiatedFromMemberEnum(); while (auto *NewED = ED->getInstantiatedFromMemberEnum()) ED = NewED; - return getDefinitionOrSelf(ED); + return ::getDefinitionOrSelf(ED); } } @@ -5125,21 +5108,15 @@ RecordDecl::RecordDecl(Kind DK, TagKind TK, const ASTContext &C, RecordDecl *RecordDecl::Create(const ASTContext &C, TagKind TK, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, RecordDecl* PrevDecl) { - RecordDecl *R = new (C, DC) RecordDecl(Record, TK, C, DC, - StartLoc, IdLoc, Id, PrevDecl); - R->setMayHaveOutOfDateDef(C.getLangOpts().Modules); - - C.getTypeDeclType(R, PrevDecl); - return R; + return new (C, DC) + RecordDecl(Record, TK, C, DC, StartLoc, IdLoc, Id, PrevDecl); } RecordDecl *RecordDecl::CreateDeserialized(const ASTContext &C, GlobalDeclID ID) { - RecordDecl *R = new (C, ID) + return new (C, ID) RecordDecl(Record, TagTypeKind::Struct, C, nullptr, SourceLocation(), SourceLocation(), nullptr, nullptr); - R->setMayHaveOutOfDateDef(C.getLangOpts().Modules); - return R; } bool RecordDecl::isLambda() const { @@ -5163,7 +5140,7 @@ bool RecordDecl::isOrContainsUnion() const { if (const RecordDecl *Def = getDefinition()) { for (const FieldDecl *FD : Def->fields()) { const RecordType *RT = FD->getType()->getAs<RecordType>(); - if (RT && RT->getDecl()->isOrContainsUnion()) + if (RT && RT->getOriginalDecl()->isOrContainsUnion()) return true; } } @@ -5295,8 +5272,9 @@ const FieldDecl *RecordDecl::findFirstNamedDataMember() const { return I; if (const auto *RT = I->getType()->getAs<RecordType>()) - if (const FieldDecl *NamedDataMember = - RT->getDecl()->findFirstNamedDataMember()) + if (const FieldDecl *NamedDataMember = RT->getOriginalDecl() + ->getDefinitionOrSelf() + ->findFirstNamedDataMember()) return NamedDataMember; } @@ -5658,14 +5636,14 @@ void TypedefNameDecl::anchor() {} TagDecl *TypedefNameDecl::getAnonDeclWithTypedefName(bool AnyRedecl) const { if (auto *TT = getTypeSourceInfo()->getType()->getAs<TagType>()) { - auto *OwningTypedef = TT->getDecl()->getTypedefNameForAnonDecl(); + auto *OwningTypedef = TT->getOriginalDecl()->getTypedefNameForAnonDecl(); auto *ThisTypedef = this; if (AnyRedecl && OwningTypedef) { OwningTypedef = OwningTypedef->getCanonicalDecl(); ThisTypedef = ThisTypedef->getCanonicalDecl(); } if (OwningTypedef == ThisTypedef) - return TT->getDecl(); + return TT->getOriginalDecl()->getDefinitionOrSelf(); } return nullptr; @@ -5674,7 +5652,7 @@ TagDecl *TypedefNameDecl::getAnonDeclWithTypedefName(bool AnyRedecl) const { bool TypedefNameDecl::isTransparentTagSlow() const { auto determineIsTransparent = [&]() { if (auto *TT = getUnderlyingType()->getAs<TagType>()) { - if (auto *TD = TT->getDecl()) { + if (auto *TD = TT->getOriginalDecl()) { if (TD->getName() != getName()) return false; SourceLocation TTLoc = getLocation(); diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 13c46fd..680a4d7 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -58,10 +58,6 @@ using namespace clang; #define ABSTRACT_DECL(DECL) #include "clang/AST/DeclNodes.inc" -void Decl::updateOutOfDate(IdentifierInfo &II) const { - getASTContext().getExternalSource()->updateOutOfDateIdentifier(II); -} - #define DECL(DERIVED, BASE) \ static_assert(alignof(Decl) >= alignof(DERIVED##Decl), \ "Alignment sufficient after objects prepended to " #DERIVED); @@ -489,8 +485,7 @@ bool Decl::isFlexibleArrayMemberLike( // Look through typedefs. if (TypedefTypeLoc TTL = TL.getAsAdjusted<TypedefTypeLoc>()) { - const TypedefNameDecl *TDL = TTL.getTypedefNameDecl(); - TInfo = TDL->getTypeSourceInfo(); + TInfo = TTL.getDecl()->getTypeSourceInfo(); continue; } @@ -1512,30 +1507,19 @@ DeclContext *DeclContext::getPrimaryContext() { case Decl::ObjCCategoryImpl: return this; - default: - if (getDeclKind() >= Decl::firstTag && getDeclKind() <= Decl::lastTag) { - // If this is a tag type that has a definition or is currently - // being defined, that definition is our primary context. - auto *Tag = cast<TagDecl>(this); - - if (TagDecl *Def = Tag->getDefinition()) - return Def; - - 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()) - return PossiblePartialDef; - } else { - assert(isa<InjectedClassNameType>(Tag->getTypeForDecl())); - } - - return Tag; - } + // If this is a tag type that has a definition or is currently + // being defined, that definition is our primary context. + case Decl::ClassTemplatePartialSpecialization: + case Decl::ClassTemplateSpecialization: + case Decl::CXXRecord: + return cast<CXXRecordDecl>(this)->getDefinitionOrSelf(); + case Decl::Record: + case Decl::Enum: + return cast<TagDecl>(this)->getDefinitionOrSelf(); + default: assert(getDeclKind() >= Decl::firstFunction && - getDeclKind() <= Decl::lastFunction && - "Unknown DeclContext kind"); + getDeclKind() <= Decl::lastFunction && "Unknown DeclContext kind"); return this; } } diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index 037a28c4..50b1a1d 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -132,16 +132,9 @@ CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, const ASTContext &C, CXXRecordDecl *CXXRecordDecl::Create(const ASTContext &C, TagKind TK, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, - CXXRecordDecl *PrevDecl, - bool DelayTypeCreation) { - auto *R = new (C, DC) CXXRecordDecl(CXXRecord, TK, C, DC, StartLoc, IdLoc, Id, - PrevDecl); - R->setMayHaveOutOfDateDef(C.getLangOpts().Modules); - - // FIXME: DelayTypeCreation seems like such a hack - if (!DelayTypeCreation) - C.getTypeDeclType(R, PrevDecl); - return R; + CXXRecordDecl *PrevDecl) { + return new (C, DC) + CXXRecordDecl(CXXRecord, TK, C, DC, StartLoc, IdLoc, Id, PrevDecl); } CXXRecordDecl * @@ -154,10 +147,7 @@ CXXRecordDecl::CreateLambda(const ASTContext &C, DeclContext *DC, R->setBeingDefined(true); R->DefinitionData = new (C) struct LambdaDefinitionData( R, Info, DependencyKind, IsGeneric, CaptureDefault); - R->setMayHaveOutOfDateDef(false); R->setImplicit(true); - - C.getTypeDeclType(R, /*PrevDecl=*/nullptr); return R; } @@ -166,7 +156,6 @@ CXXRecordDecl *CXXRecordDecl::CreateDeserialized(const ASTContext &C, auto *R = new (C, ID) CXXRecordDecl(CXXRecord, TagTypeKind::Struct, C, nullptr, SourceLocation(), SourceLocation(), nullptr, nullptr); - R->setMayHaveOutOfDateDef(false); return R; } @@ -178,7 +167,7 @@ static bool hasRepeatedBaseClass(const CXXRecordDecl *StartRD) { SmallVector<const CXXRecordDecl*, 8> WorkList = {StartRD}; while (!WorkList.empty()) { const CXXRecordDecl *RD = WorkList.pop_back_val(); - if (RD->getTypeForDecl()->isDependentType()) + if (RD->isDependentType()) continue; for (const CXXBaseSpecifier &BaseSpec : RD->bases()) { if (const CXXRecordDecl *B = BaseSpec.getType()->getAsCXXRecordDecl()) { @@ -228,7 +217,8 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, if (BaseType->isDependentType()) continue; auto *BaseClassDecl = - cast<CXXRecordDecl>(BaseType->castAs<RecordType>()->getDecl()); + cast<CXXRecordDecl>(BaseType->castAs<RecordType>()->getOriginalDecl()) + ->getDefinitionOrSelf(); // C++2a [class]p7: // A standard-layout class is a class that: @@ -1218,7 +1208,7 @@ void CXXRecordDecl::addedMember(Decl *D) { bool IsZeroSize = Field->isZeroSize(Context); if (const auto *RecordTy = T->getAs<RecordType>()) { - auto *FieldRec = cast<CXXRecordDecl>(RecordTy->getDecl()); + auto *FieldRec = cast<CXXRecordDecl>(RecordTy->getOriginalDecl()); if (FieldRec->getDefinition()) { addedClassSubobject(FieldRec); @@ -1925,7 +1915,8 @@ static void CollectVisibleConversions( = CXXRecordDecl::MergeAccess(Access, I.getAccessSpecifier()); bool BaseInVirtual = InVirtual || I.isVirtual(); - auto *Base = cast<CXXRecordDecl>(RT->getDecl()); + auto *Base = + cast<CXXRecordDecl>(RT->getOriginalDecl())->getDefinitionOrSelf(); CollectVisibleConversions(Context, Base, BaseInVirtual, BaseAccess, *HiddenTypes, Output, VOutput, HiddenVBaseCs); } @@ -1963,9 +1954,11 @@ static void CollectVisibleConversions(ASTContext &Context, const auto *RT = I.getType()->getAs<RecordType>(); if (!RT) continue; - CollectVisibleConversions(Context, cast<CXXRecordDecl>(RT->getDecl()), - I.isVirtual(), I.getAccessSpecifier(), - HiddenTypes, Output, VBaseCs, HiddenVBaseCs); + CollectVisibleConversions( + Context, + cast<CXXRecordDecl>(RT->getOriginalDecl())->getDefinitionOrSelf(), + I.isVirtual(), I.getAccessSpecifier(), HiddenTypes, Output, VBaseCs, + HiddenVBaseCs); } // Add any unhidden conversions provided by virtual bases. @@ -2125,11 +2118,10 @@ const CXXRecordDecl *CXXRecordDecl::getTemplateInstantiationPattern() const { CXXDestructorDecl *CXXRecordDecl::getDestructor() const { ASTContext &Context = getASTContext(); - QualType ClassType = Context.getTypeDeclType(this); + CanQualType ClassType = Context.getCanonicalTagType(this); - DeclarationName Name - = Context.DeclarationNames.getCXXDestructorName( - Context.getCanonicalType(ClassType)); + DeclarationName Name = + Context.DeclarationNames.getCXXDestructorName(ClassType); DeclContext::lookup_result R = lookup(Name); @@ -2159,6 +2151,29 @@ bool CXXRecordDecl::isInjectedClassName() const { return false; } +bool CXXRecordDecl::hasInjectedClassType() const { + switch (getDeclKind()) { + case Decl::ClassTemplatePartialSpecialization: + return true; + case Decl::ClassTemplateSpecialization: + return false; + case Decl::CXXRecord: + return getDescribedClassTemplate() != nullptr; + default: + llvm_unreachable("unexpected decl kind"); + } +} + +CanQualType CXXRecordDecl::getCanonicalTemplateSpecializationType( + const ASTContext &Ctx) const { + if (auto *RD = dyn_cast<ClassTemplatePartialSpecializationDecl>(this)) + return RD->getCanonicalInjectedSpecializationType(Ctx); + if (const ClassTemplateDecl *TD = getDescribedClassTemplate(); + TD && !isa<ClassTemplateSpecializationDecl>(this)) + return TD->getCanonicalInjectedSpecializationType(Ctx); + return CanQualType(); +} + static bool isDeclContextInNamespace(const DeclContext *DC) { while (!DC->isTranslationUnit()) { if (DC->isNamespace()) @@ -2272,7 +2287,7 @@ void CXXRecordDecl::completeDefinition(CXXFinalOverriderMap *FinalOverriders) { Context.getDiagnostics().Report( AT->getLocation(), diag::warn_cxx20_compat_requires_explicit_init_non_aggregate) - << AT << FD << Context.getRecordType(this); + << AT << FD << Context.getCanonicalTagType(this); } } @@ -2284,7 +2299,7 @@ void CXXRecordDecl::completeDefinition(CXXFinalOverriderMap *FinalOverriders) { if (const auto *AT = FD->getAttr<ExplicitInitAttr>()) Context.getDiagnostics().Report(AT->getLocation(), diag::warn_attribute_needs_aggregate) - << AT << Context.getRecordType(this); + << AT << Context.getCanonicalTagType(this); } setHasUninitializedExplicitInitFields(false); } @@ -2296,8 +2311,8 @@ bool CXXRecordDecl::mayBeAbstract() const { return false; for (const auto &B : bases()) { - const auto *BaseDecl = - cast<CXXRecordDecl>(B.getType()->castAs<RecordType>()->getDecl()); + const auto *BaseDecl = cast<CXXRecordDecl>( + B.getType()->castAs<RecordType>()->getOriginalDecl()); if (BaseDecl->isAbstract()) return true; } @@ -2460,7 +2475,8 @@ CXXMethodDecl::getCorrespondingMethodInClass(const CXXRecordDecl *RD, const RecordType *RT = I.getType()->getAs<RecordType>(); if (!RT) continue; - const auto *Base = cast<CXXRecordDecl>(RT->getDecl()); + const auto *Base = + cast<CXXRecordDecl>(RT->getOriginalDecl())->getDefinitionOrSelf(); if (CXXMethodDecl *D = this->getCorrespondingMethodInClass(Base)) AddFinalOverrider(D); } @@ -2712,8 +2728,7 @@ bool CXXMethodDecl::isCopyAssignmentOperator() const { ParamType = Ref->getPointeeType(); ASTContext &Context = getASTContext(); - QualType ClassType - = Context.getCanonicalType(Context.getTypeDeclType(getParent())); + CanQualType ClassType = Context.getCanonicalTagType(getParent()); return Context.hasSameUnqualifiedType(ClassType, ParamType); } @@ -2733,8 +2748,7 @@ bool CXXMethodDecl::isMoveAssignmentOperator() const { ParamType = ParamType->getPointeeType(); ASTContext &Context = getASTContext(); - QualType ClassType - = Context.getCanonicalType(Context.getTypeDeclType(getParent())); + CanQualType ClassType = Context.getCanonicalTagType(getParent()); return Context.hasSameUnqualifiedType(ClassType, ParamType); } @@ -2769,7 +2783,7 @@ CXXMethodDecl::overridden_methods() const { static QualType getThisObjectType(ASTContext &C, const FunctionProtoType *FPT, const CXXRecordDecl *Decl) { - QualType ClassTy = C.getTypeDeclType(Decl); + CanQualType ClassTy = C.getCanonicalTagType(Decl); return C.getQualifiedType(ClassTy, FPT->getMethodQuals()); } @@ -3027,11 +3041,9 @@ bool CXXConstructorDecl::isCopyOrMoveConstructor(unsigned &TypeQuals) const { // Is it a reference to our class type? ASTContext &Context = getASTContext(); - CanQualType PointeeType - = Context.getCanonicalType(ParamRefType->getPointeeType()); - CanQualType ClassTy - = Context.getCanonicalType(Context.getTagDeclType(getParent())); - if (PointeeType.getUnqualifiedType() != ClassTy) + QualType PointeeType = ParamRefType->getPointeeType(); + CanQualType ClassTy = Context.getCanonicalTagType(getParent()); + if (!Context.hasSameUnqualifiedType(PointeeType, ClassTy)) return false; // FIXME: other qualifiers? @@ -3066,15 +3078,11 @@ bool CXXConstructorDecl::isSpecializationCopyingObject() const { const ParmVarDecl *Param = getParamDecl(0); ASTContext &Context = getASTContext(); - CanQualType ParamType = Context.getCanonicalType(Param->getType()); + CanQualType ParamType = Param->getType()->getCanonicalTypeUnqualified(); // Is it the same as our class type? - CanQualType ClassTy - = Context.getCanonicalType(Context.getTagDeclType(getParent())); - if (ParamType.getUnqualifiedType() != ClassTy) - return false; - - return true; + CanQualType ClassTy = Context.getCanonicalTagType(getParent()); + return ParamType == ClassTy; } void CXXDestructorDecl::anchor() {} @@ -3371,7 +3379,7 @@ ConstructorUsingShadowDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { } CXXRecordDecl *ConstructorUsingShadowDecl::getNominatedBaseClass() const { - return getIntroducer()->getQualifier()->getAsRecordDecl(); + return getIntroducer()->getQualifier().getAsRecordDecl(); } void BaseUsingDecl::anchor() {} diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp index f4265dd0..196057f 100644 --- a/clang/lib/AST/DeclPrinter.cpp +++ b/clang/lib/AST/DeclPrinter.cpp @@ -202,8 +202,7 @@ void Decl::printGroup(Decl** Begin, unsigned NumDecls, } Decl** End = Begin + NumDecls; - TagDecl* TD = dyn_cast<TagDecl>(*Begin); - if (TD) + if (isa<TagDecl>(*Begin)) ++Begin; PrintingPolicy SubPolicy(Policy); @@ -211,13 +210,9 @@ void Decl::printGroup(Decl** Begin, unsigned NumDecls, bool isFirst = true; for ( ; Begin != End; ++Begin) { if (isFirst) { - if(TD) - SubPolicy.IncludeTagDefinition = true; - SubPolicy.SuppressSpecifiers = false; isFirst = false; } else { - if (!isFirst) Out << ", "; - SubPolicy.IncludeTagDefinition = false; + Out << ", "; SubPolicy.SuppressSpecifiers = true; } @@ -487,10 +482,12 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) { QualType CurDeclType = getDeclType(*D); if (!Decls.empty() && !CurDeclType.isNull()) { QualType BaseType = GetBaseType(CurDeclType); - if (!BaseType.isNull() && isa<ElaboratedType>(BaseType) && - cast<ElaboratedType>(BaseType)->getOwnedTagDecl() == Decls[0]) { - Decls.push_back(*D); - continue; + if (const auto *TT = dyn_cast_or_null<TagType>(BaseType); + TT && TT->isTagOwned()) { + if (TT->getOriginalDecl() == Decls[0]) { + Decls.push_back(*D); + continue; + } } } @@ -662,16 +659,6 @@ static void printExplicitSpecifier(ExplicitSpecifier ES, llvm::raw_ostream &Out, Out << Proto; } -static void MaybePrintTagKeywordIfSupressingScopes(PrintingPolicy &Policy, - QualType T, - llvm::raw_ostream &Out) { - StringRef prefix = T->isClassType() ? "class " - : T->isStructureType() ? "struct " - : T->isUnionType() ? "union " - : ""; - Out << prefix; -} - void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { if (!D->getDescribedFunctionTemplate() && !D->isFunctionTemplateSpecialization()) { @@ -721,11 +708,8 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { Proto += D->getQualifiedNameAsString(); } else { llvm::raw_string_ostream OS(Proto); - if (!Policy.SuppressScope) { - if (const NestedNameSpecifier *NS = D->getQualifier()) { - NS->print(OS, Policy); - } - } + if (!Policy.SuppressScope) + D->getQualifier().print(OS, Policy); D->getNameInfo().printName(OS, Policy); } @@ -833,10 +817,6 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { Out << Proto << " -> "; Proto.clear(); } - if (!Policy.SuppressTagKeyword && Policy.SuppressScope && - !Policy.SuppressUnwrittenScope) - MaybePrintTagKeywordIfSupressingScopes(Policy, AFT->getReturnType(), - Out); AFT->getReturnType().print(Out, Policy, Proto); Proto.clear(); } @@ -995,10 +975,6 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) { } } - if (!Policy.SuppressTagKeyword && Policy.SuppressScope && - !Policy.SuppressUnwrittenScope) - MaybePrintTagKeywordIfSupressingScopes(Policy, T, Out); - printDeclType(T, (isa<ParmVarDecl>(D) && Policy.CleanUglifiedParameters && D->getIdentifier()) ? D->getIdentifier()->deuglifiedName() @@ -1028,7 +1004,6 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) { } PrintingPolicy SubPolicy(Policy); SubPolicy.SuppressSpecifiers = false; - SubPolicy.IncludeTagDefinition = false; Init->printPretty(Out, nullptr, SubPolicy, Indentation, "\n", &Context); if ((D->getInitStyle() == VarDecl::CallInit) && !isa<ParenListExpr>(Init)) Out << ")"; @@ -1086,15 +1061,13 @@ void DeclPrinter::VisitNamespaceDecl(NamespaceDecl *D) { void DeclPrinter::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { Out << "using namespace "; - if (D->getQualifier()) - D->getQualifier()->print(Out, Policy); + D->getQualifier().print(Out, Policy); Out << *D->getNominatedNamespaceAsWritten(); } void DeclPrinter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { Out << "namespace " << *D << " = "; - if (D->getQualifier()) - D->getQualifier()->print(Out, Policy); + D->getQualifier().print(Out, Policy); Out << *D->getAliasedNamespace(); } @@ -1115,8 +1088,7 @@ void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) { Out << ' '; if (D->getIdentifier()) { - if (auto *NNS = D->getQualifier()) - NNS->print(Out, Policy); + D->getQualifier().print(Out, Policy); Out << *D; if (auto *S = dyn_cast<ClassTemplateSpecializationDecl>(D)) { @@ -1746,7 +1718,7 @@ void DeclPrinter::VisitUsingDecl(UsingDecl *D) { Out << "using "; if (D->hasTypename()) Out << "typename "; - D->getQualifier()->print(Out, Policy); + D->getQualifier().print(Out, Policy); // Use the correct record name when the using declaration is used for // inheriting constructors. @@ -1768,14 +1740,14 @@ void DeclPrinter::VisitUsingEnumDecl(UsingEnumDecl *D) { void DeclPrinter::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) { Out << "using typename "; - D->getQualifier()->print(Out, Policy); + D->getQualifier().print(Out, Policy); Out << D->getDeclName(); } void DeclPrinter::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) { if (!D->isAccessDeclaration()) Out << "using "; - D->getQualifier()->print(Out, Policy); + D->getQualifier().print(Out, Policy); Out << D->getDeclName(); } diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index bc4a299..8a6fb33 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -632,7 +632,8 @@ ClassTemplateDecl::findPartialSpecialization(QualType T) { ASTContext &Context = getASTContext(); for (ClassTemplatePartialSpecializationDecl &P : getPartialSpecializations()) { - if (Context.hasSameType(P.getInjectedSpecializationType(), T)) + if (Context.hasSameType(P.getCanonicalInjectedSpecializationType(Context), + T)) return P.getMostRecentDecl(); } @@ -651,28 +652,20 @@ ClassTemplateDecl::findPartialSpecInstantiatedFromMember( return nullptr; } -QualType -ClassTemplateDecl::getInjectedClassNameSpecialization() { +CanQualType ClassTemplateDecl::getCanonicalInjectedSpecializationType( + const ASTContext &Ctx) const { Common *CommonPtr = getCommonPtr(); - if (!CommonPtr->InjectedClassNameType.isNull()) - return CommonPtr->InjectedClassNameType; - - // C++0x [temp.dep.type]p2: - // The template argument list of a primary template is a template argument - // list in which the nth template argument has the value of the nth template - // parameter of the class template. If the nth template parameter is a - // template parameter pack (14.5.3), the nth template argument is a pack - // expansion (14.5.3) whose pattern is the name of the template parameter - // pack. - ASTContext &Context = getASTContext(); - TemplateName Name = Context.getQualifiedTemplateName( - /*NNS=*/nullptr, /*TemplateKeyword=*/false, TemplateName(this)); - auto TemplateArgs = getTemplateParameters()->getInjectedTemplateArgs(Context); - CommonPtr->InjectedClassNameType = - Context.getTemplateSpecializationType(Name, - /*SpecifiedArgs=*/TemplateArgs, - /*CanonicalArgs=*/{}); - return CommonPtr->InjectedClassNameType; + + if (CommonPtr->CanonInjectedTST.isNull()) { + SmallVector<TemplateArgument> CanonicalArgs( + getTemplateParameters()->getInjectedTemplateArgs(Ctx)); + Ctx.canonicalizeTemplateArguments(CanonicalArgs); + CommonPtr->CanonInjectedTST = + CanQualType::CreateUnsafe(Ctx.getCanonicalTemplateSpecializationType( + TemplateName(const_cast<ClassTemplateDecl *>(getCanonicalDecl())), + CanonicalArgs)); + } + return CommonPtr->CanonInjectedTST; } //===----------------------------------------------------------------------===// @@ -998,7 +991,6 @@ ClassTemplateSpecializationDecl *ClassTemplateSpecializationDecl::Create( auto *Result = new (Context, DC) ClassTemplateSpecializationDecl( Context, ClassTemplateSpecialization, TK, DC, StartLoc, IdLoc, SpecializedTemplate, Args, StrictPackMatch, PrevDecl); - Result->setMayHaveOutOfDateDef(false); // If the template decl is incomplete, copy the external lexical storage from // the base template. This allows instantiations of incomplete types to @@ -1008,17 +1000,14 @@ ClassTemplateSpecializationDecl *ClassTemplateSpecializationDecl::Create( Result->setHasExternalLexicalStorage( SpecializedTemplate->getTemplatedDecl()->hasExternalLexicalStorage()); - Context.getTypeDeclType(Result, PrevDecl); return Result; } ClassTemplateSpecializationDecl * ClassTemplateSpecializationDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { - auto *Result = - new (C, ID) ClassTemplateSpecializationDecl(C, ClassTemplateSpecialization); - Result->setMayHaveOutOfDateDef(false); - return Result; + return new (C, ID) + ClassTemplateSpecializationDecl(C, ClassTemplateSpecialization); } void ClassTemplateSpecializationDecl::getNameForDiagnostic( @@ -1180,13 +1169,15 @@ ClassTemplatePartialSpecializationDecl::ClassTemplatePartialSpecializationDecl( ASTContext &Context, TagKind TK, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, TemplateParameterList *Params, ClassTemplateDecl *SpecializedTemplate, ArrayRef<TemplateArgument> Args, + CanQualType CanonInjectedTST, ClassTemplatePartialSpecializationDecl *PrevDecl) : ClassTemplateSpecializationDecl( Context, ClassTemplatePartialSpecialization, TK, DC, StartLoc, IdLoc, // Tracking StrictPackMatch for Partial // Specializations is not needed. SpecializedTemplate, Args, /*StrictPackMatch=*/false, PrevDecl), - TemplateParams(Params), InstantiatedFromMember(nullptr, false) { + TemplateParams(Params), InstantiatedFromMember(nullptr, false), + CanonInjectedTST(CanonInjectedTST) { if (AdoptTemplateParameterList(Params, this)) setInvalidDecl(); } @@ -1196,24 +1187,31 @@ ClassTemplatePartialSpecializationDecl::Create( ASTContext &Context, TagKind TK, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, TemplateParameterList *Params, ClassTemplateDecl *SpecializedTemplate, ArrayRef<TemplateArgument> Args, - QualType CanonInjectedType, + CanQualType CanonInjectedTST, ClassTemplatePartialSpecializationDecl *PrevDecl) { auto *Result = new (Context, DC) ClassTemplatePartialSpecializationDecl( Context, TK, DC, StartLoc, IdLoc, Params, SpecializedTemplate, Args, - PrevDecl); + CanonInjectedTST, PrevDecl); Result->setSpecializationKind(TSK_ExplicitSpecialization); - Result->setMayHaveOutOfDateDef(false); - - Context.getInjectedClassNameType(Result, CanonInjectedType); return Result; } ClassTemplatePartialSpecializationDecl * ClassTemplatePartialSpecializationDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { - auto *Result = new (C, ID) ClassTemplatePartialSpecializationDecl(C); - Result->setMayHaveOutOfDateDef(false); - return Result; + return new (C, ID) ClassTemplatePartialSpecializationDecl(C); +} + +CanQualType +ClassTemplatePartialSpecializationDecl::getCanonicalInjectedSpecializationType( + const ASTContext &Ctx) const { + if (CanonInjectedTST.isNull()) { + CanonInjectedTST = + CanQualType::CreateUnsafe(Ctx.getCanonicalTemplateSpecializationType( + TemplateName(getSpecializedTemplate()->getCanonicalDecl()), + getTemplateArgs().asArray())); + } + return CanonInjectedTST; } SourceRange ClassTemplatePartialSpecializationDecl::getSourceRange() const { diff --git a/clang/lib/AST/DeclarationName.cpp b/clang/lib/AST/DeclarationName.cpp index ae5fcf6..6c7b995 100644 --- a/clang/lib/AST/DeclarationName.cpp +++ b/clang/lib/AST/DeclarationName.cpp @@ -115,12 +115,12 @@ static void printCXXConstructorDestructorName(QualType ClassType, Policy.adjustForCPlusPlus(); if (const RecordType *ClassRec = ClassType->getAs<RecordType>()) { - ClassRec->getDecl()->printName(OS, Policy); + ClassRec->getOriginalDecl()->printName(OS, Policy); return; } if (Policy.SuppressTemplateArgsInCXXConstructors) { if (auto *InjTy = ClassType->getAs<InjectedClassNameType>()) { - InjTy->getDecl()->printName(OS, Policy); + InjTy->getOriginalDecl()->printName(OS, Policy); return; } } @@ -184,7 +184,7 @@ void DeclarationName::print(raw_ostream &OS, OS << "operator "; QualType Type = getCXXNameType(); if (const RecordType *Rec = Type->getAs<RecordType>()) { - OS << *Rec->getDecl(); + OS << *Rec->getOriginalDecl(); return; } // We know we're printing C++ here, ensure we print 'bool' properly. diff --git a/clang/lib/AST/DynamicRecursiveASTVisitor.cpp b/clang/lib/AST/DynamicRecursiveASTVisitor.cpp index b478e7a..8821cd3 100644 --- a/clang/lib/AST/DynamicRecursiveASTVisitor.cpp +++ b/clang/lib/AST/DynamicRecursiveASTVisitor.cpp @@ -115,8 +115,12 @@ template <bool Const> struct Impl : RecursiveASTVisitor<Impl<Const>> { bool TraverseAST(ASTContext &AST) { return Visitor.TraverseAST(AST); } bool TraverseAttr(Attr *At) { return Visitor.TraverseAttr(At); } bool TraverseDecl(Decl *D) { return Visitor.TraverseDecl(D); } - bool TraverseType(QualType T) { return Visitor.TraverseType(T); } - bool TraverseTypeLoc(TypeLoc TL) { return Visitor.TraverseTypeLoc(TL); } + bool TraverseType(QualType T, bool TraverseQualifier = true) { + return Visitor.TraverseType(T, TraverseQualifier); + } + bool TraverseTypeLoc(TypeLoc TL, bool TraverseQualifier = true) { + return Visitor.TraverseTypeLoc(TL, TraverseQualifier); + } bool TraverseStmt(Stmt *S) { return Visitor.TraverseStmt(S); } bool TraverseConstructorInitializer(CXXCtorInitializer *Init) { @@ -172,7 +176,7 @@ template <bool Const> struct Impl : RecursiveASTVisitor<Impl<Const>> { return Visitor.TraverseLambdaCapture(LE, C, Init); } - bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS) { + bool TraverseNestedNameSpecifier(NestedNameSpecifier NNS) { return Visitor.TraverseNestedNameSpecifier(NNS); } @@ -241,8 +245,8 @@ template <bool Const> struct Impl : RecursiveASTVisitor<Impl<Const>> { // Types. #define ABSTRACT_TYPE(CLASS, BASE) #define TYPE(CLASS, BASE) \ - bool Traverse##CLASS##Type(CLASS##Type *T) { \ - return Visitor.Traverse##CLASS##Type(T); \ + bool Traverse##CLASS##Type(CLASS##Type *T, bool TraverseQualifier) { \ + return Visitor.Traverse##CLASS##Type(T, TraverseQualifier); \ } #include "clang/AST/TypeNodes.inc" @@ -255,8 +259,8 @@ template <bool Const> struct Impl : RecursiveASTVisitor<Impl<Const>> { // TypeLocs. #define ABSTRACT_TYPELOC(CLASS, BASE) #define TYPELOC(CLASS, BASE) \ - bool Traverse##CLASS##TypeLoc(CLASS##TypeLoc TL) { \ - return Visitor.Traverse##CLASS##TypeLoc(TL); \ + bool Traverse##CLASS##TypeLoc(CLASS##TypeLoc TL, bool TraverseQualifier) { \ + return Visitor.Traverse##CLASS##TypeLoc(TL, TraverseQualifier); \ } #include "clang/AST/TypeLocNodes.def" @@ -297,7 +301,6 @@ FORWARD_TO_BASE(TraverseAttr, Attr, *) FORWARD_TO_BASE(TraverseConstructorInitializer, CXXCtorInitializer, *) FORWARD_TO_BASE(TraverseDecl, Decl, *) FORWARD_TO_BASE(TraverseStmt, Stmt, *) -FORWARD_TO_BASE(TraverseNestedNameSpecifier, NestedNameSpecifier, *) FORWARD_TO_BASE(TraverseTemplateInstantiations, ClassTemplateDecl, *) FORWARD_TO_BASE(TraverseTemplateInstantiations, VarTemplateDecl, *) FORWARD_TO_BASE(TraverseTemplateInstantiations, FunctionTemplateDecl, *) @@ -314,8 +317,22 @@ FORWARD_TO_BASE_EXACT(TraverseTemplateArgument, const TemplateArgument &) FORWARD_TO_BASE_EXACT(TraverseTemplateArguments, ArrayRef<TemplateArgument>) FORWARD_TO_BASE_EXACT(TraverseTemplateArgumentLoc, const TemplateArgumentLoc &) FORWARD_TO_BASE_EXACT(TraverseTemplateName, TemplateName) -FORWARD_TO_BASE_EXACT(TraverseType, QualType) -FORWARD_TO_BASE_EXACT(TraverseTypeLoc, TypeLoc) +FORWARD_TO_BASE_EXACT(TraverseNestedNameSpecifier, NestedNameSpecifier) + +template <bool Const> +bool DynamicRecursiveASTVisitorBase<Const>::TraverseType( + QualType T, bool TraverseQualifier) { + return Impl<Const>(*this).RecursiveASTVisitor<Impl<Const>>::TraverseType( + T, TraverseQualifier); +} + +template <bool Const> +bool DynamicRecursiveASTVisitorBase<Const>::TraverseTypeLoc( + TypeLoc TL, bool TraverseQualifier) { + return Impl<Const>(*this).RecursiveASTVisitor<Impl<Const>>::TraverseTypeLoc( + TL, TraverseQualifier); +} + FORWARD_TO_BASE_EXACT(TraverseTypeConstraint, const TypeConstraint *) FORWARD_TO_BASE_EXACT(TraverseObjCProtocolLoc, ObjCProtocolLoc) FORWARD_TO_BASE_EXACT(TraverseNestedNameSpecifierLoc, NestedNameSpecifierLoc) @@ -354,13 +371,25 @@ bool DynamicRecursiveASTVisitorBase<Const>::dataTraverseNode( // Declare Traverse*() and friends for all concrete Type classes. #define ABSTRACT_TYPE(CLASS, BASE) #define TYPE(CLASS, BASE) \ - FORWARD_TO_BASE(Traverse##CLASS##Type, CLASS##Type, *) \ + template <bool Const> \ + bool DynamicRecursiveASTVisitorBase<Const>::Traverse##CLASS##Type( \ + MaybeConst<CLASS##Type> *T, bool TraverseQualifier) { \ + return Impl<Const>(*this) \ + .RecursiveASTVisitor<Impl<Const>>::Traverse##CLASS##Type( \ + const_cast<CLASS##Type *>(T), TraverseQualifier); \ + } \ FORWARD_TO_BASE(WalkUpFrom##CLASS##Type, CLASS##Type, *) #include "clang/AST/TypeNodes.inc" #define ABSTRACT_TYPELOC(CLASS, BASE) #define TYPELOC(CLASS, BASE) \ - FORWARD_TO_BASE_EXACT(Traverse##CLASS##TypeLoc, CLASS##TypeLoc) + template <bool Const> \ + bool DynamicRecursiveASTVisitorBase<Const>::Traverse##CLASS##TypeLoc( \ + CLASS##TypeLoc TL, bool TraverseQualifier) { \ + return Impl<Const>(*this) \ + .RecursiveASTVisitor<Impl<Const>>::Traverse##CLASS##TypeLoc( \ + TL, TraverseQualifier); \ + } #include "clang/AST/TypeLocNodes.def" #define TYPELOC(CLASS, BASE) \ diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index cd9672d..7cac655 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -75,8 +75,7 @@ const CXXRecordDecl *Expr::getBestDynamicClassType() const { return nullptr; const RecordType *Ty = DerivedType->castAs<RecordType>(); - Decl *D = Ty->getDecl(); - return cast<CXXRecordDecl>(D); + return cast<CXXRecordDecl>(Ty->getOriginalDecl())->getDefinitionOrSelf(); } const Expr *Expr::skipRValueSubobjectAdjustments( @@ -92,7 +91,9 @@ const Expr *Expr::skipRValueSubobjectAdjustments( E->getType()->isRecordType()) { E = CE->getSubExpr(); const auto *Derived = - cast<CXXRecordDecl>(E->getType()->castAs<RecordType>()->getDecl()); + cast<CXXRecordDecl>( + E->getType()->castAs<RecordType>()->getOriginalDecl()) + ->getDefinitionOrSelf(); Adjustments.push_back(SubobjectAdjustment(CE, Derived)); continue; } @@ -268,7 +269,7 @@ QualType Expr::getEnumCoercedType(const ASTContext &Ctx) const { if (const auto *ECD = getEnumConstantDecl()) { const auto *ED = cast<EnumDecl>(ECD->getDeclContext()); if (ED->isCompleteDefinition()) - return Ctx.getTypeDeclType(ED); + return Ctx.getCanonicalTagType(ED); } return getType(); } @@ -2031,7 +2032,8 @@ CXXBaseSpecifier **CastExpr::path_buffer() { const FieldDecl *CastExpr::getTargetFieldForToUnionCast(QualType unionType, QualType opType) { - auto RD = unionType->castAs<RecordType>()->getDecl(); + auto RD = + unionType->castAs<RecordType>()->getOriginalDecl()->getDefinitionOrSelf(); return getTargetFieldForToUnionCast(RD, opType); } @@ -3221,7 +3223,7 @@ static const Expr *skipTemporaryBindingsNoOpCastsAndParens(const Expr *E) { /// isTemporaryObject - Determines if this expression produces a /// temporary of the given class type. bool Expr::isTemporaryObject(ASTContext &C, const CXXRecordDecl *TempTy) const { - if (!C.hasSameUnqualifiedType(getType(), C.getTypeDeclType(TempTy))) + if (!C.hasSameUnqualifiedType(getType(), C.getCanonicalTagType(TempTy))) return false; const Expr *E = skipTemporaryBindingsNoOpCastsAndParens(this); @@ -3407,7 +3409,10 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef, if (ILE->getType()->isRecordType()) { unsigned ElementNo = 0; - RecordDecl *RD = ILE->getType()->castAs<RecordType>()->getDecl(); + RecordDecl *RD = ILE->getType() + ->castAs<RecordType>() + ->getOriginalDecl() + ->getDefinitionOrSelf(); // In C++17, bases were added to the list of members used by aggregate // initialization. @@ -4050,8 +4055,10 @@ Expr::isNullPointerConstant(ASTContext &Ctx, return NPCK_CXX11_nullptr; if (const RecordType *UT = getType()->getAsUnionType()) - if (!Ctx.getLangOpts().CPlusPlus11 && - UT && UT->getDecl()->hasAttr<TransparentUnionAttr>()) + if (!Ctx.getLangOpts().CPlusPlus11 && UT && + UT->getOriginalDecl() + ->getMostRecentDecl() + ->hasAttr<TransparentUnionAttr>()) if (const CompoundLiteralExpr *CLE = dyn_cast<CompoundLiteralExpr>(this)){ const Expr *InitExpr = CLE->getInitializer(); if (const InitListExpr *ILE = dyn_cast<InitListExpr>(InitExpr)) diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp index a099e97..97ae4a0 100644 --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/lib/AST/ExprCXX.cpp @@ -1319,7 +1319,7 @@ LambdaExpr *LambdaExpr::Create(const ASTContext &Context, CXXRecordDecl *Class, bool ContainsUnexpandedParameterPack) { // Determine the type of the expression (i.e., the type of the // function object we're creating). - QualType T = Context.getTypeDeclType(Class); + CanQualType T = Context.getCanonicalTagType(Class); unsigned Size = totalSizeToAlloc<Stmt *>(CaptureInits.size() + 1); void *Mem = Context.Allocate(Size); @@ -1687,10 +1687,9 @@ CXXRecordDecl *UnresolvedMemberExpr::getNamingClass() { // It can't be dependent: after all, we were actually able to do the // lookup. CXXRecordDecl *Record = nullptr; - auto *NNS = getQualifier(); - if (NNS && NNS->getKind() != NestedNameSpecifier::Super) { - const Type *T = getQualifier()->getAsType(); - assert(T && "qualifier in member expression does not name type"); + if (NestedNameSpecifier Qualifier = getQualifier(); + Qualifier.getKind() == NestedNameSpecifier::Kind::Type) { + const Type *T = getQualifier().getAsType(); Record = T->getAsCXXRecordDecl(); assert(Record && "qualifier in member expression does not name record"); } diff --git a/clang/lib/AST/ExprConcepts.cpp b/clang/lib/AST/ExprConcepts.cpp index ac0e566..36f910d 100644 --- a/clang/lib/AST/ExprConcepts.cpp +++ b/clang/lib/AST/ExprConcepts.cpp @@ -41,10 +41,10 @@ ConceptSpecializationExpr::ConceptSpecializationExpr( assert(!Loc->getNestedNameSpecifierLoc() || (!Loc->getNestedNameSpecifierLoc() .getNestedNameSpecifier() - ->isInstantiationDependent() && + .isInstantiationDependent() && !Loc->getNestedNameSpecifierLoc() .getNestedNameSpecifier() - ->containsUnexpandedParameterPack())); + .containsUnexpandedParameterPack())); assert((!isValueDependent() || isInstantiationDependent()) && "should not be value-dependent"); } diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 34af9cc..5cf2b9a 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -401,7 +401,7 @@ namespace { assert(!Invalid && "invalid designator has no subobject type"); return MostDerivedPathLength == Entries.size() ? MostDerivedType - : Ctx.getRecordType(getAsBaseClass(Entries.back())); + : Ctx.getCanonicalTagType(getAsBaseClass(Entries.back())); } /// Update this designator to refer to the first element within this array. @@ -2623,7 +2623,8 @@ static bool CheckEvaluationResult(CheckEvaluationResultKind CERK, Value.getUnionValue(), Kind, Value.getUnionField(), CheckedTemps); } if (Value.isStruct()) { - RecordDecl *RD = Type->castAs<RecordType>()->getDecl(); + RecordDecl *RD = + Type->castAs<RecordType>()->getOriginalDecl()->getDefinitionOrSelf(); if (const CXXRecordDecl *CD = dyn_cast<CXXRecordDecl>(RD)) { unsigned BaseIndex = 0; for (const CXXBaseSpecifier &BS : CD->bases()) { @@ -4109,7 +4110,7 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, } // Next subobject is a class, struct or union field. - RecordDecl *RD = ObjType->castAs<RecordType>()->getDecl(); + RecordDecl *RD = ObjType->castAs<RecordType>()->getOriginalDecl(); if (RD->isUnion()) { const FieldDecl *UnionField = O->getUnionField(); if (!UnionField || @@ -4144,7 +4145,7 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, const CXXRecordDecl *Base = getAsBaseClass(Sub.Entries[I]); O = &O->getStructBase(getBaseIndex(Derived, Base)); - ObjType = getSubobjectType(ObjType, Info.Ctx.getRecordType(Base)); + ObjType = getSubobjectType(ObjType, Info.Ctx.getCanonicalTagType(Base)); } } } @@ -6363,7 +6364,7 @@ static bool HandleDynamicCast(EvalInfo &Info, const ExplicitCastExpr *E, const CXXRecordDecl *C = E->getTypeAsWritten()->getPointeeCXXRecordDecl(); assert(C && "dynamic_cast target is not void pointer nor class"); - CanQualType CQT = Info.Ctx.getCanonicalType(Info.Ctx.getRecordType(C)); + CanQualType CQT = Info.Ctx.getCanonicalTagType(C); auto RuntimeCheckFailed = [&] (CXXBasePaths *Paths) { // C++ [expr.dynamic.cast]p9: @@ -6389,7 +6390,7 @@ static bool HandleDynamicCast(EvalInfo &Info, const ExplicitCastExpr *E, } Info.FFDiag(E, diag::note_constexpr_dynamic_cast_to_reference_failed) << DiagKind << Ptr.Designator.getType(Info.Ctx) - << Info.Ctx.getRecordType(DynType->Type) + << Info.Ctx.getCanonicalTagType(DynType->Type) << E->getType().getUnqualifiedType(); return false; }; @@ -6886,8 +6887,8 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This, // FIXME: This immediately starts the lifetime of all members of // an anonymous struct. It would be preferable to strictly start // member lifetime in initialization order. - Success &= - handleDefaultInitValue(Info.Ctx.getRecordType(CD), *Value); + Success &= handleDefaultInitValue(Info.Ctx.getCanonicalTagType(CD), + *Value); } // Store Subobject as its parent before updating it for the last element // in the chain. @@ -7794,7 +7795,8 @@ class BufferToAPValueConverter { } std::optional<APValue> visit(const EnumType *Ty, CharUnits Offset) { - QualType RepresentationType = Ty->getDecl()->getIntegerType(); + QualType RepresentationType = + Ty->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); assert(!RepresentationType.isNull() && "enum forward decl should be caught by Sema"); const auto *AsBuiltin = @@ -8528,7 +8530,7 @@ public: if (auto *DD = dyn_cast<CXXDestructorDecl>(FD)) { assert(This && "no 'this' pointer for destructor call"); return HandleDestruction(Info, E, *This, - Info.Ctx.getRecordType(DD->getParent())) && + Info.Ctx.getCanonicalTagType(DD->getParent())) && CallScope.destroy(); } @@ -8589,8 +8591,10 @@ public: const FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl()); if (!FD) return Error(E); assert(!FD->getType()->isReferenceType() && "prvalue reference?"); - assert(BaseTy->castAs<RecordType>()->getDecl()->getCanonicalDecl() == - FD->getParent()->getCanonicalDecl() && "record / field mismatch"); + assert( + BaseTy->castAs<RecordType>()->getOriginalDecl()->getCanonicalDecl() == + FD->getParent()->getCanonicalDecl() && + "record / field mismatch"); // Note: there is no lvalue base here. But this case should only ever // happen in C or in C++98, where we cannot be evaluating a constexpr @@ -8817,8 +8821,10 @@ public: const ValueDecl *MD = E->getMemberDecl(); if (const FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl())) { - assert(BaseTy->castAs<RecordType>()->getDecl()->getCanonicalDecl() == - FD->getParent()->getCanonicalDecl() && "record / field mismatch"); + assert( + BaseTy->castAs<RecordType>()->getOriginalDecl()->getCanonicalDecl() == + FD->getParent()->getCanonicalDecl() && + "record / field mismatch"); (void)BaseTy; if (!HandleLValueMember(this->Info, E, Result, FD)) return false; @@ -9257,8 +9263,8 @@ bool LValueExprEvaluator::VisitCXXTypeidExpr(const CXXTypeidExpr *E) { if (!DynType) return false; - TypeInfo = - TypeInfoLValue(Info.Ctx.getRecordType(DynType->Type).getTypePtr()); + TypeInfo = TypeInfoLValue( + Info.Ctx.getCanonicalTagType(DynType->Type).getTypePtr()); } return Success(APValue::LValueBase::getTypeInfo(TypeInfo, E->getType())); @@ -9860,11 +9866,15 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr *E) { if (Value.isInt()) { unsigned Size = Info.Ctx.getTypeSize(E->getType()); uint64_t N = Value.getInt().extOrTrunc(Size).getZExtValue(); - Result.Base = (Expr*)nullptr; - Result.InvalidBase = false; - Result.Offset = CharUnits::fromQuantity(N); - Result.Designator.setInvalid(); - Result.IsNullPtr = false; + if (N == Info.Ctx.getTargetNullPointerValue(E->getType())) { + Result.setNull(Info.Ctx, E->getType()); + } else { + Result.Base = (Expr *)nullptr; + Result.InvalidBase = false; + Result.Offset = CharUnits::fromQuantity(N); + Result.Designator.setInvalid(); + Result.IsNullPtr = false; + } return true; } else { // In rare instances, the value isn't an lvalue. @@ -10814,7 +10824,8 @@ static bool HandleClassZeroInitialization(EvalInfo &Info, const Expr *E, } bool RecordExprEvaluator::ZeroInitialization(const Expr *E, QualType T) { - const RecordDecl *RD = T->castAs<RecordType>()->getDecl(); + const RecordDecl *RD = + T->castAs<RecordType>()->getOriginalDecl()->getDefinitionOrSelf(); if (RD->isInvalidDecl()) return false; if (RD->isUnion()) { // C++11 [dcl.init]p5: If T is a (possibly cv-qualified) union type, the @@ -10883,8 +10894,10 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) { bool RecordExprEvaluator::VisitCXXParenListOrInitListExpr( const Expr *ExprToVisit, ArrayRef<Expr *> Args) { - const RecordDecl *RD = - ExprToVisit->getType()->castAs<RecordType>()->getDecl(); + const RecordDecl *RD = ExprToVisit->getType() + ->castAs<RecordType>() + ->getOriginalDecl() + ->getDefinitionOrSelf(); if (RD->isInvalidDecl()) return false; const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD); auto *CXXRD = dyn_cast<CXXRecordDecl>(RD); @@ -11112,7 +11125,10 @@ bool RecordExprEvaluator::VisitCXXStdInitializerListExpr( Result = APValue(APValue::UninitStruct(), 0, 2); Array.moveInto(Result.getStructField(0)); - RecordDecl *Record = E->getType()->castAs<RecordType>()->getDecl(); + RecordDecl *Record = E->getType() + ->castAs<RecordType>() + ->getOriginalDecl() + ->getDefinitionOrSelf(); RecordDecl::field_iterator Field = Record->field_begin(); assert(Field != Record->field_end() && Info.Ctx.hasSameType(Field->getType()->getPointeeType(), @@ -11624,7 +11640,13 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) { return Success(APValue(ResultElements.data(), ResultElements.size()), E); } case Builtin::BI__builtin_elementwise_add_sat: - case Builtin::BI__builtin_elementwise_sub_sat: { + case Builtin::BI__builtin_elementwise_sub_sat: + case clang::X86::BI__builtin_ia32_pmulhuw128: + case clang::X86::BI__builtin_ia32_pmulhuw256: + case clang::X86::BI__builtin_ia32_pmulhuw512: + case clang::X86::BI__builtin_ia32_pmulhw128: + case clang::X86::BI__builtin_ia32_pmulhw256: + case clang::X86::BI__builtin_ia32_pmulhw512: { APValue SourceLHS, SourceRHS; if (!EvaluateAsRValue(Info, E->getArg(0), SourceLHS) || !EvaluateAsRValue(Info, E->getArg(1), SourceRHS)) @@ -11649,6 +11671,18 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) { APSInt(LHS.isSigned() ? LHS.ssub_sat(RHS) : LHS.usub_sat(RHS), DestEltTy->isUnsignedIntegerOrEnumerationType()))); break; + case clang::X86::BI__builtin_ia32_pmulhuw128: + case clang::X86::BI__builtin_ia32_pmulhuw256: + case clang::X86::BI__builtin_ia32_pmulhuw512: + ResultElements.push_back(APValue(APSInt(llvm::APIntOps::mulhu(LHS, RHS), + /*isUnsigned=*/true))); + break; + case clang::X86::BI__builtin_ia32_pmulhw128: + case clang::X86::BI__builtin_ia32_pmulhw256: + case clang::X86::BI__builtin_ia32_pmulhw512: + ResultElements.push_back(APValue(APSInt(llvm::APIntOps::mulhs(LHS, RHS), + /*isUnsigned=*/false))); + break; } } @@ -12885,7 +12919,10 @@ static bool convertUnsignedAPIntToCharUnits(const llvm::APInt &Int, static void addFlexibleArrayMemberInitSize(EvalInfo &Info, const QualType &T, const LValue &LV, CharUnits &Size) { if (!T.isNull() && T->isStructureType() && - T->getAsStructureType()->getDecl()->hasFlexibleArrayMember()) + T->getAsStructureType() + ->getOriginalDecl() + ->getDefinitionOrSelf() + ->hasFlexibleArrayMember()) if (const auto *V = LV.getLValueBase().dyn_cast<const ValueDecl *>()) if (const auto *VD = dyn_cast<VarDecl>(V)) if (VD->hasInit()) @@ -15132,7 +15169,7 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *OOE) { const RecordType *RT = CurrentType->getAs<RecordType>(); if (!RT) return Error(OOE); - RecordDecl *RD = RT->getDecl(); + RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); if (RD->isInvalidDecl()) return false; const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD); unsigned i = MemberDecl->getFieldIndex(); @@ -15154,7 +15191,7 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *OOE) { const RecordType *RT = CurrentType->getAs<RecordType>(); if (!RT) return Error(OOE); - RecordDecl *RD = RT->getDecl(); + RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); if (RD->isInvalidDecl()) return false; const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD); @@ -15165,7 +15202,8 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *OOE) { return Error(OOE); // Add the offset to the base. - Result += RL.getBaseClassOffset(cast<CXXRecordDecl>(BaseRT->getDecl())); + Result += RL.getBaseClassOffset(cast<CXXRecordDecl>( + BaseRT->getOriginalDecl()->getDefinitionOrSelf())); break; } } @@ -15344,7 +15382,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) { if (Info.Ctx.getLangOpts().CPlusPlus && DestType->isEnumeralType()) { const EnumType *ET = dyn_cast<EnumType>(DestType.getCanonicalType()); - const EnumDecl *ED = ET->getDecl(); + const EnumDecl *ED = ET->getOriginalDecl()->getDefinitionOrSelf(); // Check that the value is within the range of the enumeration values. // // This corressponds to [expr.static.cast]p10 which says: @@ -18006,7 +18044,8 @@ bool Expr::isPotentialConstantExpr(const FunctionDecl *FD, // Fabricate an arbitrary expression on the stack and pretend that it // is a temporary being used as the 'this' pointer. LValue This; - ImplicitValueInitExpr VIE(RD ? Info.Ctx.getRecordType(RD) : Info.Ctx.IntTy); + ImplicitValueInitExpr VIE(RD ? Info.Ctx.getCanonicalTagType(RD) + : Info.Ctx.IntTy); This.set({&VIE, Info.CurrentCall->Index}); ArrayRef<const Expr*> Args; diff --git a/clang/lib/AST/FormatString.cpp b/clang/lib/AST/FormatString.cpp index 112b756d..502a3e6 100644 --- a/clang/lib/AST/FormatString.cpp +++ b/clang/lib/AST/FormatString.cpp @@ -417,10 +417,11 @@ ArgType::matchesType(ASTContext &C, QualType argTy) const { // If the enum is incomplete we know nothing about the underlying type. // Assume that it's 'int'. Do not use the underlying type for a scoped // enumeration. - if (!ETy->getDecl()->isComplete()) + const EnumDecl *ED = ETy->getOriginalDecl()->getDefinitionOrSelf(); + if (!ED->isComplete()) return NoMatch; if (ETy->isUnscopedEnumerationType()) - argTy = ETy->getDecl()->getIntegerType(); + argTy = ED->getIntegerType(); } if (const auto *BT = argTy->getAs<BuiltinType>()) { @@ -466,10 +467,11 @@ ArgType::matchesType(ASTContext &C, QualType argTy) const { // If the enum is incomplete we know nothing about the underlying type. // Assume that it's 'int'. Do not use the underlying type for a scoped // enumeration as that needs an exact match. - if (!ETy->getDecl()->isComplete()) + const EnumDecl *ED = ETy->getOriginalDecl()->getDefinitionOrSelf(); + if (!ED->isComplete()) argTy = C.IntTy; else if (ETy->isUnscopedEnumerationType()) - argTy = ETy->getDecl()->getIntegerType(); + argTy = ED->getIntegerType(); } if (argTy->isSaturatedFixedPointType()) diff --git a/clang/lib/AST/InheritViz.cpp b/clang/lib/AST/InheritViz.cpp index 1dafed8..c03492c 100644 --- a/clang/lib/AST/InheritViz.cpp +++ b/clang/lib/AST/InheritViz.cpp @@ -89,8 +89,8 @@ void InheritanceHierarchyWriter::WriteNode(QualType Type, bool FromVirtual) { Out << " \"];\n"; // Display the base classes. - const auto *Decl = - static_cast<const CXXRecordDecl *>(Type->castAs<RecordType>()->getDecl()); + const auto *Decl = static_cast<const CXXRecordDecl *>( + Type->castAs<RecordType>()->getOriginalDecl()); for (const auto &Base : Decl->bases()) { QualType CanonBaseType = Context.getCanonicalType(Base.getType()); @@ -133,7 +133,7 @@ InheritanceHierarchyWriter::WriteNodeReference(QualType Type, /// viewInheritance - Display the inheritance hierarchy of this C++ /// class using GraphViz. void CXXRecordDecl::viewInheritance(ASTContext& Context) const { - QualType Self = Context.getTypeDeclType(this); + QualType Self = Context.getCanonicalTagType(this); int FD; SmallString<128> Filename; diff --git a/clang/lib/AST/ItaniumCXXABI.cpp b/clang/lib/AST/ItaniumCXXABI.cpp index 6ceedd6..43a8bcd 100644 --- a/clang/lib/AST/ItaniumCXXABI.cpp +++ b/clang/lib/AST/ItaniumCXXABI.cpp @@ -42,10 +42,10 @@ namespace { /// /// Returns the name of anonymous union VarDecl or nullptr if it is not found. static const IdentifierInfo *findAnonymousUnionVarDeclName(const VarDecl& VD) { - const RecordType *RT = VD.getType()->getAs<RecordType>(); - assert(RT && "type of VarDecl is expected to be RecordType."); - assert(RT->getDecl()->isUnion() && "RecordType is expected to be a union."); - if (const FieldDecl *FD = RT->getDecl()->findFirstNamedDataMember()) { + const auto *RT = VD.getType()->castAs<RecordType>(); + const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); + assert(RD->isUnion() && "RecordType is expected to be a union."); + if (const FieldDecl *FD = RD->findFirstNamedDataMember()) { return FD->getIdentifier(); } diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 5233648..a7380a1 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -463,9 +463,7 @@ public: void mangleVendorType(StringRef Name); private: - bool mangleSubstitution(const NamedDecl *ND); - bool mangleSubstitution(NestedNameSpecifier *NNS); bool mangleSubstitution(QualType T); bool mangleSubstitution(TemplateName Template); bool mangleSubstitution(uintptr_t Ptr); @@ -479,21 +477,15 @@ private: addSubstitution(reinterpret_cast<uintptr_t>(ND)); } - void addSubstitution(NestedNameSpecifier *NNS) { - NNS = Context.getASTContext().getCanonicalNestedNameSpecifier(NNS); - - addSubstitution(reinterpret_cast<uintptr_t>(NNS)); - } void addSubstitution(QualType T); void addSubstitution(TemplateName Template); void addSubstitution(uintptr_t Ptr); // Destructive copy substitutions from other mangler. void extendSubstitutions(CXXNameMangler* Other); - void mangleUnresolvedPrefix(NestedNameSpecifier *qualifier, + void mangleUnresolvedPrefix(NestedNameSpecifier Qualifier, bool recursive = false); - void mangleUnresolvedName(NestedNameSpecifier *qualifier, - DeclarationName name, + void mangleUnresolvedName(NestedNameSpecifier Qualifier, DeclarationName name, const TemplateArgumentLoc *TemplateArgs, unsigned NumTemplateArgs, unsigned KnownArity = UnknownArity); @@ -542,7 +534,7 @@ private: void mangleNestedNameWithClosurePrefix(GlobalDecl GD, const NamedDecl *PrefixND, const AbiTagList *AdditionalAbiTags); - void manglePrefix(NestedNameSpecifier *qualifier); + void manglePrefix(NestedNameSpecifier Qualifier); void manglePrefix(const DeclContext *DC, bool NoFunction=false); void manglePrefix(QualType type); void mangleTemplatePrefix(GlobalDecl GD, bool NoFunction=false); @@ -588,12 +580,10 @@ private: void mangleMemberExprBase(const Expr *base, bool isArrow); void mangleMemberExpr(const Expr *base, bool isArrow, - NestedNameSpecifier *qualifier, - NamedDecl *firstQualifierLookup, - DeclarationName name, + NestedNameSpecifier Qualifier, + NamedDecl *firstQualifierLookup, DeclarationName name, const TemplateArgumentLoc *TemplateArgs, - unsigned NumTemplateArgs, - unsigned knownArity); + unsigned NumTemplateArgs, unsigned knownArity); void mangleCastExpression(const Expr *E, StringRef CastEncoding); void mangleInitListElements(const InitListExpr *InitList); void mangleRequirement(SourceLocation RequiresExprLoc, @@ -1334,6 +1324,21 @@ void CXXNameMangler::manglePrefix(QualType type) { mangleTemplateArgs(Template, DTST->template_arguments()); addSubstitution(QualType(DTST, 0)); } + } else if (const auto *DNT = type->getAs<DependentNameType>()) { + // Clang 14 and before did not consider this substitutable. + bool Clang14Compat = isCompatibleWith(LangOptions::ClangABI::Ver14); + if (!Clang14Compat && mangleSubstitution(QualType(DNT, 0))) + return; + + // Member expressions can have these without prefixes, but that + // should end up in mangleUnresolvedPrefix instead. + assert(DNT->getQualifier()); + manglePrefix(DNT->getQualifier()); + + mangleSourceName(DNT->getIdentifier()); + + if (!Clang14Compat) + addSubstitution(QualType(DNT, 0)); } else { // We use the QualType mangle type variant here because it handles // substitutions. @@ -1345,7 +1350,7 @@ void CXXNameMangler::manglePrefix(QualType type) { /// /// \param recursive - true if this is being called recursively, /// i.e. if there is more prefix "to the right". -void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier, +void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier Qualifier, bool recursive) { // x, ::x @@ -1362,8 +1367,11 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier, // <unresolved-name> ::= [gs] sr <unresolved-qualifier-level>+ E // <base-unresolved-name> - switch (qualifier->getKind()) { - case NestedNameSpecifier::Global: + switch (Qualifier.getKind()) { + case NestedNameSpecifier::Kind::Null: + llvm_unreachable("unexpected null nested name specifier"); + + case NestedNameSpecifier::Kind::Global: Out << "gs"; // We want an 'sr' unless this is the entire NNS. @@ -1373,27 +1381,29 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier, // We never want an 'E' here. return; - case NestedNameSpecifier::Super: + case NestedNameSpecifier::Kind::MicrosoftSuper: llvm_unreachable("Can't mangle __super specifier"); - case NestedNameSpecifier::Namespace: - if (qualifier->getPrefix()) - mangleUnresolvedPrefix(qualifier->getPrefix(), + case NestedNameSpecifier::Kind::Namespace: { + auto [Namespace, Prefix] = Qualifier.getAsNamespaceAndPrefix(); + if (Prefix) + mangleUnresolvedPrefix(Prefix, /*recursive*/ true); else Out << "sr"; - mangleSourceNameWithAbiTags(qualifier->getAsNamespace()); + mangleSourceNameWithAbiTags(Namespace); break; + } - case NestedNameSpecifier::TypeSpec: { - const Type *type = qualifier->getAsType(); + case NestedNameSpecifier::Kind::Type: { + const Type *type = Qualifier.getAsType(); // We only want to use an unresolved-type encoding if this is one of: // - a decltype // - a template type parameter // - a template template parameter with arguments // In all of these cases, we should have no prefix. - if (NestedNameSpecifier *Prefix = qualifier->getPrefix()) { + if (NestedNameSpecifier Prefix = type->getPrefix()) { mangleUnresolvedPrefix(Prefix, /*recursive=*/true); } else { @@ -1406,18 +1416,6 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier, break; } - - case NestedNameSpecifier::Identifier: - // Member expressions can have these without prefixes. - if (qualifier->getPrefix()) - mangleUnresolvedPrefix(qualifier->getPrefix(), - /*recursive*/ true); - else - Out << "sr"; - - mangleSourceName(qualifier->getAsIdentifier()); - // An Identifier has no type information, so we can't emit abi tags for it. - break; } // If this was the innermost part of the NNS, and we fell out to @@ -1429,10 +1427,11 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier, /// Mangle an unresolved-name, which is generally used for names which /// weren't resolved to specific entities. void CXXNameMangler::mangleUnresolvedName( - NestedNameSpecifier *qualifier, DeclarationName name, + NestedNameSpecifier Qualifier, DeclarationName name, const TemplateArgumentLoc *TemplateArgs, unsigned NumTemplateArgs, unsigned knownArity) { - if (qualifier) mangleUnresolvedPrefix(qualifier); + if (Qualifier) + mangleUnresolvedPrefix(Qualifier); switch (name.getNameKind()) { // <base-unresolved-name> ::= <simple-id> case DeclarationName::Identifier: @@ -1581,7 +1580,10 @@ void CXXNameMangler::mangleUnqualifiedName( if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) { // We must have an anonymous union or struct declaration. - const RecordDecl *RD = VD->getType()->castAs<RecordType>()->getDecl(); + const RecordDecl *RD = VD->getType() + ->castAs<RecordType>() + ->getOriginalDecl() + ->getDefinitionOrSelf(); // Itanium C++ ABI 5.1.2: // @@ -2167,49 +2169,22 @@ void CXXNameMangler::mangleLambdaSig(const CXXRecordDecl *Lambda) { Lambda->getLambdaStaticInvoker()); } -void CXXNameMangler::manglePrefix(NestedNameSpecifier *qualifier) { - switch (qualifier->getKind()) { - case NestedNameSpecifier::Global: +void CXXNameMangler::manglePrefix(NestedNameSpecifier Qualifier) { + switch (Qualifier.getKind()) { + case NestedNameSpecifier::Kind::Null: + case NestedNameSpecifier::Kind::Global: // nothing return; - case NestedNameSpecifier::Super: + case NestedNameSpecifier::Kind::MicrosoftSuper: llvm_unreachable("Can't mangle __super specifier"); - case NestedNameSpecifier::Namespace: - mangleName(qualifier->getAsNamespace()->getNamespace()); + case NestedNameSpecifier::Kind::Namespace: + mangleName(Qualifier.getAsNamespaceAndPrefix().Namespace->getNamespace()); return; - case NestedNameSpecifier::TypeSpec: - if (NestedNameSpecifier *Prefix = qualifier->getPrefix()) { - const auto *DTST = - cast<DependentTemplateSpecializationType>(qualifier->getAsType()); - QualType NewT = getASTContext().getDependentTemplateSpecializationType( - DTST->getKeyword(), - {Prefix, DTST->getDependentTemplateName().getName(), - /*HasTemplateKeyword=*/true}, - DTST->template_arguments(), /*IsCanonical=*/true); - manglePrefix(NewT); - return; - } - manglePrefix(QualType(qualifier->getAsType(), 0)); - return; - - case NestedNameSpecifier::Identifier: - // Clang 14 and before did not consider this substitutable. - bool Clang14Compat = isCompatibleWith(LangOptions::ClangABI::Ver14); - if (!Clang14Compat && mangleSubstitution(qualifier)) - return; - - // Member expressions can have these without prefixes, but that - // should end up in mangleUnresolvedPrefix instead. - assert(qualifier->getPrefix()); - manglePrefix(qualifier->getPrefix()); - - mangleSourceName(qualifier->getAsIdentifier()); - - if (!Clang14Compat) - addSubstitution(qualifier); + case NestedNameSpecifier::Kind::Type: + manglePrefix(QualType(Qualifier.getAsType(), 0)); return; } @@ -2269,8 +2244,7 @@ void CXXNameMangler::mangleTemplatePrefix(TemplateName Template) { if (!Clang11Compat && mangleSubstitution(Template)) return; - if (NestedNameSpecifier *Qualifier = Dependent->getQualifier()) - manglePrefix(Qualifier); + manglePrefix(Dependent->getQualifier()); if (Clang11Compat && mangleSubstitution(Template)) return; @@ -2525,7 +2499,8 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty, case Type::Enum: case Type::Record: - mangleSourceNameWithAbiTags(cast<TagType>(Ty)->getDecl()); + mangleSourceNameWithAbiTags( + cast<TagType>(Ty)->getOriginalDecl()->getDefinitionOrSelf()); break; case Type::TemplateSpecialization: { @@ -2586,8 +2561,9 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty, } case Type::InjectedClassName: - mangleSourceNameWithAbiTags( - cast<InjectedClassNameType>(Ty)->getDecl()); + mangleSourceNameWithAbiTags(cast<InjectedClassNameType>(Ty) + ->getOriginalDecl() + ->getDefinitionOrSelf()); break; case Type::DependentName: @@ -2608,9 +2584,6 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty, case Type::Using: return mangleUnresolvedTypeOrSimpleId(cast<UsingType>(Ty)->desugar(), Prefix); - case Type::Elaborated: - return mangleUnresolvedTypeOrSimpleId( - cast<ElaboratedType>(Ty)->getNamedType(), Prefix); } return false; @@ -3838,7 +3811,7 @@ void CXXNameMangler::mangleType(const RecordType *T) { mangleType(static_cast<const TagType*>(T)); } void CXXNameMangler::mangleType(const TagType *T) { - mangleName(T->getDecl()); + mangleName(T->getOriginalDecl()->getDefinitionOrSelf()); } // <type> ::= <array-type> @@ -3875,16 +3848,10 @@ void CXXNameMangler::mangleType(const IncompleteArrayType *T) { // <pointer-to-member-type> ::= M <class type> <member type> void CXXNameMangler::mangleType(const MemberPointerType *T) { Out << 'M'; - if (auto *RD = T->getMostRecentCXXRecordDecl()) { + if (auto *RD = T->getMostRecentCXXRecordDecl()) mangleCXXRecordDecl(RD); - } else { - NestedNameSpecifier *NNS = T->getQualifier(); - if (auto *II = NNS->getAsIdentifier()) - mangleType(getASTContext().getDependentNameType( - ElaboratedTypeKeyword::None, NNS->getPrefix(), II)); - else - manglePrefix(NNS); - } + else + mangleType(QualType(T->getQualifier().getAsType(), 0)); QualType PointeeType = T->getPointeeType(); if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(PointeeType)) { mangleType(FPT); @@ -4471,7 +4438,8 @@ void CXXNameMangler::mangleType(const InjectedClassNameType *T) { // Mangle injected class name types as if the user had written the // specialization out fully. It may not actually be possible to see // this mangling, though. - mangleType(T->getInjectedSpecializationType()); + mangleType(T->getOriginalDecl()->getCanonicalTemplateSpecializationType( + getASTContext())); } void CXXNameMangler::mangleType(const TemplateSpecializationType *T) { @@ -4747,7 +4715,7 @@ void CXXNameMangler::mangleIntegerLiteral(QualType T, void CXXNameMangler::mangleMemberExprBase(const Expr *Base, bool IsArrow) { // Ignore member expressions involving anonymous unions. while (const auto *RT = Base->getType()->getAs<RecordType>()) { - if (!RT->getDecl()->isAnonymousStructOrUnion()) + if (!RT->getOriginalDecl()->isAnonymousStructOrUnion()) break; const auto *ME = dyn_cast<MemberExpr>(Base); if (!ME) @@ -4768,9 +4736,8 @@ void CXXNameMangler::mangleMemberExprBase(const Expr *Base, bool IsArrow) { } /// Mangles a member expression. -void CXXNameMangler::mangleMemberExpr(const Expr *base, - bool isArrow, - NestedNameSpecifier *qualifier, +void CXXNameMangler::mangleMemberExpr(const Expr *base, bool isArrow, + NestedNameSpecifier Qualifier, NamedDecl *firstQualifierLookup, DeclarationName member, const TemplateArgumentLoc *TemplateArgs, @@ -4780,7 +4747,7 @@ void CXXNameMangler::mangleMemberExpr(const Expr *base, // ::= pt <expression> <unresolved-name> if (base) mangleMemberExprBase(base, isArrow); - mangleUnresolvedName(qualifier, member, TemplateArgs, NumTemplateArgs, arity); + mangleUnresolvedName(Qualifier, member, TemplateArgs, NumTemplateArgs, arity); } /// Look at the callee of the given call expression and determine if @@ -5230,7 +5197,7 @@ recurse: const auto *PDE = cast<CXXPseudoDestructorExpr>(E); if (const Expr *Base = PDE->getBase()) mangleMemberExprBase(Base, PDE->isArrow()); - NestedNameSpecifier *Qualifier = PDE->getQualifier(); + NestedNameSpecifier Qualifier = PDE->getQualifier(); if (TypeSourceInfo *ScopeInfo = PDE->getScopeTypeInfo()) { if (Qualifier) { mangleUnresolvedPrefix(Qualifier, @@ -5855,7 +5822,8 @@ recurse: // externally-visible declaration, so there's no standard mangling for // this, but mangling as a literal of the closure type seems reasonable. Out << "L"; - mangleType(Context.getASTContext().getRecordType(cast<LambdaExpr>(E)->getLambdaClass())); + mangleType(Context.getASTContext().getCanonicalTagType( + cast<LambdaExpr>(E)->getLambdaClass())); Out << "E"; break; } @@ -6528,7 +6496,7 @@ static QualType getLValueType(ASTContext &Ctx, const APValue &LV) { dyn_cast<FieldDecl>(E.getAsBaseOrMember().getPointer())) T = FD->getType(); else - T = Ctx.getRecordType( + T = Ctx.getCanonicalTagType( cast<CXXRecordDecl>(E.getAsBaseOrMember().getPointer())); } return T; @@ -6895,7 +6863,7 @@ void CXXNameMangler::mangleValueInTemplateArg(QualType T, const APValue &V, } TypeSoFar = FD->getType(); } else { - TypeSoFar = Ctx.getRecordType(cast<CXXRecordDecl>(D)); + TypeSoFar = Ctx.getCanonicalTagType(cast<CXXRecordDecl>(D)); } } } @@ -7005,14 +6973,6 @@ bool CXXNameMangler::mangleSubstitution(const NamedDecl *ND) { return mangleSubstitution(reinterpret_cast<uintptr_t>(ND)); } -bool CXXNameMangler::mangleSubstitution(NestedNameSpecifier *NNS) { - assert(NNS->getKind() == NestedNameSpecifier::Identifier && - "mangleSubstitution(NestedNameSpecifier *) is only used for " - "identifier nested name specifiers."); - NNS = Context.getASTContext().getCanonicalNestedNameSpecifier(NNS); - return mangleSubstitution(reinterpret_cast<uintptr_t>(NNS)); -} - /// Determine whether the given type has any qualifiers that are relevant for /// substitutions. static bool hasMangledSubstitutionQualifiers(QualType T) { @@ -7023,7 +6983,7 @@ static bool hasMangledSubstitutionQualifiers(QualType T) { bool CXXNameMangler::mangleSubstitution(QualType T) { if (!hasMangledSubstitutionQualifiers(T)) { if (const RecordType *RT = T->getAs<RecordType>()) - return mangleSubstitution(RT->getDecl()); + return mangleSubstitution(RT->getOriginalDecl()->getDefinitionOrSelf()); } uintptr_t TypePtr = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr()); @@ -7064,7 +7024,7 @@ bool CXXNameMangler::isSpecializedAs(QualType S, llvm::StringRef Name, return false; const ClassTemplateSpecializationDecl *SD = - dyn_cast<ClassTemplateSpecializationDecl>(RT->getDecl()); + dyn_cast<ClassTemplateSpecializationDecl>(RT->getOriginalDecl()); if (!SD || !SD->getIdentifier()->isStr(Name)) return false; @@ -7194,7 +7154,7 @@ bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) { void CXXNameMangler::addSubstitution(QualType T) { if (!hasMangledSubstitutionQualifiers(T)) { if (const RecordType *RT = T->getAs<RecordType>()) { - addSubstitution(RT->getDecl()); + addSubstitution(RT->getOriginalDecl()->getDefinitionOrSelf()); return; } } diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp index 64ddb1e..b3f12a1 100644 --- a/clang/lib/AST/JSONNodeDumper.cpp +++ b/clang/lib/AST/JSONNodeDumper.cpp @@ -395,8 +395,8 @@ llvm::json::Array JSONNodeDumper::createCastPath(const CastExpr *C) { for (auto I = C->path_begin(), E = C->path_end(); I != E; ++I) { const CXXBaseSpecifier *Base = *I; - const auto *RD = - cast<CXXRecordDecl>(Base->getType()->castAs<RecordType>()->getDecl()); + const auto *RD = cast<CXXRecordDecl>( + Base->getType()->castAs<RecordType>()->getOriginalDecl()); llvm::json::Object Val{{"name", RD->getName()}}; if (Base->isVirtual()) @@ -606,9 +606,8 @@ void JSONNodeDumper::VisitTypedefType(const TypedefType *TT) { } void JSONNodeDumper::VisitUsingType(const UsingType *TT) { - JOS.attribute("decl", createBareDeclRef(TT->getFoundDecl())); - if (!TT->typeMatchesDecl()) - JOS.attribute("type", createQualType(TT->desugar())); + JOS.attribute("decl", createBareDeclRef(TT->getDecl())); + JOS.attribute("type", createQualType(TT->desugar())); } void JSONNodeDumper::VisitFunctionType(const FunctionType *T) { @@ -759,7 +758,15 @@ void JSONNodeDumper::VisitUnaryTransformType(const UnaryTransformType *UTT) { } void JSONNodeDumper::VisitTagType(const TagType *TT) { - JOS.attribute("decl", createBareDeclRef(TT->getDecl())); + if (NestedNameSpecifier Qualifier = TT->getQualifier()) { + std::string Str; + llvm::raw_string_ostream OS(Str); + Qualifier.print(OS, PrintPolicy, /*ResolveTemplateArguments=*/true); + JOS.attribute("qualifier", Str); + } + JOS.attribute("decl", createBareDeclRef(TT->getOriginalDecl())); + if (TT->isTagOwned()) + JOS.attribute("isTagOwned", true); } void JSONNodeDumper::VisitTemplateTypeParmType( @@ -809,7 +816,7 @@ void JSONNodeDumper::VisitTemplateSpecializationType( void JSONNodeDumper::VisitInjectedClassNameType( const InjectedClassNameType *ICNT) { - JOS.attribute("decl", createBareDeclRef(ICNT->getDecl())); + JOS.attribute("decl", createBareDeclRef(ICNT->getOriginalDecl())); } void JSONNodeDumper::VisitObjCInterfaceType(const ObjCInterfaceType *OIT) { @@ -821,17 +828,6 @@ void JSONNodeDumper::VisitPackExpansionType(const PackExpansionType *PET) { JOS.attribute("numExpansions", *N); } -void JSONNodeDumper::VisitElaboratedType(const ElaboratedType *ET) { - if (const NestedNameSpecifier *NNS = ET->getQualifier()) { - std::string Str; - llvm::raw_string_ostream OS(Str); - NNS->print(OS, PrintPolicy, /*ResolveTemplateArgs*/ true); - JOS.attribute("qualifier", Str); - } - if (const TagDecl *TD = ET->getOwnedTagDecl()) - JOS.attribute("ownedTagDecl", createBareDeclRef(TD)); -} - void JSONNodeDumper::VisitMacroQualifiedType(const MacroQualifiedType *MQT) { JOS.attribute("macroName", MQT->getMacroIdentifier()->getName()); } @@ -902,9 +898,9 @@ void JSONNodeDumper::VisitNamespaceAliasDecl(const NamespaceAliasDecl *NAD) { void JSONNodeDumper::VisitUsingDecl(const UsingDecl *UD) { std::string Name; - if (const NestedNameSpecifier *NNS = UD->getQualifier()) { + if (NestedNameSpecifier Qualifier = UD->getQualifier()) { llvm::raw_string_ostream SOS(Name); - NNS->print(SOS, UD->getASTContext().getPrintingPolicy()); + Qualifier.print(SOS, UD->getASTContext().getPrintingPolicy()); } Name += UD->getNameAsString(); JOS.attribute("name", Name); diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp index e6ea0ad..241c7c3 100644 --- a/clang/lib/AST/MicrosoftMangle.cpp +++ b/clang/lib/AST/MicrosoftMangle.cpp @@ -1805,17 +1805,16 @@ void MicrosoftCXXNameMangler::mangleTemplateArg(const TemplateDecl *TD, case TemplateArgument::Declaration: { const NamedDecl *ND = TA.getAsDecl(); if (isa<FieldDecl>(ND) || isa<IndirectFieldDecl>(ND)) { - mangleMemberDataPointer(cast<CXXRecordDecl>(ND->getDeclContext()) - ->getMostRecentNonInjectedDecl(), - cast<ValueDecl>(ND), - cast<NonTypeTemplateParmDecl>(Parm), - TA.getParamTypeForDecl()); + mangleMemberDataPointer( + cast<CXXRecordDecl>(ND->getDeclContext())->getMostRecentDecl(), + cast<ValueDecl>(ND), cast<NonTypeTemplateParmDecl>(Parm), + TA.getParamTypeForDecl()); } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) { const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD); if (MD && MD->isInstance()) { - mangleMemberFunctionPointer( - MD->getParent()->getMostRecentNonInjectedDecl(), MD, - cast<NonTypeTemplateParmDecl>(Parm), TA.getParamTypeForDecl()); + mangleMemberFunctionPointer(MD->getParent()->getMostRecentDecl(), MD, + cast<NonTypeTemplateParmDecl>(Parm), + TA.getParamTypeForDecl()); } else { mangleFunctionPointer(FD, cast<NonTypeTemplateParmDecl>(Parm), TA.getParamTypeForDecl()); @@ -2021,7 +2020,7 @@ void MicrosoftCXXNameMangler::mangleTemplateArgValue(QualType T, if (RD->isAnonymousStructOrUnion()) continue; } else { - ET = getASTContext().getRecordType(cast<CXXRecordDecl>(D)); + ET = getASTContext().getCanonicalTagType(cast<CXXRecordDecl>(D)); // Bug in MSVC: fully qualified name of base class should be used for // mangling to prevent collisions e.g. on base classes with same names // in different namespaces. @@ -3247,11 +3246,11 @@ void MicrosoftCXXNameMangler::mangleTagTypeKind(TagTypeKind TTK) { } void MicrosoftCXXNameMangler::mangleType(const EnumType *T, Qualifiers, SourceRange) { - mangleType(cast<TagType>(T)->getDecl()); + mangleType(cast<TagType>(T)->getOriginalDecl()->getDefinitionOrSelf()); } void MicrosoftCXXNameMangler::mangleType(const RecordType *T, Qualifiers, SourceRange) { - mangleType(cast<TagType>(T)->getDecl()); + mangleType(cast<TagType>(T)->getOriginalDecl()->getDefinitionOrSelf()); } void MicrosoftCXXNameMangler::mangleType(const TagDecl *TD) { mangleTagTypeKind(TD->getTagKind()); diff --git a/clang/lib/AST/NestedNameSpecifier.cpp b/clang/lib/AST/NestedNameSpecifier.cpp index 56f74b9..c6af91f 100644 --- a/clang/lib/AST/NestedNameSpecifier.cpp +++ b/clang/lib/AST/NestedNameSpecifier.cpp @@ -15,7 +15,6 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" -#include "clang/AST/DeclTemplate.h" #include "clang/AST/DependenceFlags.h" #include "clang/AST/PrettyPrinter.h" #include "clang/AST/TemplateName.h" @@ -35,250 +34,67 @@ using namespace clang; -NestedNameSpecifier * -NestedNameSpecifier::FindOrInsert(const ASTContext &Context, - const NestedNameSpecifier &Mockup) { +const NamespaceAndPrefixStorage * +NestedNameSpecifier::MakeNamespaceAndPrefixStorage( + const ASTContext &Ctx, const NamespaceBaseDecl *Namespace, + NestedNameSpecifier Prefix) { llvm::FoldingSetNodeID ID; - Mockup.Profile(ID); + NamespaceAndPrefixStorage::Profile(ID, Namespace, Prefix); void *InsertPos = nullptr; - NestedNameSpecifier *NNS - = Context.NestedNameSpecifiers.FindNodeOrInsertPos(ID, InsertPos); - if (!NNS) { - NNS = - new (Context, alignof(NestedNameSpecifier)) NestedNameSpecifier(Mockup); - Context.NestedNameSpecifiers.InsertNode(NNS, InsertPos); + NamespaceAndPrefixStorage *S = + Ctx.NamespaceAndPrefixStorages.FindNodeOrInsertPos(ID, InsertPos); + if (!S) { + S = new (Ctx, alignof(NamespaceAndPrefixStorage)) + NamespaceAndPrefixStorage(Namespace, Prefix); + Ctx.NamespaceAndPrefixStorages.InsertNode(S, InsertPos); } - - return NNS; -} - -NestedNameSpecifier *NestedNameSpecifier::Create(const ASTContext &Context, - NestedNameSpecifier *Prefix, - const IdentifierInfo *II) { - assert(II && "Identifier cannot be NULL"); - assert((!Prefix || Prefix->isDependent()) && "Prefix must be dependent"); - - NestedNameSpecifier Mockup; - Mockup.Prefix.setPointer(Prefix); - Mockup.Prefix.setInt(StoredIdentifier); - Mockup.Specifier = const_cast<IdentifierInfo *>(II); - return FindOrInsert(Context, Mockup); -} - -NestedNameSpecifier *NestedNameSpecifier::Create(const ASTContext &Context, - NestedNameSpecifier *Prefix, - const NamespaceBaseDecl *NS) { - assert(NS && "Namespace cannot be NULL"); - assert((!Prefix || - (Prefix->getAsType() == nullptr && - Prefix->getAsIdentifier() == nullptr)) && - "Broken nested name specifier"); - NestedNameSpecifier Mockup; - Mockup.Prefix.setPointer(Prefix); - Mockup.Prefix.setInt(StoredDecl); - Mockup.Specifier = const_cast<NamespaceBaseDecl *>(NS); - return FindOrInsert(Context, Mockup); -} - -NestedNameSpecifier *NestedNameSpecifier::Create(const ASTContext &Context, - NestedNameSpecifier *Prefix, - const Type *T) { - assert(T && "Type cannot be NULL"); - NestedNameSpecifier Mockup; - Mockup.Prefix.setPointer(Prefix); - Mockup.Prefix.setInt(StoredTypeSpec); - Mockup.Specifier = const_cast<Type*>(T); - return FindOrInsert(Context, Mockup); -} - -NestedNameSpecifier *NestedNameSpecifier::Create(const ASTContext &Context, - const IdentifierInfo *II) { - assert(II && "Identifier cannot be NULL"); - NestedNameSpecifier Mockup; - Mockup.Prefix.setPointer(nullptr); - Mockup.Prefix.setInt(StoredIdentifier); - Mockup.Specifier = const_cast<IdentifierInfo *>(II); - return FindOrInsert(Context, Mockup); -} - -NestedNameSpecifier * -NestedNameSpecifier::GlobalSpecifier(const ASTContext &Context) { - if (!Context.GlobalNestedNameSpecifier) - Context.GlobalNestedNameSpecifier = - new (Context, alignof(NestedNameSpecifier)) NestedNameSpecifier(); - return Context.GlobalNestedNameSpecifier; -} - -NestedNameSpecifier * -NestedNameSpecifier::SuperSpecifier(const ASTContext &Context, - CXXRecordDecl *RD) { - NestedNameSpecifier Mockup; - Mockup.Prefix.setPointer(nullptr); - Mockup.Prefix.setInt(StoredDecl); - Mockup.Specifier = RD; - return FindOrInsert(Context, Mockup); + return S; } -NestedNameSpecifier::SpecifierKind NestedNameSpecifier::getKind() const { - if (!Specifier) - return Global; - - switch (Prefix.getInt()) { - case StoredIdentifier: - return Identifier; - - case StoredDecl: { - NamedDecl *ND = static_cast<NamedDecl *>(Specifier); - return isa<CXXRecordDecl>(ND) ? Super : Namespace; - } - - case StoredTypeSpec: - return TypeSpec; - } - - llvm_unreachable("Invalid NNS Kind!"); -} - -/// Retrieve the namespace or namespace alias stored in this nested name -/// specifier. -NamespaceBaseDecl *NestedNameSpecifier::getAsNamespace() const { - if (Prefix.getInt() == StoredDecl) - return dyn_cast<NamespaceBaseDecl>(static_cast<NamedDecl *>(Specifier)); - - return nullptr; -} - -/// Retrieve the record declaration stored in this nested name specifier. -CXXRecordDecl *NestedNameSpecifier::getAsRecordDecl() const { - switch (Prefix.getInt()) { - case StoredIdentifier: - return nullptr; - - case StoredDecl: - return dyn_cast<CXXRecordDecl>(static_cast<NamedDecl *>(Specifier)); - - case StoredTypeSpec: - return getAsType()->getAsCXXRecordDecl(); +bool NestedNameSpecifier::isFullyQualified() const { + switch (getKind()) { + case NestedNameSpecifier::Kind::Global: + return true; + case NestedNameSpecifier::Kind::Null: + case NestedNameSpecifier::Kind::MicrosoftSuper: + return false; + case NestedNameSpecifier::Kind::Namespace: + return getAsNamespaceAndPrefix().Prefix.isFullyQualified(); + case NestedNameSpecifier::Kind::Type: + return getAsType()->getPrefix().isFullyQualified(); } - llvm_unreachable("Invalid NNS Kind!"); } NestedNameSpecifierDependence NestedNameSpecifier::getDependence() const { switch (getKind()) { - case Identifier: { - // Identifier specifiers always represent dependent types - auto F = NestedNameSpecifierDependence::Dependent | - NestedNameSpecifierDependence::Instantiation; - // Prefix can contain unexpanded template parameters. - if (getPrefix()) - return F | getPrefix()->getDependence(); - return F; - } - - case Namespace: - case Global: - return NestedNameSpecifierDependence::None; - - case Super: { - CXXRecordDecl *RD = static_cast<CXXRecordDecl *>(Specifier); - for (const auto &Base : RD->bases()) - if (Base.getType()->isDependentType()) - // FIXME: must also be instantiation-dependent. - return NestedNameSpecifierDependence::Dependent; + case Kind::Null: + case Kind::Global: + case Kind::Namespace: return NestedNameSpecifierDependence::None; + case Kind::MicrosoftSuper: { + CXXRecordDecl *RD = getAsMicrosoftSuper(); + return RD->isDependentContext() + ? NestedNameSpecifierDependence::DependentInstantiation | + NestedNameSpecifierDependence::Dependent + : NestedNameSpecifierDependence::None; } - - case TypeSpec: { - NestedNameSpecifierDependence Dep = - toNestedNameSpecifierDependendence(getAsType()->getDependence()); - if (NestedNameSpecifier *Prefix = getPrefix()) - Dep |= - Prefix->getDependence() & ~NestedNameSpecifierDependence::Dependent; - return Dep; - } + case Kind::Type: + return toNestedNameSpecifierDependence(getAsType()->getDependence()); } llvm_unreachable("Invalid NNS Kind!"); } -bool NestedNameSpecifier::isDependent() const { - return getDependence() & NestedNameSpecifierDependence::Dependent; -} - -bool NestedNameSpecifier::isInstantiationDependent() const { - return getDependence() & NestedNameSpecifierDependence::Instantiation; -} - -bool NestedNameSpecifier::containsUnexpandedParameterPack() const { - return getDependence() & NestedNameSpecifierDependence::UnexpandedPack; -} - -bool NestedNameSpecifier::containsErrors() const { - return getDependence() & NestedNameSpecifierDependence::Error; -} - -const Type * -NestedNameSpecifier::translateToType(const ASTContext &Context) const { - NestedNameSpecifier *Prefix = getPrefix(); - switch (getKind()) { - case SpecifierKind::Identifier: - return Context - .getDependentNameType(ElaboratedTypeKeyword::None, Prefix, - getAsIdentifier()) - .getTypePtr(); - case SpecifierKind::TypeSpec: { - const Type *T = getAsType(); - switch (T->getTypeClass()) { - case Type::DependentTemplateSpecialization: { - const auto *DT = cast<DependentTemplateSpecializationType>(T); - const DependentTemplateStorage &DTN = DT->getDependentTemplateName(); - return Context - .getDependentTemplateSpecializationType( - ElaboratedTypeKeyword::None, - {Prefix, DTN.getName(), DTN.hasTemplateKeyword()}, - DT->template_arguments()) - .getTypePtr(); - } - case Type::Record: - case Type::TemplateSpecialization: - case Type::Using: - case Type::Enum: - case Type::Typedef: - case Type::UnresolvedUsing: - return Context - .getElaboratedType(ElaboratedTypeKeyword::None, Prefix, - QualType(T, 0)) - .getTypePtr(); - default: - assert(Prefix == nullptr && "unexpected type with elaboration"); - return T; - } - } - case SpecifierKind::Global: - case SpecifierKind::Namespace: - case SpecifierKind::Super: - // These are not representable as types. - return nullptr; - } - llvm_unreachable("Unhandled SpecifierKind enum"); -} - /// Print this nested name specifier to the given output /// stream. void NestedNameSpecifier::print(raw_ostream &OS, const PrintingPolicy &Policy, bool ResolveTemplateArguments, bool PrintFinalScopeResOp) const { - if (getPrefix()) - getPrefix()->print(OS, Policy); - switch (getKind()) { - case Identifier: - OS << getAsIdentifier()->getName(); - break; - - case Namespace: { - NamespaceBaseDecl *Namespace = getAsNamespace(); + case Kind::Namespace: { + auto [Namespace, Prefix] = getAsNamespaceAndPrefix(); + Prefix.print(OS, Policy); if (const auto *NS = dyn_cast<NamespaceDecl>(Namespace)) { assert(!NS->isAnonymousNamespace()); OS << NS->getName(); @@ -287,134 +103,49 @@ void NestedNameSpecifier::print(raw_ostream &OS, const PrintingPolicy &Policy, } break; } - - case Global: + case Kind::Global: OS << "::"; return; - - case Super: + case Kind::MicrosoftSuper: OS << "__super"; break; - - case TypeSpec: { + case Kind::Type: { PrintingPolicy InnerPolicy(Policy); - InnerPolicy.SuppressScope = true; InnerPolicy.SuppressTagKeyword = true; QualType(getAsType(), 0).print(OS, InnerPolicy); break; } + case Kind::Null: + return; } - if (PrintFinalScopeResOp) OS << "::"; } -LLVM_DUMP_METHOD void NestedNameSpecifier::dump(const LangOptions &LO) const { - dump(llvm::errs(), LO); +LLVM_DUMP_METHOD void NestedNameSpecifier::dump(llvm::raw_ostream *OS, + const LangOptions *LO) const { + print(OS ? *OS : llvm::errs(), LO ? *LO : LangOptions()); } -LLVM_DUMP_METHOD void NestedNameSpecifier::dump() const { dump(llvm::errs()); } - +LLVM_DUMP_METHOD void NestedNameSpecifier::dump(const LangOptions &LO) const { + dump(/*OS=*/nullptr, &LO); +} LLVM_DUMP_METHOD void NestedNameSpecifier::dump(llvm::raw_ostream &OS) const { - LangOptions LO; - dump(OS, LO); + dump(&OS); } - LLVM_DUMP_METHOD void NestedNameSpecifier::dump(llvm::raw_ostream &OS, const LangOptions &LO) const { - print(OS, PrintingPolicy(LO)); -} - -unsigned -NestedNameSpecifierLoc::getLocalDataLength(NestedNameSpecifier *Qualifier) { - assert(Qualifier && "Expected a non-NULL qualifier"); - - // Location of the trailing '::'. - unsigned Length = sizeof(SourceLocation::UIntTy); - - switch (Qualifier->getKind()) { - case NestedNameSpecifier::Global: - // Nothing more to add. - break; - - case NestedNameSpecifier::Identifier: - case NestedNameSpecifier::Namespace: - case NestedNameSpecifier::Super: - // The location of the identifier or namespace name. - Length += sizeof(SourceLocation::UIntTy); - break; - - case NestedNameSpecifier::TypeSpec: - // The "void*" that points at the TypeLoc data. - // Note: the 'template' keyword is part of the TypeLoc. - Length += sizeof(void *); - break; - } - - return Length; -} - -unsigned -NestedNameSpecifierLoc::getDataLength(NestedNameSpecifier *Qualifier) { - unsigned Length = 0; - for (; Qualifier; Qualifier = Qualifier->getPrefix()) - Length += getLocalDataLength(Qualifier); - return Length; -} - -/// Load a (possibly unaligned) source location from a given address -/// and offset. -static SourceLocation LoadSourceLocation(void *Data, unsigned Offset) { - SourceLocation::UIntTy Raw; - memcpy(&Raw, static_cast<char *>(Data) + Offset, sizeof(Raw)); - return SourceLocation::getFromRawEncoding(Raw); + dump(&OS, &LO); } -/// Load a (possibly unaligned) pointer from a given address and -/// offset. -static void *LoadPointer(void *Data, unsigned Offset) { - void *Result; - memcpy(&Result, static_cast<char *>(Data) + Offset, sizeof(void*)); - return Result; -} - -SourceRange NestedNameSpecifierLoc::getLocalSourceRange() const { +SourceLocation NestedNameSpecifierLoc::getBeginLoc() const { if (!Qualifier) - return SourceRange(); - - unsigned Offset = getDataLength(Qualifier->getPrefix()); - switch (Qualifier->getKind()) { - case NestedNameSpecifier::Global: - return LoadSourceLocation(Data, Offset); - - case NestedNameSpecifier::Identifier: - case NestedNameSpecifier::Namespace: - case NestedNameSpecifier::Super: - return SourceRange( - LoadSourceLocation(Data, Offset), - LoadSourceLocation(Data, Offset + sizeof(SourceLocation::UIntTy))); - - case NestedNameSpecifier::TypeSpec: { - // The "void*" that points at the TypeLoc data. - // Note: the 'template' keyword is part of the TypeLoc. - void *TypeData = LoadPointer(Data, Offset); - TypeLoc TL(Qualifier->getAsType(), TypeData); - return SourceRange(TL.getBeginLoc(), - LoadSourceLocation(Data, Offset + sizeof(void*))); - } - } + return SourceLocation(); - llvm_unreachable("Invalid NNS Kind!"); -} - -TypeLoc NestedNameSpecifierLoc::getTypeLoc() const { - if (Qualifier->getKind() != NestedNameSpecifier::TypeSpec) - return TypeLoc(); - - // The "void*" that points at the TypeLoc data. - unsigned Offset = getDataLength(Qualifier->getPrefix()); - void *TypeData = LoadPointer(Data, Offset); - return TypeLoc(Qualifier->getAsType(), TypeData); + NestedNameSpecifierLoc First = *this; + while (NestedNameSpecifierLoc Prefix = First.getAsNamespaceAndPrefix().Prefix) + First = Prefix; + return First.getLocalSourceRange().getBegin(); } static void Append(char *Start, char *End, char *&Buffer, unsigned &BufferSize, @@ -516,10 +247,10 @@ operator=(const NestedNameSpecifierLocBuilder &Other) { return *this; } -void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context, TypeLoc TL, - SourceLocation ColonColonLoc) { - Representation = - NestedNameSpecifier::Create(Context, Representation, TL.getTypePtr()); +void NestedNameSpecifierLocBuilder::Make(ASTContext &Context, TypeLoc TL, + SourceLocation ColonColonLoc) { + assert(!Representation); + Representation = NestedNameSpecifier(TL.getTypePtr()); // Push source-location info into the buffer. SavePointer(TL.getOpaqueData(), Buffer, BufferSize, BufferCapacity); @@ -527,23 +258,10 @@ void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context, TypeLoc TL, } void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context, - IdentifierInfo *Identifier, - SourceLocation IdentifierLoc, - SourceLocation ColonColonLoc) { - Representation = NestedNameSpecifier::Create(Context, Representation, - Identifier); - - // Push source-location info into the buffer. - SaveSourceLocation(IdentifierLoc, Buffer, BufferSize, BufferCapacity); - SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity); -} - -void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context, - NamespaceBaseDecl *Namespace, + const NamespaceBaseDecl *Namespace, SourceLocation NamespaceLoc, SourceLocation ColonColonLoc) { - Representation = NestedNameSpecifier::Create(Context, Representation, - Namespace); + Representation = NestedNameSpecifier(Context, Namespace, Representation); // Push source-location info into the buffer. SaveSourceLocation(NamespaceLoc, Buffer, BufferSize, BufferCapacity); @@ -553,60 +271,48 @@ void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context, void NestedNameSpecifierLocBuilder::MakeGlobal(ASTContext &Context, SourceLocation ColonColonLoc) { assert(!Representation && "Already have a nested-name-specifier!?"); - Representation = NestedNameSpecifier::GlobalSpecifier(Context); + Representation = NestedNameSpecifier::getGlobal(); // Push source-location info into the buffer. SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity); } -void NestedNameSpecifierLocBuilder::MakeSuper(ASTContext &Context, - CXXRecordDecl *RD, - SourceLocation SuperLoc, - SourceLocation ColonColonLoc) { - Representation = NestedNameSpecifier::SuperSpecifier(Context, RD); +void NestedNameSpecifierLocBuilder::MakeMicrosoftSuper( + ASTContext &Context, CXXRecordDecl *RD, SourceLocation SuperLoc, + SourceLocation ColonColonLoc) { + Representation = NestedNameSpecifier(RD); // Push source-location info into the buffer. SaveSourceLocation(SuperLoc, Buffer, BufferSize, BufferCapacity); SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity); } -void NestedNameSpecifierLocBuilder::MakeTrivial(ASTContext &Context, - NestedNameSpecifier *Qualifier, +void NestedNameSpecifierLocBuilder::PushTrivial(ASTContext &Context, + NestedNameSpecifier Qualifier, SourceRange R) { - Representation = Qualifier; - // Construct bogus (but well-formed) source information for the // nested-name-specifier. - BufferSize = 0; - SmallVector<NestedNameSpecifier *, 4> Stack; - for (NestedNameSpecifier *NNS = Qualifier; NNS; NNS = NNS->getPrefix()) - Stack.push_back(NNS); - while (!Stack.empty()) { - NestedNameSpecifier *NNS = Stack.pop_back_val(); - switch (NNS->getKind()) { - case NestedNameSpecifier::Identifier: - case NestedNameSpecifier::Namespace: - SaveSourceLocation(R.getBegin(), Buffer, BufferSize, BufferCapacity); - break; - - case NestedNameSpecifier::TypeSpec: { - TypeSourceInfo *TSInfo - = Context.getTrivialTypeSourceInfo(QualType(NNS->getAsType(), 0), - R.getBegin()); - SavePointer(TSInfo->getTypeLoc().getOpaqueData(), Buffer, BufferSize, - BufferCapacity); - break; - } - - case NestedNameSpecifier::Global: - case NestedNameSpecifier::Super: - break; - } - - // Save the location of the '::'. - SaveSourceLocation(Stack.empty()? R.getEnd() : R.getBegin(), - Buffer, BufferSize, BufferCapacity); + switch (Qualifier.getKind()) { + case NestedNameSpecifier::Kind::Null: + return; + case NestedNameSpecifier::Kind::Namespace: { + auto [_1, Prefix] = Qualifier.getAsNamespaceAndPrefix(); + PushTrivial(Context, Prefix, R.getBegin()); + SaveSourceLocation(R.getBegin(), Buffer, BufferSize, BufferCapacity); + break; + } + case NestedNameSpecifier::Kind::Type: { + TypeSourceInfo *TSInfo = Context.getTrivialTypeSourceInfo( + QualType(Qualifier.getAsType(), 0), R.getBegin()); + SavePointer(TSInfo->getTypeLoc().getOpaqueData(), Buffer, BufferSize, + BufferCapacity); + break; + } + case NestedNameSpecifier::Kind::Global: + case NestedNameSpecifier::Kind::MicrosoftSuper: + break; } + SaveSourceLocation(R.getEnd(), Buffer, BufferSize, BufferCapacity); } void NestedNameSpecifierLocBuilder::Adopt(NestedNameSpecifierLoc Other) { @@ -614,7 +320,7 @@ void NestedNameSpecifierLocBuilder::Adopt(NestedNameSpecifierLoc Other) { free(Buffer); if (!Other) { - Representation = nullptr; + Representation = std::nullopt; BufferSize = 0; return; } diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp index bd87d44..fb95f58 100644 --- a/clang/lib/AST/ODRHash.cpp +++ b/clang/lib/AST/ODRHash.cpp @@ -111,34 +111,28 @@ void ODRHash::AddDeclarationNameInfoImpl(DeclarationNameInfo NameInfo) { } } -void ODRHash::AddNestedNameSpecifier(const NestedNameSpecifier *NNS) { - assert(NNS && "Expecting non-null pointer."); - const auto *Prefix = NNS->getPrefix(); - AddBoolean(Prefix); - if (Prefix) { - AddNestedNameSpecifier(Prefix); - } - auto Kind = NNS->getKind(); - ID.AddInteger(Kind); +void ODRHash::AddNestedNameSpecifier(NestedNameSpecifier NNS) { + auto Kind = NNS.getKind(); + ID.AddInteger(llvm::to_underlying(Kind)); switch (Kind) { - case NestedNameSpecifier::Identifier: - AddIdentifierInfo(NNS->getAsIdentifier()); - break; - case NestedNameSpecifier::Namespace: - AddDecl(NNS->getAsNamespace()); + case NestedNameSpecifier::Kind::Namespace: { + auto [Namespace, Prefix] = NNS.getAsNamespaceAndPrefix(); + AddDecl(Namespace); + AddNestedNameSpecifier(Prefix); break; - case NestedNameSpecifier::TypeSpec: - AddType(NNS->getAsType()); + } + case NestedNameSpecifier::Kind::Type: + AddType(NNS.getAsType()); break; - case NestedNameSpecifier::Global: - case NestedNameSpecifier::Super: + case NestedNameSpecifier::Kind::Null: + case NestedNameSpecifier::Kind::Global: + case NestedNameSpecifier::Kind::MicrosoftSuper: break; } } void ODRHash::AddDependentTemplateName(const DependentTemplateStorage &Name) { - if (NestedNameSpecifier *NNS = Name.getQualifier()) - AddNestedNameSpecifier(NNS); + AddNestedNameSpecifier(Name.getQualifier()); if (IdentifierOrOverloadedOperator IO = Name.getName(); const IdentifierInfo *II = IO.getIdentifier()) AddIdentifierInfo(II); @@ -156,8 +150,7 @@ void ODRHash::AddTemplateName(TemplateName Name) { break; case TemplateName::QualifiedTemplate: { QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName(); - if (NestedNameSpecifier *NNS = QTN->getQualifier()) - AddNestedNameSpecifier(NNS); + AddNestedNameSpecifier(QTN->getQualifier()); AddBoolean(QTN->hasTemplateKeyword()); AddTemplateName(QTN->getUnderlyingTemplate()); break; @@ -889,11 +882,8 @@ public: } } - void AddNestedNameSpecifier(const NestedNameSpecifier *NNS) { - Hash.AddBoolean(NNS); - if (NNS) { - Hash.AddNestedNameSpecifier(NNS); - } + void AddNestedNameSpecifier(NestedNameSpecifier NNS) { + Hash.AddNestedNameSpecifier(NNS); } void AddIdentifierInfo(const IdentifierInfo *II) { @@ -907,52 +897,33 @@ public: ID.AddInteger(Quals.getAsOpaqueValue()); } - // Return the RecordType if the typedef only strips away a keyword. - // Otherwise, return the original type. - static const Type *RemoveTypedef(const Type *T) { + // Handle typedefs which only strip away a keyword. + bool handleTypedef(const Type *T) { const auto *TypedefT = dyn_cast<TypedefType>(T); - if (!TypedefT) { - return T; - } - - const TypedefNameDecl *D = TypedefT->getDecl(); - QualType UnderlyingType = D->getUnderlyingType(); - - if (UnderlyingType.hasLocalQualifiers()) { - return T; - } - - const auto *ElaboratedT = dyn_cast<ElaboratedType>(UnderlyingType); - if (!ElaboratedT) { - return T; - } + if (!TypedefT) + return false; - if (ElaboratedT->getQualifier() != nullptr) { - return T; - } + QualType UnderlyingType = TypedefT->desugar(); - QualType NamedType = ElaboratedT->getNamedType(); - if (NamedType.hasLocalQualifiers()) { - return T; - } + if (UnderlyingType.hasLocalQualifiers()) + return false; - const auto *RecordT = dyn_cast<RecordType>(NamedType); - if (!RecordT) { - return T; - } + const auto *TagT = dyn_cast<TagType>(UnderlyingType); + if (!TagT || TagT->getQualifier()) + return false; - const IdentifierInfo *TypedefII = TypedefT->getDecl()->getIdentifier(); - const IdentifierInfo *RecordII = RecordT->getDecl()->getIdentifier(); - if (!TypedefII || !RecordII || - TypedefII->getName() != RecordII->getName()) { - return T; - } + if (TypedefT->getDecl()->getIdentifier() != + TagT->getOriginalDecl()->getIdentifier()) + return false; - return RecordT; + ID.AddInteger(TagT->getTypeClass()); + VisitTagType(TagT, /*ElaboratedOverride=*/TypedefT); + return true; } void Visit(const Type *T) { - T = RemoveTypedef(T); + if (handleTypedef(T)) + return; ID.AddInteger(T->getTypeClass()); Inherited::Visit(T); } @@ -1088,7 +1059,7 @@ public: } void VisitInjectedClassNameType(const InjectedClassNameType *T) { - AddDecl(T->getDecl()); + AddDecl(T->getOriginalDecl()->getDefinitionOrSelf()); VisitType(T); } @@ -1186,14 +1157,17 @@ public: VisitType(T); } - void VisitTagType(const TagType *T) { - AddDecl(T->getDecl()); + void VisitTagType(const TagType *T, + const TypedefType *ElaboratedOverride = nullptr) { + ID.AddInteger(llvm::to_underlying( + ElaboratedOverride ? ElaboratedTypeKeyword::None : T->getKeyword())); + AddNestedNameSpecifier(ElaboratedOverride + ? ElaboratedOverride->getQualifier() + : T->getQualifier()); + AddDecl(T->getOriginalDecl()->getDefinitionOrSelf()); VisitType(T); } - void VisitRecordType(const RecordType *T) { VisitTagType(T); } - void VisitEnumType(const EnumType *T) { VisitTagType(T); } - void VisitTemplateSpecializationType(const TemplateSpecializationType *T) { ID.AddInteger(T->template_arguments().size()); for (const auto &TA : T->template_arguments()) { @@ -1211,6 +1185,8 @@ public: } void VisitTypedefType(const TypedefType *T) { + ID.AddInteger(llvm::to_underlying(T->getKeyword())); + AddNestedNameSpecifier(T->getQualifier()); AddDecl(T->getDecl()); VisitType(T); } @@ -1247,12 +1223,6 @@ public: VisitTypeWithKeyword(T); } - void VisitElaboratedType(const ElaboratedType *T) { - AddNestedNameSpecifier(T->getQualifier()); - AddQualType(T->getNamedType()); - VisitTypeWithKeyword(T); - } - void VisitUnaryTransformType(const UnaryTransformType *T) { AddQualType(T->getUnderlyingType()); AddQualType(T->getBaseType()); @@ -1330,7 +1300,7 @@ void ODRHash::AddStructuralValue(const APValue &Value) { TypeSoFar = FD->getType(); } else { TypeSoFar = - D->getASTContext().getRecordType(cast<CXXRecordDecl>(D)); + D->getASTContext().getCanonicalTagType(cast<CXXRecordDecl>(D)); } } } diff --git a/clang/lib/AST/OpenACCClause.cpp b/clang/lib/AST/OpenACCClause.cpp index f7a98bd..fe20004 100644 --- a/clang/lib/AST/OpenACCClause.cpp +++ b/clang/lib/AST/OpenACCClause.cpp @@ -329,10 +329,11 @@ OpenACCPrivateClause::Create(const ASTContext &C, SourceLocation BeginLoc, OpenACCFirstPrivateClause *OpenACCFirstPrivateClause::Create( const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc, - ArrayRef<Expr *> VarList, ArrayRef<VarDecl *> InitRecipes, + ArrayRef<Expr *> VarList, ArrayRef<OpenACCFirstPrivateRecipe> InitRecipes, SourceLocation EndLoc) { - void *Mem = - C.Allocate(OpenACCFirstPrivateClause::totalSizeToAlloc<Expr *, VarDecl *>( + void *Mem = C.Allocate( + OpenACCFirstPrivateClause::totalSizeToAlloc<Expr *, + OpenACCFirstPrivateRecipe>( VarList.size(), InitRecipes.size())); return new (Mem) OpenACCFirstPrivateClause(BeginLoc, LParenLoc, VarList, InitRecipes, EndLoc); diff --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp index de8b599..588b0dc 100644 --- a/clang/lib/AST/OpenMPClause.cpp +++ b/clang/lib/AST/OpenMPClause.cpp @@ -2350,17 +2350,16 @@ void OMPClausePrinter::VisitOMPReductionClause(OMPReductionClause *Node) { if (Node->getModifierLoc().isValid()) OS << getOpenMPSimpleClauseTypeName(OMPC_reduction, Node->getModifier()) << ", "; - NestedNameSpecifier *QualifierLoc = + NestedNameSpecifier Qualifier = Node->getQualifierLoc().getNestedNameSpecifier(); OverloadedOperatorKind OOK = Node->getNameInfo().getName().getCXXOverloadedOperator(); - if (QualifierLoc == nullptr && OOK != OO_None) { + if (!Qualifier && OOK != OO_None) { // Print reduction identifier in C format OS << getOperatorSpelling(OOK); } else { // Use C++ format - if (QualifierLoc != nullptr) - QualifierLoc->print(OS, Policy); + Qualifier.print(OS, Policy); OS << Node->getNameInfo(); } OS << ":"; @@ -2373,17 +2372,16 @@ void OMPClausePrinter::VisitOMPTaskReductionClause( OMPTaskReductionClause *Node) { if (!Node->varlist_empty()) { OS << "task_reduction("; - NestedNameSpecifier *QualifierLoc = + NestedNameSpecifier Qualifier = Node->getQualifierLoc().getNestedNameSpecifier(); OverloadedOperatorKind OOK = Node->getNameInfo().getName().getCXXOverloadedOperator(); - if (QualifierLoc == nullptr && OOK != OO_None) { + if (!Qualifier && OOK != OO_None) { // Print reduction identifier in C format OS << getOperatorSpelling(OOK); } else { // Use C++ format - if (QualifierLoc != nullptr) - QualifierLoc->print(OS, Policy); + Qualifier.print(OS, Policy); OS << Node->getNameInfo(); } OS << ":"; @@ -2395,17 +2393,16 @@ void OMPClausePrinter::VisitOMPTaskReductionClause( void OMPClausePrinter::VisitOMPInReductionClause(OMPInReductionClause *Node) { if (!Node->varlist_empty()) { OS << "in_reduction("; - NestedNameSpecifier *QualifierLoc = + NestedNameSpecifier Qualifier = Node->getQualifierLoc().getNestedNameSpecifier(); OverloadedOperatorKind OOK = Node->getNameInfo().getName().getCXXOverloadedOperator(); - if (QualifierLoc == nullptr && OOK != OO_None) { + if (!Qualifier && OOK != OO_None) { // Print reduction identifier in C format OS << getOperatorSpelling(OOK); } else { // Use C++ format - if (QualifierLoc != nullptr) - QualifierLoc->print(OS, Policy); + Qualifier.print(OS, Policy); OS << Node->getNameInfo(); } OS << ":"; @@ -2508,10 +2505,9 @@ template <typename T> static void PrintMapper(raw_ostream &OS, T *Node, const PrintingPolicy &Policy) { OS << '('; - NestedNameSpecifier *MapperNNS = + NestedNameSpecifier MapperNNS = Node->getMapperQualifierLoc().getNestedNameSpecifier(); - if (MapperNNS) - MapperNNS->print(OS, Policy); + MapperNNS.print(OS, Policy); OS << Node->getMapperIdInfo() << ')'; } diff --git a/clang/lib/AST/ParentMapContext.cpp b/clang/lib/AST/ParentMapContext.cpp index 68dfe4d..acc011c 100644 --- a/clang/lib/AST/ParentMapContext.cpp +++ b/clang/lib/AST/ParentMapContext.cpp @@ -438,10 +438,12 @@ private: DeclNode, DeclNode, [&] { return VisitorBase::TraverseDecl(DeclNode); }, &Map.PointerParents); } - bool TraverseTypeLoc(TypeLoc TypeLocNode) { + bool TraverseTypeLoc(TypeLoc TypeLocNode, bool TraverseQualifier = true) { return TraverseNode( TypeLocNode, DynTypedNode::create(TypeLocNode), - [&] { return VisitorBase::TraverseTypeLoc(TypeLocNode); }, + [&] { + return VisitorBase::TraverseTypeLoc(TypeLocNode, TraverseQualifier); + }, &Map.OtherParents); } bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNSLocNode) { diff --git a/clang/lib/AST/PrintfFormatString.cpp b/clang/lib/AST/PrintfFormatString.cpp index bcd44f0..687160c 100644 --- a/clang/lib/AST/PrintfFormatString.cpp +++ b/clang/lib/AST/PrintfFormatString.cpp @@ -794,7 +794,7 @@ bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt, // If it's an enum, get its underlying type. if (const EnumType *ETy = QT->getAs<EnumType>()) - QT = ETy->getDecl()->getIntegerType(); + QT = ETy->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); const BuiltinType *BT = QT->getAs<BuiltinType>(); if (!BT) { diff --git a/clang/lib/AST/QualTypeNames.cpp b/clang/lib/AST/QualTypeNames.cpp index 9731b3a..ee7fec3 100644 --- a/clang/lib/AST/QualTypeNames.cpp +++ b/clang/lib/AST/QualTypeNames.cpp @@ -24,10 +24,9 @@ namespace TypeName { /// is requested. /// \param[in] WithGlobalNsPrefix - Indicate whether the global namespace /// specifier "::" should be prepended or not. -static NestedNameSpecifier *createNestedNameSpecifier( - const ASTContext &Ctx, - const NamespaceDecl *Namesp, - bool WithGlobalNsPrefix); +static NestedNameSpecifier +createNestedNameSpecifier(const ASTContext &Ctx, const NamespaceDecl *Namesp, + bool WithGlobalNsPrefix); /// Create a NestedNameSpecifier for TagDecl and its enclosing /// scopes. @@ -39,22 +38,24 @@ static NestedNameSpecifier *createNestedNameSpecifier( /// qualified names. /// \param[in] WithGlobalNsPrefix - Indicate whether the global namespace /// specifier "::" should be prepended or not. -static NestedNameSpecifier *createNestedNameSpecifier( - const ASTContext &Ctx, const TypeDecl *TD, - bool FullyQualify, bool WithGlobalNsPrefix); +static NestedNameSpecifier createNestedNameSpecifier(const ASTContext &Ctx, + const TypeDecl *TD, + bool FullyQualify, + bool WithGlobalNsPrefix); -static NestedNameSpecifier *createNestedNameSpecifierForScopeOf( - const ASTContext &Ctx, const Decl *decl, - bool FullyQualified, bool WithGlobalNsPrefix); +static NestedNameSpecifier +createNestedNameSpecifierForScopeOf(const ASTContext &Ctx, const Decl *decl, + bool FullyQualified, + bool WithGlobalNsPrefix); -static NestedNameSpecifier *getFullyQualifiedNestedNameSpecifier( - const ASTContext &Ctx, NestedNameSpecifier *scope, bool WithGlobalNsPrefix); +static NestedNameSpecifier getFullyQualifiedNestedNameSpecifier( + const ASTContext &Ctx, NestedNameSpecifier NNS, bool WithGlobalNsPrefix); static bool getFullyQualifiedTemplateName(const ASTContext &Ctx, TemplateName &TName, bool WithGlobalNsPrefix) { bool Changed = false; - NestedNameSpecifier *NNS = nullptr; + NestedNameSpecifier NNS = std::nullopt; TemplateDecl *ArgTDecl = TName.getAsTemplateDecl(); // ArgTDecl won't be NULL because we asserted that this isn't a @@ -65,13 +66,13 @@ static bool getFullyQualifiedTemplateName(const ASTContext &Ctx, if (QTName && !QTName->hasTemplateKeyword() && (NNS = QTName->getQualifier())) { - NestedNameSpecifier *QNNS = getFullyQualifiedNestedNameSpecifier( - Ctx, NNS, WithGlobalNsPrefix); + NestedNameSpecifier QNNS = + getFullyQualifiedNestedNameSpecifier(Ctx, NNS, WithGlobalNsPrefix); if (QNNS != NNS) { Changed = true; NNS = QNNS; } else { - NNS = nullptr; + NNS = std::nullopt; } } else { NNS = createNestedNameSpecifierForScopeOf( @@ -116,76 +117,81 @@ static bool getFullyQualifiedTemplateArgument(const ASTContext &Ctx, } static const Type *getFullyQualifiedTemplateType(const ASTContext &Ctx, - const Type *TypePtr, + const TagType *TSTRecord, + ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, bool WithGlobalNsPrefix) { - // DependentTemplateTypes exist within template declarations and - // definitions. Therefore we shouldn't encounter them at the end of - // a translation unit. If we do, the caller has made an error. - assert(!isa<DependentTemplateSpecializationType>(TypePtr)); - // In case of template specializations, iterate over the arguments - // and fully qualify them as well. - if (const auto *TST = dyn_cast<const TemplateSpecializationType>(TypePtr)) { - bool MightHaveChanged = false; - SmallVector<TemplateArgument, 4> FQArgs; - // Cheap to copy and potentially modified by - // getFullyQualifedTemplateArgument. - for (TemplateArgument Arg : TST->template_arguments()) { - MightHaveChanged |= getFullyQualifiedTemplateArgument( - Ctx, Arg, WithGlobalNsPrefix); - FQArgs.push_back(Arg); - } + // We are asked to fully qualify and we have a Record Type, + // which can point to a template instantiation with no sugar in any of + // its template argument, however we still need to fully qualify them. + + const auto *TD = TSTRecord->getOriginalDecl(); + const auto *TSTDecl = dyn_cast<ClassTemplateSpecializationDecl>(TD); + if (!TSTDecl) + return Ctx.getTagType(Keyword, Qualifier, TD, /*OwnsTag=*/false) + .getTypePtr(); + + const TemplateArgumentList &TemplateArgs = TSTDecl->getTemplateArgs(); + + bool MightHaveChanged = false; + SmallVector<TemplateArgument, 4> FQArgs; + for (unsigned int I = 0, E = TemplateArgs.size(); I != E; ++I) { + // cheap to copy and potentially modified by + // getFullyQualifedTemplateArgument + TemplateArgument Arg(TemplateArgs[I]); + MightHaveChanged |= + getFullyQualifiedTemplateArgument(Ctx, Arg, WithGlobalNsPrefix); + FQArgs.push_back(Arg); + } - // If a fully qualified arg is different from the unqualified arg, - // allocate new type in the AST. - if (MightHaveChanged) { - QualType QT = Ctx.getTemplateSpecializationType( - TST->getTemplateName(), FQArgs, - /*CanonicalArgs=*/{}, TST->desugar()); - // getTemplateSpecializationType returns a fully qualified - // version of the specialization itself, so no need to qualify - // it. - return QT.getTypePtr(); - } - } else if (const auto *TSTRecord = dyn_cast<const RecordType>(TypePtr)) { - // We are asked to fully qualify and we have a Record Type, - // which can point to a template instantiation with no sugar in any of - // its template argument, however we still need to fully qualify them. - - if (const auto *TSTDecl = - dyn_cast<ClassTemplateSpecializationDecl>(TSTRecord->getDecl())) { - const TemplateArgumentList &TemplateArgs = TSTDecl->getTemplateArgs(); - - bool MightHaveChanged = false; - SmallVector<TemplateArgument, 4> FQArgs; - for (unsigned int I = 0, E = TemplateArgs.size(); I != E; ++I) { - // cheap to copy and potentially modified by - // getFullyQualifedTemplateArgument - TemplateArgument Arg(TemplateArgs[I]); - MightHaveChanged |= getFullyQualifiedTemplateArgument( - Ctx, Arg, WithGlobalNsPrefix); - FQArgs.push_back(Arg); - } + if (!MightHaveChanged) + return Ctx.getTagType(Keyword, Qualifier, TD, /*OwnsTag=*/false) + .getTypePtr(); + // If a fully qualified arg is different from the unqualified arg, + // allocate new type in the AST. + TemplateName TN = Ctx.getQualifiedTemplateName( + Qualifier, /*TemplateKeyword=*/false, + TemplateName(TSTDecl->getSpecializedTemplate())); + QualType QT = Ctx.getTemplateSpecializationType( + Keyword, TN, FQArgs, + /*CanonicalArgs=*/{}, TSTRecord->getCanonicalTypeInternal()); + // getTemplateSpecializationType returns a fully qualified + // version of the specialization itself, so no need to qualify + // it. + return QT.getTypePtr(); +} - // If a fully qualified arg is different from the unqualified arg, - // allocate new type in the AST. - if (MightHaveChanged) { - TemplateName TN(TSTDecl->getSpecializedTemplate()); - QualType QT = Ctx.getTemplateSpecializationType( - TN, FQArgs, - /*CanonicalArgs=*/{}, TSTRecord->getCanonicalTypeInternal()); - // getTemplateSpecializationType returns a fully qualified - // version of the specialization itself, so no need to qualify - // it. - return QT.getTypePtr(); - } - } +static const Type * +getFullyQualifiedTemplateType(const ASTContext &Ctx, + const TemplateSpecializationType *TST, + bool WithGlobalNsPrefix) { + TemplateName TName = TST->getTemplateName(); + bool MightHaveChanged = + getFullyQualifiedTemplateName(Ctx, TName, WithGlobalNsPrefix); + SmallVector<TemplateArgument, 4> FQArgs; + // Cheap to copy and potentially modified by + // getFullyQualifedTemplateArgument. + for (TemplateArgument Arg : TST->template_arguments()) { + MightHaveChanged |= + getFullyQualifiedTemplateArgument(Ctx, Arg, WithGlobalNsPrefix); + FQArgs.push_back(Arg); } - return TypePtr; + + if (!MightHaveChanged) + return TST; + + QualType NewQT = + Ctx.getTemplateSpecializationType(TST->getKeyword(), TName, FQArgs, + /*CanonicalArgs=*/{}, TST->desugar()); + // getTemplateSpecializationType returns a fully qualified + // version of the specialization itself, so no need to qualify + // it. + return NewQT.getTypePtr(); } -static NestedNameSpecifier *createOuterNNS(const ASTContext &Ctx, const Decl *D, - bool FullyQualify, - bool WithGlobalNsPrefix) { +static NestedNameSpecifier createOuterNNS(const ASTContext &Ctx, const Decl *D, + bool FullyQualify, + bool WithGlobalNsPrefix) { const DeclContext *DC = D->getDeclContext(); if (const auto *NS = dyn_cast<NamespaceDecl>(DC)) { while (NS && NS->isInline()) { @@ -195,71 +201,63 @@ static NestedNameSpecifier *createOuterNNS(const ASTContext &Ctx, const Decl *D, if (NS && NS->getDeclName()) { return createNestedNameSpecifier(Ctx, NS, WithGlobalNsPrefix); } - return nullptr; // no starting '::', no anonymous - } else if (const auto *TD = dyn_cast<TagDecl>(DC)) { - return createNestedNameSpecifier(Ctx, TD, FullyQualify, WithGlobalNsPrefix); - } else if (const auto *TDD = dyn_cast<TypedefNameDecl>(DC)) { - return createNestedNameSpecifier( - Ctx, TDD, FullyQualify, WithGlobalNsPrefix); - } else if (WithGlobalNsPrefix && DC->isTranslationUnit()) { - return NestedNameSpecifier::GlobalSpecifier(Ctx); + return std::nullopt; // no starting '::', no anonymous } - return nullptr; // no starting '::' if |WithGlobalNsPrefix| is false + if (const auto *TD = dyn_cast<TagDecl>(DC)) + return createNestedNameSpecifier(Ctx, TD, FullyQualify, WithGlobalNsPrefix); + if (const auto *TDD = dyn_cast<TypedefNameDecl>(DC)) + return createNestedNameSpecifier(Ctx, TDD, FullyQualify, + WithGlobalNsPrefix); + if (WithGlobalNsPrefix && DC->isTranslationUnit()) + return NestedNameSpecifier::getGlobal(); + return std::nullopt; // no starting '::' if |WithGlobalNsPrefix| is false } /// Return a fully qualified version of this name specifier. -static NestedNameSpecifier *getFullyQualifiedNestedNameSpecifier( - const ASTContext &Ctx, NestedNameSpecifier *Scope, - bool WithGlobalNsPrefix) { - switch (Scope->getKind()) { - case NestedNameSpecifier::Global: - case NestedNameSpecifier::Super: - // Already fully qualified - return Scope; - case NestedNameSpecifier::Namespace: - return TypeName::createNestedNameSpecifier( - Ctx, Scope->getAsNamespace()->getNamespace(), WithGlobalNsPrefix); - case NestedNameSpecifier::Identifier: - // A function or some other construct that makes it un-namable - // at the end of the TU. Skip the current component of the name, - // but use the name of it's prefix. - return getFullyQualifiedNestedNameSpecifier( - Ctx, Scope->getPrefix(), WithGlobalNsPrefix); - case NestedNameSpecifier::TypeSpec: { - const Type *Type = Scope->getAsType(); - // Find decl context. - const TagDecl *TD = nullptr; - if (const TagType *TagDeclType = Type->getAs<TagType>()) { - TD = TagDeclType->getDecl(); - } else { - TD = Type->getAsCXXRecordDecl(); - } - if (TD) { - return TypeName::createNestedNameSpecifier(Ctx, TD, - true /*FullyQualified*/, - WithGlobalNsPrefix); - } else if (const auto *TDD = dyn_cast<TypedefType>(Type)) { - return TypeName::createNestedNameSpecifier(Ctx, TDD->getDecl(), - true /*FullyQualified*/, - WithGlobalNsPrefix); - } +static NestedNameSpecifier getFullyQualifiedNestedNameSpecifier( + const ASTContext &Ctx, NestedNameSpecifier Scope, bool WithGlobalNsPrefix) { + switch (Scope.getKind()) { + case NestedNameSpecifier::Kind::Null: + llvm_unreachable("can't fully qualify the empty nested name specifier"); + case NestedNameSpecifier::Kind::Global: + case NestedNameSpecifier::Kind::MicrosoftSuper: + // Already fully qualified + return Scope; + case NestedNameSpecifier::Kind::Namespace: + return TypeName::createNestedNameSpecifier( + Ctx, Scope.getAsNamespaceAndPrefix().Namespace->getNamespace(), + WithGlobalNsPrefix); + case NestedNameSpecifier::Kind::Type: { + const Type *Type = Scope.getAsType(); + // Find decl context. + const TypeDecl *TD; + if (const TagType *TagDeclType = Type->getAs<TagType>()) + TD = TagDeclType->getOriginalDecl(); + else if (const auto *D = dyn_cast<TypedefType>(Type)) + TD = D->getDecl(); + else return Scope; - } + return TypeName::createNestedNameSpecifier(Ctx, TD, /*FullyQualify=*/true, + WithGlobalNsPrefix); + } } llvm_unreachable("bad NNS kind"); } /// Create a nested name specifier for the declaring context of /// the type. -static NestedNameSpecifier *createNestedNameSpecifierForScopeOf( - const ASTContext &Ctx, const Decl *Decl, - bool FullyQualified, bool WithGlobalNsPrefix) { +static NestedNameSpecifier +createNestedNameSpecifierForScopeOf(const ASTContext &Ctx, const Decl *Decl, + bool FullyQualified, + bool WithGlobalNsPrefix) { assert(Decl); const DeclContext *DC = Decl->getDeclContext()->getRedeclContext(); const auto *Outer = dyn_cast<NamedDecl>(DC); const auto *OuterNS = dyn_cast<NamespaceDecl>(DC); - if (Outer && !(OuterNS && OuterNS->isAnonymousNamespace())) { + if (OuterNS && OuterNS->isAnonymousNamespace()) + OuterNS = dyn_cast<NamespaceDecl>(OuterNS->getParent()); + if (Outer) { if (const auto *CxxDecl = dyn_cast<CXXRecordDecl>(DC)) { if (ClassTemplateDecl *ClassTempl = CxxDecl->getDescribedClassTemplate()) { @@ -288,76 +286,80 @@ static NestedNameSpecifier *createNestedNameSpecifierForScopeOf( Ctx, TD, FullyQualified, WithGlobalNsPrefix); } else if (isa<TranslationUnitDecl>(Outer)) { // Context is the TU. Nothing needs to be done. - return nullptr; + return std::nullopt; } else { // Decl's context was neither the TU, a namespace, nor a // TagDecl, which means it is a type local to a scope, and not // accessible at the end of the TU. - return nullptr; + return std::nullopt; } } else if (WithGlobalNsPrefix && DC->isTranslationUnit()) { - return NestedNameSpecifier::GlobalSpecifier(Ctx); + return NestedNameSpecifier::getGlobal(); } - return nullptr; + return std::nullopt; } /// Create a nested name specifier for the declaring context of /// the type. -static NestedNameSpecifier *createNestedNameSpecifierForScopeOf( - const ASTContext &Ctx, const Type *TypePtr, - bool FullyQualified, bool WithGlobalNsPrefix) { - if (!TypePtr) return nullptr; +static NestedNameSpecifier +createNestedNameSpecifierForScopeOf(const ASTContext &Ctx, const Type *TypePtr, + bool FullyQualified, + bool WithGlobalNsPrefix) { + if (!TypePtr) + return std::nullopt; Decl *Decl = nullptr; // There are probably other cases ... if (const auto *TDT = dyn_cast<TypedefType>(TypePtr)) { Decl = TDT->getDecl(); } else if (const auto *TagDeclType = dyn_cast<TagType>(TypePtr)) { - Decl = TagDeclType->getDecl(); + Decl = TagDeclType->getOriginalDecl(); } else if (const auto *TST = dyn_cast<TemplateSpecializationType>(TypePtr)) { Decl = TST->getTemplateName().getAsTemplateDecl(); } else { Decl = TypePtr->getAsCXXRecordDecl(); } - if (!Decl) return nullptr; + if (!Decl) + return std::nullopt; return createNestedNameSpecifierForScopeOf( Ctx, Decl, FullyQualified, WithGlobalNsPrefix); } -NestedNameSpecifier *createNestedNameSpecifier(const ASTContext &Ctx, - const NamespaceDecl *Namespace, - bool WithGlobalNsPrefix) { +static NestedNameSpecifier +createNestedNameSpecifier(const ASTContext &Ctx, const NamespaceDecl *Namespace, + bool WithGlobalNsPrefix) { while (Namespace && Namespace->isInline()) { // Ignore inline namespace; Namespace = dyn_cast<NamespaceDecl>(Namespace->getDeclContext()); } - if (!Namespace) return nullptr; + if (!Namespace) + return std::nullopt; - bool FullyQualified = true; // doesn't matter, DeclContexts are namespaces - return NestedNameSpecifier::Create( - Ctx, - createOuterNNS(Ctx, Namespace, FullyQualified, WithGlobalNsPrefix), - Namespace); + bool FullyQualify = true; // doesn't matter, DeclContexts are namespaces + return NestedNameSpecifier( + Ctx, Namespace, + createOuterNNS(Ctx, Namespace, FullyQualify, WithGlobalNsPrefix)); } -NestedNameSpecifier *createNestedNameSpecifier(const ASTContext &Ctx, - const TypeDecl *TD, - bool FullyQualify, - bool WithGlobalNsPrefix) { - const Type *TypePtr = TD->getTypeForDecl(); - if (isa<const TemplateSpecializationType>(TypePtr) || - isa<const RecordType>(TypePtr)) { +NestedNameSpecifier createNestedNameSpecifier(const ASTContext &Ctx, + const TypeDecl *TD, + bool FullyQualify, + bool WithGlobalNsPrefix) { + const Type *TypePtr = Ctx.getTypeDeclType(TD).getTypePtr(); + if (auto *RD = dyn_cast<TagType>(TypePtr)) { // We are asked to fully qualify and we have a Record Type (which // may point to a template specialization) or Template // Specialization Type. We need to fully qualify their arguments. - - TypePtr = getFullyQualifiedTemplateType(Ctx, TypePtr, WithGlobalNsPrefix); + TypePtr = getFullyQualifiedTemplateType( + Ctx, RD, ElaboratedTypeKeyword::None, + createOuterNNS(Ctx, TD, FullyQualify, WithGlobalNsPrefix), + WithGlobalNsPrefix); + } else if (auto *TST = dyn_cast<TemplateSpecializationType>(TypePtr)) { + TypePtr = getFullyQualifiedTemplateType(Ctx, TST, WithGlobalNsPrefix); } - - return NestedNameSpecifier::Create( - Ctx, createOuterNNS(Ctx, TD, FullyQualify, WithGlobalNsPrefix), TypePtr); + return NestedNameSpecifier(TypePtr); } /// Return the fully qualified type, including fully-qualified @@ -381,7 +383,7 @@ QualType getFullyQualifiedType(QualType QT, const ASTContext &Ctx, Qualifiers Quals = QT.getQualifiers(); // Fully qualify the pointee and class types. QT = getFullyQualifiedType(QT->getPointeeType(), Ctx, WithGlobalNsPrefix); - NestedNameSpecifier *Qualifier = getFullyQualifiedNestedNameSpecifier( + NestedNameSpecifier Qualifier = getFullyQualifiedNestedNameSpecifier( Ctx, MPT->getQualifier(), WithGlobalNsPrefix); QT = Ctx.getMemberPointerType(QT, Qualifier, MPT->getMostRecentCXXRecordDecl()); @@ -434,45 +436,48 @@ QualType getFullyQualifiedType(QualType QT, const ASTContext &Ctx, QT = Ctx.getQualifiedType(QT, Quals); } - NestedNameSpecifier *Prefix = nullptr; + if (const auto *TST = + dyn_cast<const TemplateSpecializationType>(QT.getTypePtr())) { + + const Type *T = getFullyQualifiedTemplateType(Ctx, TST, WithGlobalNsPrefix); + if (T == TST) + return QT; + return Ctx.getQualifiedType(T, QT.getQualifiers()); + } + // Local qualifiers are attached to the QualType outside of the // elaborated type. Retrieve them before descending into the // elaborated type. Qualifiers PrefixQualifiers = QT.getLocalQualifiers(); QT = QualType(QT.getTypePtr(), 0); - ElaboratedTypeKeyword Keyword = ElaboratedTypeKeyword::None; - if (const auto *ETypeInput = dyn_cast<ElaboratedType>(QT.getTypePtr())) { - QT = ETypeInput->getNamedType(); - assert(!QT.hasLocalQualifiers()); - Keyword = ETypeInput->getKeyword(); - } // We don't consider the alias introduced by `using a::X` as a new type. // The qualified name is still a::X. if (const auto *UT = QT->getAs<UsingType>()) { - QT = Ctx.getQualifiedType(UT->getUnderlyingType(), PrefixQualifiers); + QT = Ctx.getQualifiedType(UT->desugar(), PrefixQualifiers); return getFullyQualifiedType(QT, Ctx, WithGlobalNsPrefix); } // Create a nested name specifier if needed. - Prefix = createNestedNameSpecifierForScopeOf(Ctx, QT.getTypePtr(), - true /*FullyQualified*/, - WithGlobalNsPrefix); + NestedNameSpecifier Prefix = createNestedNameSpecifierForScopeOf( + Ctx, QT.getTypePtr(), true /*FullyQualified*/, WithGlobalNsPrefix); // In case of template specializations iterate over the arguments and // fully qualify them as well. - if (isa<const TemplateSpecializationType>(QT.getTypePtr()) || - isa<const RecordType>(QT.getTypePtr())) { + if (const auto *TT = dyn_cast<TagType>(QT.getTypePtr())) { // We are asked to fully qualify and we have a Record Type (which // may point to a template specialization) or Template // Specialization Type. We need to fully qualify their arguments. const Type *TypePtr = getFullyQualifiedTemplateType( - Ctx, QT.getTypePtr(), WithGlobalNsPrefix); + Ctx, TT, TT->getKeyword(), Prefix, WithGlobalNsPrefix); QT = QualType(TypePtr, 0); - } - if (Prefix || Keyword != ElaboratedTypeKeyword::None) { - QT = Ctx.getElaboratedType(Keyword, Prefix, QT); + } else if (const auto *TT = dyn_cast<TypedefType>(QT.getTypePtr())) { + QT = Ctx.getTypedefType( + TT->getKeyword(), Prefix, TT->getDecl(), + getFullyQualifiedType(TT->desugar(), Ctx, WithGlobalNsPrefix)); + } else { + assert(!Prefix && "Unhandled type node"); } QT = Ctx.getQualifiedType(QT, PrefixQualifiers); return QT; @@ -486,5 +491,12 @@ std::string getFullyQualifiedName(QualType QT, return FQQT.getAsString(Policy); } +NestedNameSpecifier getFullyQualifiedDeclaredContext(const ASTContext &Ctx, + const Decl *Decl, + bool WithGlobalNsPrefix) { + return createNestedNameSpecifierForScopeOf(Ctx, Decl, /*FullyQualified=*/true, + WithGlobalNsPrefix); +} + } // end namespace TypeName } // end namespace clang diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp index 760b2fc..f1f21f4 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -2012,8 +2012,7 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D, } else if (const BuiltinType *BTy = BaseTy->getAs<BuiltinType>()) { performBuiltinTypeAlignmentUpgrade(BTy); } else if (const RecordType *RT = BaseTy->getAs<RecordType>()) { - const RecordDecl *RD = RT->getDecl(); - assert(RD && "Expected non-null RecordDecl."); + const RecordDecl *RD = RT->getOriginalDecl(); const ASTRecordLayout &FieldRecord = Context.getASTRecordLayout(RD); PreferredAlign = FieldRecord.getPreferredAlignment(); } @@ -2128,7 +2127,8 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D, // TODO: Takes no account the alignment of the outer struct if (FieldOffset % OriginalFieldAlign != 0) Diag(D->getLocation(), diag::warn_unaligned_access) - << Context.getTypeDeclType(RD) << D->getName() << D->getType(); + << Context.getCanonicalTagType(RD) << D->getName() + << D->getType(); } } @@ -2193,8 +2193,7 @@ void ItaniumRecordLayoutBuilder::FinishLayout(const NamedDecl *D) { InBits = false; } Diag(RD->getLocation(), diag::warn_padded_struct_size) - << Context.getTypeDeclType(RD) - << PadSize + << Context.getCanonicalTagType(RD) << PadSize << (InBits ? 1 : 0); // (byte|bit) } @@ -2212,7 +2211,7 @@ void ItaniumRecordLayoutBuilder::FinishLayout(const NamedDecl *D) { Context.getLangOpts().getClangABICompat() <= LangOptions::ClangABI::Ver15)) Diag(D->getLocation(), diag::warn_unnecessary_packed) - << Context.getTypeDeclType(RD); + << Context.getCanonicalTagType(RD); } } @@ -2306,7 +2305,7 @@ static void CheckFieldPadding(const ASTContext &Context, bool IsUnion, Context.getDiagnostics().Report(D->getLocation(), Diagnostic) << getPaddingDiagFromTagKind(D->getParent()->getTagKind()) - << Context.getTypeDeclType(D->getParent()) << PadSize + << Context.getCanonicalTagType(D->getParent()) << PadSize << (InBits ? 1 : 0) // (byte|bit) << D->getIdentifier(); } else { @@ -2315,7 +2314,7 @@ static void CheckFieldPadding(const ASTContext &Context, bool IsUnion, Context.getDiagnostics().Report(D->getLocation(), Diagnostic) << getPaddingDiagFromTagKind(D->getParent()->getTagKind()) - << Context.getTypeDeclType(D->getParent()) << PadSize + << Context.getCanonicalTagType(D->getParent()) << PadSize << (InBits ? 1 : 0); // (byte|bit) } } @@ -2714,7 +2713,7 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo( else { if (auto RT = FD->getType()->getBaseElementTypeUnsafe()->getAs<RecordType>()) { - auto const &Layout = Context.getASTRecordLayout(RT->getDecl()); + auto const &Layout = Context.getASTRecordLayout(RT->getOriginalDecl()); EndsWithZeroSizedObject = Layout.endsWithZeroSizedObject(); FieldRequiredAlignment = std::max(FieldRequiredAlignment, Layout.getRequiredAlignment()); @@ -3273,7 +3272,7 @@ void MicrosoftRecordLayoutBuilder::finalizeLayout(const RecordDecl *RD) { Context.getDiagnostics().Report(RD->getLocation(), diag::warn_padded_struct_size) - << Context.getTypeDeclType(RD) << PadSize + << Context.getCanonicalTagType(RD) << PadSize << (InBits ? 1 : 0); // (byte|bit) } } @@ -3631,7 +3630,7 @@ static void DumpRecordLayout(raw_ostream &OS, const RecordDecl *RD, auto CXXRD = dyn_cast<CXXRecordDecl>(RD); PrintOffset(OS, Offset, IndentLevel); - OS << C.getTypeDeclType(const_cast<RecordDecl *>(RD)); + OS << C.getCanonicalTagType(const_cast<RecordDecl *>(RD)); if (Description) OS << ' ' << Description; if (CXXRD && CXXRD->isEmpty()) @@ -3697,8 +3696,8 @@ static void DumpRecordLayout(raw_ostream &OS, const RecordDecl *RD, // Recursively dump fields of record type. if (auto RT = Field->getType()->getAs<RecordType>()) { - DumpRecordLayout(OS, RT->getDecl(), C, FieldOffset, IndentLevel, - Field->getName().data(), + DumpRecordLayout(OS, RT->getOriginalDecl()->getDefinitionOrSelf(), C, + FieldOffset, IndentLevel, Field->getName().data(), /*PrintSizeInfo=*/false, /*IncludeVirtualBases=*/true); continue; @@ -3781,7 +3780,7 @@ void ASTContext::DumpRecordLayout(const RecordDecl *RD, raw_ostream &OS, // in libFrontend. const ASTRecordLayout &Info = getASTRecordLayout(RD); - OS << "Type: " << getTypeDeclType(RD) << "\n"; + OS << "Type: " << getCanonicalTagType(RD) << "\n"; OS << "\nLayout: "; OS << "<ASTRecordLayout\n"; OS << " Size:" << toBits(Info.getSize()) << "\n"; diff --git a/clang/lib/AST/ScanfFormatString.cpp b/clang/lib/AST/ScanfFormatString.cpp index 1227edd..31c001d 100644 --- a/clang/lib/AST/ScanfFormatString.cpp +++ b/clang/lib/AST/ScanfFormatString.cpp @@ -432,9 +432,10 @@ bool ScanfSpecifier::fixType(QualType QT, QualType RawQT, // If it's an enum, get its underlying type. if (const EnumType *ETy = PT->getAs<EnumType>()) { // Don't try to fix incomplete enums. - if (!ETy->getDecl()->isComplete()) + const EnumDecl *ED = ETy->getOriginalDecl()->getDefinitionOrSelf(); + if (!ED->isComplete()) return false; - PT = ETy->getDecl()->getIntegerType(); + PT = ED->getIntegerType(); } const BuiltinType *BT = PT->getAs<BuiltinType>(); diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index 6ba5ec8..afccba8 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -454,10 +454,7 @@ void StmtPrinter::VisitMSDependentExistsStmt(MSDependentExistsStmt *Node) { else OS << "__if_not_exists ("; - if (NestedNameSpecifier *Qualifier - = Node->getQualifierLoc().getNestedNameSpecifier()) - Qualifier->print(OS, Policy); - + Node->getQualifierLoc().getNestedNameSpecifier().print(OS, Policy); OS << Node->getNameInfo() << ") "; PrintRawCompoundStmt(Node->getSubStmt()); @@ -1309,8 +1306,7 @@ void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) { TPOD->printAsExpr(OS, Policy); return; } - if (NestedNameSpecifier *Qualifier = Node->getQualifier()) - Qualifier->print(OS, Policy); + Node->getQualifier().print(OS, Policy); if (Node->hasTemplateKeyword()) OS << "template "; @@ -1359,8 +1355,7 @@ void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) { void StmtPrinter::VisitDependentScopeDeclRefExpr( DependentScopeDeclRefExpr *Node) { - if (NestedNameSpecifier *Qualifier = Node->getQualifier()) - Qualifier->print(OS, Policy); + Node->getQualifier().print(OS, Policy); if (Node->hasTemplateKeyword()) OS << "template "; OS << Node->getNameInfo(); @@ -1369,8 +1364,7 @@ void StmtPrinter::VisitDependentScopeDeclRefExpr( } void StmtPrinter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node) { - if (Node->getQualifier()) - Node->getQualifier()->print(OS, Policy); + Node->getQualifier().print(OS, Policy); if (Node->hasTemplateKeyword()) OS << "template "; OS << Node->getNameInfo(); @@ -1778,8 +1772,7 @@ void StmtPrinter::VisitMemberExpr(MemberExpr *Node) { if (FD->isAnonymousStructOrUnion()) return; - if (NestedNameSpecifier *Qualifier = Node->getQualifier()) - Qualifier->print(OS, Policy); + Node->getQualifier().print(OS, Policy); if (Node->hasTemplateKeyword()) OS << "template "; OS << Node->getMemberNameInfo(); @@ -2177,9 +2170,7 @@ void StmtPrinter::VisitMSPropertyRefExpr(MSPropertyRefExpr *Node) { OS << "->"; else OS << "."; - if (NestedNameSpecifier *Qualifier = - Node->getQualifierLoc().getNestedNameSpecifier()) - Qualifier->print(OS, Policy); + Node->getQualifierLoc().getNestedNameSpecifier().print(OS, Policy); OS << Node->getPropertyDecl()->getDeclName(); } @@ -2509,8 +2500,7 @@ void StmtPrinter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) { OS << "->"; else OS << '.'; - if (E->getQualifier()) - E->getQualifier()->print(OS, Policy); + E->getQualifier().print(OS, Policy); OS << "~"; if (const IdentifierInfo *II = E->getDestroyedTypeIdentifier()) @@ -2572,8 +2562,7 @@ void StmtPrinter::VisitCXXDependentScopeMemberExpr( PrintExpr(Node->getBase()); OS << (Node->isArrow() ? "->" : "."); } - if (NestedNameSpecifier *Qualifier = Node->getQualifier()) - Qualifier->print(OS, Policy); + Node->getQualifier().print(OS, Policy); if (Node->hasTemplateKeyword()) OS << "template "; OS << Node->getMemberNameInfo(); @@ -2586,8 +2575,7 @@ void StmtPrinter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *Node) { PrintExpr(Node->getBase()); OS << (Node->isArrow() ? "->" : "."); } - if (NestedNameSpecifier *Qualifier = Node->getQualifier()) - Qualifier->print(OS, Policy); + Node->getQualifier().print(OS, Policy); if (Node->hasTemplateKeyword()) OS << "template "; OS << Node->getMemberNameInfo(); @@ -2678,8 +2666,7 @@ void StmtPrinter::VisitCXXParenListInitExpr(CXXParenListInitExpr *Node) { void StmtPrinter::VisitConceptSpecializationExpr(ConceptSpecializationExpr *E) { NestedNameSpecifierLoc NNS = E->getNestedNameSpecifierLoc(); - if (NNS) - NNS.getNestedNameSpecifier()->print(OS, Policy); + NNS.getNestedNameSpecifier().print(OS, Policy); if (E->getTemplateKWLoc().isValid()) OS << "template "; OS << E->getFoundDecl()->getName(); diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index 4c36f24..5fee884 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -65,7 +65,7 @@ namespace { /// Visit a nested-name-specifier that occurs within an expression /// or statement. - virtual void VisitNestedNameSpecifier(NestedNameSpecifier *NNS) = 0; + virtual void VisitNestedNameSpecifier(NestedNameSpecifier NNS) = 0; /// Visit a template name that occurs within an expression or /// statement. @@ -167,10 +167,10 @@ namespace { ID.AddPointer(II); } - void VisitNestedNameSpecifier(NestedNameSpecifier *NNS) override { + void VisitNestedNameSpecifier(NestedNameSpecifier NNS) override { if (Canonical) - NNS = Context.getCanonicalNestedNameSpecifier(NNS); - ID.AddPointer(NNS); + NNS = NNS.getCanonical(); + NNS.Profile(ID); } void VisitTemplateName(TemplateName Name) override { @@ -226,11 +226,10 @@ namespace { void VisitTemplateName(TemplateName Name) override { Hash.AddTemplateName(Name); } - void VisitNestedNameSpecifier(NestedNameSpecifier *NNS) override { - ID.AddBoolean(NNS); - if (NNS) { + void VisitNestedNameSpecifier(NestedNameSpecifier NNS) override { + ID.AddBoolean(bool(NNS)); + if (NNS) Hash.AddNestedNameSpecifier(NNS); - } } }; } @@ -2645,8 +2644,10 @@ void OpenACCClauseProfiler::VisitFirstPrivateClause( const OpenACCFirstPrivateClause &Clause) { VisitClauseWithVarList(Clause); - for (auto *VD : Clause.getInitRecipes()) - Profiler.VisitDecl(VD); + for (auto &Recipe : Clause.getInitRecipes()) { + Profiler.VisitDecl(Recipe.RecipeDecl); + Profiler.VisitDecl(Recipe.InitFromTemporary); + } } void OpenACCClauseProfiler::VisitAttachClause( diff --git a/clang/lib/AST/TemplateBase.cpp b/clang/lib/AST/TemplateBase.cpp index 7a0f740..76050ce 100644 --- a/clang/lib/AST/TemplateBase.cpp +++ b/clang/lib/AST/TemplateBase.cpp @@ -57,7 +57,7 @@ static void printIntegral(const TemplateArgument &TemplArg, raw_ostream &Out, if (Policy.UseEnumerators) { if (const EnumType *ET = T->getAs<EnumType>()) { - for (const EnumConstantDecl *ECD : ET->getDecl()->enumerators()) { + for (const EnumConstantDecl *ECD : ET->getOriginalDecl()->enumerators()) { // In Sema::CheckTemplateArugment, enum template arguments value are // extended to the size of the integer underlying the enum type. This // may create a size difference between the enum value and template @@ -596,6 +596,29 @@ void TemplateArgument::print(const PrintingPolicy &Policy, raw_ostream &Out, // TemplateArgumentLoc Implementation //===----------------------------------------------------------------------===// +TemplateArgumentLoc::TemplateArgumentLoc(ASTContext &Ctx, + const TemplateArgument &Argument, + SourceLocation TemplateKWLoc, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateNameLoc, + SourceLocation EllipsisLoc) + : Argument(Argument), + LocInfo(Ctx, TemplateKWLoc, QualifierLoc, TemplateNameLoc, EllipsisLoc) { + assert(Argument.getKind() == TemplateArgument::Template || + Argument.getKind() == TemplateArgument::TemplateExpansion); + assert(QualifierLoc.getNestedNameSpecifier() == + Argument.getAsTemplateOrTemplatePattern().getQualifier()); +} + +NestedNameSpecifierLoc TemplateArgumentLoc::getTemplateQualifierLoc() const { + if (Argument.getKind() != TemplateArgument::Template && + Argument.getKind() != TemplateArgument::TemplateExpansion) + return NestedNameSpecifierLoc(); + return NestedNameSpecifierLoc( + Argument.getAsTemplateOrTemplatePattern().getQualifier(), + LocInfo.getTemplate()->QualifierLocData); +} + SourceRange TemplateArgumentLoc::getSourceRange() const { switch (Argument.getKind()) { case TemplateArgument::Expression: @@ -702,10 +725,11 @@ const StreamingDiagnostic &clang::operator<<(const StreamingDiagnostic &DB, } clang::TemplateArgumentLocInfo::TemplateArgumentLocInfo( - ASTContext &Ctx, NestedNameSpecifierLoc QualifierLoc, - SourceLocation TemplateNameLoc, SourceLocation EllipsisLoc) { + ASTContext &Ctx, SourceLocation TemplateKWLoc, + NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateNameLoc, + SourceLocation EllipsisLoc) { TemplateTemplateArgLocInfo *Template = new (Ctx) TemplateTemplateArgLocInfo; - Template->Qualifier = QualifierLoc.getNestedNameSpecifier(); + Template->TemplateKwLoc = TemplateKWLoc; Template->QualifierLocData = QualifierLoc.getOpaqueData(); Template->TemplateNameLoc = TemplateNameLoc; Template->EllipsisLoc = EllipsisLoc; diff --git a/clang/lib/AST/TemplateName.cpp b/clang/lib/AST/TemplateName.cpp index 5b7abc4..c171516 100644 --- a/clang/lib/AST/TemplateName.cpp +++ b/clang/lib/AST/TemplateName.cpp @@ -289,10 +289,30 @@ QualifiedTemplateName *TemplateName::getAsQualifiedTemplateName() const { return dyn_cast_if_present<QualifiedTemplateName *>(Storage); } +QualifiedTemplateName * +TemplateName::getAsAdjustedQualifiedTemplateName() const { + for (std::optional<TemplateName> Cur = *this; Cur; + Cur = Cur->desugar(/*IgnoreDeduced=*/true)) + if (QualifiedTemplateName *N = Cur->getAsQualifiedTemplateName()) + return N; + return nullptr; +} + DependentTemplateName *TemplateName::getAsDependentTemplateName() const { return Storage.dyn_cast<DependentTemplateName *>(); } +NestedNameSpecifier TemplateName::getQualifier() const { + for (std::optional<TemplateName> Cur = *this; Cur; + Cur = Cur->desugar(/*IgnoreDeduced=*/true)) { + if (DependentTemplateName *N = Cur->getAsDependentTemplateName()) + return N->getQualifier(); + if (QualifiedTemplateName *N = Cur->getAsQualifiedTemplateName()) + return N->getQualifier(); + } + return std::nullopt; +} + UsingShadowDecl *TemplateName::getAsUsingShadowDecl() const { if (Decl *D = Storage.dyn_cast<Decl *>()) if (UsingShadowDecl *USD = dyn_cast<UsingShadowDecl>(D)) @@ -303,24 +323,21 @@ UsingShadowDecl *TemplateName::getAsUsingShadowDecl() const { } DependentTemplateStorage::DependentTemplateStorage( - NestedNameSpecifier *Qualifier, IdentifierOrOverloadedOperator Name, + NestedNameSpecifier Qualifier, IdentifierOrOverloadedOperator Name, bool HasTemplateKeyword) : Qualifier(Qualifier, HasTemplateKeyword), Name(Name) { - assert((!Qualifier || Qualifier->isDependent()) && + assert((!Qualifier || Qualifier.isDependent()) && "Qualifier must be dependent"); } TemplateNameDependence DependentTemplateStorage::getDependence() const { - auto D = TemplateNameDependence::DependentInstantiation; - if (NestedNameSpecifier *Qualifier = getQualifier()) - D |= toTemplateNameDependence(Qualifier->getDependence()); - return D; + return toTemplateNameDependence(getQualifier().getDependence()) | + TemplateNameDependence::DependentInstantiation; } void DependentTemplateStorage::print(raw_ostream &OS, const PrintingPolicy &Policy) const { - if (NestedNameSpecifier *NNS = getQualifier()) - NNS->print(OS, Policy); + getQualifier().print(OS, Policy); if (hasTemplateKeyword()) OS << "template "; @@ -363,16 +380,13 @@ TemplateNameDependence TemplateName::getDependence() const { case NameKind::QualifiedTemplate: { QualifiedTemplateName *S = getAsQualifiedTemplateName(); TemplateNameDependence D = S->getUnderlyingTemplate().getDependence(); - if (NestedNameSpecifier *NNS = S->getQualifier()) - D |= toTemplateNameDependence(NNS->getDependence()); + D |= toTemplateNameDependence(S->getQualifier().getDependence()); return D; } case NameKind::DependentTemplate: { DependentTemplateName *S = getAsDependentTemplateName(); - auto D = TemplateNameDependence::DependentInstantiation; - if (NestedNameSpecifier *Qualifier = S->getQualifier()) - D |= toTemplateNameDependence(Qualifier->getDependence()); - return D; + return toTemplateNameDependence(S->getQualifier().getDependence()) | + TemplateNameDependence::DependentInstantiation; } case NameKind::SubstTemplateTemplateParm: { auto *S = getAsSubstTemplateTemplateParm(); @@ -434,18 +448,20 @@ void TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy, Template = cast<TemplateDecl>(Template->getCanonicalDecl()); if (handleAnonymousTTP(Template, OS)) return; - if (Qual == Qualified::None) + if (Qual == Qualified::None || Policy.SuppressScope) { OS << *Template; - else - Template->printQualifiedName(OS, Policy); + } else { + PrintingPolicy NestedNamePolicy = Policy; + NestedNamePolicy.SuppressUnwrittenScope = true; + Template->printQualifiedName(OS, NestedNamePolicy); + } } else if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) { if (Policy.PrintAsCanonical) { QTN->getUnderlyingTemplate().print(OS, Policy, Qual); return; } - if (NestedNameSpecifier *NNS = QTN->getQualifier(); - Qual != Qualified::None && NNS) - NNS->print(OS, Policy); + if (Qual != Qualified::None) + QTN->getQualifier().print(OS, Policy); if (QTN->hasTemplateKeyword()) OS << "template "; diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index 6b524cf..0856160 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -1037,35 +1037,34 @@ void clang::TextNodeDumper::dumpTemplateSpecializationKind( } } -void clang::TextNodeDumper::dumpNestedNameSpecifier(const NestedNameSpecifier *NNS) { +void clang::TextNodeDumper::dumpNestedNameSpecifier(NestedNameSpecifier NNS) { if (!NNS) return; AddChild([=] { OS << "NestedNameSpecifier"; - switch (NNS->getKind()) { - case NestedNameSpecifier::Identifier: - OS << " Identifier"; - OS << " '" << NNS->getAsIdentifier()->getName() << "'"; - break; - case NestedNameSpecifier::Namespace: + switch (NNS.getKind()) { + case NestedNameSpecifier::Kind::Namespace: { + auto [Namespace, Prefix] = NNS.getAsNamespaceAndPrefix(); OS << " "; // "Namespace" is printed as the decl kind. - dumpBareDeclRef(NNS->getAsNamespace()); + dumpBareDeclRef(Namespace); + dumpNestedNameSpecifier(Prefix); break; - case NestedNameSpecifier::TypeSpec: + } + case NestedNameSpecifier::Kind::Type: OS << " TypeSpec"; - dumpType(QualType(NNS->getAsType(), 0)); + dumpType(QualType(NNS.getAsType(), 0)); break; - case NestedNameSpecifier::Global: + case NestedNameSpecifier::Kind::Global: OS << " Global"; break; - case NestedNameSpecifier::Super: + case NestedNameSpecifier::Kind::MicrosoftSuper: OS << " Super"; break; + case NestedNameSpecifier::Kind::Null: + llvm_unreachable("unexpected null nested name specifier"); } - - dumpNestedNameSpecifier(NNS->getPrefix()); }); } @@ -1401,8 +1400,8 @@ static void dumpBasePath(raw_ostream &OS, const CastExpr *Node) { if (!First) OS << " -> "; - const auto *RD = - cast<CXXRecordDecl>(Base->getType()->castAs<RecordType>()->getDecl()); + const auto *RD = cast<CXXRecordDecl>( + Base->getType()->castAs<RecordType>()->getOriginalDecl()); if (Base->isVirtual()) OS << "virtual "; @@ -2112,19 +2111,32 @@ void TextNodeDumper::VisitFunctionProtoType(const FunctionProtoType *T) { } void TextNodeDumper::VisitUnresolvedUsingType(const UnresolvedUsingType *T) { + if (ElaboratedTypeKeyword K = T->getKeyword(); + K != ElaboratedTypeKeyword::None) + OS << ' ' << TypeWithKeyword::getKeywordName(K); + dumpNestedNameSpecifier(T->getQualifier()); dumpDeclRef(T->getDecl()); } void TextNodeDumper::VisitUsingType(const UsingType *T) { - dumpDeclRef(T->getFoundDecl()); - if (!T->typeMatchesDecl()) - OS << " divergent"; + if (ElaboratedTypeKeyword K = T->getKeyword(); + K != ElaboratedTypeKeyword::None) + OS << ' ' << TypeWithKeyword::getKeywordName(K); + dumpNestedNameSpecifier(T->getQualifier()); + dumpDeclRef(T->getDecl()); + dumpType(T->desugar()); } void TextNodeDumper::VisitTypedefType(const TypedefType *T) { + if (ElaboratedTypeKeyword K = T->getKeyword(); + K != ElaboratedTypeKeyword::None) + OS << ' ' << TypeWithKeyword::getKeywordName(K); + dumpNestedNameSpecifier(T->getQualifier()); dumpDeclRef(T->getDecl()); - if (!T->typeMatchesDecl()) + if (!T->typeMatchesDecl()) { OS << " divergent"; + dumpType(T->desugar()); + } } void TextNodeDumper::VisitUnaryTransformType(const UnaryTransformType *T) { @@ -2138,7 +2150,17 @@ void TextNodeDumper::VisitUnaryTransformType(const UnaryTransformType *T) { } void TextNodeDumper::VisitTagType(const TagType *T) { - dumpDeclRef(T->getDecl()); + if (T->isCanonicalUnqualified()) + OS << " canonical"; + if (T->isTagOwned()) + OS << " owns_tag"; + if (T->isInjected()) + OS << " injected"; + if (ElaboratedTypeKeyword K = T->getKeyword(); + K != ElaboratedTypeKeyword::None) + OS << ' ' << TypeWithKeyword::getKeywordName(K); + dumpNestedNameSpecifier(T->getQualifier()); + dumpDeclRef(T->getOriginalDecl()); } void TextNodeDumper::VisitTemplateTypeParmType(const TemplateTypeParmType *T) { @@ -2182,12 +2204,15 @@ void TextNodeDumper::VisitTemplateSpecializationType( const TemplateSpecializationType *T) { if (T->isTypeAlias()) OS << " alias"; + if (ElaboratedTypeKeyword K = T->getKeyword(); + K != ElaboratedTypeKeyword::None) + OS << ' ' << TypeWithKeyword::getKeywordName(K); dumpTemplateName(T->getTemplateName(), "name"); } void TextNodeDumper::VisitInjectedClassNameType( const InjectedClassNameType *T) { - dumpDeclRef(T->getDecl()); + dumpDeclRef(T->getOriginalDecl()); } void TextNodeDumper::VisitObjCInterfaceType(const ObjCInterfaceType *T) { @@ -2778,8 +2803,7 @@ void TextNodeDumper::VisitTemplateTemplateParmDecl( void TextNodeDumper::VisitUsingDecl(const UsingDecl *D) { OS << ' '; - if (D->getQualifier()) - D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy()); + D->getQualifier().print(OS, D->getASTContext().getPrintingPolicy()); OS << D->getDeclName(); dumpNestedNameSpecifier(D->getQualifier()); } @@ -2792,16 +2816,14 @@ void TextNodeDumper::VisitUsingEnumDecl(const UsingEnumDecl *D) { void TextNodeDumper::VisitUnresolvedUsingTypenameDecl( const UnresolvedUsingTypenameDecl *D) { OS << ' '; - if (D->getQualifier()) - D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy()); + D->getQualifier().print(OS, D->getASTContext().getPrintingPolicy()); OS << D->getDeclName(); } void TextNodeDumper::VisitUnresolvedUsingValueDecl( const UnresolvedUsingValueDecl *D) { OS << ' '; - if (D->getQualifier()) - D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy()); + D->getQualifier().print(OS, D->getASTContext().getPrintingPolicy()); OS << D->getDeclName(); dumpType(D->getType()); } diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 141edc8..c382e58 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -109,12 +109,14 @@ bool Qualifiers::isTargetAddressSpaceSupersetOf(LangAS A, LangAS B, const IdentifierInfo *QualType::getBaseTypeIdentifier() const { const Type *ty = getTypePtr(); NamedDecl *ND = nullptr; + if (const auto *DNT = ty->getAs<DependentNameType>()) + return DNT->getIdentifier(); if (ty->isPointerOrReferenceType()) return ty->getPointeeType().getBaseTypeIdentifier(); - else if (ty->isRecordType()) - ND = ty->castAs<RecordType>()->getDecl(); + if (ty->isRecordType()) + ND = ty->castAs<RecordType>()->getOriginalDecl(); else if (ty->isEnumeralType()) - ND = ty->castAs<EnumType>()->getDecl(); + ND = ty->castAs<EnumType>()->getOriginalDecl(); else if (ty->getTypeClass() == Type::Typedef) ND = ty->castAs<TypedefType>()->getDecl(); else if (ty->isArrayType()) @@ -671,13 +673,13 @@ const Type *Type::getUnqualifiedDesugaredType() const { bool Type::isClassType() const { if (const auto *RT = getAs<RecordType>()) - return RT->getDecl()->isClass(); + return RT->getOriginalDecl()->isClass(); return false; } bool Type::isStructureType() const { if (const auto *RT = getAs<RecordType>()) - return RT->getDecl()->isStruct(); + return RT->getOriginalDecl()->isStruct(); return false; } @@ -685,7 +687,7 @@ bool Type::isStructureTypeWithFlexibleArrayMember() const { const auto *RT = getAs<RecordType>(); if (!RT) return false; - const auto *Decl = RT->getDecl(); + const auto *Decl = RT->getOriginalDecl()->getDefinitionOrSelf(); if (!Decl->isStruct()) return false; return Decl->hasFlexibleArrayMember(); @@ -693,19 +695,21 @@ bool Type::isStructureTypeWithFlexibleArrayMember() const { bool Type::isObjCBoxableRecordType() const { if (const auto *RT = getAs<RecordType>()) - return RT->getDecl()->hasAttr<ObjCBoxableAttr>(); + return RT->getOriginalDecl() + ->getDefinitionOrSelf() + ->hasAttr<ObjCBoxableAttr>(); return false; } bool Type::isInterfaceType() const { if (const auto *RT = getAs<RecordType>()) - return RT->getDecl()->isInterface(); + return RT->getOriginalDecl()->isInterface(); return false; } bool Type::isStructureOrClassType() const { if (const auto *RT = getAs<RecordType>()) { - RecordDecl *RD = RT->getDecl(); + RecordDecl *RD = RT->getOriginalDecl(); return RD->isStruct() || RD->isClass() || RD->isInterface(); } return false; @@ -719,7 +723,7 @@ bool Type::isVoidPointerType() const { bool Type::isUnionType() const { if (const auto *RT = getAs<RecordType>()) - return RT->getDecl()->isUnion(); + return RT->getOriginalDecl()->isUnion(); return false; } @@ -736,7 +740,7 @@ bool Type::isComplexIntegerType() const { bool Type::isScopedEnumeralType() const { if (const auto *ET = getAs<EnumType>()) - return ET->getDecl()->isScoped(); + return ET->getOriginalDecl()->isScoped(); return false; } @@ -770,13 +774,13 @@ QualType Type::getPointeeType() const { const RecordType *Type::getAsStructureType() const { // If this is directly a structure type, return it. if (const auto *RT = dyn_cast<RecordType>(this)) { - if (RT->getDecl()->isStruct()) + if (RT->getOriginalDecl()->isStruct()) return RT; } // If the canonical form of this type isn't the right kind, reject it. if (const auto *RT = dyn_cast<RecordType>(CanonicalType)) { - if (!RT->getDecl()->isStruct()) + if (!RT->getOriginalDecl()->isStruct()) return nullptr; // If this is a typedef for a structure type, strip the typedef off without @@ -789,13 +793,13 @@ const RecordType *Type::getAsStructureType() const { const RecordType *Type::getAsUnionType() const { // If this is directly a union type, return it. if (const auto *RT = dyn_cast<RecordType>(this)) { - if (RT->getDecl()->isUnion()) + if (RT->getOriginalDecl()->isUnion()) return RT; } // If the canonical form of this type isn't the right kind, reject it. if (const auto *RT = dyn_cast<RecordType>(CanonicalType)) { - if (!RT->getDecl()->isUnion()) + if (!RT->getOriginalDecl()->isUnion()) return nullptr; // If this is a typedef for a union type, strip the typedef off without @@ -1272,9 +1276,6 @@ public: TRIVIAL_TYPE_CLASS(Record) TRIVIAL_TYPE_CLASS(Enum) - // FIXME: Non-trivial to implement, but important for C++ - SUGARED_TYPE_CLASS(Elaborated) - QualType VisitAttributedType(const AttributedType *T) { QualType modifiedType = recurse(T->getModifiedType()); if (modifiedType.isNull()) @@ -1921,25 +1922,32 @@ const CXXRecordDecl *Type::getPointeeCXXRecordDecl() const { return nullptr; if (const auto *RT = PointeeType->getAs<RecordType>()) - return dyn_cast<CXXRecordDecl>(RT->getDecl()); + return dyn_cast<CXXRecordDecl>( + RT->getOriginalDecl()->getDefinitionOrSelf()); return nullptr; } CXXRecordDecl *Type::getAsCXXRecordDecl() const { - return dyn_cast_or_null<CXXRecordDecl>(getAsTagDecl()); + const auto *TT = dyn_cast<TagType>(CanonicalType); + if (!isa_and_present<RecordType, InjectedClassNameType>(TT)) + return nullptr; + auto *TD = TT->getOriginalDecl(); + if (!isa<InjectedClassNameType>(TT) && !isa<CXXRecordDecl>(TD)) + return nullptr; + return cast<CXXRecordDecl>(TD)->getDefinitionOrSelf(); } RecordDecl *Type::getAsRecordDecl() const { - return dyn_cast_or_null<RecordDecl>(getAsTagDecl()); + const auto *TT = dyn_cast<TagType>(CanonicalType); + if (!isa_and_present<RecordType, InjectedClassNameType>(TT)) + return nullptr; + return cast<RecordDecl>(TT->getOriginalDecl())->getDefinitionOrSelf(); } TagDecl *Type::getAsTagDecl() const { - if (const auto *TT = getAs<TagType>()) - return TT->getDecl(); - if (const auto *Injected = getAs<InjectedClassNameType>()) - return Injected->getDecl(); - + if (const auto *TT = dyn_cast<TagType>(CanonicalType)) + return TT->getOriginalDecl()->getDefinitionOrSelf(); return nullptr; } @@ -1951,6 +1959,35 @@ Type::getAsNonAliasTemplateSpecializationType() const { return TST; } +NestedNameSpecifier Type::getPrefix() const { + switch (getTypeClass()) { + case Type::DependentName: + return cast<DependentNameType>(this)->getQualifier(); + case Type::TemplateSpecialization: { + QualifiedTemplateName *S = cast<TemplateSpecializationType>(this) + ->getTemplateName() + .getAsAdjustedQualifiedTemplateName(); + return S ? S->getQualifier() : std::nullopt; + } + case Type::DependentTemplateSpecialization: + return cast<DependentTemplateSpecializationType>(this) + ->getDependentTemplateName() + .getQualifier(); + case Type::Enum: + case Type::Record: + case Type::InjectedClassName: + return cast<TagType>(this)->getQualifier(); + case Type::Typedef: + return cast<TypedefType>(this)->getQualifier(); + case Type::UnresolvedUsing: + return cast<UnresolvedUsingType>(this)->getQualifier(); + case Type::Using: + return cast<UsingType>(this)->getQualifier(); + default: + return std::nullopt; + } +} + bool Type::hasAttr(attr::Kind AK) const { const Type *Cur = this; while (const auto *AT = Cur->getAs<AttributedType>()) { @@ -1989,10 +2026,6 @@ public: return Visit(T->getReplacementType()); } - Type *VisitElaboratedType(const ElaboratedType *T) { - return Visit(T->getNamedType()); - } - Type *VisitPointerType(const PointerType *T) { return Visit(T->getPointeeType()); } @@ -2114,7 +2147,7 @@ bool Type::isIntegralType(const ASTContext &Ctx) const { // Complete enum types are integral in C. if (!Ctx.getLangOpts().CPlusPlus) if (const auto *ET = dyn_cast<EnumType>(CanonicalType)) - return ET->getDecl()->isComplete(); + return IsEnumDeclComplete(ET->getOriginalDecl()); return isBitIntType(); } @@ -2131,7 +2164,7 @@ bool Type::isIntegralOrUnscopedEnumerationType() const { bool Type::isUnscopedEnumerationType() const { if (const auto *ET = dyn_cast<EnumType>(CanonicalType)) - return !ET->getDecl()->isScoped(); + return !ET->getOriginalDecl()->isScoped(); return false; } @@ -2216,8 +2249,10 @@ bool Type::isSignedIntegerType() const { if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) { // Incomplete enum types are not treated as integer types. // FIXME: In C++, enum types are never integer types. - if (ET->getDecl()->isComplete() && !ET->getDecl()->isScoped()) - return ET->getDecl()->getIntegerType()->isSignedIntegerType(); + const auto *ED = ET->getOriginalDecl()->getDefinitionOrSelf(); + if (!ED->isComplete() || ED->isScoped()) + return false; + return ED->getIntegerType()->isSignedIntegerType(); } if (const auto *IT = dyn_cast<BitIntType>(CanonicalType)) @@ -2232,9 +2267,12 @@ bool Type::isSignedIntegerOrEnumerationType() const { if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType)) return BT->isSignedInteger(); - if (const auto *ET = dyn_cast<EnumType>(CanonicalType); - ET && ET->getDecl()->isComplete()) - return ET->getDecl()->getIntegerType()->isSignedIntegerType(); + if (const auto *ET = dyn_cast<EnumType>(CanonicalType)) { + const auto *ED = ET->getOriginalDecl()->getDefinitionOrSelf(); + if (!ED->isComplete()) + return false; + return ED->getIntegerType()->isSignedIntegerType(); + } if (const auto *IT = dyn_cast<BitIntType>(CanonicalType)) return IT->isSigned(); @@ -2261,8 +2299,10 @@ bool Type::isUnsignedIntegerType() const { 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()) - return ET->getDecl()->getIntegerType()->isUnsignedIntegerType(); + const auto *ED = ET->getOriginalDecl()->getDefinitionOrSelf(); + if (!ED->isComplete() || ED->isScoped()) + return false; + return ED->getIntegerType()->isUnsignedIntegerType(); } if (const auto *IT = dyn_cast<BitIntType>(CanonicalType)) @@ -2277,9 +2317,12 @@ bool Type::isUnsignedIntegerOrEnumerationType() const { if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType)) return BT->isUnsignedInteger(); - if (const auto *ET = dyn_cast<EnumType>(CanonicalType); - ET && ET->getDecl()->isComplete()) - return ET->getDecl()->getIntegerType()->isUnsignedIntegerType(); + if (const auto *ET = dyn_cast<EnumType>(CanonicalType)) { + const auto *ED = ET->getOriginalDecl()->getDefinitionOrSelf(); + if (!ED->isComplete()) + return false; + return ED->getIntegerType()->isUnsignedIntegerType(); + } if (const auto *IT = dyn_cast<BitIntType>(CanonicalType)) return IT->isUnsigned(); @@ -2328,8 +2371,10 @@ bool Type::isRealType() const { if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType)) return BT->getKind() >= BuiltinType::Bool && BT->getKind() <= BuiltinType::Ibm128; - if (const auto *ET = dyn_cast<EnumType>(CanonicalType)) - return ET->getDecl()->isComplete() && !ET->getDecl()->isScoped(); + if (const auto *ET = dyn_cast<EnumType>(CanonicalType)) { + const auto *ED = ET->getOriginalDecl(); + return !ED->isScoped() && ED->getDefinitionOrSelf()->isComplete(); + } return isBitIntType(); } @@ -2337,14 +2382,16 @@ bool Type::isArithmeticType() const { if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType)) return BT->getKind() >= BuiltinType::Bool && BT->getKind() <= BuiltinType::Ibm128; - if (const auto *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. // // C++0x: Enumerations are not arithmetic types. For now, just return // false for scoped enumerations since that will disable any // unwanted implicit conversions. - return !ET->getDecl()->isScoped() && ET->getDecl()->isComplete(); + const auto *ED = ET->getOriginalDecl(); + return !ED->isScoped() && ED->getDefinitionOrSelf()->isComplete(); + } return isa<ComplexType>(CanonicalType) || isBitIntType(); } @@ -2352,8 +2399,8 @@ bool Type::hasBooleanRepresentation() const { if (const auto *VT = dyn_cast<VectorType>(CanonicalType)) return VT->getElementType()->isBooleanType(); if (const auto *ET = dyn_cast<EnumType>(CanonicalType)) { - return ET->getDecl()->isComplete() && - ET->getDecl()->getIntegerType()->isBooleanType(); + const auto *ED = ET->getOriginalDecl()->getDefinitionOrSelf(); + return ED->isComplete() && ED->getIntegerType()->isBooleanType(); } if (const auto *IT = dyn_cast<BitIntType>(CanonicalType)) return IT->getNumBits() == 1; @@ -2385,7 +2432,10 @@ Type::ScalarTypeKind Type::getScalarTypeKind() const { } else if (isa<MemberPointerType>(T)) { return STK_MemberPointer; } else if (isa<EnumType>(T)) { - assert(cast<EnumType>(T)->getDecl()->isComplete()); + assert(cast<EnumType>(T) + ->getOriginalDecl() + ->getDefinitionOrSelf() + ->isComplete()); return STK_Integral; } else if (const auto *CT = dyn_cast<ComplexType>(T)) { if (CT->getElementType()->isRealFloatingType()) @@ -2409,7 +2459,8 @@ Type::ScalarTypeKind Type::getScalarTypeKind() const { /// includes union types. bool Type::isAggregateType() const { if (const auto *Record = dyn_cast<RecordType>(CanonicalType)) { - if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>(Record->getDecl())) + if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>( + Record->getOriginalDecl()->getDefinitionOrSelf())) return ClassDecl->isAggregate(); return true; @@ -2443,7 +2494,8 @@ bool Type::isIncompleteType(NamedDecl **Def) const { // be completed. return isVoidType(); case Enum: { - EnumDecl *EnumD = cast<EnumType>(CanonicalType)->getDecl(); + EnumDecl *EnumD = + cast<EnumType>(CanonicalType)->getOriginalDecl()->getDefinitionOrSelf(); if (Def) *Def = EnumD; return !EnumD->isComplete(); @@ -2451,13 +2503,17 @@ bool Type::isIncompleteType(NamedDecl **Def) const { case Record: { // A tagged type (struct/union/enum/class) is incomplete if the decl is a // forward declaration, but not a full definition (C99 6.2.5p22). - RecordDecl *Rec = cast<RecordType>(CanonicalType)->getDecl(); + RecordDecl *Rec = cast<RecordType>(CanonicalType) + ->getOriginalDecl() + ->getDefinitionOrSelf(); if (Def) *Def = Rec; return !Rec->isCompleteDefinition(); } case InjectedClassName: { - CXXRecordDecl *Rec = cast<InjectedClassNameType>(CanonicalType)->getDecl(); + CXXRecordDecl *Rec = cast<InjectedClassNameType>(CanonicalType) + ->getOriginalDecl() + ->getDefinitionOrSelf(); if (!Rec->isBeingDefined()) return false; if (Def) @@ -2739,9 +2795,9 @@ bool QualType::isCXX98PODType(const ASTContext &Context) const { return true; case Type::Record: - if (const auto *ClassDecl = - dyn_cast<CXXRecordDecl>(cast<RecordType>(CanonicalType)->getDecl())) - return ClassDecl->isPOD(); + if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>( + cast<RecordType>(CanonicalType)->getOriginalDecl())) + return ClassDecl->getDefinitionOrSelf()->isPOD(); // C struct/union is POD. return true; @@ -2782,7 +2838,8 @@ bool QualType::isTrivialType(const ASTContext &Context) const { if (CanonicalType->isScalarType() || CanonicalType->isVectorType()) return true; if (const auto *RT = CanonicalType->getAs<RecordType>()) { - if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) { + if (const auto *ClassDecl = + dyn_cast<CXXRecordDecl>(RT->getOriginalDecl())) { // C++20 [class]p6: // A trivial class is a class that is trivially copyable, and // has one or more eligible default constructors such that each is @@ -2841,14 +2898,17 @@ static bool isTriviallyCopyableTypeImpl(const QualType &type, return true; if (const auto *RT = CanonicalType->getAs<RecordType>()) { - if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) { + if (const auto *ClassDecl = + dyn_cast<CXXRecordDecl>(RT->getOriginalDecl())) { if (IsCopyConstructible) { return ClassDecl->isTriviallyCopyConstructible(); } else { return ClassDecl->isTriviallyCopyable(); } } - return !RT->getDecl()->isNonTrivialToPrimitiveCopy(); + return !RT->getOriginalDecl() + ->getDefinitionOrSelf() + ->isNonTrivialToPrimitiveCopy(); } // No other types can match. return false; @@ -2938,7 +2998,9 @@ QualType::PrimitiveDefaultInitializeKind QualType::isNonTrivialToPrimitiveDefaultInitialize() const { if (const auto *RT = getTypePtr()->getBaseElementTypeUnsafe()->getAs<RecordType>()) - if (RT->getDecl()->isNonTrivialToPrimitiveDefaultInitialize()) + if (RT->getOriginalDecl() + ->getDefinitionOrSelf() + ->isNonTrivialToPrimitiveDefaultInitialize()) return PDIK_Struct; switch (getQualifiers().getObjCLifetime()) { @@ -2954,7 +3016,9 @@ QualType::isNonTrivialToPrimitiveDefaultInitialize() const { QualType::PrimitiveCopyKind QualType::isNonTrivialToPrimitiveCopy() const { if (const auto *RT = getTypePtr()->getBaseElementTypeUnsafe()->getAs<RecordType>()) - if (RT->getDecl()->isNonTrivialToPrimitiveCopy()) + if (RT->getOriginalDecl() + ->getDefinitionOrSelf() + ->isNonTrivialToPrimitiveCopy()) return PCK_Struct; Qualifiers Qs = getQualifiers(); @@ -3022,8 +3086,8 @@ 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 auto *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) - return ClassDecl->isLiteral(); + if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getOriginalDecl())) + return ClassDecl->getDefinitionOrSelf()->isLiteral(); return true; } @@ -3076,8 +3140,8 @@ bool Type::isStandardLayoutType() const { if (BaseTy->isScalarType() || BaseTy->isVectorType()) return true; if (const auto *RT = BaseTy->getAs<RecordType>()) { - if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) - if (!ClassDecl->isStandardLayout()) + if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getOriginalDecl())) + if (!ClassDecl->getDefinitionOrSelf()->isStandardLayout()) return false; // Default to 'true' for non-C++ class types. @@ -3119,7 +3183,9 @@ bool QualType::isCXX11PODType(const ASTContext &Context) const { if (BaseTy->isScalarType() || BaseTy->isVectorType()) return true; if (const auto *RT = BaseTy->getAs<RecordType>()) { - if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) { + if (const auto *ClassDecl = + dyn_cast<CXXRecordDecl>(RT->getOriginalDecl())) { + ClassDecl = ClassDecl->getDefinitionOrSelf(); // C++11 [class]p10: // A POD struct is a non-union class that is both a trivial class [...] if (!ClassDecl->isTrivial()) @@ -3159,8 +3225,9 @@ bool Type::isNothrowT() const { bool Type::isAlignValT() const { if (const auto *ET = getAs<EnumType>()) { - IdentifierInfo *II = ET->getDecl()->getIdentifier(); - if (II && II->isStr("align_val_t") && ET->getDecl()->isInStdNamespace()) + const auto *ED = ET->getOriginalDecl(); + IdentifierInfo *II = ED->getIdentifier(); + if (II && II->isStr("align_val_t") && ED->isInStdNamespace()) return true; } return false; @@ -3168,8 +3235,9 @@ bool Type::isAlignValT() const { bool Type::isStdByteType() const { if (const auto *ET = getAs<EnumType>()) { - IdentifierInfo *II = ET->getDecl()->getIdentifier(); - if (II && II->isStr("byte") && ET->getDecl()->isInStdNamespace()) + const auto *ED = ET->getOriginalDecl(); + IdentifierInfo *II = ED->getIdentifier(); + if (II && II->isStr("byte") && ED->isInStdNamespace()) return true; } return false; @@ -3188,7 +3256,6 @@ bool Type::isSpecifierType() const { case TemplateTypeParm: case SubstTemplateTypeParm: case TemplateSpecialization: - case Elaborated: case DependentName: case DependentTemplateSpecialization: case ObjCInterface: @@ -3199,8 +3266,7 @@ bool Type::isSpecifierType() const { } } -ElaboratedTypeKeyword -TypeWithKeyword::getKeywordForTypeSpec(unsigned TypeSpec) { +ElaboratedTypeKeyword KeywordHelpers::getKeywordForTypeSpec(unsigned TypeSpec) { switch (TypeSpec) { default: return ElaboratedTypeKeyword::None; @@ -3219,7 +3285,7 @@ TypeWithKeyword::getKeywordForTypeSpec(unsigned TypeSpec) { } } -TagTypeKind TypeWithKeyword::getTagTypeKindForTypeSpec(unsigned TypeSpec) { +TagTypeKind KeywordHelpers::getTagTypeKindForTypeSpec(unsigned TypeSpec) { switch (TypeSpec) { case TST_class: return TagTypeKind::Class; @@ -3237,7 +3303,7 @@ TagTypeKind TypeWithKeyword::getTagTypeKindForTypeSpec(unsigned TypeSpec) { } ElaboratedTypeKeyword -TypeWithKeyword::getKeywordForTagTypeKind(TagTypeKind Kind) { +KeywordHelpers::getKeywordForTagTypeKind(TagTypeKind Kind) { switch (Kind) { case TagTypeKind::Class: return ElaboratedTypeKeyword::Class; @@ -3254,7 +3320,7 @@ TypeWithKeyword::getKeywordForTagTypeKind(TagTypeKind Kind) { } TagTypeKind -TypeWithKeyword::getTagTypeKindForKeyword(ElaboratedTypeKeyword Keyword) { +KeywordHelpers::getTagTypeKindForKeyword(ElaboratedTypeKeyword Keyword) { switch (Keyword) { case ElaboratedTypeKeyword::Class: return TagTypeKind::Class; @@ -3273,7 +3339,7 @@ TypeWithKeyword::getTagTypeKindForKeyword(ElaboratedTypeKeyword Keyword) { llvm_unreachable("Unknown elaborated type keyword."); } -bool TypeWithKeyword::KeywordIsTagTypeKind(ElaboratedTypeKeyword Keyword) { +bool KeywordHelpers::KeywordIsTagTypeKind(ElaboratedTypeKeyword Keyword) { switch (Keyword) { case ElaboratedTypeKeyword::None: case ElaboratedTypeKeyword::Typename: @@ -3288,7 +3354,7 @@ bool TypeWithKeyword::KeywordIsTagTypeKind(ElaboratedTypeKeyword Keyword) { llvm_unreachable("Unknown elaborated type keyword."); } -StringRef TypeWithKeyword::getKeywordName(ElaboratedTypeKeyword Keyword) { +StringRef KeywordHelpers::getKeywordName(ElaboratedTypeKeyword Keyword) { switch (Keyword) { case ElaboratedTypeKeyword::None: return {}; @@ -3338,13 +3404,21 @@ void DependentTemplateSpecializationType::Profile( bool Type::isElaboratedTypeSpecifier() const { ElaboratedTypeKeyword Keyword; - if (const auto *Elab = dyn_cast<ElaboratedType>(this)) - Keyword = Elab->getKeyword(); + if (const auto *TST = dyn_cast<TemplateSpecializationType>(this)) + Keyword = TST->getKeyword(); else if (const auto *DepName = dyn_cast<DependentNameType>(this)) Keyword = DepName->getKeyword(); else if (const auto *DepTST = dyn_cast<DependentTemplateSpecializationType>(this)) Keyword = DepTST->getKeyword(); + else if (const auto *T = dyn_cast<TagType>(this)) + Keyword = T->getKeyword(); + else if (const auto *T = dyn_cast<TypedefType>(this)) + Keyword = T->getKeyword(); + else if (const auto *T = dyn_cast<UnresolvedUsingType>(this)) + Keyword = T->getKeyword(); + else if (const auto *T = dyn_cast<UsingType>(this)) + Keyword = T->getKeyword(); else return false; @@ -4011,34 +4085,53 @@ StringRef CountAttributedType::getAttributeName(bool WithMacroPrefix) const { #undef ENUMERATE_ATTRS } -TypedefType::TypedefType(TypeClass tc, const TypedefNameDecl *D, - QualType UnderlyingType, bool HasTypeDifferentFromDecl) - : Type(tc, UnderlyingType.getCanonicalType(), - toSemanticDependence(UnderlyingType->getDependence())), +TypedefType::TypedefType(TypeClass TC, ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, + const TypedefNameDecl *D, QualType UnderlyingType, + bool HasTypeDifferentFromDecl) + : TypeWithKeyword( + Keyword, TC, UnderlyingType.getCanonicalType(), + toSemanticDependence(UnderlyingType->getDependence()) | + (Qualifier + ? toTypeDependence(Qualifier.getDependence() & + ~NestedNameSpecifierDependence::Dependent) + : TypeDependence{})), Decl(const_cast<TypedefNameDecl *>(D)) { - TypedefBits.hasTypeDifferentFromDecl = HasTypeDifferentFromDecl; - if (!typeMatchesDecl()) - *getTrailingObjects() = UnderlyingType; + if ((TypedefBits.hasQualifier = !!Qualifier)) + *getTrailingObjects<NestedNameSpecifier>() = Qualifier; + if ((TypedefBits.hasTypeDifferentFromDecl = HasTypeDifferentFromDecl)) + *getTrailingObjects<QualType>() = UnderlyingType; } QualType TypedefType::desugar() const { - return typeMatchesDecl() ? Decl->getUnderlyingType() : *getTrailingObjects(); -} - -UsingType::UsingType(const UsingShadowDecl *Found, QualType Underlying, - QualType Canon) - : Type(Using, Canon, toSemanticDependence(Canon->getDependence())), - Found(const_cast<UsingShadowDecl *>(Found)) { - UsingBits.hasTypeDifferentFromDecl = !Underlying.isNull(); - if (!typeMatchesDecl()) - *getTrailingObjects() = Underlying; -} - -QualType UsingType::getUnderlyingType() const { - return typeMatchesDecl() - ? QualType( - cast<TypeDecl>(Found->getTargetDecl())->getTypeForDecl(), 0) - : *getTrailingObjects(); + return typeMatchesDecl() ? Decl->getUnderlyingType() + : *getTrailingObjects<QualType>(); +} + +UnresolvedUsingType::UnresolvedUsingType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, + const UnresolvedUsingTypenameDecl *D, + const Type *CanonicalType) + : TypeWithKeyword( + Keyword, UnresolvedUsing, QualType(CanonicalType, 0), + TypeDependence::DependentInstantiation | + (Qualifier + ? toTypeDependence(Qualifier.getDependence() & + ~NestedNameSpecifierDependence::Dependent) + : TypeDependence{})), + Decl(const_cast<UnresolvedUsingTypenameDecl *>(D)) { + if ((UnresolvedUsingBits.hasQualifier = !!Qualifier)) + *getTrailingObjects<NestedNameSpecifier>() = Qualifier; +} + +UsingType::UsingType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, const UsingShadowDecl *D, + QualType UnderlyingType) + : TypeWithKeyword(Keyword, Using, UnderlyingType.getCanonicalType(), + toSemanticDependence(UnderlyingType->getDependence())), + D(const_cast<UsingShadowDecl *>(D)), UnderlyingType(UnderlyingType) { + if ((UsingBits.hasQualifier = !!Qualifier)) + *getTrailingObjects() = Qualifier; } QualType MacroQualifiedType::desugar() const { return getUnderlyingType(); } @@ -4212,24 +4305,79 @@ UnaryTransformType::UnaryTransformType(QualType BaseType, : Type(UnaryTransform, CanonicalType, BaseType->getDependence()), BaseType(BaseType), UnderlyingType(UnderlyingType), UKind(UKind) {} -TagType::TagType(TypeClass TC, const TagDecl *D, QualType can) - : Type(TC, can, - D->isDependentType() ? TypeDependence::DependentInstantiation - : TypeDependence::None), - decl(const_cast<TagDecl *>(D)) {} - -static TagDecl *getInterestingTagDecl(TagDecl *decl) { - for (auto *I : decl->redecls()) { - if (I->isCompleteDefinition() || I->isBeingDefined()) - return I; +TagType::TagType(TypeClass TC, ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, const TagDecl *Tag, + bool OwnsTag, bool ISInjected, const Type *CanonicalType) + : TypeWithKeyword( + Keyword, TC, QualType(CanonicalType, 0), + (Tag->isDependentType() ? TypeDependence::DependentInstantiation + : TypeDependence::None) | + (Qualifier + ? toTypeDependence(Qualifier.getDependence() & + ~NestedNameSpecifierDependence::Dependent) + : TypeDependence{})), + decl(const_cast<TagDecl *>(Tag)) { + if ((TagTypeBits.HasQualifier = !!Qualifier)) + getTrailingQualifier() = Qualifier; + TagTypeBits.OwnsTag = !!OwnsTag; + TagTypeBits.IsInjected = ISInjected; +} + +void *TagType::getTrailingPointer() const { + switch (getTypeClass()) { + case Type::Enum: + return const_cast<EnumType *>(cast<EnumType>(this) + 1); + case Type::Record: + return const_cast<RecordType *>(cast<RecordType>(this) + 1); + case Type::InjectedClassName: + return const_cast<InjectedClassNameType *>( + cast<InjectedClassNameType>(this) + 1); + default: + llvm_unreachable("unexpected type class"); } - // If there's no definition (not even in progress), return what we have. - return decl; } -TagDecl *TagType::getDecl() const { return getInterestingTagDecl(decl); } +NestedNameSpecifier &TagType::getTrailingQualifier() const { + assert(TagTypeBits.HasQualifier); + return *reinterpret_cast<NestedNameSpecifier *>(llvm::alignAddr( + getTrailingPointer(), llvm::Align::Of<NestedNameSpecifier *>())); +} + +NestedNameSpecifier TagType::getQualifier() const { + return TagTypeBits.HasQualifier ? getTrailingQualifier() : std::nullopt; +} + +ClassTemplateDecl *TagType::getTemplateDecl() const { + auto *Decl = dyn_cast<CXXRecordDecl>(decl); + if (!Decl) + return nullptr; + if (auto *RD = dyn_cast<ClassTemplateSpecializationDecl>(Decl)) + return RD->getSpecializedTemplate(); + return Decl->getDescribedClassTemplate(); +} -bool TagType::isBeingDefined() const { return getDecl()->isBeingDefined(); } +TemplateName TagType::getTemplateName(const ASTContext &Ctx) const { + auto *TD = getTemplateDecl(); + if (!TD) + return TemplateName(); + if (isCanonicalUnqualified()) + return TemplateName(TD); + return Ctx.getQualifiedTemplateName(getQualifier(), /*TemplateKeyword=*/false, + TemplateName(TD)); +} + +ArrayRef<TemplateArgument> +TagType::getTemplateArgs(const ASTContext &Ctx) const { + auto *Decl = dyn_cast<CXXRecordDecl>(decl); + if (!Decl) + return {}; + + if (auto *RD = dyn_cast<ClassTemplateSpecializationDecl>(Decl)) + return RD->getTemplateArgs().asArray(); + if (ClassTemplateDecl *TD = Decl->getDescribedClassTemplate()) + return TD->getTemplateParameters()->getInjectedTemplateArgs(Ctx); + return {}; +} bool RecordType::hasConstFields() const { std::vector<const RecordType *> RecordTypeList; @@ -4237,8 +4385,10 @@ bool RecordType::hasConstFields() const { unsigned NextToCheckIndex = 0; while (RecordTypeList.size() > NextToCheckIndex) { - for (FieldDecl *FD : - RecordTypeList[NextToCheckIndex]->getDecl()->fields()) { + for (FieldDecl *FD : RecordTypeList[NextToCheckIndex] + ->getOriginalDecl() + ->getDefinitionOrSelf() + ->fields()) { QualType FieldTy = FD->getType(); if (FieldTy.isConstQualified()) return true; @@ -4253,6 +4403,13 @@ bool RecordType::hasConstFields() const { return false; } +InjectedClassNameType::InjectedClassNameType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, + const TagDecl *TD, bool IsInjected, + const Type *CanonicalType) + : TagType(TypeClass::InjectedClassName, Keyword, Qualifier, TD, + /*OwnsTag=*/false, IsInjected, CanonicalType) {} + AttributedType::AttributedType(QualType canon, const Attr *attr, QualType modified, QualType equivalent) : AttributedType(canon, attr->getKind(), attr, modified, equivalent) {} @@ -4340,10 +4497,6 @@ bool AttributedType::isCallingConv() const { llvm_unreachable("invalid attr kind"); } -CXXRecordDecl *InjectedClassNameType::getDecl() const { - return cast<CXXRecordDecl>(getInterestingTagDecl(Decl)); -} - IdentifierInfo *TemplateTypeParmType::getIdentifier() const { return isCanonicalUnqualified() ? nullptr : getDecl()->getIdentifier(); } @@ -4467,16 +4620,17 @@ bool TemplateSpecializationType::anyInstantiationDependentTemplateArguments( } TemplateSpecializationType::TemplateSpecializationType( - TemplateName T, bool IsAlias, ArrayRef<TemplateArgument> Args, - QualType Underlying) - : Type(TemplateSpecialization, - Underlying.isNull() ? QualType(this, 0) - : Underlying.getCanonicalType(), - (Underlying.isNull() - ? TypeDependence::DependentInstantiation - : toSemanticDependence(Underlying->getDependence())) | - (toTypeDependence(T.getDependence()) & - TypeDependence::UnexpandedPack)), + ElaboratedTypeKeyword Keyword, TemplateName T, bool IsAlias, + ArrayRef<TemplateArgument> Args, QualType Underlying) + : TypeWithKeyword( + Keyword, TemplateSpecialization, + Underlying.isNull() ? QualType(this, 0) + : Underlying.getCanonicalType(), + (Underlying.isNull() + ? TypeDependence::DependentInstantiation + : toSemanticDependence(Underlying->getDependence())) | + (toTypeDependence(T.getDependence()) & + TypeDependence::UnexpandedPack)), Template(T) { TemplateSpecializationTypeBits.NumArgs = Args.size(); TemplateSpecializationTypeBits.TypeAlias = IsAlias; @@ -4699,7 +4853,8 @@ static CachedProperties computeCachedProperties(const Type *T) { case Type::Record: case Type::Enum: { - const TagDecl *Tag = cast<TagType>(T)->getDecl(); + const TagDecl *Tag = + cast<TagType>(T)->getOriginalDecl()->getDefinitionOrSelf(); // C++ [basic.link]p8: // - it is a class or enumeration type that is named (or has a name @@ -4726,12 +4881,9 @@ static CachedProperties computeCachedProperties(const Type *T) { case Type::MemberPointer: { const auto *MPT = cast<MemberPointerType>(T); CachedProperties Cls = [&] { - if (auto *RD = MPT->getMostRecentCXXRecordDecl()) - return Cache::get(QualType(RD->getTypeForDecl(), 0)); - if (const Type *T = MPT->getQualifier()->getAsType()) - return Cache::get(T); - // Treat as a dependent type. - return CachedProperties(Linkage::External, false); + if (MPT->isSugared()) + MPT = cast<MemberPointerType>(MPT->getCanonicalTypeInternal()); + return Cache::get(MPT->getQualifier().getAsType()); }(); return merge(Cls, Cache::get(MPT->getPointeeType())); } @@ -4811,7 +4963,8 @@ LinkageInfo LinkageComputer::computeTypeLinkageInfo(const Type *T) { case Type::Record: case Type::Enum: - return getDeclLinkageAndVisibility(cast<TagType>(T)->getDecl()); + return getDeclLinkageAndVisibility( + cast<TagType>(T)->getOriginalDecl()->getDefinitionOrSelf()); case Type::Complex: return computeTypeLinkageInfo(cast<ComplexType>(T)->getElementType()); @@ -4827,8 +4980,8 @@ LinkageInfo LinkageComputer::computeTypeLinkageInfo(const Type *T) { LinkageInfo LV; if (auto *D = MPT->getMostRecentCXXRecordDecl()) { LV.merge(getDeclLinkageAndVisibility(D)); - } else if (auto *Ty = MPT->getQualifier()->getAsType()) { - LV.merge(computeTypeLinkageInfo(Ty)); + } else { + LV.merge(computeTypeLinkageInfo(MPT->getQualifier().getAsType())); } LV.merge(computeTypeLinkageInfo(MPT->getPointeeType())); return LV; @@ -5014,7 +5167,7 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const { llvm_unreachable("unknown builtin type"); case Type::Record: { - const RecordDecl *RD = cast<RecordType>(type)->getDecl(); + const RecordDecl *RD = cast<RecordType>(type)->getOriginalDecl(); // For template specializations, look only at primary template attributes. // This is a consistent regardless of whether the instantiation is known. if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD)) @@ -5212,14 +5365,18 @@ bool Type::isCARCBridgableType() const { /// Check if the specified type is the CUDA device builtin surface type. bool Type::isCUDADeviceBuiltinSurfaceType() const { if (const auto *RT = getAs<RecordType>()) - return RT->getDecl()->hasAttr<CUDADeviceBuiltinSurfaceTypeAttr>(); + return RT->getOriginalDecl() + ->getMostRecentDecl() + ->hasAttr<CUDADeviceBuiltinSurfaceTypeAttr>(); return false; } /// Check if the specified type is the CUDA device builtin texture type. bool Type::isCUDADeviceBuiltinTextureType() const { if (const auto *RT = getAs<RecordType>()) - return RT->getDecl()->hasAttr<CUDADeviceBuiltinTextureTypeAttr>(); + return RT->getOriginalDecl() + ->getMostRecentDecl() + ->hasAttr<CUDADeviceBuiltinTextureTypeAttr>(); return false; } @@ -5246,6 +5403,15 @@ bool Type::isHLSLResourceRecord() const { return HLSLAttributedResourceType::findHandleTypeOnResource(this) != nullptr; } +bool Type::isHLSLResourceRecordArray() const { + const Type *Ty = getUnqualifiedDesugaredType(); + if (!Ty->isArrayType()) + return false; + while (isa<ConstantArrayType>(Ty)) + Ty = Ty->getArrayElementTypeNoTypeQual(); + return Ty->isHLSLResourceRecord(); +} + bool Type::isHLSLIntangibleType() const { const Type *Ty = getUnqualifiedDesugaredType(); @@ -5283,7 +5449,7 @@ QualType::DestructionKind QualType::isDestructedTypeImpl(QualType type) { } if (const auto *RT = type->getBaseElementTypeUnsafe()->getAs<RecordType>()) { - const RecordDecl *RD = RT->getDecl(); + const RecordDecl *RD = RT->getOriginalDecl(); 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()) @@ -5291,7 +5457,7 @@ QualType::DestructionKind QualType::isDestructedTypeImpl(QualType type) { } 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()) + if (RD->getDefinitionOrSelf()->isNonTrivialToPrimitiveDestroy()) return DK_nontrivial_c_struct; } } @@ -5301,16 +5467,16 @@ QualType::DestructionKind QualType::isDestructedTypeImpl(QualType type) { bool MemberPointerType::isSugared() const { CXXRecordDecl *D1 = getMostRecentCXXRecordDecl(), - *D2 = getQualifier()->getAsRecordDecl(); + *D2 = getQualifier().getAsRecordDecl(); assert(!D1 == !D2); return D1 != D2 && D1->getCanonicalDecl() != D2->getCanonicalDecl(); } void MemberPointerType::Profile(llvm::FoldingSetNodeID &ID, QualType Pointee, - const NestedNameSpecifier *Qualifier, + const NestedNameSpecifier Qualifier, const CXXRecordDecl *Cls) { ID.AddPointer(Pointee.getAsOpaquePtr()); - ID.AddPointer(Qualifier); + Qualifier.Profile(ID); if (Cls) ID.AddPointer(Cls->getCanonicalDecl()); } @@ -5318,14 +5484,14 @@ void MemberPointerType::Profile(llvm::FoldingSetNodeID &ID, QualType Pointee, CXXRecordDecl *MemberPointerType::getCXXRecordDecl() const { return dyn_cast<MemberPointerType>(getCanonicalTypeInternal()) ->getQualifier() - ->getAsRecordDecl(); + .getAsRecordDecl(); } CXXRecordDecl *MemberPointerType::getMostRecentCXXRecordDecl() const { auto *RD = getCXXRecordDecl(); if (!RD) return nullptr; - return RD->getMostRecentNonInjectedDecl(); + return RD->getMostRecentDecl(); } void clang::FixedPointValueToString(SmallVectorImpl<char> &Str, diff --git a/clang/lib/AST/TypeLoc.cpp b/clang/lib/AST/TypeLoc.cpp index 5c45c59..fbe8772 100644 --- a/clang/lib/AST/TypeLoc.cpp +++ b/clang/lib/AST/TypeLoc.cpp @@ -195,15 +195,6 @@ SourceLocation TypeLoc::getBeginLoc() const { TypeLoc LeftMost = Cur; while (true) { switch (Cur.getTypeLocClass()) { - case Elaborated: - if (Cur.getLocalSourceRange().getBegin().isValid()) { - LeftMost = Cur; - break; - } - Cur = Cur.getNextTypeLoc(); - if (Cur.isNull()) - break; - continue; case FunctionProto: if (Cur.castAs<FunctionProtoTypeLoc>().getTypePtr() ->hasTrailingReturn()) { @@ -275,7 +266,6 @@ SourceLocation TypeLoc::getEndLoc() const { Last = Cur; break; case Qualified: - case Elaborated: break; } Cur = Cur.getNextTypeLoc(); @@ -313,9 +303,8 @@ bool TypeSpecTypeLoc::isKind(const TypeLoc &TL) { } bool TagTypeLoc::isDefinition() const { - TagDecl *D = getDecl(); - return D->isCompleteDefinition() && - (D->getIdentifier() == nullptr || D->getLocation() == getNameLoc()); + return getTypePtr()->isTagOwned() && + getOriginalDecl()->isCompleteDefinition(); } // Reimplemented to account for GNU/C++ extension @@ -482,6 +471,134 @@ TypeLoc TypeLoc::findExplicitQualifierLoc() const { return {}; } +NestedNameSpecifierLoc TypeLoc::getPrefix() const { + switch (getTypeLocClass()) { + case TypeLoc::DependentName: + return castAs<DependentNameTypeLoc>().getQualifierLoc(); + case TypeLoc::TemplateSpecialization: + return castAs<TemplateSpecializationTypeLoc>().getQualifierLoc(); + case TypeLoc::DependentTemplateSpecialization: + return castAs<DependentTemplateSpecializationTypeLoc>().getQualifierLoc(); + case TypeLoc::DeducedTemplateSpecialization: + return castAs<DeducedTemplateSpecializationTypeLoc>().getQualifierLoc(); + case TypeLoc::Enum: + case TypeLoc::Record: + case TypeLoc::InjectedClassName: + return castAs<TagTypeLoc>().getQualifierLoc(); + case TypeLoc::Typedef: + return castAs<TypedefTypeLoc>().getQualifierLoc(); + case TypeLoc::UnresolvedUsing: + return castAs<UnresolvedUsingTypeLoc>().getQualifierLoc(); + case TypeLoc::Using: + return castAs<UsingTypeLoc>().getQualifierLoc(); + default: + return NestedNameSpecifierLoc(); + } +} + +SourceLocation TypeLoc::getNonPrefixBeginLoc() const { + switch (getTypeLocClass()) { + case TypeLoc::TemplateSpecialization: { + auto TL = castAs<TemplateSpecializationTypeLoc>(); + SourceLocation Loc = TL.getTemplateKeywordLoc(); + if (!Loc.isValid()) + Loc = TL.getTemplateNameLoc(); + return Loc; + } + case TypeLoc::DependentTemplateSpecialization: { + auto TL = castAs<DependentTemplateSpecializationTypeLoc>(); + SourceLocation Loc = TL.getTemplateKeywordLoc(); + if (!Loc.isValid()) + Loc = TL.getTemplateNameLoc(); + return Loc; + } + case TypeLoc::DeducedTemplateSpecialization: { + auto TL = castAs<DeducedTemplateSpecializationTypeLoc>(); + SourceLocation Loc = TL.getTemplateKeywordLoc(); + if (!Loc.isValid()) + Loc = TL.getTemplateNameLoc(); + return Loc; + } + case TypeLoc::DependentName: + return castAs<DependentNameTypeLoc>().getNameLoc(); + case TypeLoc::Enum: + case TypeLoc::Record: + case TypeLoc::InjectedClassName: + return castAs<TagTypeLoc>().getNameLoc(); + case TypeLoc::Typedef: + return castAs<TypedefTypeLoc>().getNameLoc(); + case TypeLoc::UnresolvedUsing: + return castAs<UnresolvedUsingTypeLoc>().getNameLoc(); + case TypeLoc::Using: + return castAs<UsingTypeLoc>().getNameLoc(); + default: + return getBeginLoc(); + } +} + +SourceLocation TypeLoc::getNonElaboratedBeginLoc() const { + // For elaborated types (e.g. `struct a::A`) we want the portion after the + // `struct` but including the namespace qualifier, `a::`. + switch (getTypeLocClass()) { + case TypeLoc::Qualified: + return castAs<QualifiedTypeLoc>() + .getUnqualifiedLoc() + .getNonElaboratedBeginLoc(); + case TypeLoc::TemplateSpecialization: { + auto T = castAs<TemplateSpecializationTypeLoc>(); + if (NestedNameSpecifierLoc QualifierLoc = T.getQualifierLoc()) + return QualifierLoc.getBeginLoc(); + return T.getTemplateNameLoc(); + } + case TypeLoc::DependentTemplateSpecialization: { + auto T = castAs<DependentTemplateSpecializationTypeLoc>(); + if (NestedNameSpecifierLoc QualifierLoc = T.getQualifierLoc()) + return QualifierLoc.getBeginLoc(); + return T.getTemplateNameLoc(); + } + case TypeLoc::DeducedTemplateSpecialization: { + auto T = castAs<DeducedTemplateSpecializationTypeLoc>(); + if (NestedNameSpecifierLoc QualifierLoc = T.getQualifierLoc()) + return QualifierLoc.getBeginLoc(); + return T.getTemplateNameLoc(); + } + case TypeLoc::DependentName: { + auto T = castAs<DependentNameTypeLoc>(); + if (NestedNameSpecifierLoc QualifierLoc = T.getQualifierLoc()) + return QualifierLoc.getBeginLoc(); + return T.getNameLoc(); + } + case TypeLoc::Enum: + case TypeLoc::Record: + case TypeLoc::InjectedClassName: { + auto T = castAs<TagTypeLoc>(); + if (NestedNameSpecifierLoc QualifierLoc = T.getQualifierLoc()) + return QualifierLoc.getBeginLoc(); + return T.getNameLoc(); + } + case TypeLoc::Typedef: { + auto T = castAs<TypedefTypeLoc>(); + if (NestedNameSpecifierLoc QualifierLoc = T.getQualifierLoc()) + return QualifierLoc.getBeginLoc(); + return T.getNameLoc(); + } + case TypeLoc::UnresolvedUsing: { + auto T = castAs<UnresolvedUsingTypeLoc>(); + if (NestedNameSpecifierLoc QualifierLoc = T.getQualifierLoc()) + return QualifierLoc.getBeginLoc(); + return T.getNameLoc(); + } + case TypeLoc::Using: { + auto T = castAs<UsingTypeLoc>(); + if (NestedNameSpecifierLoc QualifierLoc = T.getQualifierLoc()) + return QualifierLoc.getBeginLoc(); + return T.getNameLoc(); + } + default: + return getBeginLoc(); + } +} + void ObjCTypeParamTypeLoc::initializeLocal(ASTContext &Context, SourceLocation Loc) { setNameLoc(Loc); @@ -555,9 +672,9 @@ static void initializeElaboratedKeyword(TL T, SourceLocation Loc) { : SourceLocation()); } -static NestedNameSpecifierLoc -initializeQualifier(ASTContext &Context, NestedNameSpecifier *Qualifier, - SourceLocation Loc) { +static NestedNameSpecifierLoc initializeQualifier(ASTContext &Context, + NestedNameSpecifier Qualifier, + SourceLocation Loc) { if (!Qualifier) return NestedNameSpecifierLoc(); NestedNameSpecifierLocBuilder Builder; @@ -565,15 +682,6 @@ initializeQualifier(ASTContext &Context, NestedNameSpecifier *Qualifier, return Builder.getWithLocInContext(Context); } -void ElaboratedTypeLoc::initializeLocal(ASTContext &Context, - SourceLocation Loc) { - if (isEmpty()) - return; - initializeElaboratedKeyword(*this, Loc); - setQualifierLoc( - initializeQualifier(Context, getTypePtr()->getQualifier(), Loc)); -} - void DependentNameTypeLoc::initializeLocal(ASTContext &Context, SourceLocation Loc) { initializeElaboratedKeyword(*this, Loc); @@ -596,6 +704,78 @@ DependentTemplateSpecializationTypeLoc::initializeLocal(ASTContext &Context, Context, getTypePtr()->template_arguments(), getArgInfos(), Loc); } +void TemplateSpecializationTypeLoc::set(SourceLocation ElaboratedKeywordLoc, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateKeywordLoc, + SourceLocation NameLoc, + SourceLocation LAngleLoc, + SourceLocation RAngleLoc) { + TemplateSpecializationLocInfo &Data = *getLocalData(); + + Data.ElaboratedKWLoc = ElaboratedKeywordLoc; + SourceLocation BeginLoc = ElaboratedKeywordLoc; + + getLocalData()->QualifierData = QualifierLoc.getOpaqueData(); + + assert(QualifierLoc.getNestedNameSpecifier() == + getTypePtr()->getTemplateName().getQualifier()); + Data.QualifierData = QualifierLoc ? QualifierLoc.getOpaqueData() : nullptr; + if (QualifierLoc && !BeginLoc.isValid()) + BeginLoc = QualifierLoc.getBeginLoc(); + + Data.TemplateKWLoc = TemplateKeywordLoc; + if (!BeginLoc.isValid()) + BeginLoc = TemplateKeywordLoc; + + Data.NameLoc = NameLoc; + if (!BeginLoc.isValid()) + BeginLoc = NameLoc; + + Data.LAngleLoc = LAngleLoc; + Data.SR = SourceRange(BeginLoc, RAngleLoc); +} + +void TemplateSpecializationTypeLoc::set(SourceLocation ElaboratedKeywordLoc, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateKeywordLoc, + SourceLocation NameLoc, + const TemplateArgumentListInfo &TAL) { + set(ElaboratedKeywordLoc, QualifierLoc, TemplateKeywordLoc, NameLoc, + TAL.getLAngleLoc(), TAL.getRAngleLoc()); + MutableArrayRef<TemplateArgumentLocInfo> ArgInfos = getArgLocInfos(); + assert(TAL.size() == ArgInfos.size()); + for (unsigned I = 0, N = TAL.size(); I != N; ++I) + ArgInfos[I] = TAL[I].getLocInfo(); +} + +void TemplateSpecializationTypeLoc::initializeLocal(ASTContext &Context, + SourceLocation Loc) { + QualifiedTemplateName *Name = + getTypePtr()->getTemplateName().getAsAdjustedQualifiedTemplateName(); + + SourceLocation ElaboratedKeywordLoc = + getTypePtr()->getKeyword() != ElaboratedTypeKeyword::None + ? Loc + : SourceLocation(); + + NestedNameSpecifierLoc QualifierLoc; + if (NestedNameSpecifier Qualifier = + Name ? Name->getQualifier() : std::nullopt) { + NestedNameSpecifierLocBuilder Builder; + Builder.MakeTrivial(Context, Qualifier, Loc); + QualifierLoc = Builder.getWithLocInContext(Context); + } + + TemplateArgumentListInfo TAL(Loc, Loc); + set(ElaboratedKeywordLoc, QualifierLoc, + /*TemplateKeywordLoc=*/Name && Name->hasTemplateKeyword() + ? Loc + : SourceLocation(), + /*NameLoc=*/Loc, /*LAngleLoc=*/Loc, /*RAngleLoc=*/Loc); + initializeArgLocs(Context, getTypePtr()->template_arguments(), getArgInfos(), + Loc); +} + void TemplateSpecializationTypeLoc::initializeArgLocs( ASTContext &Context, ArrayRef<TemplateArgument> Args, TemplateArgumentLocInfo *ArgInfos, SourceLocation Loc) { @@ -631,7 +811,7 @@ void TemplateSpecializationTypeLoc::initializeArgLocs( Builder.MakeTrivial(Context, QTN->getQualifier(), Loc); ArgInfos[i] = TemplateArgumentLocInfo( - Context, Builder.getWithLocInContext(Context), Loc, + Context, Loc, Builder.getWithLocInContext(Context), Loc, Args[i].getKind() == TemplateArgument::Template ? SourceLocation() : Loc); break; @@ -680,6 +860,14 @@ void AutoTypeLoc::initializeLocal(ASTContext &Context, SourceLocation Loc) { } } +void DeducedTemplateSpecializationTypeLoc::initializeLocal(ASTContext &Context, + SourceLocation Loc) { + initializeElaboratedKeyword(*this, Loc); + setQualifierLoc(initializeQualifier( + Context, getTypePtr()->getTemplateName().getQualifier(), Loc)); + setTemplateNameLoc(Loc); +} + namespace { class GetContainedAutoTypeLocVisitor : @@ -693,10 +881,6 @@ namespace { // Only these types can contain the desired 'auto' type. - TypeLoc VisitElaboratedTypeLoc(ElaboratedTypeLoc T) { - return Visit(T.getNamedTypeLoc()); - } - TypeLoc VisitQualifiedTypeLoc(QualifiedTypeLoc T) { return Visit(T.getUnqualifiedLoc()); } diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index deb453f..ce5870e 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -133,7 +133,7 @@ public: void printAfter(QualType T, raw_ostream &OS); void AppendScope(DeclContext *DC, raw_ostream &OS, DeclarationName NameInScope); - void printTag(TagDecl *T, raw_ostream &OS); + void printTagType(const TagType *T, raw_ostream &OS); void printFunctionAfter(const FunctionType::ExtInfo &Info, raw_ostream &OS); #define ABSTRACT_TYPE(CLASS, PARENT) #define TYPE(CLASS, PARENT) \ @@ -230,7 +230,6 @@ bool TypePrinter::canPrefixQualifiers(const Type *T, case Type::UnaryTransform: case Type::Record: case Type::Enum: - case Type::Elaborated: case Type::TemplateTypeParm: case Type::SubstTemplateTypeParmPack: case Type::DeducedTemplateSpecialization: @@ -504,11 +503,7 @@ void TypePrinter::printMemberPointerBefore(const MemberPointerType *T, // FIXME: this should include vectors, but vectors use attributes I guess. if (isa<ArrayType>(T->getPointeeType())) OS << '('; - - PrintingPolicy InnerPolicy(Policy); - InnerPolicy.IncludeTagDefinition = false; - T->getQualifier()->print(OS, InnerPolicy); - + T->getQualifier().print(OS, Policy); OS << "*"; } @@ -1211,29 +1206,50 @@ void TypePrinter::printTypeSpec(NamedDecl *D, raw_ostream &OS) { void TypePrinter::printUnresolvedUsingBefore(const UnresolvedUsingType *T, raw_ostream &OS) { - printTypeSpec(T->getDecl(), OS); + OS << TypeWithKeyword::getKeywordName(T->getKeyword()); + if (T->getKeyword() != ElaboratedTypeKeyword::None) + OS << ' '; + auto *D = T->getDecl(); + if (Policy.FullyQualifiedName || T->isCanonicalUnqualified()) { + AppendScope(D->getDeclContext(), OS, D->getDeclName()); + } else { + T->getQualifier().print(OS, Policy); + } + OS << D->getIdentifier()->getName(); + spaceBeforePlaceHolder(OS); } void TypePrinter::printUnresolvedUsingAfter(const UnresolvedUsingType *T, raw_ostream &OS) {} void TypePrinter::printUsingBefore(const UsingType *T, raw_ostream &OS) { - // After `namespace b { using a::X }`, is the type X within B a::X or b::X? - // - // - b::X is more formally correct given the UsingType model - // - b::X makes sense if "re-exporting" a symbol in a new namespace - // - a::X makes sense if "importing" a symbol for convenience - // - // The "importing" use seems much more common, so we print a::X. - // This could be a policy option, but the right choice seems to rest more - // with the intent of the code than the caller. - printTypeSpec(T->getFoundDecl()->getUnderlyingDecl(), OS); + OS << TypeWithKeyword::getKeywordName(T->getKeyword()); + if (T->getKeyword() != ElaboratedTypeKeyword::None) + OS << ' '; + auto *D = T->getDecl(); + if (Policy.FullyQualifiedName) { + AppendScope(D->getDeclContext(), OS, D->getDeclName()); + } else { + T->getQualifier().print(OS, Policy); + } + OS << D->getIdentifier()->getName(); + spaceBeforePlaceHolder(OS); } void TypePrinter::printUsingAfter(const UsingType *T, raw_ostream &OS) {} void TypePrinter::printTypedefBefore(const TypedefType *T, raw_ostream &OS) { - printTypeSpec(T->getDecl(), OS); + OS << TypeWithKeyword::getKeywordName(T->getKeyword()); + if (T->getKeyword() != ElaboratedTypeKeyword::None) + OS << ' '; + auto *D = T->getDecl(); + if (Policy.FullyQualifiedName) { + AppendScope(D->getDeclContext(), OS, D->getDeclName()); + } else { + T->getQualifier().print(OS, Policy); + } + OS << D->getIdentifier()->getName(); + spaceBeforePlaceHolder(OS); } void TypePrinter::printMacroQualifiedBefore(const MacroQualifiedType *T, @@ -1354,14 +1370,53 @@ void TypePrinter::printAutoAfter(const AutoType *T, raw_ostream &OS) { void TypePrinter::printDeducedTemplateSpecializationBefore( const DeducedTemplateSpecializationType *T, raw_ostream &OS) { - // If the type has been deduced, print the deduced type. + if (ElaboratedTypeKeyword Keyword = T->getKeyword(); + T->getKeyword() != ElaboratedTypeKeyword::None) + OS << KeywordHelpers::getKeywordName(Keyword) << ' '; + + TemplateName Name = T->getTemplateName(); + + // If the type has been deduced, print the template arguments, as if this was + // printing the deduced type, but including elaboration and template name + // qualification. + // FIXME: There should probably be a policy which controls this. + // We would probably want to do this on diagnostics, but not on -ast-print. + ArrayRef<TemplateArgument> Args; + TemplateDecl *DeducedTD = nullptr; if (!T->getDeducedType().isNull()) { - printBefore(T->getDeducedType(), OS); - } else { + if (const auto *TST = + dyn_cast<TemplateSpecializationType>(T->getDeducedType())) { + DeducedTD = TST->getTemplateName().getAsTemplateDecl( + /*IgnoreDeduced=*/true); + Args = TST->template_arguments(); + } else { + // Should only get here for canonical types. + const auto *CD = cast<ClassTemplateSpecializationDecl>( + cast<RecordType>(T->getDeducedType())->getOriginalDecl()); + DeducedTD = CD->getSpecializedTemplate(); + Args = CD->getTemplateArgs().asArray(); + } + + // FIXME: Workaround for alias template CTAD not producing guides which + // include the alias template specialization type. + // Purposefully disregard qualification when building this TemplateName; + // any qualification we might have, might not make sense in the + // context this was deduced. + if (!declaresSameEntity(DeducedTD, Name.getAsTemplateDecl( + /*IgnoreDeduced=*/true))) + Name = TemplateName(DeducedTD); + } + + { IncludeStrongLifetimeRAII Strong(Policy); - T->getTemplateName().print(OS, Policy); - spaceBeforePlaceHolder(OS); + Name.print(OS, Policy); + } + if (DeducedTD) { + printTemplateArgumentList(OS, Args, Policy, + DeducedTD->getTemplateParameters()); } + + spaceBeforePlaceHolder(OS); } void TypePrinter::printDeducedTemplateSpecializationAfter( @@ -1480,30 +1535,37 @@ void TypePrinter::AppendScope(DeclContext *DC, raw_ostream &OS, } } -void TypePrinter::printTag(TagDecl *D, raw_ostream &OS) { - if (Policy.IncludeTagDefinition) { - PrintingPolicy SubPolicy = Policy; - SubPolicy.IncludeTagDefinition = false; - D->print(OS, SubPolicy, Indentation); +void TypePrinter::printTagType(const TagType *T, raw_ostream &OS) { + TagDecl *D = T->getOriginalDecl(); + + if (Policy.IncludeTagDefinition && T->isTagOwned()) { + D->print(OS, Policy, Indentation); spaceBeforePlaceHolder(OS); return; } bool HasKindDecoration = false; - // We don't print tags unless this is an elaborated type. - // In C, we just assume every RecordType is an elaborated type. - if (!Policy.SuppressTagKeyword && !D->getTypedefNameForAnonDecl()) { - HasKindDecoration = true; - OS << D->getKindName(); - OS << ' '; + if (T->isCanonicalUnqualified()) { + if (!Policy.SuppressTagKeyword && !D->getTypedefNameForAnonDecl()) { + HasKindDecoration = true; + OS << D->getKindName(); + OS << ' '; + } + } else { + OS << TypeWithKeyword::getKeywordName(T->getKeyword()); + if (T->getKeyword() != ElaboratedTypeKeyword::None) + OS << ' '; } - // Compute the full nested-name-specifier for this type. - // In C, this will always be empty except when the type - // being printed is anonymous within other Record. - if (!Policy.SuppressScope) + if (!Policy.FullyQualifiedName && !T->isCanonicalUnqualified()) { + T->getQualifier().print(OS, Policy); + } else if (!Policy.SuppressScope) { + // Compute the full nested-name-specifier for this type. + // In C, this will always be empty except when the type + // being printed is anonymous within other Record. AppendScope(D->getDeclContext(), OS, D->getDeclName()); + } if (const IdentifierInfo *II = D->getIdentifier()) OS << II->getName(); @@ -1578,9 +1640,11 @@ void TypePrinter::printTag(TagDecl *D, raw_ostream &OS) { void TypePrinter::printRecordBefore(const RecordType *T, raw_ostream &OS) { // Print the preferred name if we have one for this type. if (Policy.UsePreferredNames) { - for (const auto *PNA : T->getDecl()->specific_attrs<PreferredNameAttr>()) { + for (const auto *PNA : T->getOriginalDecl() + ->getMostRecentDecl() + ->specific_attrs<PreferredNameAttr>()) { if (!declaresSameEntity(PNA->getTypedefType()->getAsCXXRecordDecl(), - T->getDecl())) + T->getOriginalDecl())) continue; // Find the outermost typedef or alias template. QualType T = PNA->getTypedefType(); @@ -1594,17 +1658,44 @@ void TypePrinter::printRecordBefore(const RecordType *T, raw_ostream &OS) { } } - printTag(T->getDecl(), OS); + printTagType(T, OS); } void TypePrinter::printRecordAfter(const RecordType *T, raw_ostream &OS) {} void TypePrinter::printEnumBefore(const EnumType *T, raw_ostream &OS) { - printTag(T->getDecl(), OS); + printTagType(T, OS); } void TypePrinter::printEnumAfter(const EnumType *T, raw_ostream &OS) {} +void TypePrinter::printInjectedClassNameBefore(const InjectedClassNameType *T, + raw_ostream &OS) { + const ASTContext &Ctx = T->getOriginalDecl()->getASTContext(); + IncludeStrongLifetimeRAII Strong(Policy); + T->getTemplateName(Ctx).print(OS, Policy); + if (Policy.PrintInjectedClassNameWithArguments) { + auto *Decl = T->getOriginalDecl(); + // FIXME: Use T->getTemplateArgs(Ctx) when that supports as-written + // arguments. + if (auto *RD = dyn_cast<ClassTemplateSpecializationDecl>(Decl)) { + printTemplateArgumentList(OS, RD->getTemplateArgsAsWritten()->arguments(), + Policy, + T->getTemplateDecl()->getTemplateParameters()); + } else { + ClassTemplateDecl *TD = Decl->getDescribedClassTemplate(); + assert(TD); + printTemplateArgumentList( + OS, TD->getTemplateParameters()->getInjectedTemplateArgs(Ctx), Policy, + T->getTemplateDecl()->getTemplateParameters()); + } + } + spaceBeforePlaceHolder(OS); +} + +void TypePrinter::printInjectedClassNameAfter(const InjectedClassNameType *T, + raw_ostream &OS) {} + void TypePrinter::printTemplateTypeParmBefore(const TemplateTypeParmType *T, raw_ostream &OS) { TemplateTypeParmDecl *D = T->getDecl(); @@ -1671,6 +1762,10 @@ void TypePrinter::printTemplateId(const TemplateSpecializationType *T, raw_ostream &OS, bool FullyQualify) { IncludeStrongLifetimeRAII Strong(Policy); + if (ElaboratedTypeKeyword K = T->getKeyword(); + K != ElaboratedTypeKeyword::None) + OS << TypeWithKeyword::getKeywordName(K) << ' '; + TemplateDecl *TD = T->getTemplateName().getAsTemplateDecl(/*IgnoreDeduced=*/true); // FIXME: Null TD never exercised in test suite. @@ -1680,7 +1775,10 @@ void TypePrinter::printTemplateId(const TemplateSpecializationType *T, OS << TD->getName(); } else { - T->getTemplateName().print(OS, Policy, TemplateName::Qualified::None); + T->getTemplateName().print(OS, Policy, + !Policy.SuppressScope + ? TemplateName::Qualified::AsWritten + : TemplateName::Qualified::None); } DefaultTemplateArgsPolicyRAII TemplateArgs(Policy); @@ -1699,77 +1797,6 @@ void TypePrinter::printTemplateSpecializationAfter( const TemplateSpecializationType *T, raw_ostream &OS) {} -void TypePrinter::printInjectedClassNameBefore(const InjectedClassNameType *T, - raw_ostream &OS) { - if (Policy.PrintInjectedClassNameWithArguments) - return printTemplateSpecializationBefore(T->getInjectedTST(), OS); - - IncludeStrongLifetimeRAII Strong(Policy); - T->getTemplateName().print(OS, Policy); - spaceBeforePlaceHolder(OS); -} - -void TypePrinter::printInjectedClassNameAfter(const InjectedClassNameType *T, - 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; - } - - if (Policy.SuppressElaboration) { - printBefore(T->getNamedType(), OS); - return; - } - - // The tag definition will take care of these. - if (!Policy.IncludeTagDefinition) - { - OS << TypeWithKeyword::getKeywordName(T->getKeyword()); - if (T->getKeyword() != ElaboratedTypeKeyword::None) - OS << " "; - NestedNameSpecifier *Qualifier = T->getQualifier(); - if (!Policy.SuppressTagKeyword && Policy.SuppressScope && - !Policy.SuppressUnwrittenScope) { - bool OldTagKeyword = Policy.SuppressTagKeyword; - bool OldSupressScope = Policy.SuppressScope; - Policy.SuppressTagKeyword = true; - Policy.SuppressScope = false; - printBefore(T->getNamedType(), OS); - Policy.SuppressTagKeyword = OldTagKeyword; - Policy.SuppressScope = OldSupressScope; - return; - } - if (Qualifier) - Qualifier->print(OS, Policy); - } - - ElaboratedTypePolicyRAII PolicyRAII(Policy); - printBefore(T->getNamedType(), OS); -} - -void TypePrinter::printElaboratedAfter(const ElaboratedType *T, - raw_ostream &OS) { - if (Policy.IncludeTagDefinition && T->getOwnedTagDecl()) - return; - - if (Policy.SuppressElaboration) { - printAfter(T->getNamedType(), OS); - return; - } - - ElaboratedTypePolicyRAII PolicyRAII(Policy); - printAfter(T->getNamedType(), OS); -} - void TypePrinter::printParenBefore(const ParenType *T, raw_ostream &OS) { if (!HasEmptyPlaceHolder && !isa<FunctionType>(T->getInnerType())) { printBefore(T->getInnerType(), OS); @@ -1791,9 +1818,7 @@ void TypePrinter::printDependentNameBefore(const DependentNameType *T, OS << TypeWithKeyword::getKeywordName(T->getKeyword()); if (T->getKeyword() != ElaboratedTypeKeyword::None) OS << " "; - - T->getQualifier()->print(OS, Policy); - + T->getQualifier().print(OS, Policy); OS << T->getIdentifier()->getName(); spaceBeforePlaceHolder(OS); } diff --git a/clang/lib/AST/VTTBuilder.cpp b/clang/lib/AST/VTTBuilder.cpp index de01184..85101ae 100644 --- a/clang/lib/AST/VTTBuilder.cpp +++ b/clang/lib/AST/VTTBuilder.cpp @@ -64,7 +64,9 @@ void VTTBuilder::LayoutSecondaryVTTs(BaseSubobject Base) { continue; const auto *BaseDecl = - cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl()); + cast<CXXRecordDecl>( + I.getType()->castAs<RecordType>()->getOriginalDecl()) + ->getDefinitionOrSelf(); const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD); CharUnits BaseOffset = Base.getBaseOffset() + @@ -90,7 +92,9 @@ VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base, for (const auto &I : RD->bases()) { const auto *BaseDecl = - cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl()); + cast<CXXRecordDecl>( + I.getType()->castAs<RecordType>()->getOriginalDecl()) + ->getDefinitionOrSelf(); // Itanium C++ ABI 2.6.2: // Secondary virtual pointers are present for all bases with either @@ -154,7 +158,9 @@ void VTTBuilder::LayoutVirtualVTTs(const CXXRecordDecl *RD, VisitedVirtualBasesSetTy &VBases) { for (const auto &I : RD->bases()) { const auto *BaseDecl = - cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl()); + cast<CXXRecordDecl>( + I.getType()->castAs<RecordType>()->getOriginalDecl()) + ->getDefinitionOrSelf(); // Check if this is a virtual base. if (I.isVirtual()) { diff --git a/clang/lib/AST/VTableBuilder.cpp b/clang/lib/AST/VTableBuilder.cpp index 0001745..6cec526 100644 --- a/clang/lib/AST/VTableBuilder.cpp +++ b/clang/lib/AST/VTableBuilder.cpp @@ -313,10 +313,12 @@ ComputeReturnAdjustmentBaseOffset(ASTContext &Context, } const CXXRecordDecl *DerivedRD = - cast<CXXRecordDecl>(cast<RecordType>(CanDerivedReturnType)->getDecl()); + cast<CXXRecordDecl>( + cast<RecordType>(CanDerivedReturnType)->getOriginalDecl()) + ->getDefinitionOrSelf(); - const CXXRecordDecl *BaseRD = - cast<CXXRecordDecl>(cast<RecordType>(CanBaseReturnType)->getDecl()); + const CXXRecordDecl *BaseRD = cast<CXXRecordDecl>( + cast<RecordType>(CanBaseReturnType)->getOriginalDecl()); return ComputeBaseOffset(Context, BaseRD, DerivedRD); } |