diff options
Diffstat (limited to 'clang/lib/AST')
84 files changed, 5220 insertions, 3830 deletions
diff --git a/clang/lib/AST/APValue.cpp b/clang/lib/AST/APValue.cpp index ee3dc84..7173c2a 100644 --- a/clang/lib/AST/APValue.cpp +++ b/clang/lib/AST/APValue.cpp @@ -902,8 +902,8 @@ void APValue::printPretty(raw_ostream &Out, const PrintingPolicy &Policy, } case APValue::Struct: { Out << '{'; - const RecordDecl *RD = Ty->castAs<RecordType>()->getDecl(); bool First = true; + const auto *RD = Ty->castAsRecordDecl(); 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..dca05b4 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -654,9 +654,9 @@ 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 (comments::FullComment *FC = getCommentForDecl(TD, PP)) - return cloneFullComment(FC, D); + if (comments::FullComment *FC = + getCommentForDecl(TT->getOriginalDecl(), PP)) + return cloneFullComment(FC, D); } else if (const auto *IC = dyn_cast<ObjCInterfaceDecl>(D)) { while (IC->getSuperClass()) { @@ -1708,7 +1708,7 @@ void ASTContext::setRelocationInfoForCXXRecord( } static bool primaryBaseHaseAddressDiscriminatedVTableAuthentication( - ASTContext &Context, const CXXRecordDecl *Class) { + const ASTContext &Context, const CXXRecordDecl *Class) { if (!Class->isPolymorphic()) return false; const CXXRecordDecl *BaseType = Context.baseForVTableAuthentication(Class); @@ -1723,7 +1723,8 @@ static bool primaryBaseHaseAddressDiscriminatedVTableAuthentication( return AddressDiscrimination == AuthAttr::AddressDiscrimination; } -ASTContext::PointerAuthContent ASTContext::findPointerAuthContent(QualType T) { +ASTContext::PointerAuthContent +ASTContext::findPointerAuthContent(QualType T) const { assert(isPointerAuthenticationAvailable()); T = T.getCanonicalType(); @@ -1933,9 +1934,8 @@ 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()); + if (const auto *RD = T->getAsCXXRecordDecl(); RD && !RD->isInvalidDecl()) { + const ASTRecordLayout &layout = getASTRecordLayout(RD); Info.Width = layout.getDataSize(); } } @@ -2002,9 +2002,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()) + if (const auto *ED = T->getAsEnumDecl()) { + if (T->isDependentType() || ED->getPromotionType().isNull() || + ED->isScoped()) return false; return true; @@ -2040,8 +2040,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 +2472,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 +2491,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 +2543,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()); @@ -2618,11 +2615,10 @@ unsigned ASTContext::getTypeUnadjustedAlign(const Type *T) const { return I->second; unsigned UnadjustedAlign; - if (const auto *RT = T->getAs<RecordType>()) { - const RecordDecl *RD = RT->getDecl(); - const ASTRecordLayout &Layout = getASTRecordLayout(RD); + if (const auto *RT = T->getAsCanonical<RecordType>()) { + const ASTRecordLayout &Layout = getASTRecordLayout(RT->getOriginalDecl()); UnadjustedAlign = toBits(Layout.getUnadjustedAlignment()); - } else if (const auto *ObjCI = T->getAs<ObjCInterfaceType>()) { + } else if (const auto *ObjCI = T->getAsCanonical<ObjCInterfaceType>()) { const ASTRecordLayout &Layout = getASTObjCInterfaceLayout(ObjCI->getDecl()); UnadjustedAlign = toBits(Layout.getUnadjustedAlignment()); } else { @@ -2695,9 +2691,7 @@ unsigned ASTContext::getPreferredTypeAlign(const Type *T) const { if (!Target->allowsLargerPreferedTypeAlignment()) return ABIAlign; - if (const auto *RT = T->getAs<RecordType>()) { - const RecordDecl *RD = RT->getDecl(); - + if (const auto *RD = T->getAsRecordDecl()) { // 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 // 'packed' case is already taken into consideration when computing the @@ -2718,8 +2712,8 @@ unsigned ASTContext::getPreferredTypeAlign(const Type *T) const { // possible. if (const auto *CT = T->getAs<ComplexType>()) T = CT->getElementType().getTypePtr(); - if (const auto *ET = T->getAs<EnumType>()) - T = ET->getDecl()->getIntegerType().getTypePtr(); + if (const auto *ED = T->getAsEnumDecl()) + T = ED->getIntegerType().getTypePtr(); if (T->isSpecificBuiltinType(BuiltinType::Double) || T->isSpecificBuiltinType(BuiltinType::LongLong) || T->isSpecificBuiltinType(BuiltinType::ULongLong) || @@ -2851,7 +2845,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(), @@ -2884,12 +2879,10 @@ structHasUniqueObjectRepresentations(const ASTContext &Context, static std::optional<int64_t> getSubobjectSizeInBits(const FieldDecl *Field, const ASTContext &Context, bool CheckIfTriviallyCopyable) { - if (Field->getType()->isRecordType()) { - const RecordDecl *RD = Field->getType()->getAsRecordDecl(); - if (!RD->isUnion()) - return structHasUniqueObjectRepresentations(Context, RD, - CheckIfTriviallyCopyable); - } + if (const auto *RD = Field->getType()->getAsRecordDecl(); + RD && !RD->isUnion()) + return structHasUniqueObjectRepresentations(Context, RD, + CheckIfTriviallyCopyable); // A _BitInt type may not be unique if it has padding bits // but if it is a bitfield the padding bits are not used. @@ -3037,16 +3030,14 @@ bool ASTContext::hasUniqueObjectRepresentations( return true; } - // All other pointers (except __ptrauth pointers) are unique. + // All other pointers are unique. if (Ty->isPointerType()) return !Ty.hasAddressDiscriminatedPointerAuth(); if (const auto *MPT = Ty->getAs<MemberPointerType>()) return !ABI->getMemberPointerInfo(MPT).HasPadding; - if (Ty->isRecordType()) { - const RecordDecl *Record = Ty->castAs<RecordType>()->getDecl(); - + if (const auto *Record = Ty->getAsRecordDecl()) { if (Record->isInvalidDecl()) return false; @@ -3418,7 +3409,7 @@ 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 = T->castAsEnumDecl()->getIntegerType(); return encodeTypeForFunctionPointerAuth( Ctx, OS, UnderlyingType.isNull() ? Ctx.IntTy : UnderlyingType); } @@ -3456,7 +3447,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 +3553,7 @@ 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->castAsCanonical<RecordType>()->getOriginalDecl(); const IdentifierInfo *II = RD->getIdentifier(); // In C++, an immediate typedef of an anonymous struct or union @@ -3740,12 +3731,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 +4148,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 +4166,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 @@ -4306,6 +4289,7 @@ QualType ASTContext::getVariableArrayDecayedType(QualType type) const { case Type::DependentTemplateSpecialization: case Type::TemplateTypeParm: case Type::SubstTemplateTypeParmPack: + case Type::SubstBuiltinTemplatePack: case Type::Auto: case Type::DeducedTemplateSpecialization: case Type::PackExpansion: @@ -5128,10 +5112,12 @@ QualType ASTContext::getFunctionTypeInternal( EPI.ExceptionSpec.Type, EPI.ExceptionSpec.Exceptions.size()); size_t Size = FunctionProtoType::totalSizeToAlloc< QualType, SourceLocation, FunctionType::FunctionTypeExtraBitfields, + FunctionType::FunctionTypeExtraAttributeInfo, FunctionType::FunctionTypeArmAttributes, FunctionType::ExceptionType, Expr *, FunctionDecl *, FunctionProtoType::ExtParameterInfo, Qualifiers, FunctionEffect, EffectConditionExpr>( NumArgs, EPI.Variadic, EPI.requiresFunctionProtoTypeExtraBitfields(), + EPI.requiresFunctionProtoTypeExtraAttributeInfo(), EPI.requiresFunctionProtoTypeArmAttributes(), ESH.NumExceptionType, ESH.NumExprPtr, ESH.NumFunctionDeclPtr, EPI.ExtParameterInfos ? NumArgs : 0, @@ -5245,7 +5231,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 +5239,296 @@ 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 const TagDecl *getNonInjectedClassName(const TagDecl *TD) { + if (const auto *RD = dyn_cast<CXXRecordDecl>(TD); + RD && RD->isInjectedClassName()) + return cast<TagDecl>(RD->getDeclContext()); + return TD; } -QualType ASTContext::getEnumType(const EnumDecl *Decl) const { - if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0); +CanQualType ASTContext::getCanonicalTagType(const TagDecl *TD) const { + TD = ::getNonInjectedClassName(TD)->getCanonicalDecl(); + if (TD->TypeForDecl) + return TD->TypeForDecl->getCanonicalTypeUnqualified(); - if (const EnumDecl *PrevDecl = Decl->getPreviousDecl()) - if (PrevDecl->TypeForDecl) - return QualType(Decl->TypeForDecl = PrevDecl->TypeForDecl, 0); + 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)); +} - auto *newType = new (*this, alignof(EnumType)) EnumType(Decl); - Decl->TypeForDecl = newType; - Types.push_back(newType); - return QualType(newType, 0); +QualType ASTContext::getTagType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, + const TagDecl *TD, bool OwnsTag) const { + + const TagDecl *NonInjectedTD = ::getNonInjectedClassName(TD); + bool IsInjected = TD != NonInjectedTD; + + ElaboratedTypeKeyword PreferredKeyword = + getLangOpts().CPlusPlus ? ElaboratedTypeKeyword::None + : KeywordHelpers::getKeywordForTagTypeKind( + NonInjectedTD->getTagKind()); + + if (Keyword == PreferredKeyword && !Qualifier && !OwnsTag) { + if (const Type *T = TD->TypeForDecl; T && !T->isCanonicalUnqualified()) + return QualType(T, 0); + + const Type *CanonicalType = getCanonicalTagType(NonInjectedTD).getTypePtr(); + const Type *T = + getTagTypeInternal(Keyword, + /*Qualifier=*/std::nullopt, NonInjectedTD, + /*OwnsTag=*/false, IsInjected, CanonicalType, + /*WithFoldingSetNode=*/false); + TD->TypeForDecl = T; + return QualType(T, 0); + } + + llvm::FoldingSetNodeID ID; + TagTypeFoldingSetPlaceholder::Profile(ID, Keyword, Qualifier, NonInjectedTD, + OwnsTag, IsInjected); + + void *InsertPos = nullptr; + if (TagTypeFoldingSetPlaceholder *T = + TagTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(T->getTagType(), 0); + + const Type *CanonicalType = getCanonicalTagType(NonInjectedTD).getTypePtr(); + TagType *T = + getTagTypeInternal(Keyword, Qualifier, NonInjectedTD, OwnsTag, IsInjected, + CanonicalType, /*WithFoldingSetNode=*/true); + TagTypes.InsertNode(TagTypeFoldingSetPlaceholder::fromTagType(T), InsertPos); + return QualType(T, 0); } bool ASTContext::computeBestEnumTypes(bool IsPacked, unsigned NumNegativeBits, @@ -5495,21 +5623,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, @@ -5655,7 +5831,6 @@ QualType ASTContext::getSubstTemplateTypeParmType(QualType Replacement, return QualType(SubstParm, 0); } -/// Retrieve a QualType ASTContext::getSubstTemplateTypeParmPackType(Decl *AssociatedDecl, unsigned Index, bool Final, @@ -5694,6 +5869,34 @@ ASTContext::getSubstTemplateTypeParmPackType(Decl *AssociatedDecl, return QualType(SubstParm, 0); } +QualType +ASTContext::getSubstBuiltinTemplatePack(const TemplateArgument &ArgPack) { + assert(llvm::all_of(ArgPack.pack_elements(), + [](const auto &P) { + return P.getKind() == TemplateArgument::Type; + }) && + "Pack contains a non-type"); + + llvm::FoldingSetNodeID ID; + SubstBuiltinTemplatePackType::Profile(ID, ArgPack); + + void *InsertPos = nullptr; + if (auto *T = + SubstBuiltinTemplatePackTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(T, 0); + + QualType Canon; + TemplateArgument CanonArgPack = getCanonicalTemplateArgument(ArgPack); + if (!CanonArgPack.structurallyEquals(ArgPack)) + Canon = getSubstBuiltinTemplatePack(CanonArgPack); + + auto *PackType = new (*this, alignof(SubstBuiltinTemplatePackType)) + SubstBuiltinTemplatePackType(Canon, ArgPack); + Types.push_back(PackType); + SubstBuiltinTemplatePackTypes.InsertNode(PackType, InsertPos); + return QualType(PackType, 0); +} + /// Retrieve the template type parameter type for a template /// parameter or parameter pack with the given depth, index, and (optionally) /// name. @@ -5729,34 +5932,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 +5988,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 +5998,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 +6009,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 +6041,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 +6109,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 +6121,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 +6159,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 +6180,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 +6236,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 +6509,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 +6912,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 +6941,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 +7004,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 +7225,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 +7383,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 +7601,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 +8027,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()) { @@ -8228,8 +8344,8 @@ QualType ASTContext::isPromotableBitField(Expr *E) const { QualType ASTContext::getPromotedIntegerType(QualType Promotable) const { assert(!Promotable.isNull()); assert(isPromotableIntegerType(Promotable)); - if (const auto *ET = Promotable->getAs<EnumType>()) - return ET->getDecl()->getPromotionType(); + if (const auto *ED = Promotable->getAsEnumDecl()) + return ED->getPromotionType(); if (const auto *BT = Promotable->getAs<BuiltinType>()) { // C++ [conv.prom]: A prvalue of type char16_t, char32_t, or wchar_t @@ -8288,8 +8404,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 +8535,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,28 +8550,28 @@ 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; } 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(); + const auto *TT = T->castAs<TypedefType>(); + CFConstantStringTypeDecl = cast<TypedefDecl>(TT->getDecl()); + CFConstantStringTagDecl = TT->castAsRecordDecl(); } QualType ASTContext::getBlockDescriptorType() const { if (BlockDescriptorType) - return getTagDeclType(BlockDescriptorType); + return getCanonicalTagType(BlockDescriptorType); RecordDecl *RD; // FIXME: Needs the FlagAppleBlock bit. @@ -8484,12 +8601,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 +8640,7 @@ QualType ASTContext::getBlockDescriptorExtendedType() const { RD->completeDefinition(); BlockDescriptorExtendedType = RD; - return getTagDeclType(BlockDescriptorExtendedType); + return getCanonicalTagType(BlockDescriptorExtendedType); } OpenCLTypeKind ASTContext::getOpenCLTypeKind(const Type *T) const { @@ -9160,8 +9277,8 @@ static char getObjCEncodingForPrimitiveType(const ASTContext *C, llvm_unreachable("invalid BuiltinType::Kind value"); } -static char ObjCEncodingForEnumType(const ASTContext *C, const EnumType *ET) { - EnumDecl *Enum = ET->getDecl(); +static char ObjCEncodingForEnumDecl(const ASTContext *C, const EnumDecl *ED) { + EnumDecl *Enum = ED->getDefinitionOrSelf(); // The encoding of an non-fixed enum type is always 'i', regardless of size. if (!Enum->isFixed()) @@ -9204,8 +9321,8 @@ static void EncodeBitField(const ASTContext *Ctx, std::string& S, S += llvm::utostr(Offset); - if (const auto *ET = T->getAs<EnumType>()) - S += ObjCEncodingForEnumType(Ctx, ET); + if (const auto *ET = T->getAsCanonical<EnumType>()) + S += ObjCEncodingForEnumDecl(Ctx, ET->getOriginalDecl()); else { const auto *BT = T->castAs<BuiltinType>(); S += getObjCEncodingForPrimitiveType(Ctx, BT); @@ -9262,7 +9379,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S, if (const auto *BT = dyn_cast<BuiltinType>(CT)) S += getObjCEncodingForPrimitiveType(this, BT); else - S += ObjCEncodingForEnumType(this, cast<EnumType>(CT)); + S += ObjCEncodingForEnumDecl(this, cast<EnumType>(CT)->getOriginalDecl()); return; case Type::Complex: @@ -9329,14 +9446,15 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S, S += '*'; return; } - } else if (const auto *RTy = PointeeTy->getAs<RecordType>()) { + } else if (const auto *RTy = PointeeTy->getAsCanonical<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 +9519,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 +10018,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 +10070,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 +10130,7 @@ CreateX86_64ABIBuiltinVaListDecl(const ASTContext *Context) { } VaListTagDecl->completeDefinition(); Context->VaListTagDecl = VaListTagDecl; - QualType VaListTagType = Context->getRecordType(VaListTagDecl); + CanQualType VaListTagType = Context->getCanonicalTagType(VaListTagDecl); // }; @@ -10059,7 +10178,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 +10225,7 @@ CreateSystemZBuiltinVaListDecl(const ASTContext *Context) { } VaListTagDecl->completeDefinition(); Context->VaListTagDecl = VaListTagDecl; - QualType VaListTagType = Context->getRecordType(VaListTagDecl); + CanQualType VaListTagType = Context->getCanonicalTagType(VaListTagDecl); // }; @@ -10153,13 +10272,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 +10318,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,22 +10432,28 @@ 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 || Template.getKind() == TemplateName::UsingTemplate); + if (Template.getAsTemplateDecl()->getKind() == Decl::TemplateTemplateParm) { + assert(!Qualifier && "unexpected qualified template template parameter"); + assert(TemplateKeyword == false); + return Template; + } + // 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 +11423,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(); @@ -11442,6 +11569,11 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, if (lproto->getMethodQuals() != rproto->getMethodQuals()) return {}; + // Function protos with different 'cfi_salt' values aren't compatible. + if (lproto->getExtraAttributeInfo().CFISalt != + rproto->getExtraAttributeInfo().CFISalt) + return {}; + // Function effects are handled similarly to noreturn, see above. FunctionEffectsRef LHSFX = lproto->getFunctionEffects(); FunctionEffectsRef RHSFX = rproto->getFunctionEffects(); @@ -11527,8 +11659,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(); + if (const auto *ED = paramTy->getAsEnumDecl()) { + paramTy = ED->getIntegerType(); if (paramTy.isNull()) return {}; } @@ -11560,7 +11692,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)) @@ -11685,10 +11818,10 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, bool OfBlockPointer, if (LHSClass != RHSClass) { // Note that we only have special rules for turning block enum // returns into block int returns, not vice-versa. - if (const auto *ETy = LHS->getAs<EnumType>()) { + if (const auto *ETy = LHS->getAsCanonical<EnumType>()) { return mergeEnumWithInteger(*this, ETy, RHS, false); } - if (const EnumType* ETy = RHS->getAs<EnumType>()) { + if (const EnumType *ETy = RHS->getAsCanonical<EnumType>()) { return mergeEnumWithInteger(*this, ETy, LHS, BlockReturnType); } // allow block pointer type to match an 'id' type. @@ -12118,8 +12251,8 @@ QualType ASTContext::mergeObjCGCQualifiers(QualType LHS, QualType RHS) { //===----------------------------------------------------------------------===// unsigned ASTContext::getIntWidth(QualType T) const { - if (const auto *ET = T->getAs<EnumType>()) - T = ET->getDecl()->getIntegerType(); + if (const auto *ED = T->getAsEnumDecl()) + T = ED->getIntegerType(); if (T->isBooleanType()) return 1; if (const auto *EIT = T->getAs<BitIntType>()) @@ -12144,8 +12277,8 @@ 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(); + if (const auto *ED = T->getAsEnumDecl()) + T = ED->getIntegerType(); switch (T->castAs<BuiltinType>()->getKind()) { case BuiltinType::Char_U: @@ -12218,8 +12351,8 @@ 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(); + if (const auto *ED = T->getAsEnumDecl()) + T = ED->getIntegerType(); switch (T->castAs<BuiltinType>()->getKind()) { case BuiltinType::Char_S: @@ -12980,6 +13113,14 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) { if (D->hasAttr<WeakRefAttr>()) return false; + // SYCL device compilation requires that functions defined with the + // sycl_kernel_entry_point or sycl_external attributes be emitted. All + // other entities are emitted only if they are used by a function + // defined with one of those attributes. + if (LangOpts.SYCLIsDevice) + return isa<FunctionDecl>(D) && (D->hasAttr<SYCLKernelEntryPointAttr>() || + D->hasAttr<SYCLExternalAttr>()); + // Aliases and used decls are required. if (D->hasAttr<AliasAttr>() || D->hasAttr<UsedAttr>()) return true; @@ -12989,15 +13130,6 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) { if (!FD->doesThisDeclarationHaveABody()) return FD->doesDeclarationForceExternallyVisibleDefinition(); - // Function definitions with the sycl_kernel_entry_point attribute are - // required during device compilation so that SYCL kernel caller offload - // entry points are emitted. - if (LangOpts.SYCLIsDevice && FD->hasAttr<SYCLKernelEntryPointAttr>()) - return true; - - // FIXME: Functions declared with SYCL_EXTERNAL are required during - // device compilation. - // Constructors and destructors are required. if (FD->hasAttr<ConstructorAttr>() || FD->hasAttr<DestructorAttr>()) return true; @@ -13573,7 +13705,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 +13720,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 +13728,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 +13743,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 +13789,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 +13804,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 +13815,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 +13926,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 +13952,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 +13973,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 +14037,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,11 +14055,10 @@ 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(SubstBuiltinTemplatePack) SUGAR_FREE_TYPE(UnresolvedUsing) SUGAR_FREE_TYPE(HLSLAttributedResource) SUGAR_FREE_TYPE(HLSLInlineSpirv) @@ -14203,13 +14275,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 +14291,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 +14319,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 +14335,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 +14376,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 +14488,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 +14531,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 +14574,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 +14638,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; @@ -15119,7 +15189,7 @@ StringRef ASTContext::getCUIDHash() const { } const CXXRecordDecl * -ASTContext::baseForVTableAuthentication(const CXXRecordDecl *ThisClass) { +ASTContext::baseForVTableAuthentication(const CXXRecordDecl *ThisClass) const { assert(ThisClass); assert(ThisClass->isPolymorphic()); const CXXRecordDecl *PrimaryBase = ThisClass; 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..6299efa 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); +} - return Importer.getToContext().getTagDeclType(*ToDeclOrErr); +ExpectedType ASTNodeImporter::VisitRecordType(const RecordType *T) { + return VisitTagType(T); +} + +ExpectedType +ASTNodeImporter::VisitInjectedClassNameType(const InjectedClassNameType *T) { + return VisitTagType(T); } ExpectedType ASTNodeImporter::VisitAttributedType(const AttributedType *T) { @@ -1834,6 +1842,14 @@ ExpectedType ASTNodeImporter::VisitSubstTemplateTypeParmPackType( *ReplacedOrErr, T->getIndex(), T->getFinal(), *ToArgumentPack); } +ExpectedType ASTNodeImporter::VisitSubstBuiltinTemplatePackType( + const SubstBuiltinTemplatePackType *T) { + Expected<TemplateArgument> ToArgumentPack = import(T->getArgumentPack()); + if (!ToArgumentPack) + return ToArgumentPack.takeError(); + return Importer.getToContext().getSubstBuiltinTemplatePack(*ToArgumentPack); +} + ExpectedType ASTNodeImporter::VisitTemplateSpecializationType( const TemplateSpecializationType *T) { auto ToTemplateOrErr = import(T->getTemplateName()); @@ -1850,27 +1866,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 +2165,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 +2418,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 +2640,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 +3215,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 +3346,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 +3425,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 +3444,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 +3767,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 +3784,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 +6457,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 +9980,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 +10021,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 +10656,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..1292c30 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 = cast<EnumType>(T1)->getOriginalDecl()->getIntegerType(); assert(T2->isBuiltinType() && !T1.isNull()); // Sanity check } else if (T2->getTypeClass() == Type::Enum) { - T2 = T2->getAs<EnumType>()->getDecl()->getIntegerType(); + T2 = cast<EnumType>(T2)->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); @@ -1322,6 +1337,14 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, break; } + case Type::SubstBuiltinTemplatePack: { + const auto *Subst1 = cast<SubstBuiltinTemplatePackType>(T1); + const auto *Subst2 = cast<SubstBuiltinTemplatePackType>(T2); + if (!IsStructurallyEquivalent(Context, Subst1->getArgumentPack(), + Subst2->getArgumentPack())) + return false; + break; + } case Type::SubstTemplateTypeParmPack: { const auto *Subst1 = cast<SubstTemplateTypeParmPackType>(T1); const auto *Subst2 = cast<SubstTemplateTypeParmPackType>(T2); @@ -1348,33 +1371,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 +1545,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 +1624,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 +1797,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 +1899,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 +1920,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 +1936,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 +1958,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 +1971,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 +1985,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 +1997,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 +2009,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 +2020,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 +2037,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 +2097,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 +2120,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 +2158,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 +2176,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 +2194,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 +2591,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 +2613,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 cc99efa..56552f3 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -60,16 +60,18 @@ template <class Emitter> class OptionScope final { public: /// Root constructor, compiling or discarding primitives. OptionScope(Compiler<Emitter> *Ctx, bool NewDiscardResult, - bool NewInitializing) + bool NewInitializing, bool NewToLValue) : Ctx(Ctx), OldDiscardResult(Ctx->DiscardResult), - OldInitializing(Ctx->Initializing) { + OldInitializing(Ctx->Initializing), OldToLValue(Ctx->ToLValue) { Ctx->DiscardResult = NewDiscardResult; Ctx->Initializing = NewInitializing; + Ctx->ToLValue = NewToLValue; } ~OptionScope() { Ctx->DiscardResult = OldDiscardResult; Ctx->Initializing = OldInitializing; + Ctx->ToLValue = OldToLValue; } private: @@ -78,6 +80,7 @@ private: /// Old discard flag to restore. bool OldDiscardResult; bool OldInitializing; + bool OldToLValue; }; template <class Emitter> @@ -222,6 +225,9 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) { switch (CE->getCastKind()) { case CK_LValueToRValue: { + if (ToLValue && CE->getType()->isPointerType()) + return this->delegate(SubExpr); + if (SubExpr->getType().isVolatileQualified()) return this->emitInvalidCast(CastKind::Volatile, /*Fatal=*/true, CE); @@ -250,7 +256,7 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) { // Prepare storage for the result. if (!Initializing && !SubExprT) { - std::optional<unsigned> LocalIndex = allocateLocal(SubExpr); + UnsignedOrNone LocalIndex = allocateLocal(SubExpr); if (!LocalIndex) return false; if (!this->emitGetPtrLocal(*LocalIndex, CE)) @@ -553,9 +559,9 @@ 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 *ED = CE->getType()->castAsEnumDecl(); + if (!ED->isFixed()) { + if (!this->emitCheckEnumValue(*FromT, ED, CE)) return false; } } @@ -602,7 +608,7 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) { // We're creating a complex value here, so we need to // allocate storage for it. if (!Initializing) { - std::optional<unsigned> LocalIndex = allocateTemporary(CE); + UnsignedOrNone LocalIndex = allocateTemporary(CE); if (!LocalIndex) return false; if (!this->emitGetPtrLocal(*LocalIndex, CE)) @@ -626,7 +632,7 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) { assert(CE->getType()->isAnyComplexType()); assert(SubExpr->getType()->isAnyComplexType()); if (!Initializing) { - std::optional<unsigned> LocalIndex = allocateLocal(CE); + UnsignedOrNone LocalIndex = allocateLocal(CE); if (!LocalIndex) return false; if (!this->emitGetPtrLocal(*LocalIndex, CE)) @@ -666,12 +672,12 @@ 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) { - std::optional<unsigned> LocalIndex = allocateLocal(CE); + UnsignedOrNone LocalIndex = allocateLocal(CE); if (!LocalIndex) return false; if (!this->emitGetPtrLocal(*LocalIndex, CE)) @@ -715,7 +721,7 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) { assert(CE->getType()->isVectorType()); if (!Initializing) { - std::optional<unsigned> LocalIndex = allocateTemporary(CE); + UnsignedOrNone LocalIndex = allocateTemporary(CE); if (!LocalIndex) return false; if (!this->emitGetPtrLocal(*LocalIndex, CE)) @@ -803,7 +809,7 @@ bool Compiler<Emitter>::VisitImaginaryLiteral(const ImaginaryLiteral *E) { return true; if (!Initializing) { - std::optional<unsigned> LocalIndex = allocateTemporary(E); + UnsignedOrNone LocalIndex = allocateTemporary(E); if (!LocalIndex) return false; if (!this->emitGetPtrLocal(*LocalIndex, E)) @@ -904,7 +910,7 @@ bool Compiler<Emitter>::VisitBinaryOperator(const BinaryOperator *BO) { // We need a temporary variable holding our return value. if (!Initializing) { - std::optional<unsigned> ResultIndex = this->allocateLocal(BO); + UnsignedOrNone ResultIndex = this->allocateLocal(BO); if (!this->emitGetPtrLocal(*ResultIndex, BO)) return false; } @@ -936,7 +942,7 @@ bool Compiler<Emitter>::VisitBinaryOperator(const BinaryOperator *BO) { if (!Result) return false; if (DiscardResult) - return this->emitPop(*T, BO); + return this->emitPopBool(BO); if (T != PT_Bool) return this->emitCast(PT_Bool, *T, BO); return true; @@ -1144,7 +1150,7 @@ template <class Emitter> bool Compiler<Emitter>::VisitComplexBinOp(const BinaryOperator *E) { // Prepare storage for result. if (!Initializing) { - std::optional<unsigned> LocalIndex = allocateTemporary(E); + UnsignedOrNone LocalIndex = allocateTemporary(E); if (!LocalIndex) return false; if (!this->emitGetPtrLocal(*LocalIndex, E)) @@ -1203,7 +1209,7 @@ bool Compiler<Emitter>::VisitComplexBinOp(const BinaryOperator *E) { if (!LHSIsComplex) { // This is using the RHS type for the fake-complex LHS. - std::optional<unsigned> LocalIndex = allocateTemporary(RHS); + UnsignedOrNone LocalIndex = allocateTemporary(RHS); if (!LocalIndex) return false; LHSOffset = *LocalIndex; @@ -1370,23 +1376,27 @@ bool Compiler<Emitter>::VisitComplexBinOp(const BinaryOperator *E) { template <class Emitter> bool Compiler<Emitter>::VisitVectorBinOp(const BinaryOperator *E) { + const Expr *LHS = E->getLHS(); + const Expr *RHS = E->getRHS(); assert(!E->isCommaOp() && "Comma op should be handled in VisitBinaryOperator"); assert(E->getType()->isVectorType()); - assert(E->getLHS()->getType()->isVectorType()); - assert(E->getRHS()->getType()->isVectorType()); + assert(LHS->getType()->isVectorType()); + assert(RHS->getType()->isVectorType()); + + // We can only handle vectors with primitive element types. + if (!canClassify(LHS->getType()->castAs<VectorType>()->getElementType())) + return false; // Prepare storage for result. - if (!Initializing && !E->isCompoundAssignmentOp()) { - std::optional<unsigned> LocalIndex = allocateTemporary(E); + if (!Initializing && !E->isCompoundAssignmentOp() && !E->isAssignmentOp()) { + UnsignedOrNone LocalIndex = allocateTemporary(E); if (!LocalIndex) return false; if (!this->emitGetPtrLocal(*LocalIndex, E)) return false; } - const Expr *LHS = E->getLHS(); - const Expr *RHS = E->getRHS(); const auto *VecTy = E->getType()->getAs<VectorType>(); auto Op = E->isCompoundAssignmentOp() ? BinaryOperator::getOpForCompoundAssignment(E->getOpcode()) @@ -1396,6 +1406,21 @@ bool Compiler<Emitter>::VisitVectorBinOp(const BinaryOperator *E) { PrimType RHSElemT = this->classifyVectorElementType(RHS->getType()); PrimType ResultElemT = this->classifyVectorElementType(E->getType()); + if (E->getOpcode() == BO_Assign) { + assert(Ctx.getASTContext().hasSameUnqualifiedType( + LHS->getType()->castAs<VectorType>()->getElementType(), + RHS->getType()->castAs<VectorType>()->getElementType())); + if (!this->visit(LHS)) + return false; + if (!this->visit(RHS)) + return false; + if (!this->emitCopyArray(ElemT, 0, 0, VecTy->getNumElements(), E)) + return false; + if (DiscardResult) + return this->emitPopPtr(E); + return true; + } + // Evaluate LHS and save value to LHSOffset. unsigned LHSOffset = this->allocateLocalPrimitive(LHS, PT_Ptr, /*IsConst=*/true); @@ -1931,15 +1956,19 @@ bool Compiler<Emitter>::visitInitList(ArrayRef<const Expr *> Inits, dyn_cast<EmbedExpr>(Init->IgnoreParenImpCasts())) { PrimType TargetT = classifyPrim(Init->getType()); - auto Eval = [&](const Expr *Init, unsigned ElemIndex) { - PrimType InitT = classifyPrim(Init->getType()); - if (!this->visit(Init)) - return false; - if (InitT != TargetT) { - if (!this->emitCast(InitT, TargetT, E)) + auto Eval = [&](const IntegerLiteral *IL, unsigned ElemIndex) { + if (TargetT == PT_Float) { + if (!this->emitConst(IL->getValue(), classifyPrim(IL), Init)) + return false; + const auto *Sem = &Ctx.getFloatSemantics(CAT->getElementType()); + if (!this->emitCastIntegralFloating(classifyPrim(IL), Sem, + getFPOptions(E), E)) + return false; + } else { + if (!this->emitConst(IL->getValue(), TargetT, Init)) return false; } - return this->emitInitElem(TargetT, ElemIndex, Init); + return this->emitInitElem(TargetT, ElemIndex, IL); }; if (!EmbedS->doForEachDataElement(Eval, ElementIndex)) return false; @@ -2061,24 +2090,36 @@ bool Compiler<Emitter>::visitArrayElemInit(unsigned ElemIndex, const Expr *Init, template <class Emitter> bool Compiler<Emitter>::visitCallArgs(ArrayRef<const Expr *> Args, const FunctionDecl *FuncDecl, - bool Activate) { + bool Activate, bool IsOperatorCall) { 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); - } + + bool ExplicitMemberFn = false; + if (const auto *MD = dyn_cast_if_present<CXXMethodDecl>(FuncDecl)) + ExplicitMemberFn = MD->isExplicitObjectMemberFunction(); unsigned ArgIndex = 0; for (const Expr *Arg : Args) { - if (OptPrimType T = classify(Arg)) { + if (canClassify(Arg)) { if (!this->visit(Arg)) return false; } else { - std::optional<unsigned> LocalIndex = allocateLocal( - Arg, Arg->getType(), /*ExtendingDecl=*/nullptr, ScopeKind::Call); + DeclTy Source = Arg; + if (FuncDecl) { + // Try to use the parameter declaration instead of the argument + // expression as a source. + unsigned DeclIndex = ArgIndex - IsOperatorCall + ExplicitMemberFn; + if (DeclIndex < FuncDecl->getNumParams()) + Source = FuncDecl->getParamDecl(ArgIndex - IsOperatorCall + + ExplicitMemberFn); + } + + UnsignedOrNone LocalIndex = + allocateLocal(std::move(Source), Arg->getType(), + /*ExtendingDecl=*/nullptr, ScopeKind::Call); if (!LocalIndex) return false; @@ -2094,7 +2135,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)) @@ -2225,7 +2266,9 @@ bool Compiler<Emitter>::VisitUnaryExprOrTypeTraitExpr( assert(VAT); if (VAT->getElementType()->isArrayType()) { std::optional<APSInt> Res = - VAT->getSizeExpr()->getIntegerConstantExpr(ASTCtx); + VAT->getSizeExpr() + ? VAT->getSizeExpr()->getIntegerConstantExpr(ASTCtx) + : std::nullopt; if (Res) { if (DiscardResult) return true; @@ -2919,7 +2962,7 @@ bool Compiler<Emitter>::VisitMaterializeTemporaryExpr( return false; const Expr *Inner = E->getSubExpr()->skipRValueSubobjectAdjustments(); - if (std::optional<unsigned> LocalIndex = + if (UnsignedOrNone LocalIndex = allocateLocal(E, Inner->getType(), E->getExtendingDecl())) { InitLinkScope<Emitter> ILS(this, InitLink::Temp(*LocalIndex)); if (!this->emitGetPtrLocal(*LocalIndex, E)) @@ -2966,20 +3009,25 @@ bool Compiler<Emitter>::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) { if (T && !E->isLValue()) return this->delegate(Init); - if (std::optional<unsigned> GlobalIndex = P.createGlobal(E)) { - if (!this->emitGetPtrGlobal(*GlobalIndex, E)) - return false; + std::optional<unsigned> GlobalIndex = P.createGlobal(E); + if (!GlobalIndex) + return false; - if (T) { - if (!this->visit(Init)) - return false; - return this->emitInitGlobal(*T, *GlobalIndex, E); - } + if (!this->emitGetPtrGlobal(*GlobalIndex, E)) + return false; + + // Since this is a global variable, we might've already seen, + // don't do it again. + if (P.isGlobalInitialized(*GlobalIndex)) + return true; - return this->visitInitializer(Init) && this->emitFinishInit(E); + if (T) { + if (!this->visit(Init)) + return false; + return this->emitInitGlobal(*T, *GlobalIndex, E); } - return false; + return this->visitInitializer(Init) && this->emitFinishInit(E); } // Otherwise, use a local variable. @@ -2991,7 +3039,7 @@ bool Compiler<Emitter>::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) { unsigned LocalIndex; if (T) LocalIndex = this->allocateLocalPrimitive(Init, *T, /*IsConst=*/false); - else if (std::optional<unsigned> MaybeIndex = this->allocateLocal(Init)) + else if (UnsignedOrNone MaybeIndex = this->allocateLocal(Init)) LocalIndex = *MaybeIndex; else return false; @@ -3157,25 +3205,18 @@ 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(); - // Trivial copy/move constructor. Avoid copy. - if (Ctor->isDefaulted() && Ctor->isCopyOrMoveConstructor() && - Ctor->isTrivial() && - E->getArg(0)->isTemporaryObject(Ctx.getASTContext(), - T->getAsCXXRecordDecl())) - return this->visitInitializer(E->getArg(0)); - // If we're discarding a construct expression, we still need // to allocate a variable and call the constructor and destructor. if (DiscardResult) { if (Ctor->isTrivial()) return true; assert(!Initializing); - std::optional<unsigned> LocalIndex = allocateLocal(E); + UnsignedOrNone LocalIndex = allocateLocal(E); if (!LocalIndex) return false; @@ -3184,6 +3225,13 @@ bool Compiler<Emitter>::VisitCXXConstructExpr(const CXXConstructExpr *E) { return false; } + // Trivial copy/move constructor. Avoid copy. + if (Ctor->isDefaulted() && Ctor->isCopyOrMoveConstructor() && + Ctor->isTrivial() && + E->getArg(0)->isTemporaryObject(Ctx.getASTContext(), + T->getAsCXXRecordDecl())) + return this->visitInitializer(E->getArg(0)); + // Zero initialization. if (E->requiresZeroInitialization()) { const Record *R = getRecord(E->getType()); @@ -3378,7 +3426,7 @@ bool Compiler<Emitter>::VisitCXXScalarValueInitExpr( if (const auto *CT = Ty->getAs<ComplexType>()) { if (!Initializing) { - std::optional<unsigned> LocalIndex = allocateLocal(E); + UnsignedOrNone LocalIndex = allocateLocal(E); if (!LocalIndex) return false; if (!this->emitGetPtrLocal(*LocalIndex, E)) @@ -3401,7 +3449,7 @@ bool Compiler<Emitter>::VisitCXXScalarValueInitExpr( if (const auto *VT = Ty->getAs<VectorType>()) { // FIXME: Code duplication with the _Complex case above. if (!Initializing) { - std::optional<unsigned> LocalIndex = allocateLocal(E); + UnsignedOrNone LocalIndex = allocateLocal(E); if (!LocalIndex) return false; if (!this->emitGetPtrLocal(*LocalIndex, E)) @@ -3851,6 +3899,8 @@ bool Compiler<Emitter>::VisitCXXUuidofExpr(const CXXUuidofExpr *E) { template <class Emitter> bool Compiler<Emitter>::VisitRequiresExpr(const RequiresExpr *E) { assert(classifyPrim(E->getType()) == PT_Bool); + if (E->isValueDependent()) + return false; if (DiscardResult) return true; return this->emitConstBool(E->isSatisfied(), E); @@ -4027,8 +4077,7 @@ bool Compiler<Emitter>::VisitExtVectorElementExpr( // Now the vector variable for the return value. if (!Initializing) { - std::optional<unsigned> ResultIndex; - ResultIndex = allocateLocal(E); + UnsignedOrNone ResultIndex = allocateLocal(E); if (!ResultIndex) return false; if (!this->emitGetPtrLocal(*ResultIndex, E)) @@ -4089,8 +4138,7 @@ bool Compiler<Emitter>::VisitCXXStdInitializerListExpr( PrimType SecondFieldT = classifyPrim(R->getField(1u)->Decl->getType()); if (isIntegralType(SecondFieldT)) { - if (!this->emitConst(static_cast<APSInt>(ArrayType->getSize()), - SecondFieldT, E)) + if (!this->emitConst(ArrayType->getSize(), SecondFieldT, E)) return false; return this->emitInitField(SecondFieldT, R->getField(1u)->Offset, E); } @@ -4100,7 +4148,7 @@ bool Compiler<Emitter>::VisitCXXStdInitializerListExpr( return false; if (!this->emitExpandPtr(E)) return false; - if (!this->emitConst(static_cast<APSInt>(ArrayType->getSize()), PT_Uint64, E)) + if (!this->emitConst(ArrayType->getSize(), PT_Uint64, E)) return false; if (!this->emitArrayElemPtrPop(PT_Uint64, E)) return false; @@ -4132,13 +4180,13 @@ bool Compiler<Emitter>::VisitStmtExpr(const StmtExpr *E) { template <class Emitter> bool Compiler<Emitter>::discard(const Expr *E) { OptionScope<Emitter> Scope(this, /*NewDiscardResult=*/true, - /*NewInitializing=*/false); + /*NewInitializing=*/false, /*ToLValue=*/false); return this->Visit(E); } template <class Emitter> bool Compiler<Emitter>::delegate(const Expr *E) { // We're basically doing: - // OptionScope<Emitter> Scope(this, DicardResult, Initializing); + // OptionScope<Emitter> Scope(this, DicardResult, Initializing, ToLValue); // but that's unnecessary of course. return this->Visit(E); } @@ -4152,8 +4200,8 @@ 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())) { - std::optional<unsigned> LocalIndex = allocateLocal(E); + !canClassify(E->getType())) { + UnsignedOrNone LocalIndex = allocateLocal(E); if (!LocalIndex) return false; @@ -4166,16 +4214,22 @@ template <class Emitter> bool Compiler<Emitter>::visit(const Expr *E) { // Otherwise,we have a primitive return value, produce the value directly // and push it on the stack. OptionScope<Emitter> Scope(this, /*NewDiscardResult=*/false, - /*NewInitializing=*/false); + /*NewInitializing=*/false, /*ToLValue=*/ToLValue); return this->Visit(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); + /*NewInitializing=*/true, /*ToLValue=*/false); + return this->Visit(E); +} + +template <class Emitter> bool Compiler<Emitter>::visitAsLValue(const Expr *E) { + OptionScope<Emitter> Scope(this, /*NewDiscardResult=*/false, + /*NewInitializing=*/false, /*ToLValue=*/true); return this->Visit(E); } @@ -4379,7 +4433,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)) @@ -4472,12 +4526,18 @@ bool Compiler<Emitter>::emitConst(T Value, const Expr *E) { template <class Emitter> bool Compiler<Emitter>::emitConst(const APSInt &Value, PrimType Ty, const Expr *E) { + return this->emitConst(static_cast<const APInt &>(Value), Ty, E); +} + +template <class Emitter> +bool Compiler<Emitter>::emitConst(const APInt &Value, PrimType Ty, + const Expr *E) { if (Ty == PT_IntAPS) return this->emitConstIntAPS(Value, E); if (Ty == PT_IntAP) return this->emitConstIntAP(Value, E); - if (Value.isSigned()) + if (isSignedType(Ty)) return this->emitConst(Value.getSExtValue(), Ty, E); return this->emitConst(Value.getZExtValue(), Ty, E); } @@ -4491,14 +4551,6 @@ template <class Emitter> unsigned Compiler<Emitter>::allocateLocalPrimitive( DeclTy &&Src, PrimType Ty, bool IsConst, const ValueDecl *ExtendingDecl, ScopeKind SC, bool IsConstexprUnknown) { - // Make sure we don't accidentally register the same decl twice. - if (const auto *VD = - dyn_cast_if_present<ValueDecl>(Src.dyn_cast<const Decl *>())) { - assert(!P.getGlobal(VD)); - assert(!Locals.contains(VD)); - (void)VD; - } - // FIXME: There are cases where Src.is<Expr*>() is wrong, e.g. // (int){12} in C. Consider using Expr::isTemporaryObject() instead // or isa<MaterializeTemporaryExpr>(). @@ -4516,23 +4568,15 @@ unsigned Compiler<Emitter>::allocateLocalPrimitive( } template <class Emitter> -std::optional<unsigned> -Compiler<Emitter>::allocateLocal(DeclTy &&Src, QualType Ty, - const ValueDecl *ExtendingDecl, ScopeKind SC, - bool IsConstexprUnknown) { - // Make sure we don't accidentally register the same decl twice. - if ([[maybe_unused]] const auto *VD = - dyn_cast_if_present<ValueDecl>(Src.dyn_cast<const Decl *>())) { - assert(!P.getGlobal(VD)); - assert(!Locals.contains(VD)); - } - +UnsignedOrNone Compiler<Emitter>::allocateLocal(DeclTy &&Src, QualType Ty, + const ValueDecl *ExtendingDecl, + ScopeKind SC, + bool IsConstexprUnknown) { const ValueDecl *Key = nullptr; const Expr *Init = nullptr; bool IsTemporary = false; if (auto *VD = dyn_cast_if_present<ValueDecl>(Src.dyn_cast<const Decl *>())) { Key = VD; - Ty = VD->getType(); if (const auto *VarD = dyn_cast<VarDecl>(VD)) Init = VarD->getInit(); @@ -4561,7 +4605,7 @@ Compiler<Emitter>::allocateLocal(DeclTy &&Src, QualType Ty, } template <class Emitter> -std::optional<unsigned> Compiler<Emitter>::allocateTemporary(const Expr *E) { +UnsignedOrNone Compiler<Emitter>::allocateTemporary(const Expr *E) { QualType Ty = E->getType(); assert(!Ty->isRecordType()); @@ -4586,13 +4630,13 @@ std::optional<unsigned> Compiler<Emitter>::allocateTemporary(const Expr *E) { template <class Emitter> const RecordType *Compiler<Emitter>::getRecordTy(QualType Ty) { if (const PointerType *PT = dyn_cast<PointerType>(Ty)) - return PT->getPointeeType()->getAs<RecordType>(); - return Ty->getAs<RecordType>(); + return PT->getPointeeType()->getAsCanonical<RecordType>(); + return Ty->getAsCanonical<RecordType>(); } 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; } @@ -4640,7 +4684,7 @@ bool Compiler<Emitter>::visitExpr(const Expr *E, bool DestroyToplevelScope) { // Expressions with a composite return type. // For us, that means everything we don't // have a PrimType for. - if (std::optional<unsigned> LocalOffset = this->allocateLocal(E)) { + if (UnsignedOrNone LocalOffset = this->allocateLocal(E)) { InitLinkScope<Emitter> ILS(this, InitLink::Temp(*LocalOffset)); if (!this->emitGetPtrLocal(*LocalOffset, E)) return false; @@ -4837,7 +4881,7 @@ VarCreationState Compiler<Emitter>::visitVarDecl(const VarDecl *VD, return this->emitSetLocal(*VarT, Offset, VD); } } else { - if (std::optional<unsigned> Offset = this->allocateLocal( + if (UnsignedOrNone Offset = this->allocateLocal( VD, VD->getType(), nullptr, ScopeKind::Block, IsConstexprUnknown)) { if (!Init) return true; @@ -4952,7 +4996,6 @@ bool Compiler<Emitter>::visitAPValueInitializer(const APValue &Val, template <class Emitter> bool Compiler<Emitter>::VisitBuiltinCallExpr(const CallExpr *E, unsigned BuiltinID) { - if (BuiltinID == Builtin::BI__builtin_constant_p) { // Void argument is always invalid and harder to handle later. if (E->getArg(0)->getType()->isVoidType()) { @@ -4990,18 +5033,38 @@ bool Compiler<Emitter>::VisitBuiltinCallExpr(const CallExpr *E, // Non-primitive return type. Prepare storage. if (!Initializing && !ReturnT && !ReturnType->isVoidType()) { - std::optional<unsigned> LocalIndex = allocateLocal(E); + UnsignedOrNone LocalIndex = allocateLocal(E); if (!LocalIndex) return false; if (!this->emitGetPtrLocal(*LocalIndex, E)) return false; } - if (!Context::isUnevaluatedBuiltin(BuiltinID)) { - // Put arguments on the stack. - for (const auto *Arg : E->arguments()) { - if (!this->visit(Arg)) + // Prepare function arguments including special cases. + switch (BuiltinID) { + case Builtin::BI__builtin_object_size: + case Builtin::BI__builtin_dynamic_object_size: { + assert(E->getNumArgs() == 2); + const Expr *Arg0 = E->getArg(0); + if (Arg0->isGLValue()) { + if (!this->visit(Arg0)) return false; + + } else { + if (!this->visitAsLValue(Arg0)) + return false; + } + if (!this->visit(E->getArg(1))) + return false; + + } break; + default: + if (!Context::isUnevaluatedBuiltin(BuiltinID)) { + // Put arguments on the stack. + for (const auto *Arg : E->arguments()) { + if (!this->visit(Arg)) + return false; + } } } @@ -5066,7 +5129,7 @@ bool Compiler<Emitter>::VisitCallExpr(const CallExpr *E) { // If we need to discard the return value but the function returns its // value via an RVO pointer, we need to create one such pointer just // for this call. - if (std::optional<unsigned> LocalIndex = allocateLocal(E)) { + if (UnsignedOrNone LocalIndex = allocateLocal(E)) { if (!this->emitGetPtrLocal(*LocalIndex, E)) return false; } @@ -5074,7 +5137,7 @@ bool Compiler<Emitter>::VisitCallExpr(const CallExpr *E) { // We need the result. Prepare a pointer to return or // dup the current one. if (!Initializing) { - if (std::optional<unsigned> LocalIndex = allocateLocal(E)) { + if (UnsignedOrNone LocalIndex = allocateLocal(E)) { if (!this->emitGetPtrLocal(*LocalIndex, E)) return false; } @@ -5110,7 +5173,7 @@ bool Compiler<Emitter>::VisitCallExpr(const CallExpr *E) { } bool Devirtualized = false; - std::optional<unsigned> CalleeOffset; + UnsignedOrNone CalleeOffset = std::nullopt; // Add the (optional, implicit) This pointer. if (const auto *MC = dyn_cast<CXXMemberCallExpr>(E)) { if (!FuncDecl && classifyPrim(E->getCallee()) == PT_MemberPtr) { @@ -5154,7 +5217,8 @@ bool Compiler<Emitter>::VisitCallExpr(const CallExpr *E) { if (!this->emitCheckPseudoDtor(E)) return false; const Expr *Base = PD->getBase(); - if (!Base->isGLValue()) + // E.g. `using T = int; 0.~T();`. + if (OptPrimType BaseT = classify(Base); !BaseT || BaseT != PT_Ptr) return this->discard(Base); if (!this->visit(Base)) return false; @@ -5169,7 +5233,8 @@ bool Compiler<Emitter>::VisitCallExpr(const CallExpr *E) { return false; } - if (!this->visitCallArgs(Args, FuncDecl, IsAssignmentOperatorCall)) + if (!this->visitCallArgs(Args, FuncDecl, IsAssignmentOperatorCall, + isa<CXXOperatorCallExpr>(E))) return false; // Undo the argument reversal we did earlier. @@ -5185,6 +5250,12 @@ bool Compiler<Emitter>::VisitCallExpr(const CallExpr *E) { const Function *Func = getFunction(FuncDecl); if (!Func) return false; + + // In error cases, the function may be called with fewer arguments than + // parameters. + if (E->getNumArgs() < Func->getNumWrittenParams()) + return false; + assert(HasRVO == Func->hasRVO()); bool HasQualifier = false; @@ -6516,7 +6587,7 @@ bool Compiler<Emitter>::VisitComplexUnaryOperator(const UnaryOperator *E) { OptPrimType ResT = classify(E); auto prepareResult = [=]() -> bool { if (!ResT && !Initializing) { - std::optional<unsigned> LocalIndex = allocateLocal(SubExpr); + UnsignedOrNone LocalIndex = allocateLocal(SubExpr); if (!LocalIndex) return false; return this->emitGetPtrLocal(*LocalIndex, E); @@ -6634,7 +6705,7 @@ bool Compiler<Emitter>::VisitVectorUnaryOperator(const UnaryOperator *E) { return this->delegate(SubExpr); if (!Initializing) { - std::optional<unsigned> LocalIndex = allocateLocal(SubExpr); + UnsignedOrNone LocalIndex = allocateLocal(SubExpr); if (!LocalIndex) return false; if (!this->emitGetPtrLocal(*LocalIndex, E)) @@ -6752,6 +6823,22 @@ bool Compiler<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) { // value. bool IsReference = D->getType()->isReferenceType(); + // Function parameters. + // Note that it's important to check them first since we might have a local + // variable created for a ParmVarDecl as well. + if (const auto *PVD = dyn_cast<ParmVarDecl>(D)) { + if (Ctx.getLangOpts().CPlusPlus && !Ctx.getLangOpts().CPlusPlus11 && + !D->getType()->isIntegralOrEnumerationType()) { + return this->emitInvalidDeclRef(cast<DeclRefExpr>(E), + /*InitializerFailed=*/false, E); + } + if (auto It = this->Params.find(PVD); It != this->Params.end()) { + if (IsReference || !It->second.IsPtr) + return this->emitGetParam(classifyPrim(E), It->second.Offset, E); + + return this->emitGetPtrParam(It->second.Offset, E); + } + } // Local variables. if (auto It = Locals.find(D); It != Locals.end()) { const unsigned Offset = It->second.Offset; @@ -6769,20 +6856,6 @@ bool Compiler<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) { return this->emitGetPtrGlobal(*GlobalIndex, E); } - // Function parameters. - if (const auto *PVD = dyn_cast<ParmVarDecl>(D)) { - if (Ctx.getLangOpts().CPlusPlus && !Ctx.getLangOpts().CPlusPlus11 && - !D->getType()->isIntegralOrEnumerationType()) { - return this->emitInvalidDeclRef(cast<DeclRefExpr>(E), - /*InitializerFailed=*/false, E); - } - if (auto It = this->Params.find(PVD); It != this->Params.end()) { - if (IsReference || !It->second.IsPtr) - return this->emitGetParam(classifyPrim(E), It->second.Offset, E); - - return this->emitGetPtrParam(It->second.Offset, E); - } - } // In case we need to re-visit a declaration. auto revisit = [&](const VarDecl *VD) -> bool { @@ -7142,10 +7215,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; @@ -7240,7 +7309,7 @@ bool Compiler<Emitter>::emitBuiltinBitCast(const CastExpr *E) { // Prepare storage for the result in case we discard. if (DiscardResult && !Initializing && !ToT) { - std::optional<unsigned> LocalIndex = allocateLocal(E); + UnsignedOrNone LocalIndex = allocateLocal(E); if (!LocalIndex) return false; if (!this->emitGetPtrLocal(*LocalIndex, E)) diff --git a/clang/lib/AST/ByteCode/Compiler.h b/clang/lib/AST/ByteCode/Compiler.h index ee8327d..475faee 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 { @@ -280,6 +282,7 @@ protected: /// been created. visitInitializer() then relies on a pointer to this /// variable being on top of the stack. bool visitInitializer(const Expr *E); + bool visitAsLValue(const Expr *E); /// Evaluates an expression for side effects and discards the result. bool discard(const Expr *E); /// Just pass evaluation on to \p E. This leaves all the parsing flags @@ -304,7 +307,7 @@ protected: bool visitArrayElemInit(unsigned ElemIndex, const Expr *Init, OptPrimType InitT); bool visitCallArgs(ArrayRef<const Expr *> Args, const FunctionDecl *FuncDecl, - bool Activate); + bool Activate, bool IsOperatorCall); /// Creates a local primitive value. unsigned allocateLocalPrimitive(DeclTy &&Decl, PrimType Ty, bool IsConst, @@ -313,11 +316,11 @@ protected: bool IsConstexprUnknown = false); /// Allocates a space storing a local given its type. - std::optional<unsigned> - allocateLocal(DeclTy &&Decl, QualType Ty = QualType(), - const ValueDecl *ExtendingDecl = nullptr, - ScopeKind = ScopeKind::Block, bool IsConstexprUnknown = false); - std::optional<unsigned> allocateTemporary(const Expr *E); + UnsignedOrNone allocateLocal(DeclTy &&Decl, QualType Ty = QualType(), + const ValueDecl *ExtendingDecl = nullptr, + ScopeKind = ScopeKind::Block, + bool IsConstexprUnknown = false); + UnsignedOrNone allocateTemporary(const Expr *E); private: friend class VariableScope<Emitter>; @@ -344,9 +347,10 @@ private: /// Emits an APSInt constant. bool emitConst(const llvm::APSInt &Value, PrimType Ty, const Expr *E); + bool emitConst(const llvm::APInt &Value, PrimType Ty, const Expr *E); bool emitConst(const llvm::APSInt &Value, const Expr *E); bool emitConst(const llvm::APInt &Value, const Expr *E) { - return emitConst(static_cast<llvm::APSInt>(Value), E); + return emitConst(Value, classifyPrim(E), E); } /// Emits an integer constant. @@ -424,6 +428,7 @@ protected: bool DiscardResult = false; bool InStmtExpr = false; + bool ToLValue = false; /// Flag inidicating if we're initializing an already created /// variable. This is set in visitInitializer(). @@ -563,7 +568,7 @@ public: void addLocal(const Scope::Local &Local) override { if (!Idx) { - Idx = this->Ctx->Descriptors.size(); + Idx = static_cast<unsigned>(this->Ctx->Descriptors.size()); this->Ctx->Descriptors.emplace_back(); this->Ctx->emitInitScope(*Idx, {}); } @@ -611,7 +616,7 @@ public: } /// Index of the scope in the chain. - std::optional<unsigned> Idx; + UnsignedOrNone Idx = std::nullopt; }; /// Scope for storage declared in a compound statement. diff --git a/clang/lib/AST/ByteCode/Context.cpp b/clang/lib/AST/ByteCode/Context.cpp index f7f528c..8598996 100644 --- a/clang/lib/AST/ByteCode/Context.cpp +++ b/clang/lib/AST/ByteCode/Context.cpp @@ -91,7 +91,7 @@ bool Context::evaluateAsRValue(State &Parent, const Expr *E, APValue &Result) { #endif } - Result = Res.toAPValue(); + Result = Res.stealAPValue(); return true; } @@ -121,7 +121,7 @@ bool Context::evaluate(State &Parent, const Expr *E, APValue &Result, #endif } - Result = Res.toAPValue(); + Result = Res.stealAPValue(); return true; } @@ -153,7 +153,7 @@ bool Context::evaluateAsInitializer(State &Parent, const VarDecl *VD, #endif } - Result = Res.toAPValue(); + Result = Res.stealAPValue(); return true; } @@ -364,8 +364,7 @@ OptPrimType Context::classify(QualType T) const { return integralTypeToPrimTypeU(BT->getNumBits()); } - if (const auto *ET = T->getAs<EnumType>()) { - const auto *D = ET->getDecl(); + if (const auto *D = T->getAsEnumDecl()) { if (!D->isComplete()) return std::nullopt; return classify(D->getIntegerType()); @@ -398,17 +397,11 @@ const llvm::fltSemantics &Context::getFloatSemantics(QualType T) const { } bool Context::Run(State &Parent, const Function *Func) { - - { - InterpState State(Parent, *P, Stk, *this, Func); - if (Interpret(State)) { - assert(Stk.empty()); - return true; - } - // State gets destroyed here, so the Stk.clear() below doesn't accidentally - // remove values the State's destructor might access. + InterpState State(Parent, *P, Stk, *this, Func); + if (Interpret(State)) { + assert(Stk.empty()); + return true; } - Stk.clear(); return false; } @@ -501,7 +494,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..fa98498 100644 --- a/clang/lib/AST/ByteCode/Context.h +++ b/clang/lib/AST/ByteCode/Context.h @@ -30,7 +30,7 @@ namespace interp { class Function; class Program; class State; -enum PrimType : unsigned; +enum PrimType : uint8_t; struct ParamOffset { unsigned Offset; @@ -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 629c1ff..647de56 100644 --- a/clang/lib/AST/ByteCode/Descriptor.cpp +++ b/clang/lib/AST/ByteCode/Descriptor.cpp @@ -50,14 +50,6 @@ static void dtorTy(Block *, std::byte *Ptr, const Descriptor *) { } template <typename T> -static void moveTy(Block *, std::byte *Src, std::byte *Dst, - const Descriptor *) { - auto *SrcPtr = reinterpret_cast<T *>(Src); - auto *DstPtr = reinterpret_cast<T *>(Dst); - new (DstPtr) T(std::move(*SrcPtr)); -} - -template <typename T> static void ctorArrayTy(Block *, std::byte *Ptr, bool, bool, bool, bool, bool, const Descriptor *D) { new (Ptr) InitMapPtr(std::nullopt); @@ -85,28 +77,6 @@ static void dtorArrayTy(Block *, std::byte *Ptr, const Descriptor *D) { } } -template <typename T> -static void moveArrayTy(Block *, std::byte *Src, std::byte *Dst, - const Descriptor *D) { - InitMapPtr &SrcIMP = *reinterpret_cast<InitMapPtr *>(Src); - if (SrcIMP) { - // We only ever invoke the moveFunc when moving block contents to a - // DeadBlock. DeadBlocks don't need InitMaps, so we destroy them here. - SrcIMP = std::nullopt; - } - Src += sizeof(InitMapPtr); - Dst += sizeof(InitMapPtr); - if constexpr (!needsCtor<T>()) { - std::memcpy(Dst, Src, D->getNumElems() * D->getElemSize()); - } else { - for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) { - auto *SrcPtr = &reinterpret_cast<T *>(Src)[I]; - auto *DstPtr = &reinterpret_cast<T *>(Dst)[I]; - new (DstPtr) T(std::move(*SrcPtr)); - } - } -} - static void ctorArrayDesc(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable, bool IsVolatile, bool IsActive, bool InUnion, const Descriptor *D) { @@ -144,12 +114,14 @@ static void dtorArrayDesc(Block *B, std::byte *Ptr, const Descriptor *D) { D->ElemDesc->getAllocSize() + sizeof(InlineDescriptor); unsigned ElemOffset = 0; - for (unsigned I = 0; I < NumElems; ++I, ElemOffset += ElemSize) { + auto Dtor = D->ElemDesc->DtorFn; + assert(Dtor && + "a composite array without an elem dtor shouldn't have a dtor itself"); + for (unsigned I = 0; I != NumElems; ++I, ElemOffset += ElemSize) { auto *ElemPtr = Ptr + ElemOffset; auto *Desc = reinterpret_cast<InlineDescriptor *>(ElemPtr); auto *ElemLoc = reinterpret_cast<std::byte *>(Desc + 1); - if (auto Fn = D->ElemDesc->DtorFn) - Fn(B, ElemLoc, D->ElemDesc); + Dtor(B, ElemLoc, D->ElemDesc); } } @@ -246,34 +218,59 @@ static void dtorRecord(Block *B, std::byte *Ptr, const Descriptor *D) { destroyBase(B, Ptr, F.Desc, F.Offset); } -static BlockCtorFn getCtorPrim(PrimType Type) { - // Floating types are special. They are primitives, but need their - // constructor called. - if (Type == PT_Float) +/// Whether a record needs its descriptor dtor function called. +static bool needsRecordDtor(const Record *R) { + for (const auto &B : R->bases()) { + if (B.Desc->DtorFn) + return true; + } + + for (const auto &F : R->fields()) { + if (F.Desc->DtorFn) + return true; + } + + for (const auto &V : R->virtual_bases()) { + if (V.Desc->DtorFn) + return true; + } + return false; +} + +static BlockCtorFn getCtorPrim(PrimType T) { + switch (T) { + case PT_Float: return ctorTy<PrimConv<PT_Float>::T>; - if (Type == PT_IntAP) + case PT_IntAP: return ctorTy<PrimConv<PT_IntAP>::T>; - if (Type == PT_IntAPS) + case PT_IntAPS: return ctorTy<PrimConv<PT_IntAPS>::T>; - if (Type == PT_MemberPtr) + case PT_Ptr: + return ctorTy<PrimConv<PT_Ptr>::T>; + case PT_MemberPtr: return ctorTy<PrimConv<PT_MemberPtr>::T>; - - COMPOSITE_TYPE_SWITCH(Type, return ctorTy<T>, return nullptr); + default: + return nullptr; + } + llvm_unreachable("Unhandled PrimType"); } -static BlockDtorFn getDtorPrim(PrimType Type) { - // Floating types are special. They are primitives, but need their - // destructor called, since they might allocate memory. - if (Type == PT_Float) +static BlockDtorFn getDtorPrim(PrimType T) { + switch (T) { + case PT_Float: return dtorTy<PrimConv<PT_Float>::T>; - if (Type == PT_IntAP) + case PT_IntAP: return dtorTy<PrimConv<PT_IntAP>::T>; - if (Type == PT_IntAPS) + case PT_IntAPS: return dtorTy<PrimConv<PT_IntAPS>::T>; - if (Type == PT_MemberPtr) + case PT_Ptr: + return dtorTy<PrimConv<PT_Ptr>::T>; + case PT_MemberPtr: return dtorTy<PrimConv<PT_MemberPtr>::T>; - - COMPOSITE_TYPE_SWITCH(Type, return dtorTy<T>, return nullptr); + default: + return nullptr; + } + llvm_unreachable("Unhandled PrimType"); } static BlockCtorFn getCtorArrayPrim(PrimType Type) { @@ -336,7 +333,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) { + DtorFn(Elem->DtorFn ? dtorArrayDesc : nullptr) { assert(Source && "Missing source"); } @@ -347,7 +344,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) { + CtorFn(ctorArrayDesc), DtorFn(Elem->DtorFn ? dtorArrayDesc : nullptr) { assert(Source && "Missing source"); } @@ -359,7 +356,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) { + DtorFn(needsRecordDtor(R) ? dtorRecord : nullptr) { assert(Source && "Missing source"); } @@ -367,7 +364,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"); } @@ -377,12 +374,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"); @@ -453,7 +452,7 @@ SourceInfo Descriptor::getLoc() const { } bool Descriptor::hasTrivialDtor() const { - if (isPrimitive() || isPrimitiveArray() || isDummy()) + if (isPrimitive() || isPrimitiveArray()) return true; if (isRecord()) { @@ -462,17 +461,16 @@ bool Descriptor::hasTrivialDtor() const { return !Dtor || Dtor->isTrivial(); } + if (!ElemDesc) + return true; // Composite arrays. - assert(ElemDesc); return ElemDesc->hasTrivialDtor(); } bool Descriptor::isUnion() const { return isRecord() && ElemRecord->isUnion(); } InitMap::InitMap(unsigned N) - : UninitFields(N), Data(std::make_unique<T[]>(numFields(N))) { - std::fill_n(data(), numFields(N), 0); -} + : UninitFields(N), Data(std::make_unique<T[]>(numFields(N))) {} bool InitMap::initializeElement(unsigned I) { unsigned Bucket = I / PER_FIELD; diff --git a/clang/lib/AST/ByteCode/Descriptor.h b/clang/lib/AST/ByteCode/Descriptor.h index cd34e11..90dc2b4 100644 --- a/clang/lib/AST/ByteCode/Descriptor.h +++ b/clang/lib/AST/ByteCode/Descriptor.h @@ -24,7 +24,7 @@ class Record; class SourceInfo; struct InitMap; struct Descriptor; -enum PrimType : unsigned; +enum PrimType : uint8_t; using DeclTy = llvm::PointerUnion<const Decl *, const Expr *>; using InitMapPtr = std::optional<std::pair<bool, std::shared_ptr<InitMap>>>; @@ -166,8 +166,6 @@ 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. @@ -203,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; @@ -273,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..ac904d3 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,50 +539,27 @@ 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 << " Dynamic: " << IsDynamic << "\n"; + OS << " Weak: " << isWeak() << "\n"; + OS << " Dummy: " << isDummy() << '\n'; + OS << " Dynamic: " << isDynamic() << "\n"; } LLVM_DUMP_METHOD void EvaluationResult::dump() const { - assert(Ctx); auto &OS = llvm::errs(); - const ASTContext &ASTCtx = Ctx->getASTContext(); - switch (Kind) { - case Empty: + if (empty()) { OS << "Empty\n"; - break; - case RValue: - OS << "RValue: "; - std::get<APValue>(Value).dump(OS, ASTCtx); - break; - case LValue: { - assert(Source); - QualType SourceType; - if (const auto *D = dyn_cast<const Decl *>(Source)) { - if (const auto *VD = dyn_cast<ValueDecl>(D)) - SourceType = VD->getType(); - } else if (const auto *E = dyn_cast<const Expr *>(Source)) { - SourceType = E->getType(); - } - - OS << "LValue: "; - if (const auto *P = std::get_if<Pointer>(&Value)) - P->toAPValue(ASTCtx).printPretty(OS, ASTCtx, SourceType); - else if (const auto *FP = std::get_if<FunctionPointer>(&Value)) // Nope - FP->toAPValue(ASTCtx).printPretty(OS, ASTCtx, SourceType); - OS << "\n"; - break; - } - case Invalid: + } else if (isInvalid()) { OS << "Invalid\n"; - break; - case Valid: - OS << "Valid\n"; - break; + } else { + OS << "Value: "; +#ifndef NDEBUG + assert(Ctx); + Value.dump(OS, Ctx->getASTContext()); +#endif } } diff --git a/clang/lib/AST/ByteCode/DynamicAllocator.cpp b/clang/lib/AST/ByteCode/DynamicAllocator.cpp index 9b8b664..4fedac6 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,12 +23,15 @@ 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; - B->Pointers->PointeeStorage.BS.Pointee = nullptr; + B->Pointers->BS.Pointee = nullptr; B->Pointers = Next; } B->Pointers = nullptr; @@ -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); @@ -111,13 +101,17 @@ Block *DynamicAllocator::allocate(const Descriptor *D, unsigned EvalID, ID->LifeState = AllocForm == Form::Operator ? Lifetime::Ended : Lifetime::Started; - B->IsDynamic = true; - - if (auto It = AllocationSites.find(D->asExpr()); It != AllocationSites.end()) + if (auto It = AllocationSites.find(D->asExpr()); + It != AllocationSites.end()) { It->second.Allocations.emplace_back(std::move(Memory)); - else + B->setDynAllocId(It->second.NumAllocs); + ++It->second.NumAllocs; + } else { AllocationSites.insert( {D->asExpr(), AllocationSite(std::move(Memory), AllocForm)}); + B->setDynAllocId(0); + } + assert(B->isDynamic()); return B; } @@ -128,23 +122,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..ab1058b 100644 --- a/clang/lib/AST/ByteCode/DynamicAllocator.h +++ b/clang/lib/AST/ByteCode/DynamicAllocator.h @@ -43,18 +43,22 @@ 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 { llvm::SmallVector<Allocation> Allocations; + unsigned NumAllocs = 0; Form AllocForm; AllocationSite(std::unique_ptr<std::byte[]> Memory, Form AllocForm) : AllocForm(AllocForm) { Allocations.push_back({std::move(Memory)}); + ++NumAllocs; } size_t size() const { return Allocations.size(); } + bool empty() const { return Allocations.empty(); } }; public: @@ -65,8 +69,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 +98,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..2860a09 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; } @@ -187,7 +184,7 @@ template <PrimType OpType> bool EvalEmitter::emitRet(const SourceInfo &Info) { return true; using T = typename PrimConv<OpType>::T; - EvalResult.setValue(S.Stk.pop<T>().toAPValue(Ctx.getASTContext())); + EvalResult.takeValue(S.Stk.pop<T>().toAPValue(Ctx.getASTContext())); return true; } @@ -198,7 +195,7 @@ template <> bool EvalEmitter::emitRet<PT_Ptr>(const SourceInfo &Info) { const Pointer &Ptr = S.Stk.pop<Pointer>(); if (Ptr.isFunctionPointer()) { - EvalResult.setValue(Ptr.toAPValue(Ctx.getASTContext())); + EvalResult.takeValue(Ptr.toAPValue(Ctx.getASTContext())); return true; } @@ -216,10 +213,8 @@ template <> bool EvalEmitter::emitRet<PT_Ptr>(const SourceInfo &Info) { if (!Ptr.isZero() && !Ptr.isDereferencable()) return false; - if (S.getLangOpts().CPlusPlus11 && Ptr.isBlockPointer() && - !CheckFinalLoad(S, OpPC, Ptr)) { + if (!Ptr.isZero() && !CheckFinalLoad(S, OpPC, Ptr)) return false; - } // Never allow reading from a non-const pointer, unless the memory // has been created in this evaluation. @@ -229,7 +224,7 @@ template <> bool EvalEmitter::emitRet<PT_Ptr>(const SourceInfo &Info) { if (std::optional<APValue> V = Ptr.toRValue(Ctx, EvalResult.getSourceType())) { - EvalResult.setValue(*V); + EvalResult.takeValue(std::move(*V)); } else { return false; } @@ -238,14 +233,14 @@ template <> bool EvalEmitter::emitRet<PT_Ptr>(const SourceInfo &Info) { // the result, even if the pointer is dead. // This will later be diagnosed by CheckLValueConstantExpression. if (Ptr.isBlockPointer() && !Ptr.block()->isStatic()) { - EvalResult.setValue(Ptr.toAPValue(Ctx.getASTContext())); + EvalResult.takeValue(Ptr.toAPValue(Ctx.getASTContext())); return true; } if (!Ptr.isLive() && !Ptr.isTemporary()) return false; - EvalResult.setValue(Ptr.toAPValue(Ctx.getASTContext())); + EvalResult.takeValue(Ptr.toAPValue(Ctx.getASTContext())); } return true; @@ -266,7 +261,7 @@ bool EvalEmitter::emitRetValue(const SourceInfo &Info) { if (std::optional<APValue> APV = Ptr.toRValue(S.getASTContext(), EvalResult.getSourceType())) { - EvalResult.setValue(*APV); + EvalResult.takeValue(std::move(*APV)); return true; } @@ -292,7 +287,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/EvaluationResult.cpp b/clang/lib/AST/ByteCode/EvaluationResult.cpp index b11531f..ba81878 100644 --- a/clang/lib/AST/ByteCode/EvaluationResult.cpp +++ b/clang/lib/AST/ByteCode/EvaluationResult.cpp @@ -8,6 +8,7 @@ #include "EvaluationResult.h" #include "InterpState.h" +#include "Pointer.h" #include "Record.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SetVector.h" @@ -16,41 +17,6 @@ namespace clang { namespace interp { -APValue EvaluationResult::toAPValue() const { - assert(!empty()); - switch (Kind) { - case LValue: - // Either a pointer or a function pointer. - if (const auto *P = std::get_if<Pointer>(&Value)) - return P->toAPValue(Ctx->getASTContext()); - else if (const auto *FP = std::get_if<FunctionPointer>(&Value)) - return FP->toAPValue(Ctx->getASTContext()); - else - llvm_unreachable("Unhandled LValue type"); - break; - case RValue: - return std::get<APValue>(Value); - case Valid: - return APValue(); - default: - llvm_unreachable("Unhandled result kind?"); - } -} - -std::optional<APValue> EvaluationResult::toRValue() const { - if (Kind == RValue) - return toAPValue(); - - assert(Kind == LValue); - - // We have a pointer and want an RValue. - if (const auto *P = std::get_if<Pointer>(&Value)) - return P->toRValue(*Ctx, getSourceType()); - else if (const auto *FP = std::get_if<FunctionPointer>(&Value)) // Nope - return FP->toAPValue(Ctx->getASTContext()); - llvm_unreachable("Unhandled lvalue kind"); -} - static void DiagnoseUninitializedSubobject(InterpState &S, SourceLocation Loc, const FieldDecl *SubObjDecl) { assert(SubObjDecl && "Subobject declaration does not exist"); @@ -66,8 +32,12 @@ static bool CheckFieldsInitialized(InterpState &S, SourceLocation Loc, static bool CheckArrayInitialized(InterpState &S, SourceLocation Loc, const Pointer &BasePtr, const ConstantArrayType *CAT) { - bool Result = true; size_t NumElems = CAT->getZExtSize(); + + if (NumElems == 0) + return true; + + bool Result = true; QualType ElemType = CAT->getElementType(); if (ElemType->isRecordType()) { @@ -82,8 +52,18 @@ static bool CheckArrayInitialized(InterpState &S, SourceLocation Loc, Result &= CheckArrayInitialized(S, Loc, ElemPtr, ElemCAT); } } else { + // Primitive arrays. + if (S.getContext().canClassify(ElemType)) { + if (BasePtr.allElementsInitialized()) { + return true; + } else { + DiagnoseUninitializedSubobject(S, Loc, BasePtr.getField()); + return false; + } + } + for (size_t I = 0; I != NumElems; ++I) { - if (!BasePtr.atIndex(I).isInitialized()) { + if (!BasePtr.isElementInitialized(I)) { DiagnoseUninitializedSubobject(S, Loc, BasePtr.getField()); Result = false; } @@ -178,8 +158,8 @@ bool EvaluationResult::checkFullyInitialized(InterpState &S, static void collectBlocks(const Pointer &Ptr, llvm::SetVector<const Block *> &Blocks) { auto isUsefulPtr = [](const Pointer &P) -> bool { - return P.isLive() && !P.isZero() && !P.isDummy() && P.isDereferencable() && - !P.isUnknownSizeArray() && !P.isOnePastEnd(); + return P.isLive() && P.isBlockPointer() && !P.isZero() && !P.isDummy() && + P.isDereferencable() && !P.isUnknownSizeArray() && !P.isOnePastEnd(); }; if (!isUsefulPtr(Ptr)) diff --git a/clang/lib/AST/ByteCode/EvaluationResult.h b/clang/lib/AST/ByteCode/EvaluationResult.h index 3b6c65ef..c296cc9 100644 --- a/clang/lib/AST/ByteCode/EvaluationResult.h +++ b/clang/lib/AST/ByteCode/EvaluationResult.h @@ -9,23 +9,22 @@ #ifndef LLVM_CLANG_AST_INTERP_EVALUATION_RESULT_H #define LLVM_CLANG_AST_INTERP_EVALUATION_RESULT_H -#include "FunctionPointer.h" -#include "Pointer.h" #include "clang/AST/APValue.h" #include "clang/AST/Decl.h" #include "clang/AST/Expr.h" -#include <optional> -#include <variant> namespace clang { namespace interp { class EvalEmitter; class Context; +class Pointer; +class SourceInfo; +class InterpState; /// Defines the result of an evaluation. /// -/// The result might be in different forms--one of the pointer types, -/// an APValue, or nothing. +/// The Kind defined if the evaluation was invalid, valid (but empty, e.g. for +/// void expressions) or if we have a valid evaluation result. /// /// We use this class to inspect and diagnose the result, as well as /// convert it to the requested form. @@ -33,8 +32,6 @@ class EvaluationResult final { public: enum ResultKind { Empty, // Initial state. - LValue, // Result is an lvalue/pointer. - RValue, // Result is an rvalue. Invalid, // Result is invalid. Valid, // Result is valid and empty. }; @@ -42,29 +39,18 @@ public: using DeclTy = llvm::PointerUnion<const Decl *, const Expr *>; private: +#ifndef NDEBUG const Context *Ctx = nullptr; - std::variant<std::monostate, Pointer, FunctionPointer, APValue> Value; +#endif + APValue Value; ResultKind Kind = Empty; - DeclTy Source = nullptr; // Currently only needed for dump(). - - EvaluationResult(ResultKind Kind) : Kind(Kind) { - // Leave everything empty. Can be used as an - // error marker or for void return values. - assert(Kind == Valid || Kind == Invalid); - } + DeclTy Source = nullptr; void setSource(DeclTy D) { Source = D; } - void setValue(const APValue &V) { - // V could still be an LValue. + void takeValue(APValue &&V) { assert(empty()); Value = std::move(V); - Kind = RValue; - } - void setFunctionPointer(const FunctionPointer &P) { - assert(empty()); - Value = P; - Kind = LValue; } void setInvalid() { // We are NOT asserting empty() here, since setting it to invalid @@ -77,22 +63,23 @@ private: } public: +#ifndef NDEBUG EvaluationResult(const Context *Ctx) : Ctx(Ctx) {} +#else + EvaluationResult(const Context *Ctx) {} +#endif bool empty() const { return Kind == Empty; } bool isInvalid() const { return Kind == Invalid; } - bool isLValue() const { return Kind == LValue; } - bool isRValue() const { return Kind == RValue; } - bool isPointer() const { return std::holds_alternative<Pointer>(Value); } - /// Returns an APValue for the evaluation result. The returned - /// APValue might be an LValue or RValue. - APValue toAPValue() const; + /// Returns an APValue for the evaluation result. + APValue toAPValue() const { + assert(!empty()); + assert(!isInvalid()); + return Value; + } - /// If the result is an LValue, convert that to an RValue - /// and return it. This may fail, e.g. if the result is an - /// LValue and we can't read from it. - std::optional<APValue> toRValue() const; + APValue stealAPValue() { return std::move(Value); } /// Check that all subobjects of the given pointer have been initialized. bool checkFullyInitialized(InterpState &S, const Pointer &Ptr) const; @@ -105,7 +92,7 @@ public: if (const auto *D = dyn_cast_if_present<ValueDecl>(Source.dyn_cast<const Decl *>())) return D->getType(); - else if (const auto *E = Source.dyn_cast<const Expr *>()) + if (const auto *E = Source.dyn_cast<const Expr *>()) return E->getType(); return QualType(); } diff --git a/clang/lib/AST/ByteCode/Function.h b/clang/lib/AST/ByteCode/Function.h index 92363b6..af429b7 100644 --- a/clang/lib/AST/ByteCode/Function.h +++ b/clang/lib/AST/ByteCode/Function.h @@ -28,7 +28,7 @@ namespace interp { class Program; class ByteCodeEmitter; class Pointer; -enum PrimType : uint32_t; +enum PrimType : uint8_t; /// Describes a scope block. /// diff --git a/clang/lib/AST/ByteCode/Integral.h b/clang/lib/AST/ByteCode/Integral.h index af5cd2d..1318024 100644 --- a/clang/lib/AST/ByteCode/Integral.h +++ b/clang/lib/AST/ByteCode/Integral.h @@ -318,6 +318,11 @@ private: template <typename T> static bool CheckMulUB(T A, T B, T &R) { if constexpr (std::is_signed_v<T>) { return llvm::MulOverflow<T>(A, B, R); + } else if constexpr (sizeof(T) < sizeof(int)) { + // Silly integer promotion rules will convert both A and B to int, + // even it T is unsigned. Prevent that by manually casting to uint first. + R = static_cast<T>(static_cast<unsigned>(A) * static_cast<unsigned>(B)); + return false; } else { R = A * B; return false; diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index eb4e480..06b2bdc 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); @@ -529,7 +530,7 @@ bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, CheckSubobjectKind CSK) { - if (!Ptr.isElementPastEnd()) + if (!Ptr.isElementPastEnd() && !Ptr.isZeroSizeArray()) return true; const SourceInfo &Loc = S.Current->getSource(OpPC); S.FFDiag(Loc, diag::note_constexpr_past_end_subobject) @@ -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,30 @@ 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)) + assert(!Ptr.isZero()); + if (!Ptr.isBlockPointer()) return false; + + 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,13 +870,17 @@ 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)) - return false; - if (!CheckLifetime(S, OpPC, Ptr, AK_Assign)) + if (!Ptr.isBlockPointer()) return false; - if (!CheckExtern(S, OpPC, Ptr)) + + if (!Ptr.block()->isAccessible()) { + if (!CheckLive(S, OpPC, Ptr, AK_Assign)) + return false; + if (!CheckExtern(S, OpPC, Ptr)) + return false; + return CheckDummy(S, OpPC, Ptr.block(), AK_Assign); + } + if (!CheckLifetime(S, OpPC, Ptr.getLifetime(), AK_Assign)) return false; if (!CheckRange(S, OpPC, Ptr, AK_Assign)) return false; @@ -1098,13 +1152,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; @@ -1155,17 +1207,15 @@ static bool runRecordDestructor(InterpState &S, CodePtr OpPC, } // Destructor of this record. - if (const CXXDestructorDecl *Dtor = R->getDestructor(); - Dtor && !Dtor->isTrivial()) { - const Function *DtorFunc = S.getContext().getOrCreateFunction(Dtor); - if (!DtorFunc) - return false; + const CXXDestructorDecl *Dtor = R->getDestructor(); + assert(Dtor); + assert(!Dtor->isTrivial()); + const Function *DtorFunc = S.getContext().getOrCreateFunction(Dtor); + if (!DtorFunc) + return false; - S.Stk.push<Pointer>(BasePtr); - if (!Call(S, OpPC, DtorFunc, 0)) - return false; - } - return true; + S.Stk.push<Pointer>(BasePtr); + return Call(S, OpPC, DtorFunc, 0); } static bool RunDestructors(InterpState &S, CodePtr OpPC, const Block *B) { @@ -1177,6 +1227,9 @@ static bool RunDestructors(InterpState &S, CodePtr OpPC, const Block *B) { assert(Desc->isRecord() || Desc->isCompositeArray()); + if (Desc->hasTrivialDtor()) + return true; + if (Desc->isCompositeArray()) { unsigned N = Desc->getNumElems(); if (N == 0) @@ -1251,7 +1304,7 @@ bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm, return false; } - if (!Ptr.isRoot() || Ptr.isOnePastEnd() || + if (!Ptr.isRoot() || (Ptr.isOnePastEnd() && !Ptr.isZeroSizeArray()) || (Ptr.isArrayElement() && Ptr.getIndex() != 0)) { const SourceInfo &Loc = S.Current->getSource(OpPC); S.FFDiag(Loc, diag::note_constexpr_delete_subobject) @@ -1426,7 +1479,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 +1673,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 +1811,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,8 +1842,13 @@ 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; + + // FIXME: We need per-element lifetime information for primitive arrays. + if (Ptr.isArrayElement()) + return true; + endLifetimeRecurse(Ptr.narrow()); return true; } @@ -1789,8 +1856,13 @@ 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; + + // FIXME: We need per-element lifetime information for primitive arrays. + if (Ptr.isArrayElement()) + return true; + endLifetimeRecurse(Ptr.narrow()); return true; } @@ -1802,26 +1874,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 +2089,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 +2097,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; } @@ -2040,8 +2118,8 @@ bool DiagTypeid(InterpState &S, CodePtr OpPC) { bool arePotentiallyOverlappingStringLiterals(const Pointer &LHS, const Pointer &RHS) { - unsigned LHSOffset = LHS.getIndex(); - unsigned RHSOffset = RHS.getIndex(); + unsigned LHSOffset = LHS.isOnePastEnd() ? LHS.getNumElems() : LHS.getIndex(); + unsigned RHSOffset = RHS.isOnePastEnd() ? RHS.getNumElems() : RHS.getIndex(); unsigned LHSLength = (LHS.getNumElems() - 1) * LHS.elemSize(); unsigned RHSLength = (RHS.getNumElems() - 1) * RHS.elemSize(); diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h index 8a28106..2da2202 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; } @@ -1634,6 +1640,9 @@ bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) { const Pointer &Ptr = S.Stk.peek<Pointer>(); if (!CheckRange(S, OpPC, Ptr, CSK_Field)) return false; + if (!CheckArray(S, OpPC, Ptr)) + return false; + const Pointer &Field = Ptr.atField(I); Field.deref<T>() = Value; Field.initialize(); @@ -1646,6 +1655,9 @@ bool InitFieldActivate(InterpState &S, CodePtr OpPC, uint32_t I) { const Pointer &Ptr = S.Stk.peek<Pointer>(); if (!CheckRange(S, OpPC, Ptr, CSK_Field)) return false; + if (!CheckArray(S, OpPC, Ptr)) + return false; + const Pointer &Field = Ptr.atField(I); Field.deref<T>() = Value; Field.activate(); @@ -1657,7 +1669,13 @@ template <PrimType Name, class T = typename PrimConv<Name>::T> bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) { assert(F->isBitField()); const T &Value = S.Stk.pop<T>(); - const Pointer &Field = S.Stk.peek<Pointer>().atField(F->Offset); + const Pointer &Ptr = S.Stk.peek<Pointer>(); + if (!CheckRange(S, OpPC, Ptr, CSK_Field)) + return false; + if (!CheckArray(S, OpPC, Ptr)) + return false; + + const Pointer &Field = Ptr.atField(F->Offset); if constexpr (needsAlloc<T>()) { T Result = S.allocAP<T>(Value.bitWidth()); @@ -1683,7 +1701,13 @@ bool InitBitFieldActivate(InterpState &S, CodePtr OpPC, const Record::Field *F) { assert(F->isBitField()); const T &Value = S.Stk.pop<T>(); - const Pointer &Field = S.Stk.peek<Pointer>().atField(F->Offset); + const Pointer &Ptr = S.Stk.peek<Pointer>(); + if (!CheckRange(S, OpPC, Ptr, CSK_Field)) + return false; + if (!CheckArray(S, OpPC, Ptr)) + return false; + + const Pointer &Field = Ptr.atField(F->Offset); if constexpr (needsAlloc<T>()) { T Result = S.allocAP<T>(Value.bitWidth()); @@ -1764,10 +1788,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) @@ -1785,6 +1806,8 @@ inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) { return false; if (!Ptr.isBlockPointer()) { + if (!Ptr.isIntegralPointer()) + return false; S.Stk.push<Pointer>(Ptr.asIntPointer().baseCast(S.getASTContext(), Off)); return true; } @@ -1806,6 +1829,8 @@ inline bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off, return false; if (!Ptr.isBlockPointer()) { + if (!Ptr.isIntegralPointer()) + return false; S.Stk.push<Pointer>(Ptr.asIntPointer().baseCast(S.getASTContext(), Off)); return true; } @@ -2351,8 +2376,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 +2385,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); } @@ -2434,9 +2459,17 @@ inline bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I) { const Pointer &Ptr = S.Current->getLocalPointer(Local.Offset); if (Ptr.getLifetime() == Lifetime::Ended) { - auto *D = cast<NamedDecl>(Ptr.getFieldDesc()->asDecl()); - S.FFDiag(D->getLocation(), diag::note_constexpr_destroy_out_of_lifetime) - << D->getNameAsString(); + // Try to use the declaration for better diagnostics + if (const Decl *D = Ptr.getDeclDesc()->asDecl()) { + auto *ND = cast<NamedDecl>(D); + S.FFDiag(ND->getLocation(), + diag::note_constexpr_destroy_out_of_lifetime) + << ND->getNameAsString(); + } else { + S.FFDiag(Ptr.getDeclDesc()->getLocation(), + diag::note_constexpr_destroy_out_of_lifetime) + << Ptr.toDiagnosticString(S.getASTContext()); + } return false; } } @@ -3155,8 +3188,10 @@ inline bool ArrayDecay(InterpState &S, CodePtr OpPC) { return true; } - if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer)) - return false; + if (!Ptr.isZeroSizeArray()) { + if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer)) + return false; + } if (Ptr.isRoot() || !Ptr.isUnknownSizeArray()) { S.Stk.push<Pointer>(Ptr.atIndex(0)); @@ -3195,6 +3230,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; } @@ -3452,7 +3490,15 @@ inline bool AllocN(InterpState &S, CodePtr OpPC, PrimType T, const Expr *Source, S.Stk.push<Pointer>(0, nullptr); return true; } - assert(NumElements.isPositive()); + if (NumElements.isNegative()) { + if (!IsNoThrow) { + S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_new_negative) + << NumElements.toDiagnosticString(S.getASTContext()); + return false; + } + S.Stk.push<Pointer>(0, nullptr); + return true; + } if (!CheckArraySize(S, OpPC, static_cast<uint64_t>(NumElements))) return false; diff --git a/clang/lib/AST/ByteCode/InterpBlock.cpp b/clang/lib/AST/ByteCode/InterpBlock.cpp index 963b54e..ac6f01f 100644 --- a/clang/lib/AST/ByteCode/InterpBlock.cpp +++ b/clang/lib/AST/ByteCode/InterpBlock.cpp @@ -18,18 +18,14 @@ using namespace clang::interp; void Block::addPointer(Pointer *P) { assert(P); - if (IsStatic) { - assert(!Pointers); - return; - } #ifndef NDEBUG assert(!hasPointer(P)); #endif if (Pointers) - Pointers->PointeeStorage.BS.Prev = P; - P->PointeeStorage.BS.Next = Pointers; - P->PointeeStorage.BS.Prev = nullptr; + Pointers->BS.Prev = P; + P->BS.Next = Pointers; + P->BS.Prev = nullptr; Pointers = P; #ifndef NDEBUG assert(hasPointer(P)); @@ -39,32 +35,28 @@ void Block::addPointer(Pointer *P) { void Block::removePointer(Pointer *P) { assert(P->isBlockPointer()); assert(P); - if (IsStatic) { - assert(!Pointers); - return; - } #ifndef NDEBUG assert(hasPointer(P)); #endif - BlockPointer &BP = P->PointeeStorage.BS; + BlockPointer &BP = P->BS; if (Pointers == P) Pointers = BP.Next; if (BP.Prev) - BP.Prev->PointeeStorage.BS.Next = BP.Next; + BP.Prev->BS.Next = BP.Next; if (BP.Next) - BP.Next->PointeeStorage.BS.Prev = BP.Prev; - P->PointeeStorage.BS.Pointee = nullptr; + BP.Next->BS.Prev = BP.Prev; + P->BS.Pointee = nullptr; #ifndef NDEBUG assert(!hasPointer(P)); #endif } void Block::cleanup() { - if (Pointers == nullptr && IsDead) + if (Pointers == nullptr && !isDynamic() && isDead()) (reinterpret_cast<DeadBlock *>(this + 1) - 1)->free(); } @@ -74,21 +66,17 @@ void Block::replacePointer(Pointer *Old, Pointer *New) { assert(New); assert(New->isBlockPointer()); assert(Old != New); - if (IsStatic) { - assert(!Pointers); - return; - } #ifndef NDEBUG assert(hasPointer(Old)); #endif - BlockPointer &OldBP = Old->PointeeStorage.BS; - BlockPointer &NewBP = New->PointeeStorage.BS; + BlockPointer &OldBP = Old->BS; + BlockPointer &NewBP = New->BS; if (OldBP.Prev) - OldBP.Prev->PointeeStorage.BS.Next = New; + OldBP.Prev->BS.Next = New; if (OldBP.Next) - OldBP.Next->PointeeStorage.BS.Prev = New; + OldBP.Next->BS.Prev = New; NewBP.Prev = OldBP.Prev; NewBP.Next = OldBP.Next; if (Pointers == Old) @@ -113,8 +101,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; @@ -123,18 +111,17 @@ DeadBlock::DeadBlock(DeadBlock *&Root, Block *Blk) Prev = nullptr; Root = this; - B.IsDynamic = Blk->IsDynamic; + B.DynAllocId = Blk->DynAllocId; // Transfer pointers. B.Pointers = Blk->Pointers; for (Pointer *P = Blk->Pointers; P; P = P->asBlockPointer().Next) - P->PointeeStorage.BS.Pointee = &B; + P->BS.Pointee = &B; Blk->Pointers = nullptr; } 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..ea9f44c 100644 --- a/clang/lib/AST/ByteCode/InterpBlock.h +++ b/clang/lib/AST/ByteCode/InterpBlock.h @@ -22,7 +22,7 @@ class Block; class DeadBlock; class InterpState; class Pointer; -enum PrimType : unsigned; +enum PrimType : uint8_t; /// A memory block, either on the stack or in the heap. /// @@ -42,21 +42,31 @@ 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) { + Block(unsigned EvalID, UnsignedOrNone DeclID, const Descriptor *Desc, + bool IsStatic = false, bool IsExtern = false, 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), EvalID(EvalID), IsStatic(IsStatic) { assert(Desc); + AccessFlags |= (ExternFlag * IsExtern); + AccessFlags |= (WeakFlag * IsWeak); + AccessFlags |= (DummyFlag * IsDummy); } /// Returns the block's descriptor. @@ -64,17 +74,19 @@ 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 isDynamic() const { return IsDynamic; } + bool isWeak() const { return AccessFlags & WeakFlag; } + bool isDynamic() const { return (DynAllocId != std::nullopt); } + 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. - std::optional<unsigned> getDeclID() const { return DeclID; } + UnsignedOrNone getDeclID() const { return DeclID; } /// Returns whether the data of this block has been initialized via /// invoking the Ctor func. bool isInitialized() const { return IsInitialized; } @@ -103,6 +115,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,19 +142,28 @@ 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; friend class InterpState; friend class DynamicAllocator; + friend class Program; 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); } + /// To be called by DynamicAllocator. + void setDynAllocId(unsigned ID) { DynAllocId = ID; } + /// Deletes a dead block at the end of its lifetime. void cleanup(); @@ -150,27 +175,22 @@ 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; + UnsignedOrNone DeclID = std::nullopt; + 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; + /// Allocation ID for this dynamic allocation, if it is one. + UnsignedOrNone DynAllocId = std::nullopt; + /// 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..e05b1a8 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -141,6 +141,22 @@ static void diagnoseNonConstexprBuiltin(InterpState &S, CodePtr OpPC, S.CCEDiag(Loc, diag::note_invalid_subexpr_in_const_expr); } +static llvm::APSInt convertBoolVectorToInt(const Pointer &Val) { + assert(Val.getFieldDesc()->isPrimitiveArray() && + Val.getFieldDesc()->getElemQualType()->isBooleanType() && + "Not a boolean vector"); + unsigned NumElems = Val.getNumElems(); + + // Each element is one bit, so create an integer with NumElts bits. + llvm::APSInt Result(NumElems, 0); + for (unsigned I = 0; I != NumElems; ++I) { + if (Val.elem<bool>(I)) + Result.setBit(I); + } + + return Result; +} + static bool interp__builtin_is_constant_evaluated(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const CallExpr *Call) { @@ -205,6 +221,8 @@ static bool interp__builtin_strcmp(InterpState &S, CodePtr OpPC, if (A.isDummy() || B.isDummy()) return false; + if (!A.isBlockPointer() || !B.isBlockPointer()) + return false; bool IsWide = ID == Builtin::BIwcscmp || ID == Builtin::BIwcsncmp || ID == Builtin::BI__builtin_wcscmp || @@ -212,7 +230,10 @@ static bool interp__builtin_strcmp(InterpState &S, CodePtr OpPC, assert(A.getFieldDesc()->isPrimitiveArray()); assert(B.getFieldDesc()->isPrimitiveArray()); - assert(getElemType(A).getTypePtr() == getElemType(B).getTypePtr()); + // Different element types shouldn't happen, but with casts they can. + if (!S.getASTContext().hasSameUnqualifiedType(getElemType(A), getElemType(B))) + return false; + PrimType ElemT = *S.getContext().classify(getElemType(A)); auto returnResult = [&](int V) -> bool { @@ -276,7 +297,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()); @@ -459,12 +480,13 @@ static bool interp__builtin_isinf(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, bool CheckSign, const CallExpr *Call) { const Floating &Arg = S.Stk.pop<Floating>(); - bool IsInf = Arg.isInf(); + APFloat F = Arg.getAPFloat(); + bool IsInf = F.isInfinity(); if (CheckSign) - pushInteger(S, IsInf ? (Arg.isNegative() ? -1 : 1) : 0, Call->getType()); + pushInteger(S, IsInf ? (F.isNegative() ? -1 : 1) : 0, Call->getType()); else - pushInteger(S, Arg.isInf(), Call->getType()); + pushInteger(S, IsInf, Call->getType()); return true; } @@ -597,6 +619,17 @@ static bool interp__builtin_fpclassify(InterpState &S, CodePtr OpPC, return true; } +static inline Floating abs(InterpState &S, const Floating &In) { + if (!In.isNegative()) + return In; + + Floating Output = S.allocFloat(In.getSemantics()); + APFloat New = In.getAPFloat(); + New.changeSign(); + Output.copy(New); + return Output; +} + // The C standard says "fabs raises no floating-point exceptions, // even if x is a signaling NaN. The returned value is independent of // the current rounding direction mode." Therefore constant folding can @@ -605,16 +638,7 @@ static bool interp__builtin_fpclassify(InterpState &S, CodePtr OpPC, static bool interp__builtin_fabs(InterpState &S, CodePtr OpPC, const InterpFrame *Frame) { const Floating &Val = S.Stk.pop<Floating>(); - APFloat F = Val.getAPFloat(); - if (!F.isNegative()) { - S.Stk.push<Floating>(Val); - return true; - } - - Floating Result = S.allocFloat(Val.getSemantics()); - F.changeSign(); - Result.copy(F); - S.Stk.push<Floating>(Result); + S.Stk.push<Floating>(abs(S, Val)); return true; } @@ -635,8 +659,14 @@ static bool interp__builtin_abs(InterpState &S, CodePtr OpPC, static bool interp__builtin_popcount(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const CallExpr *Call) { - PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType()); - APSInt Val = popToAPSInt(S.Stk, ArgT); + APSInt Val; + if (Call->getArg(0)->getType()->isExtVectorBoolType()) { + const Pointer &Arg = S.Stk.pop<Pointer>(); + Val = convertBoolVectorToInt(Arg); + } else { + PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType()); + Val = popToAPSInt(S.Stk, ArgT); + } pushInteger(S, Val.popcount(), Call->getType()); return true; } @@ -932,8 +962,14 @@ static bool interp__builtin_clz(InterpState &S, CodePtr OpPC, PrimType FallbackT = *S.getContext().classify(Call->getArg(1)); Fallback = popToAPSInt(S.Stk, FallbackT); } - PrimType ValT = *S.getContext().classify(Call->getArg(0)); - const APSInt &Val = popToAPSInt(S.Stk, ValT); + APSInt Val; + if (Call->getArg(0)->getType()->isExtVectorBoolType()) { + const Pointer &Arg = S.Stk.pop<Pointer>(); + Val = convertBoolVectorToInt(Arg); + } else { + PrimType ValT = *S.getContext().classify(Call->getArg(0)); + Val = popToAPSInt(S.Stk, ValT); + } // When the argument is 0, the result of GCC builtins is undefined, whereas // for Microsoft intrinsics, the result is the bit-width of the argument. @@ -963,8 +999,14 @@ static bool interp__builtin_ctz(InterpState &S, CodePtr OpPC, PrimType FallbackT = *S.getContext().classify(Call->getArg(1)); Fallback = popToAPSInt(S.Stk, FallbackT); } - PrimType ValT = *S.getContext().classify(Call->getArg(0)); - const APSInt &Val = popToAPSInt(S.Stk, ValT); + APSInt Val; + if (Call->getArg(0)->getType()->isExtVectorBoolType()) { + const Pointer &Arg = S.Stk.pop<Pointer>(); + Val = convertBoolVectorToInt(Arg); + } else { + PrimType ValT = *S.getContext().classify(Call->getArg(0)); + Val = popToAPSInt(S.Stk, ValT); + } if (Val == 0) { if (Fallback) { @@ -1544,8 +1586,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 +1599,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); @@ -1687,6 +1727,57 @@ static bool interp__builtin_vector_reduce(InterpState &S, CodePtr OpPC, return true; } +static bool interp__builtin_elementwise_abs(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame, + const CallExpr *Call, + unsigned BuiltinID) { + assert(Call->getNumArgs() == 1); + QualType Ty = Call->getArg(0)->getType(); + if (Ty->isIntegerType()) { + PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType()); + APSInt Val = popToAPSInt(S.Stk, ArgT); + + pushInteger(S, Val.abs(), Call->getType()); + return true; + } + + if (Ty->isFloatingType()) { + Floating Val = S.Stk.pop<Floating>(); + Floating Result = abs(S, Val); + S.Stk.push<Floating>(Result); + return true; + } + + // Otherwise, the argument must be a vector. + assert(Call->getArg(0)->getType()->isVectorType()); + const Pointer &Arg = S.Stk.pop<Pointer>(); + assert(Arg.getFieldDesc()->isPrimitiveArray()); + const Pointer &Dst = S.Stk.peek<Pointer>(); + assert(Dst.getFieldDesc()->isPrimitiveArray()); + assert(Arg.getFieldDesc()->getNumElems() == + Dst.getFieldDesc()->getNumElems()); + + QualType ElemType = Arg.getFieldDesc()->getElemQualType(); + PrimType ElemT = *S.getContext().classify(ElemType); + unsigned NumElems = Arg.getNumElems(); + // we can either have a vector of integer or a vector of floating point + for (unsigned I = 0; I != NumElems; ++I) { + if (ElemType->isIntegerType()) { + INT_TYPE_SWITCH_NO_BOOL(ElemT, { + Dst.elem<T>(I) = T::from(static_cast<T>( + APSInt(Arg.elem<T>(I).toAPSInt().abs(), + ElemType->isUnsignedIntegerOrEnumerationType()))); + }); + } else { + Floating Val = Arg.elem<Floating>(I); + Dst.elem<Floating>(I) = abs(S, Val); + } + } + Dst.initializeAllElements(); + + return true; +} + /// Can be called with an integer or vector as the first and only parameter. static bool interp__builtin_elementwise_popcount(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, @@ -1733,6 +1824,94 @@ static bool interp__builtin_elementwise_popcount(InterpState &S, CodePtr OpPC, return true; } +/// Can be called with an integer or vector as the first and only parameter. +static bool interp__builtin_elementwise_countzeroes(InterpState &S, + CodePtr OpPC, + const InterpFrame *Frame, + const CallExpr *Call, + unsigned BuiltinID) { + const bool HasZeroArg = Call->getNumArgs() == 2; + const bool IsCTTZ = BuiltinID == Builtin::BI__builtin_elementwise_cttz; + assert(Call->getNumArgs() == 1 || HasZeroArg); + if (Call->getArg(0)->getType()->isIntegerType()) { + PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType()); + APSInt Val = popToAPSInt(S.Stk, ArgT); + std::optional<APSInt> ZeroVal; + if (HasZeroArg) { + ZeroVal = Val; + Val = popToAPSInt(S.Stk, ArgT); + } + + if (Val.isZero()) { + if (ZeroVal) { + pushInteger(S, *ZeroVal, Call->getType()); + return true; + } + // If we haven't been provided the second argument, the result is + // undefined + S.FFDiag(S.Current->getSource(OpPC), + diag::note_constexpr_countzeroes_zero) + << /*IsTrailing=*/IsCTTZ; + return false; + } + + if (BuiltinID == Builtin::BI__builtin_elementwise_ctlz) { + pushInteger(S, Val.countLeadingZeros(), Call->getType()); + } else { + pushInteger(S, Val.countTrailingZeros(), Call->getType()); + } + return true; + } + // Otherwise, the argument must be a vector. + const ASTContext &ASTCtx = S.getASTContext(); + Pointer ZeroArg; + if (HasZeroArg) { + assert(Call->getArg(1)->getType()->isVectorType() && + ASTCtx.hasSameUnqualifiedType(Call->getArg(0)->getType(), + Call->getArg(1)->getType())); + (void)ASTCtx; + ZeroArg = S.Stk.pop<Pointer>(); + assert(ZeroArg.getFieldDesc()->isPrimitiveArray()); + } + assert(Call->getArg(0)->getType()->isVectorType()); + const Pointer &Arg = S.Stk.pop<Pointer>(); + assert(Arg.getFieldDesc()->isPrimitiveArray()); + const Pointer &Dst = S.Stk.peek<Pointer>(); + assert(Dst.getFieldDesc()->isPrimitiveArray()); + assert(Arg.getFieldDesc()->getNumElems() == + Dst.getFieldDesc()->getNumElems()); + + QualType ElemType = Arg.getFieldDesc()->getElemQualType(); + PrimType ElemT = *S.getContext().classify(ElemType); + unsigned NumElems = Arg.getNumElems(); + + // FIXME: Reading from uninitialized vector elements? + for (unsigned I = 0; I != NumElems; ++I) { + INT_TYPE_SWITCH_NO_BOOL(ElemT, { + APInt EltVal = Arg.atIndex(I).deref<T>().toAPSInt(); + if (EltVal.isZero()) { + if (HasZeroArg) { + Dst.atIndex(I).deref<T>() = ZeroArg.atIndex(I).deref<T>(); + } else { + // If we haven't been provided the second argument, the result is + // undefined + S.FFDiag(S.Current->getSource(OpPC), + diag::note_constexpr_countzeroes_zero) + << /*IsTrailing=*/IsCTTZ; + return false; + } + } else if (IsCTTZ) { + Dst.atIndex(I).deref<T>() = T::from(EltVal.countTrailingZeros()); + } else { + Dst.atIndex(I).deref<T>() = T::from(EltVal.countLeadingZeros()); + } + Dst.atIndex(I).initialize(); + }); + } + + return true; +} + static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const CallExpr *Call, unsigned ID) { @@ -1784,7 +1963,27 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC, if (DestPtr.isDummy() || SrcPtr.isDummy()) return false; + if (DestPtr.getType()->isIncompleteType()) { + S.FFDiag(S.Current->getSource(OpPC), + diag::note_constexpr_memcpy_incomplete_type) + << Move << DestPtr.getType(); + return false; + } + if (SrcPtr.getType()->isIncompleteType()) { + S.FFDiag(S.Current->getSource(OpPC), + diag::note_constexpr_memcpy_incomplete_type) + << Move << SrcPtr.getType(); + return false; + } + QualType DestElemType = getElemType(DestPtr); + if (DestElemType->isIncompleteType()) { + S.FFDiag(S.Current->getSource(OpPC), + diag::note_constexpr_memcpy_incomplete_type) + << Move << DestElemType; + return false; + } + size_t RemainingDestElems; if (DestPtr.getFieldDesc()->isArray()) { RemainingDestElems = DestPtr.isUnknownSizeArray() @@ -1826,16 +2025,6 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC, return false; } - if (DestElemType->isIncompleteType() || - DestPtr.getType()->isIncompleteType()) { - QualType DiagType = - DestElemType->isIncompleteType() ? DestElemType : DestPtr.getType(); - S.FFDiag(S.Current->getSource(OpPC), - diag::note_constexpr_memcpy_incomplete_type) - << Move << DiagType; - return false; - } - if (!DestElemType.isTriviallyCopyableType(ASTCtx)) { S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_memcpy_nontrivial) << Move << DestElemType; @@ -2024,8 +2213,13 @@ static bool interp__builtin_memchr(InterpState &S, CodePtr OpPC, return true; } - if (Ptr.isDummy()) + if (Ptr.isDummy()) { + if (Ptr.getType()->isIncompleteType()) + S.FFDiag(S.Current->getSource(OpPC), + diag::note_constexpr_ltor_incomplete_type) + << Ptr.getType(); return false; + } // Null is only okay if the given size is 0. if (Ptr.isZero()) { @@ -2103,29 +2297,32 @@ static bool interp__builtin_memchr(InterpState &S, CodePtr OpPC, return true; } -static unsigned computeFullDescSize(const ASTContext &ASTCtx, - const Descriptor *Desc) { - +static std::optional<unsigned> computeFullDescSize(const ASTContext &ASTCtx, + const Descriptor *Desc) { if (Desc->isPrimitive()) return ASTCtx.getTypeSizeInChars(Desc->getType()).getQuantity(); - if (Desc->isArray()) return ASTCtx.getTypeSizeInChars(Desc->getElemQualType()).getQuantity() * Desc->getNumElems(); + if (Desc->isRecord()) { + // Can't use Descriptor::getType() as that may return a pointer type. Look + // at the decl directly. + return ASTCtx + .getTypeSizeInChars( + ASTCtx.getCanonicalTagType(Desc->ElemRecord->getDecl())) + .getQuantity(); + } - if (Desc->isRecord()) - return ASTCtx.getTypeSizeInChars(Desc->getType()).getQuantity(); - - llvm_unreachable("Unhandled descriptor type"); - return 0; + return std::nullopt; } +/// Compute the byte offset of \p Ptr in the full declaration. static unsigned computePointerOffset(const ASTContext &ASTCtx, const Pointer &Ptr) { unsigned Result = 0; Pointer P = Ptr; - while (P.isArrayElement() || P.isField()) { + while (P.isField() || P.isArrayElement()) { P = P.expand(); const Descriptor *D = P.getFieldDesc(); @@ -2138,7 +2335,6 @@ static unsigned computePointerOffset(const ASTContext &ASTCtx, Result += ElemSize * P.getIndex(); P = P.expand().getArray(); } else if (P.isBaseClass()) { - const auto *RD = cast<CXXRecordDecl>(D->asDecl()); bool IsVirtual = Ptr.isVirtualBaseClass(); P = P.getBase(); @@ -2167,30 +2363,136 @@ static unsigned computePointerOffset(const ASTContext &ASTCtx, return Result; } +/// Does Ptr point to the last subobject? +static bool pointsToLastObject(const Pointer &Ptr) { + Pointer P = Ptr; + while (!P.isRoot()) { + + if (P.isArrayElement()) { + P = P.expand().getArray(); + continue; + } + if (P.isBaseClass()) { + if (P.getRecord()->getNumFields() > 0) + return false; + P = P.getBase(); + continue; + } + + Pointer Base = P.getBase(); + if (const Record *R = Base.getRecord()) { + assert(P.getField()); + if (P.getField()->getFieldIndex() != R->getNumFields() - 1) + return false; + } + P = Base; + } + + return true; +} + +/// Does Ptr point to the last object AND to a flexible array member? +static bool isUserWritingOffTheEnd(const ASTContext &Ctx, const Pointer &Ptr) { + auto isFlexibleArrayMember = [&](const Descriptor *FieldDesc) { + using FAMKind = LangOptions::StrictFlexArraysLevelKind; + FAMKind StrictFlexArraysLevel = + Ctx.getLangOpts().getStrictFlexArraysLevel(); + + if (StrictFlexArraysLevel == FAMKind::Default) + return true; + + unsigned NumElems = FieldDesc->getNumElems(); + if (NumElems == 0 && StrictFlexArraysLevel != FAMKind::IncompleteOnly) + return true; + + if (NumElems == 1 && StrictFlexArraysLevel == FAMKind::OneZeroOrIncomplete) + return true; + return false; + }; + + const Descriptor *FieldDesc = Ptr.getFieldDesc(); + if (!FieldDesc->isArray()) + return false; + + return Ptr.isDummy() && pointsToLastObject(Ptr) && + isFlexibleArrayMember(FieldDesc); +} + static bool interp__builtin_object_size(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const CallExpr *Call) { + const ASTContext &ASTCtx = S.getASTContext(); PrimType KindT = *S.getContext().classify(Call->getArg(1)); - [[maybe_unused]] unsigned Kind = popToAPSInt(S.Stk, KindT).getZExtValue(); - + // From the GCC docs: + // Kind is an integer constant from 0 to 3. If the least significant bit is + // clear, objects are whole variables. If it is set, a closest surrounding + // subobject is considered the object a pointer points to. The second bit + // determines if maximum or minimum of remaining bytes is computed. + unsigned Kind = popToAPSInt(S.Stk, KindT).getZExtValue(); assert(Kind <= 3 && "unexpected kind"); - + bool UseFieldDesc = (Kind & 1u); + bool ReportMinimum = (Kind & 2u); const Pointer &Ptr = S.Stk.pop<Pointer>(); - if (Ptr.isZero()) + if (Call->getArg(0)->HasSideEffects(ASTCtx)) { + // "If there are any side effects in them, it returns (size_t) -1 + // for type 0 or 1 and (size_t) 0 for type 2 or 3." + pushInteger(S, Kind <= 1 ? -1 : 0, Call->getType()); + return true; + } + + if (Ptr.isZero() || !Ptr.isBlockPointer()) return false; - const Descriptor *DeclDesc = Ptr.getDeclDesc(); - if (!DeclDesc) + // We can't load through pointers. + if (Ptr.isDummy() && Ptr.getType()->isPointerType()) return false; - const ASTContext &ASTCtx = S.getASTContext(); + bool DetermineForCompleteObject = Ptr.getFieldDesc() == Ptr.getDeclDesc(); + const Descriptor *DeclDesc = Ptr.getDeclDesc(); + assert(DeclDesc); + + if (!UseFieldDesc || DetermineForCompleteObject) { + // Lower bound, so we can't fall back to this. + if (ReportMinimum && !DetermineForCompleteObject) + return false; - unsigned ByteOffset = computePointerOffset(ASTCtx, Ptr); - unsigned FullSize = computeFullDescSize(ASTCtx, DeclDesc); + // Can't read beyond the pointer decl desc. + if (!UseFieldDesc && !ReportMinimum && DeclDesc->getType()->isPointerType()) + return false; + } else { + if (isUserWritingOffTheEnd(ASTCtx, Ptr.expand())) { + // If we cannot determine the size of the initial allocation, then we + // can't given an accurate upper-bound. However, we are still able to give + // conservative lower-bounds for Type=3. + if (Kind == 1) + return false; + } + } - pushInteger(S, FullSize - ByteOffset, Call->getType()); + const Descriptor *Desc = UseFieldDesc ? Ptr.getFieldDesc() : DeclDesc; + assert(Desc); + std::optional<unsigned> FullSize = computeFullDescSize(ASTCtx, Desc); + if (!FullSize) + return false; + + unsigned ByteOffset; + if (UseFieldDesc) { + if (Ptr.isBaseClass()) + ByteOffset = computePointerOffset(ASTCtx, Ptr.getBase()) - + computePointerOffset(ASTCtx, Ptr); + else + ByteOffset = + computePointerOffset(ASTCtx, Ptr) - + computePointerOffset(ASTCtx, Ptr.expand().atIndex(0).narrow()); + } else + ByteOffset = computePointerOffset(ASTCtx, Ptr); + + assert(ByteOffset <= *FullSize); + unsigned Result = *FullSize - ByteOffset; + + pushInteger(S, Result, Call->getType()); return true; } @@ -2232,17 +2534,13 @@ 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; } // Check if we're currently running an initializer. - for (InterpFrame *Frame = S.Current; Frame; Frame = Frame->Caller) { - if (const Function *F = Frame->getFunction(); - F && F->isConstructor() && Frame->getThis().block() == Ptr.block()) { - return Error(2); - } - } + if (llvm::is_contained(S.InitializingBlocks, Ptr.block())) + return Error(2); if (S.EvaluatingDecl && Ptr.getDeclDesc()->asVarDecl() == S.EvaluatingDecl) return Error(2); @@ -2250,10 +2548,9 @@ static bool interp__builtin_is_within_lifetime(InterpState &S, CodePtr OpPC, return true; } -static bool interp__builtin_elementwise_sat(InterpState &S, CodePtr OpPC, - const CallExpr *Call, - unsigned BuiltinID) { - Call->dumpColor(); +static bool interp__builtin_elementwise_int_binop( + InterpState &S, CodePtr OpPC, const CallExpr *Call, unsigned BuiltinID, + llvm::function_ref<APInt(const APSInt &, const APSInt &)> Fn) { assert(Call->getNumArgs() == 2); // Single integer case. @@ -2263,11 +2560,84 @@ static bool interp__builtin_elementwise_sat(InterpState &S, CodePtr OpPC, S.Stk, *S.getContext().classify(Call->getArg(1)->getType())); APSInt LHS = popToAPSInt( S.Stk, *S.getContext().classify(Call->getArg(0)->getType())); + APInt Result = Fn(LHS, RHS); + pushInteger(S, APSInt(std::move(Result), !LHS.isSigned()), Call->getType()); + return true; + } + + const auto *VT = Call->getArg(0)->getType()->castAs<VectorType>(); + assert(VT->getElementType()->isIntegralOrEnumerationType()); + PrimType ElemT = *S.getContext().classify(VT->getElementType()); + unsigned NumElems = VT->getNumElements(); + bool DestUnsigned = Call->getType()->isUnsignedIntegerOrEnumerationType(); + + // Vector + Scalar case. + if (!Call->getArg(1)->getType()->isVectorType()) { + assert(Call->getArg(1)->getType()->isIntegralOrEnumerationType()); + + APSInt RHS = popToAPSInt( + S.Stk, *S.getContext().classify(Call->getArg(1)->getType())); + const Pointer &LHS = S.Stk.pop<Pointer>(); + const Pointer &Dst = S.Stk.peek<Pointer>(); + + for (unsigned I = 0; I != NumElems; ++I) { + INT_TYPE_SWITCH_NO_BOOL(ElemT, { + Dst.elem<T>(I) = static_cast<T>( + APSInt(Fn(LHS.elem<T>(I).toAPSInt(), RHS), DestUnsigned)); + }); + } + Dst.initializeAllElements(); + return true; + } + + // Vector case. + assert(Call->getArg(0)->getType()->isVectorType() && + Call->getArg(1)->getType()->isVectorType()); + assert(VT->getElementType() == + Call->getArg(1)->getType()->castAs<VectorType>()->getElementType()); + assert(VT->getNumElements() == + Call->getArg(1)->getType()->castAs<VectorType>()->getNumElements()); + assert(VT->getElementType()->isIntegralOrEnumerationType()); + + const Pointer &RHS = S.Stk.pop<Pointer>(); + const Pointer &LHS = S.Stk.pop<Pointer>(); + const Pointer &Dst = S.Stk.peek<Pointer>(); + for (unsigned I = 0; I != NumElems; ++I) { + INT_TYPE_SWITCH_NO_BOOL(ElemT, { + APSInt Elem1 = LHS.elem<T>(I).toAPSInt(); + APSInt Elem2 = RHS.elem<T>(I).toAPSInt(); + Dst.elem<T>(I) = static_cast<T>(APSInt(Fn(Elem1, Elem2), DestUnsigned)); + }); + } + Dst.initializeAllElements(); + + return true; +} + +static bool interp__builtin_elementwise_maxmin(InterpState &S, CodePtr OpPC, + const CallExpr *Call, + unsigned BuiltinID) { + assert(Call->getNumArgs() == 2); + + QualType Arg0Type = Call->getArg(0)->getType(); + + // TODO: Support floating-point types. + if (!(Arg0Type->isIntegerType() || + (Arg0Type->isVectorType() && + Arg0Type->castAs<VectorType>()->getElementType()->isIntegerType()))) + return false; + + if (!Arg0Type->isVectorType()) { + assert(!Call->getArg(1)->getType()->isVectorType()); + APSInt RHS = popToAPSInt( + S.Stk, *S.getContext().classify(Call->getArg(1)->getType())); + APSInt LHS = popToAPSInt( + S.Stk, *S.getContext().classify(Call->getArg(0)->getType())); APInt Result; - if (BuiltinID == Builtin::BI__builtin_elementwise_add_sat) { - Result = LHS.isSigned() ? LHS.sadd_sat(RHS) : LHS.uadd_sat(RHS); - } else if (BuiltinID == Builtin::BI__builtin_elementwise_sub_sat) { - Result = LHS.isSigned() ? LHS.ssub_sat(RHS) : LHS.usub_sat(RHS); + if (BuiltinID == Builtin::BI__builtin_elementwise_max) { + Result = std::max(LHS, RHS); + } else if (BuiltinID == Builtin::BI__builtin_elementwise_min) { + Result = std::min(LHS, RHS); } else { llvm_unreachable("Wrong builtin ID"); } @@ -2300,13 +2670,11 @@ static bool interp__builtin_elementwise_sat(InterpState &S, CodePtr OpPC, }); APSInt Result; - if (BuiltinID == Builtin::BI__builtin_elementwise_add_sat) { - Result = APSInt(Elem1.isSigned() ? Elem1.sadd_sat(Elem2) - : Elem1.uadd_sat(Elem2), + if (BuiltinID == Builtin::BI__builtin_elementwise_max) { + Result = APSInt(std::max(Elem1, Elem2), Call->getType()->isUnsignedIntegerOrEnumerationType()); - } else if (BuiltinID == Builtin::BI__builtin_elementwise_sub_sat) { - Result = APSInt(Elem1.isSigned() ? Elem1.ssub_sat(Elem2) - : Elem1.usub_sat(Elem2), + } else if (BuiltinID == Builtin::BI__builtin_elementwise_min) { + Result = APSInt(std::min(Elem1, Elem2), Call->getType()->isUnsignedIntegerOrEnumerationType()); } else { llvm_unreachable("Wrong builtin ID"); @@ -2320,6 +2688,147 @@ static bool interp__builtin_elementwise_sat(InterpState &S, CodePtr OpPC, return true; } +static bool interp__builtin_ia32_pmul(InterpState &S, CodePtr OpPC, + const CallExpr *Call, + unsigned BuiltinID) { + assert(Call->getArg(0)->getType()->isVectorType() && + Call->getArg(1)->getType()->isVectorType()); + const Pointer &RHS = S.Stk.pop<Pointer>(); + const Pointer &LHS = S.Stk.pop<Pointer>(); + const Pointer &Dst = S.Stk.peek<Pointer>(); + + const auto *VT = Call->getArg(0)->getType()->castAs<VectorType>(); + PrimType ElemT = *S.getContext().classify(VT->getElementType()); + unsigned SourceLen = VT->getNumElements(); + + PrimType DstElemT = *S.getContext().classify( + Call->getType()->castAs<VectorType>()->getElementType()); + unsigned DstElem = 0; + for (unsigned I = 0; I != SourceLen; I += 2) { + APSInt Elem1; + APSInt Elem2; + INT_TYPE_SWITCH_NO_BOOL(ElemT, { + Elem1 = LHS.elem<T>(I).toAPSInt(); + Elem2 = RHS.elem<T>(I).toAPSInt(); + }); + + APSInt Result; + switch (BuiltinID) { + case clang::X86::BI__builtin_ia32_pmuludq128: + case clang::X86::BI__builtin_ia32_pmuludq256: + case clang::X86::BI__builtin_ia32_pmuludq512: + Result = APSInt(llvm::APIntOps::muluExtended(Elem1, Elem2), + /*IsUnsigned=*/true); + break; + case clang::X86::BI__builtin_ia32_pmuldq128: + case clang::X86::BI__builtin_ia32_pmuldq256: + case clang::X86::BI__builtin_ia32_pmuldq512: + Result = APSInt(llvm::APIntOps::mulsExtended(Elem1, Elem2), + /*IsUnsigned=*/false); + break; + } + INT_TYPE_SWITCH_NO_BOOL(DstElemT, + { Dst.elem<T>(DstElem) = static_cast<T>(Result); }); + ++DstElem; + } + + Dst.initializeAllElements(); + return true; +} + +static bool interp__builtin_elementwise_fma(InterpState &S, CodePtr OpPC, + const CallExpr *Call) { + assert(Call->getNumArgs() == 3); + + FPOptions FPO = Call->getFPFeaturesInEffect(S.Ctx.getLangOpts()); + llvm::RoundingMode RM = getRoundingMode(FPO); + const QualType Arg1Type = Call->getArg(0)->getType(); + const QualType Arg2Type = Call->getArg(1)->getType(); + const QualType Arg3Type = Call->getArg(2)->getType(); + + // Non-vector floating point types. + if (!Arg1Type->isVectorType()) { + assert(!Arg2Type->isVectorType()); + assert(!Arg3Type->isVectorType()); + (void)Arg2Type; + (void)Arg3Type; + + const Floating &Z = S.Stk.pop<Floating>(); + const Floating &Y = S.Stk.pop<Floating>(); + const Floating &X = S.Stk.pop<Floating>(); + APFloat F = X.getAPFloat(); + F.fusedMultiplyAdd(Y.getAPFloat(), Z.getAPFloat(), RM); + Floating Result = S.allocFloat(X.getSemantics()); + Result.copy(F); + S.Stk.push<Floating>(Result); + return true; + } + + // Vector type. + assert(Arg1Type->isVectorType() && Arg2Type->isVectorType() && + Arg3Type->isVectorType()); + + const VectorType *VecT = Arg1Type->castAs<VectorType>(); + const QualType ElemT = VecT->getElementType(); + unsigned NumElems = VecT->getNumElements(); + + assert(ElemT == Arg2Type->castAs<VectorType>()->getElementType() && + ElemT == Arg3Type->castAs<VectorType>()->getElementType()); + assert(NumElems == Arg2Type->castAs<VectorType>()->getNumElements() && + NumElems == Arg3Type->castAs<VectorType>()->getNumElements()); + assert(ElemT->isRealFloatingType()); + (void)ElemT; + + const Pointer &VZ = S.Stk.pop<Pointer>(); + const Pointer &VY = S.Stk.pop<Pointer>(); + const Pointer &VX = S.Stk.pop<Pointer>(); + const Pointer &Dst = S.Stk.peek<Pointer>(); + for (unsigned I = 0; I != NumElems; ++I) { + using T = PrimConv<PT_Float>::T; + APFloat X = VX.elem<T>(I).getAPFloat(); + APFloat Y = VY.elem<T>(I).getAPFloat(); + APFloat Z = VZ.elem<T>(I).getAPFloat(); + (void)X.fusedMultiplyAdd(Y, Z, RM); + Dst.elem<Floating>(I) = Floating(X); + } + Dst.initializeAllElements(); + return true; +} + +/// AVX512 predicated move: "Result = Mask[] ? LHS[] : RHS[]". +static bool interp__builtin_select(InterpState &S, CodePtr OpPC, + const CallExpr *Call) { + const Pointer &RHS = S.Stk.pop<Pointer>(); + const Pointer &LHS = S.Stk.pop<Pointer>(); + PrimType MaskT = *S.getContext().classify(Call->getArg(0)); + APSInt Mask = popToAPSInt(S.Stk, MaskT); + const Pointer &Dst = S.Stk.peek<Pointer>(); + + assert(LHS.getNumElems() == RHS.getNumElems()); + assert(LHS.getNumElems() == Dst.getNumElems()); + unsigned NumElems = LHS.getNumElems(); + PrimType ElemT = LHS.getFieldDesc()->getPrimType(); + PrimType DstElemT = Dst.getFieldDesc()->getPrimType(); + + for (unsigned I = 0; I != NumElems; ++I) { + if (ElemT == PT_Float) { + assert(DstElemT == PT_Float); + Dst.elem<Floating>(I) = + Mask[I] ? LHS.elem<Floating>(I) : RHS.elem<Floating>(I); + } else { + APSInt Elem; + INT_TYPE_SWITCH(ElemT, { + Elem = Mask[I] ? LHS.elem<T>(I).toAPSInt() : RHS.elem<T>(I).toAPSInt(); + }); + INT_TYPE_SWITCH_NO_BOOL(DstElemT, + { Dst.elem<T>(I) = static_cast<T>(Elem); }); + } + } + Dst.initializeAllElements(); + + return true; +} + bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, uint32_t BuiltinID) { if (!S.getASTContext().BuiltinInfo.isConstantEvaluated(BuiltinID)) @@ -2596,6 +3105,11 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, case Builtin::BI__builtin_ctzg: return interp__builtin_ctz(S, OpPC, Frame, Call, BuiltinID); + case Builtin::BI__builtin_elementwise_ctlz: + case Builtin::BI__builtin_elementwise_cttz: + return interp__builtin_elementwise_countzeroes(S, OpPC, Frame, Call, + BuiltinID); + case Builtin::BI__builtin_bswap16: case Builtin::BI__builtin_bswap32: case Builtin::BI__builtin_bswap64: @@ -2687,6 +3201,9 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, return interp__builtin_elementwise_popcount(S, OpPC, Frame, Call, BuiltinID); + case Builtin::BI__builtin_elementwise_abs: + return interp__builtin_elementwise_abs(S, OpPC, Frame, Call, BuiltinID); + case Builtin::BI__builtin_memcpy: case Builtin::BImemcpy: case Builtin::BI__builtin_wmemcpy: @@ -2724,8 +3241,154 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, return interp__builtin_is_within_lifetime(S, OpPC, Call); case Builtin::BI__builtin_elementwise_add_sat: + return interp__builtin_elementwise_int_binop( + S, OpPC, Call, BuiltinID, [](const APSInt &LHS, const APSInt &RHS) { + return LHS.isSigned() ? LHS.sadd_sat(RHS) : LHS.uadd_sat(RHS); + }); + case Builtin::BI__builtin_elementwise_sub_sat: - return interp__builtin_elementwise_sat(S, OpPC, Call, BuiltinID); + return interp__builtin_elementwise_int_binop( + S, OpPC, Call, BuiltinID, [](const APSInt &LHS, const APSInt &RHS) { + return LHS.isSigned() ? LHS.ssub_sat(RHS) : LHS.usub_sat(RHS); + }); + + case clang::X86::BI__builtin_ia32_pmulhuw128: + case clang::X86::BI__builtin_ia32_pmulhuw256: + case clang::X86::BI__builtin_ia32_pmulhuw512: + return interp__builtin_elementwise_int_binop(S, OpPC, Call, BuiltinID, + llvm::APIntOps::mulhu); + + case clang::X86::BI__builtin_ia32_pmulhw128: + case clang::X86::BI__builtin_ia32_pmulhw256: + case clang::X86::BI__builtin_ia32_pmulhw512: + return interp__builtin_elementwise_int_binop(S, OpPC, Call, BuiltinID, + llvm::APIntOps::mulhs); + + case clang::X86::BI__builtin_ia32_psllv2di: + case clang::X86::BI__builtin_ia32_psllv4di: + case clang::X86::BI__builtin_ia32_psllv4si: + case clang::X86::BI__builtin_ia32_psllv8si: + case clang::X86::BI__builtin_ia32_psllwi128: + case clang::X86::BI__builtin_ia32_psllwi256: + case clang::X86::BI__builtin_ia32_psllwi512: + case clang::X86::BI__builtin_ia32_pslldi128: + case clang::X86::BI__builtin_ia32_pslldi256: + case clang::X86::BI__builtin_ia32_pslldi512: + case clang::X86::BI__builtin_ia32_psllqi128: + case clang::X86::BI__builtin_ia32_psllqi256: + case clang::X86::BI__builtin_ia32_psllqi512: + return interp__builtin_elementwise_int_binop( + S, OpPC, Call, BuiltinID, [](const APSInt &LHS, const APSInt &RHS) { + if (RHS.uge(LHS.getBitWidth())) { + return APInt::getZero(LHS.getBitWidth()); + } + return LHS.shl(RHS.getZExtValue()); + }); + + case clang::X86::BI__builtin_ia32_psrav4si: + case clang::X86::BI__builtin_ia32_psrav8si: + case clang::X86::BI__builtin_ia32_psrawi128: + case clang::X86::BI__builtin_ia32_psrawi256: + case clang::X86::BI__builtin_ia32_psrawi512: + case clang::X86::BI__builtin_ia32_psradi128: + case clang::X86::BI__builtin_ia32_psradi256: + case clang::X86::BI__builtin_ia32_psradi512: + case clang::X86::BI__builtin_ia32_psraqi128: + case clang::X86::BI__builtin_ia32_psraqi256: + case clang::X86::BI__builtin_ia32_psraqi512: + return interp__builtin_elementwise_int_binop( + S, OpPC, Call, BuiltinID, [](const APSInt &LHS, const APSInt &RHS) { + if (RHS.uge(LHS.getBitWidth())) { + return LHS.ashr(LHS.getBitWidth() - 1); + } + return LHS.ashr(RHS.getZExtValue()); + }); + + case clang::X86::BI__builtin_ia32_psrlv2di: + case clang::X86::BI__builtin_ia32_psrlv4di: + case clang::X86::BI__builtin_ia32_psrlv4si: + case clang::X86::BI__builtin_ia32_psrlv8si: + case clang::X86::BI__builtin_ia32_psrlwi128: + case clang::X86::BI__builtin_ia32_psrlwi256: + case clang::X86::BI__builtin_ia32_psrlwi512: + case clang::X86::BI__builtin_ia32_psrldi128: + case clang::X86::BI__builtin_ia32_psrldi256: + case clang::X86::BI__builtin_ia32_psrldi512: + case clang::X86::BI__builtin_ia32_psrlqi128: + case clang::X86::BI__builtin_ia32_psrlqi256: + case clang::X86::BI__builtin_ia32_psrlqi512: + return interp__builtin_elementwise_int_binop( + S, OpPC, Call, BuiltinID, [](const APSInt &LHS, const APSInt &RHS) { + if (RHS.uge(LHS.getBitWidth())) { + return APInt::getZero(LHS.getBitWidth()); + } + return LHS.lshr(RHS.getZExtValue()); + }); + + case clang::X86::BI__builtin_ia32_vprotbi: + case clang::X86::BI__builtin_ia32_vprotdi: + case clang::X86::BI__builtin_ia32_vprotqi: + case clang::X86::BI__builtin_ia32_vprotwi: + case clang::X86::BI__builtin_ia32_prold128: + case clang::X86::BI__builtin_ia32_prold256: + case clang::X86::BI__builtin_ia32_prold512: + case clang::X86::BI__builtin_ia32_prolq128: + case clang::X86::BI__builtin_ia32_prolq256: + case clang::X86::BI__builtin_ia32_prolq512: + return interp__builtin_elementwise_int_binop( + S, OpPC, Call, BuiltinID, + [](const APSInt &LHS, const APSInt &RHS) { return LHS.rotl(RHS); }); + + case clang::X86::BI__builtin_ia32_prord128: + case clang::X86::BI__builtin_ia32_prord256: + case clang::X86::BI__builtin_ia32_prord512: + case clang::X86::BI__builtin_ia32_prorq128: + case clang::X86::BI__builtin_ia32_prorq256: + case clang::X86::BI__builtin_ia32_prorq512: + return interp__builtin_elementwise_int_binop( + S, OpPC, Call, BuiltinID, + [](const APSInt &LHS, const APSInt &RHS) { return LHS.rotr(RHS); }); + + case Builtin::BI__builtin_elementwise_max: + case Builtin::BI__builtin_elementwise_min: + return interp__builtin_elementwise_maxmin(S, OpPC, Call, BuiltinID); + + case clang::X86::BI__builtin_ia32_pmuldq128: + case clang::X86::BI__builtin_ia32_pmuldq256: + case clang::X86::BI__builtin_ia32_pmuldq512: + case clang::X86::BI__builtin_ia32_pmuludq128: + case clang::X86::BI__builtin_ia32_pmuludq256: + case clang::X86::BI__builtin_ia32_pmuludq512: + return interp__builtin_ia32_pmul(S, OpPC, Call, BuiltinID); + + case Builtin::BI__builtin_elementwise_fma: + return interp__builtin_elementwise_fma(S, OpPC, Call); + + case X86::BI__builtin_ia32_selectb_128: + case X86::BI__builtin_ia32_selectb_256: + case X86::BI__builtin_ia32_selectb_512: + case X86::BI__builtin_ia32_selectw_128: + case X86::BI__builtin_ia32_selectw_256: + case X86::BI__builtin_ia32_selectw_512: + case X86::BI__builtin_ia32_selectd_128: + case X86::BI__builtin_ia32_selectd_256: + case X86::BI__builtin_ia32_selectd_512: + case X86::BI__builtin_ia32_selectq_128: + case X86::BI__builtin_ia32_selectq_256: + case X86::BI__builtin_ia32_selectq_512: + case X86::BI__builtin_ia32_selectph_128: + case X86::BI__builtin_ia32_selectph_256: + case X86::BI__builtin_ia32_selectph_512: + case X86::BI__builtin_ia32_selectpbf_128: + case X86::BI__builtin_ia32_selectpbf_256: + case X86::BI__builtin_ia32_selectpbf_512: + case X86::BI__builtin_ia32_selectps_128: + case X86::BI__builtin_ia32_selectps_256: + case X86::BI__builtin_ia32_selectps_512: + case X86::BI__builtin_ia32_selectpd_128: + case X86::BI__builtin_ia32_selectpd_256: + case X86::BI__builtin_ia32_selectpd_512: + return interp__builtin_select(S, OpPC, Call); default: S.FFDiag(S.Current->getLocation(OpPC), @@ -2751,11 +3414,8 @@ bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E, switch (Node.getKind()) { case OffsetOfNode::Field: { const FieldDecl *MemberDecl = Node.getField(); - const RecordType *RT = CurrentType->getAs<RecordType>(); - if (!RT) - return false; - const RecordDecl *RD = RT->getDecl(); - if (RD->isInvalidDecl()) + const auto *RD = CurrentType->getAsRecordDecl(); + if (!RD || RD->isInvalidDecl()) return false; const ASTRecordLayout &RL = S.getASTContext().getASTRecordLayout(RD); unsigned FieldIndex = MemberDecl->getFieldIndex(); @@ -2784,22 +3444,19 @@ bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E, return false; // Find the layout of the class whose base we are looking into. - const RecordType *RT = CurrentType->getAs<RecordType>(); - if (!RT) - return false; - const RecordDecl *RD = RT->getDecl(); - if (RD->isInvalidDecl()) + const auto *RD = CurrentType->getAsCXXRecordDecl(); + if (!RD || RD->isInvalidDecl()) return false; const ASTRecordLayout &RL = S.getASTContext().getASTRecordLayout(RD); // Find the base class itself. CurrentType = BaseSpec->getType(); - const RecordType *BaseRT = CurrentType->getAs<RecordType>(); - if (!BaseRT) + const auto *BaseRD = CurrentType->getAsCXXRecordDecl(); + if (!BaseRD) return false; // Add the offset to the base. - Result += RL.getBaseClassOffset(cast<CXXRecordDecl>(BaseRT->getDecl())); + Result += RL.getBaseClassOffset(BaseRD); break; } case OffsetOfNode::Identifier: diff --git a/clang/lib/AST/ByteCode/InterpFrame.cpp b/clang/lib/AST/ByteCode/InterpFrame.cpp index 9342192..b9dc2ae 100644 --- a/clang/lib/AST/ByteCode/InterpFrame.cpp +++ b/clang/lib/AST/ByteCode/InterpFrame.cpp @@ -169,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 << "."; } } @@ -195,12 +195,6 @@ void InterpFrame::describe(llvm::raw_ostream &OS) const { OS << ")"; } -Frame *InterpFrame::getCaller() const { - if (Caller->Caller) - return Caller; - return S.getSplitFrame(); -} - SourceRange InterpFrame::getCallRange() const { if (!Caller->Func) { if (SourceRange NullRange = S.getRange(nullptr, {}); NullRange.isValid()) @@ -231,6 +225,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..cf4d27d 100644 --- a/clang/lib/AST/ByteCode/InterpFrame.h +++ b/clang/lib/AST/ByteCode/InterpFrame.h @@ -59,7 +59,7 @@ public: void describe(llvm::raw_ostream &OS) const override; /// Returns the parent frame object. - Frame *getCaller() const override; + Frame *getCaller() const override { return Caller; } /// Returns the location of the call to the frame. SourceRange getCallRange() const override; @@ -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/InterpStack.cpp b/clang/lib/AST/ByteCode/InterpStack.cpp index 6b748d6..7920378 100644 --- a/clang/lib/AST/ByteCode/InterpStack.cpp +++ b/clang/lib/AST/ByteCode/InterpStack.cpp @@ -26,33 +26,33 @@ InterpStack::~InterpStack() { std::free(Chunk); Chunk = nullptr; StackSize = 0; -#ifndef NDEBUG ItemTypes.clear(); -#endif } // We keep the last chunk around to reuse. void InterpStack::clear() { - if (!Chunk) - return; - - if (Chunk->Next) - std::free(Chunk->Next); - - assert(Chunk); - StackSize = 0; -#ifndef NDEBUG - ItemTypes.clear(); -#endif + for (PrimType Item : llvm::reverse(ItemTypes)) { + TYPE_SWITCH(Item, { this->discard<T>(); }); + } + assert(ItemTypes.empty()); + assert(empty()); } void InterpStack::clearTo(size_t NewSize) { - assert(NewSize <= size()); - size_t ToShrink = size() - NewSize; - if (ToShrink == 0) + if (NewSize == 0) + return clear(); + if (NewSize == size()) return; - shrink(ToShrink); + assert(NewSize <= size()); + for (PrimType Item : llvm::reverse(ItemTypes)) { + TYPE_SWITCH(Item, { this->discard<T>(); }); + + if (size() == NewSize) + break; + } + + // Note: discard() above already removed the types from ItemTypes. assert(size() == NewSize); } @@ -105,25 +105,9 @@ void InterpStack::shrink(size_t Size) { Chunk->End -= Size; StackSize -= Size; - -#ifndef NDEBUG - size_t TypesSize = 0; - for (PrimType T : ItemTypes) - TYPE_SWITCH(T, { TypesSize += aligned_size<T>(); }); - - size_t StackSize = size(); - while (TypesSize > StackSize) { - TYPE_SWITCH(ItemTypes.back(), { - TypesSize -= aligned_size<T>(); - ItemTypes.pop_back(); - }); - } - assert(TypesSize == StackSize); -#endif } void InterpStack::dump() const { -#ifndef NDEBUG llvm::errs() << "Items: " << ItemTypes.size() << ". Size: " << size() << '\n'; if (ItemTypes.empty()) return; @@ -133,11 +117,11 @@ void InterpStack::dump() const { // The type of the item on the top of the stack is inserted to the back // of the vector, so the iteration has to happen backwards. - for (auto TyIt = ItemTypes.rbegin(); TyIt != ItemTypes.rend(); ++TyIt) { - Offset += align(primSize(*TyIt)); + for (PrimType Item : llvm::reverse(ItemTypes)) { + Offset += align(primSize(Item)); llvm::errs() << Index << '/' << Offset << ": "; - TYPE_SWITCH(*TyIt, { + TYPE_SWITCH(Item, { const T &V = peek<T>(Offset); llvm::errs() << V; }); @@ -145,5 +129,4 @@ void InterpStack::dump() const { ++Index; } -#endif } diff --git a/clang/lib/AST/ByteCode/InterpStack.h b/clang/lib/AST/ByteCode/InterpStack.h index 580494e..b0f9f6e 100644 --- a/clang/lib/AST/ByteCode/InterpStack.h +++ b/clang/lib/AST/ByteCode/InterpStack.h @@ -17,7 +17,6 @@ #include "IntegralAP.h" #include "MemberPointer.h" #include "PrimType.h" -#include <vector> namespace clang { namespace interp { @@ -33,18 +32,14 @@ public: /// Constructs a value in place on the top of the stack. template <typename T, typename... Tys> void push(Tys &&...Args) { new (grow(aligned_size<T>())) T(std::forward<Tys>(Args)...); -#ifndef NDEBUG ItemTypes.push_back(toPrimType<T>()); -#endif } /// Returns the value from the top of the stack and removes it. template <typename T> T pop() { -#ifndef NDEBUG assert(!ItemTypes.empty()); assert(ItemTypes.back() == toPrimType<T>()); ItemTypes.pop_back(); -#endif T *Ptr = &peekInternal<T>(); T Value = std::move(*Ptr); shrink(aligned_size<T>()); @@ -53,22 +48,20 @@ public: /// Discards the top value from the stack. template <typename T> void discard() { -#ifndef NDEBUG assert(!ItemTypes.empty()); assert(ItemTypes.back() == toPrimType<T>()); ItemTypes.pop_back(); -#endif T *Ptr = &peekInternal<T>(); - Ptr->~T(); + if constexpr (!std::is_trivially_destructible_v<T>) { + Ptr->~T(); + } shrink(aligned_size<T>()); } /// Returns a reference to the value on the top of the stack. template <typename T> T &peek() const { -#ifndef NDEBUG assert(!ItemTypes.empty()); assert(ItemTypes.back() == toPrimType<T>()); -#endif return peekInternal<T>(); } @@ -83,7 +76,7 @@ public: /// Returns the size of the stack in bytes. size_t size() const { return StackSize; } - /// Clears the stack without calling any destructors. + /// Clears the stack. void clear(); void clearTo(size_t NewSize); @@ -146,9 +139,11 @@ private: /// Total size of the stack. size_t StackSize = 0; -#ifndef NDEBUG - /// vector recording the type of data we pushed into the stack. - std::vector<PrimType> ItemTypes; + /// SmallVector recording the type of data we pushed into the stack. + /// We don't usually need this during normal code interpretation but + /// when aborting, we need type information to call the destructors + /// for what's left on the stack. + llvm::SmallVector<PrimType> ItemTypes; template <typename T> static constexpr PrimType toPrimType() { if constexpr (std::is_same_v<T, Pointer>) @@ -192,7 +187,6 @@ private: llvm_unreachable("unknown type push()'ed into InterpStack"); } -#endif }; } // namespace interp diff --git a/clang/lib/AST/ByteCode/InterpState.cpp b/clang/lib/AST/ByteCode/InterpState.cpp index a06b125..a2a1e58 100644 --- a/clang/lib/AST/ByteCode/InterpState.cpp +++ b/clang/lib/AST/ByteCode/InterpState.cpp @@ -45,6 +45,12 @@ InterpState::~InterpState() { while (DeadBlocks) { DeadBlock *Next = DeadBlocks->Next; + + // There might be a pointer in a global structure pointing to the dead + // block. + for (Pointer *P = DeadBlocks->B.Pointers; P; P = P->asBlockPointer().Next) + DeadBlocks->B.removePointer(P); + std::free(DeadBlocks); DeadBlocks = Next; } @@ -53,20 +59,10 @@ InterpState::~InterpState() { void InterpState::cleanup() { // As a last resort, make sure all pointers still pointing to a dead block // don't point to it anymore. - for (DeadBlock *DB = DeadBlocks; DB; DB = DB->Next) { - for (Pointer *P = DB->B.Pointers; P; P = P->asBlockPointer().Next) { - P->PointeeStorage.BS.Pointee = nullptr; - } - } - Alloc.cleanup(); } -Frame *InterpState::getCurrentFrame() { - if (Current && Current->Caller) - return Current; - return Parent.getCurrentFrame(); -} +Frame *InterpState::getCurrentFrame() { return Current; } bool InterpState::reportOverflow(const Expr *E, const llvm::APSInt &Value) { QualType Type = E->getType(); @@ -76,8 +72,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 +84,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 +93,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/InterpState.h b/clang/lib/AST/ByteCode/InterpState.h index 861e4c3..f123a1f 100644 --- a/clang/lib/AST/ByteCode/InterpState.h +++ b/clang/lib/AST/ByteCode/InterpState.h @@ -57,14 +57,11 @@ public: bool diagnosing() const { return getEvalStatus().Diag != nullptr; } // Stack frame accessors. - Frame *getSplitFrame() { return Parent.getCurrentFrame(); } Frame *getCurrentFrame() override; unsigned getCallStackDepth() override { return Current ? (Current->getDepth() + 1) : 1; } - const Frame *getBottomFrame() const override { - return Parent.getBottomFrame(); - } + const Frame *getBottomFrame() const override { return &BottomFrame; } // Access objects from the walker context. Expr::EvalStatus &getEvalStatus() const override { 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..973bc7c 100644 --- a/clang/lib/AST/ByteCode/Pointer.cpp +++ b/clang/lib/AST/ByteCode/Pointer.cpp @@ -30,39 +30,62 @@ Pointer::Pointer(Block *Pointee) Pointer::Pointer(Block *Pointee, uint64_t BaseAndOffset) : Pointer(Pointee, BaseAndOffset, BaseAndOffset) {} -Pointer::Pointer(const Pointer &P) - : Offset(P.Offset), StorageKind(P.StorageKind), - PointeeStorage(P.PointeeStorage) { - - if (isBlockPointer() && PointeeStorage.BS.Pointee) - PointeeStorage.BS.Pointee->addPointer(this); -} - Pointer::Pointer(Block *Pointee, unsigned Base, uint64_t Offset) : Offset(Offset), StorageKind(Storage::Block) { assert((Base == RootPtrMark || Base % alignof(void *) == 0) && "wrong base"); - PointeeStorage.BS = {Pointee, Base, nullptr, nullptr}; + BS = {Pointee, Base, nullptr, nullptr}; if (Pointee) Pointee->addPointer(this); } -Pointer::Pointer(Pointer &&P) - : Offset(P.Offset), StorageKind(P.StorageKind), - PointeeStorage(P.PointeeStorage) { +Pointer::Pointer(const Pointer &P) + : Offset(P.Offset), StorageKind(P.StorageKind) { + switch (StorageKind) { + case Storage::Int: + Int = P.Int; + break; + case Storage::Block: + BS = P.BS; + if (BS.Pointee) + BS.Pointee->addPointer(this); + break; + case Storage::Fn: + Fn = P.Fn; + break; + case Storage::Typeid: + Typeid = P.Typeid; + break; + } +} - if (StorageKind == Storage::Block && PointeeStorage.BS.Pointee) - PointeeStorage.BS.Pointee->replacePointer(&P, this); +Pointer::Pointer(Pointer &&P) : Offset(P.Offset), StorageKind(P.StorageKind) { + switch (StorageKind) { + case Storage::Int: + Int = P.Int; + break; + case Storage::Block: + BS = P.BS; + if (BS.Pointee) + BS.Pointee->replacePointer(&P, this); + break; + case Storage::Fn: + Fn = P.Fn; + break; + case Storage::Typeid: + Typeid = P.Typeid; + break; + } } Pointer::~Pointer() { if (!isBlockPointer()) return; - if (Block *Pointee = PointeeStorage.BS.Pointee) { + if (Block *Pointee = BS.Pointee) { Pointee->removePointer(this); - PointeeStorage.BS.Pointee = nullptr; + BS.Pointee = nullptr; Pointee->cleanup(); } } @@ -73,13 +96,13 @@ Pointer &Pointer::operator=(const Pointer &P) { if (isBlockPointer()) { if (P.isBlockPointer() && this->block() == P.block()) { Offset = P.Offset; - PointeeStorage.BS.Base = P.PointeeStorage.BS.Base; + BS.Base = P.BS.Base; return *this; } - if (Block *Pointee = PointeeStorage.BS.Pointee) { + if (Block *Pointee = BS.Pointee) { Pointee->removePointer(this); - PointeeStorage.BS.Pointee = nullptr; + BS.Pointee = nullptr; Pointee->cleanup(); } } @@ -88,16 +111,16 @@ Pointer &Pointer::operator=(const Pointer &P) { Offset = P.Offset; if (P.isBlockPointer()) { - PointeeStorage.BS = P.PointeeStorage.BS; + BS = P.BS; - if (PointeeStorage.BS.Pointee) - PointeeStorage.BS.Pointee->addPointer(this); + if (BS.Pointee) + BS.Pointee->addPointer(this); } else if (P.isIntegralPointer()) { - PointeeStorage.Int = P.PointeeStorage.Int; + Int = P.Int; } else if (P.isFunctionPointer()) { - PointeeStorage.Fn = P.PointeeStorage.Fn; + Fn = P.Fn; } else if (P.isTypeidPointer()) { - PointeeStorage.Typeid = P.PointeeStorage.Typeid; + Typeid = P.Typeid; } else { assert(false && "Unhandled storage kind"); } @@ -110,13 +133,13 @@ Pointer &Pointer::operator=(Pointer &&P) { if (isBlockPointer()) { if (P.isBlockPointer() && this->block() == P.block()) { Offset = P.Offset; - PointeeStorage.BS.Base = P.PointeeStorage.BS.Base; + BS.Base = P.BS.Base; return *this; } - if (Block *Pointee = PointeeStorage.BS.Pointee) { + if (Block *Pointee = BS.Pointee) { Pointee->removePointer(this); - PointeeStorage.BS.Pointee = nullptr; + BS.Pointee = nullptr; Pointee->cleanup(); } } @@ -125,16 +148,16 @@ Pointer &Pointer::operator=(Pointer &&P) { Offset = P.Offset; if (P.isBlockPointer()) { - PointeeStorage.BS = P.PointeeStorage.BS; + BS = P.BS; - if (PointeeStorage.BS.Pointee) - PointeeStorage.BS.Pointee->addPointer(this); + if (BS.Pointee) + BS.Pointee->addPointer(this); } else if (P.isIntegralPointer()) { - PointeeStorage.Int = P.PointeeStorage.Int; + Int = P.Int; } else if (P.isFunctionPointer()) { - PointeeStorage.Fn = P.PointeeStorage.Fn; + Fn = P.Fn; } else if (P.isTypeidPointer()) { - PointeeStorage.Typeid = P.PointeeStorage.Typeid; + Typeid = P.Typeid; } else { assert(false && "Unhandled storage kind"); } @@ -163,12 +186,11 @@ APValue Pointer::toAPValue(const ASTContext &ASTCtx) const { } if (isTypeidPointer()) { - TypeInfoLValue TypeInfo(PointeeStorage.Typeid.TypePtr); - return APValue( - APValue::LValueBase::getTypeInfo( - TypeInfo, QualType(PointeeStorage.Typeid.TypeInfoType, 0)), - CharUnits::Zero(), {}, - /*OnePastTheEnd=*/false, /*IsNull=*/false); + TypeInfoLValue TypeInfo(Typeid.TypePtr); + return APValue(APValue::LValueBase::getTypeInfo( + TypeInfo, QualType(Typeid.TypeInfoType, 0)), + CharUnits::Zero(), {}, + /*OnePastTheEnd=*/false, /*IsNull=*/false); } // Build the lvalue base from the block. @@ -179,10 +201,7 @@ APValue Pointer::toAPValue(const ASTContext &ASTCtx) const { else if (const auto *E = Desc->asExpr()) { if (block()->isDynamic()) { QualType AllocatedType = getDeclPtr().getFieldDesc()->getDataType(ASTCtx); - // FIXME: Suboptimal counting of dynamic allocations. Move this to Context - // or InterpState? - static int ReportedDynamicAllocs = 0; - DynamicAllocLValue DA(ReportedDynamicAllocs++); + DynamicAllocLValue DA(*block()->DynAllocId); Base = APValue::LValueBase::getDynamicAlloc(DA, AllocatedType); } else { Base = E; @@ -212,7 +231,7 @@ APValue Pointer::toAPValue(const ASTContext &ASTCtx) const { UsePath = false; // Build the path into the object. - bool OnePastEnd = isOnePastEnd(); + bool OnePastEnd = isOnePastEnd() && !isZeroSizeArray(); Pointer Ptr = *this; while (Ptr.isField() || Ptr.isArrayElement()) { @@ -259,10 +278,10 @@ APValue Pointer::toAPValue(const ASTContext &ASTCtx) const { Ptr = Ptr.getArray(); } else { const Descriptor *Desc = Ptr.getFieldDesc(); - bool IsVirtual = false; // Create a path entry for the field. if (const auto *BaseOrMember = Desc->asDecl()) { + bool IsVirtual = false; if (const auto *FD = dyn_cast<FieldDecl>(BaseOrMember)) { Ptr = Ptr.getBase(); Offset += getFieldOffset(FD); @@ -303,13 +322,13 @@ APValue Pointer::toAPValue(const ASTContext &ASTCtx) const { void Pointer::print(llvm::raw_ostream &OS) const { switch (StorageKind) { case Storage::Block: { - const Block *B = PointeeStorage.BS.Pointee; + const Block *B = BS.Pointee; OS << "(Block) " << B << " {"; if (isRoot()) - OS << "rootptr(" << PointeeStorage.BS.Base << "), "; + OS << "rootptr(" << BS.Base << "), "; else - OS << PointeeStorage.BS.Base << ", "; + OS << BS.Base << ", "; if (isElementPastEnd()) OS << "pastend, "; @@ -324,8 +343,7 @@ void Pointer::print(llvm::raw_ostream &OS) const { } break; case Storage::Int: OS << "(Int) {"; - OS << PointeeStorage.Int.Value << " + " << Offset << ", " - << PointeeStorage.Int.Desc; + OS << Int.Value << " + " << Offset << ", " << Int.Desc; OS << "}"; break; case Storage::Fn: @@ -378,6 +396,8 @@ size_t Pointer::computeOffsetForComparison() const { } if (const Record *R = P.getBase().getRecord(); R && R->isUnion()) { + if (P.isOnePastEnd()) + ++Result; // Direct child of a union - all have offset 0. P = P.getBase(); continue; @@ -413,45 +433,60 @@ bool Pointer::isInitialized() const { if (!isBlockPointer()) return true; - if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor)) { + if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor)) { const GlobalInlineDescriptor &GD = *reinterpret_cast<const GlobalInlineDescriptor *>(block()->rawData()); return GD.InitState == GlobalInitState::Initialized; } - assert(PointeeStorage.BS.Pointee && - "Cannot check if null pointer was initialized"); + assert(BS.Pointee && "Cannot check if null pointer was initialized"); const Descriptor *Desc = getFieldDesc(); assert(Desc); - if (Desc->isPrimitiveArray()) { - if (isStatic() && PointeeStorage.BS.Base == 0) - return true; + if (Desc->isPrimitiveArray()) + return isElementInitialized(getIndex()); - InitMapPtr &IM = getInitMap(); + if (asBlockPointer().Base == 0) + return true; + // Field has its bit in an inline descriptor. + return getInlineDesc()->IsInitialized; +} +bool Pointer::isElementInitialized(unsigned Index) const { + if (!isBlockPointer()) + return true; + + const Descriptor *Desc = getFieldDesc(); + assert(Desc); + + if (isStatic() && BS.Base == 0) + return true; + + if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor)) { + const GlobalInlineDescriptor &GD = + *reinterpret_cast<const GlobalInlineDescriptor *>(block()->rawData()); + return GD.InitState == GlobalInitState::Initialized; + } + + if (Desc->isPrimitiveArray()) { + InitMapPtr &IM = getInitMap(); if (!IM) return false; if (IM->first) return true; - return IM->second->isElementInitialized(getIndex()); + return IM->second->isElementInitialized(Index); } - - if (asBlockPointer().Base == 0) - return true; - - // Field has its bit in an inline descriptor. - return getInlineDesc()->IsInitialized; + return isInitialized(); } void Pointer::initialize() const { if (!isBlockPointer()) return; - assert(PointeeStorage.BS.Pointee && "Cannot initialize null pointer"); + assert(BS.Pointee && "Cannot initialize null pointer"); - if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor)) { + if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor)) { GlobalInlineDescriptor &GD = *reinterpret_cast<GlobalInlineDescriptor *>( asBlockPointer().Pointee->rawData()); GD.InitState = GlobalInitState::Initialized; @@ -462,7 +497,7 @@ void Pointer::initialize() const { assert(Desc); if (Desc->isPrimitiveArray()) { // Primitive global arrays don't have an initmap. - if (isStatic() && PointeeStorage.BS.Base == 0) + if (isStatic() && BS.Base == 0) return; // Nothing to do for these. @@ -488,8 +523,7 @@ void Pointer::initialize() const { } // Field has its bit in an inline descriptor. - assert(PointeeStorage.BS.Base != 0 && - "Only composite fields can be initialised"); + assert(BS.Base != 0 && "Only composite fields can be initialised"); getInlineDesc()->IsInitialized = true; } @@ -506,12 +540,28 @@ void Pointer::initializeAllElements() const { } } +bool Pointer::allElementsInitialized() const { + assert(getFieldDesc()->isPrimitiveArray()); + assert(isArrayRoot()); + + if (isStatic() && BS.Base == 0) + return true; + + if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor)) { + const GlobalInlineDescriptor &GD = + *reinterpret_cast<const GlobalInlineDescriptor *>(block()->rawData()); + return GD.InitState == GlobalInitState::Initialized; + } + + InitMapPtr &IM = getInitMap(); + return IM && IM->first; +} + void Pointer::activate() const { // Field has its bit in an inline descriptor. - assert(PointeeStorage.BS.Base != 0 && - "Only composite fields can be activated"); + assert(BS.Base != 0 && "Only composite fields can be activated"); - if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor)) + if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor)) return; if (!getInlineDesc()->InUnion) return; @@ -593,8 +643,7 @@ bool Pointer::pointToSameBlock(const Pointer &A, const Pointer &B) { } bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) { - return hasSameBase(A, B) && - A.PointeeStorage.BS.Base == B.PointeeStorage.BS.Base && + return hasSameBase(A, B) && A.BS.Base == B.BS.Base && A.getFieldDesc()->IsArray; } @@ -684,12 +733,12 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx, return true; } - if (const auto *RT = Ty->getAs<RecordType>()) { + if (const auto *RT = Ty->getAsCanonical<RecordType>()) { const auto *Record = Ptr.getRecord(); 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 +777,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)); } @@ -754,13 +804,13 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx, R = APValue(APValue::UninitArray{}, NumElems, NumElems); bool Ok = true; - for (unsigned I = 0; I < NumElems; ++I) { + OptPrimType ElemT = Ctx.classify(ElemTy); + for (unsigned I = 0; I != NumElems; ++I) { APValue &Slot = R.getArrayInitializedElt(I); - const Pointer &EP = Ptr.atIndex(I); - if (OptPrimType T = Ctx.classify(ElemTy)) { - TYPE_SWITCH(*T, Slot = EP.deref<T>().toAPValue(ASTCtx)); + if (ElemT) { + TYPE_SWITCH(*ElemT, Slot = Ptr.elem<T>(I).toAPValue(ASTCtx)); } else { - Ok &= Composite(ElemTy, EP.narrow(), Slot); + Ok &= Composite(ElemTy, Ptr.atIndex(I).narrow(), Slot); } } return Ok; @@ -768,8 +818,11 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx, // Complex types. if (const auto *CT = Ty->getAs<ComplexType>()) { - QualType ElemTy = CT->getElementType(); + // Can happen via C casts. + if (!Ptr.getFieldDesc()->isPrimitiveArray()) + return false; + QualType ElemTy = CT->getElementType(); if (ElemTy->isIntegerType()) { OptPrimType ElemT = Ctx.classify(ElemTy); assert(ElemT); diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h index 5bafc5b..49d701c 100644 --- a/clang/lib/AST/ByteCode/Pointer.h +++ b/clang/lib/AST/ByteCode/Pointer.h @@ -28,8 +28,6 @@ class Block; class DeadBlock; class Pointer; class Context; -template <unsigned A, bool B> class Integral; -enum PrimType : unsigned; class Pointer; inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Pointer &P); @@ -95,31 +93,21 @@ private: static constexpr unsigned RootPtrMark = ~0u; public: - Pointer() { - StorageKind = Storage::Int; - PointeeStorage.Int.Value = 0; - PointeeStorage.Int.Desc = nullptr; - } - Pointer(IntPointer &&IntPtr) : StorageKind(Storage::Int) { - PointeeStorage.Int = std::move(IntPtr); - } + Pointer() : StorageKind(Storage::Int), Int{nullptr, 0} {} + Pointer(IntPointer &&IntPtr) + : StorageKind(Storage::Int), Int(std::move(IntPtr)) {} Pointer(Block *B); Pointer(Block *B, uint64_t BaseAndOffset); Pointer(const Pointer &P); Pointer(Pointer &&P); Pointer(uint64_t Address, const Descriptor *Desc, uint64_t Offset = 0) - : Offset(Offset), StorageKind(Storage::Int) { - PointeeStorage.Int.Value = Address; - PointeeStorage.Int.Desc = Desc; - } + : Offset(Offset), StorageKind(Storage::Int), Int{Desc, Address} {} Pointer(const Function *F, uint64_t Offset = 0) - : Offset(Offset), StorageKind(Storage::Fn) { - PointeeStorage.Fn = FunctionPointer(F); - } + : Offset(Offset), StorageKind(Storage::Fn), Fn(F) {} Pointer(const Type *TypePtr, const Type *TypeInfoType, uint64_t Offset = 0) : Offset(Offset), StorageKind(Storage::Typeid) { - PointeeStorage.Typeid.TypePtr = TypePtr; - PointeeStorage.Typeid.TypeInfoType = TypeInfoType; + Typeid.TypePtr = TypePtr; + Typeid.TypeInfoType = TypeInfoType; } Pointer(Block *Pointee, unsigned Base, uint64_t Offset); ~Pointer(); @@ -132,17 +120,14 @@ public: if (P.StorageKind != StorageKind) return false; if (isIntegralPointer()) - return P.asIntPointer().Value == asIntPointer().Value && - P.asIntPointer().Desc == asIntPointer().Desc && P.Offset == Offset; + return P.Int.Value == Int.Value && P.Int.Desc == Int.Desc && + P.Offset == Offset; if (isFunctionPointer()) - return P.asFunctionPointer().getFunction() == - asFunctionPointer().getFunction() && - P.Offset == Offset; + return P.Fn.getFunction() == Fn.getFunction() && P.Offset == Offset; assert(isBlockPointer()); - return P.asBlockPointer().Pointee == asBlockPointer().Pointee && - P.asBlockPointer().Base == asBlockPointer().Base && + return P.BS.Pointee == BS.Pointee && P.BS.Base == BS.Base && P.Offset == Offset; } @@ -156,10 +141,10 @@ public: uint64_t getIntegerRepresentation() const { if (isIntegralPointer()) - return asIntPointer().Value + (Offset * elemSize()); + return Int.Value + (Offset * elemSize()); if (isFunctionPointer()) - return asFunctionPointer().getIntegerRepresentation() + Offset; - return reinterpret_cast<uint64_t>(asBlockPointer().Pointee) + Offset; + return Fn.getIntegerRepresentation() + Offset; + return reinterpret_cast<uint64_t>(BS.Pointee) + Offset; } /// Converts the pointer to an APValue that is an rvalue. @@ -169,27 +154,25 @@ public: /// Offsets a pointer inside an array. [[nodiscard]] Pointer atIndex(uint64_t Idx) const { if (isIntegralPointer()) - return Pointer(asIntPointer().Value, asIntPointer().Desc, Idx); + return Pointer(Int.Value, Int.Desc, Idx); if (isFunctionPointer()) - return Pointer(asFunctionPointer().getFunction(), Idx); + return Pointer(Fn.getFunction(), Idx); - if (asBlockPointer().Base == RootPtrMark) - return Pointer(asBlockPointer().Pointee, RootPtrMark, - getDeclDesc()->getSize()); + if (BS.Base == RootPtrMark) + return Pointer(BS.Pointee, RootPtrMark, getDeclDesc()->getSize()); uint64_t Off = Idx * elemSize(); if (getFieldDesc()->ElemDesc) Off += sizeof(InlineDescriptor); else Off += sizeof(InitMapPtr); - return Pointer(asBlockPointer().Pointee, asBlockPointer().Base, - asBlockPointer().Base + Off); + return Pointer(BS.Pointee, BS.Base, BS.Base + Off); } /// Creates a pointer to a field. [[nodiscard]] Pointer atField(unsigned Off) const { assert(isBlockPointer()); unsigned Field = Offset + Off; - return Pointer(asBlockPointer().Pointee, Field, Field); + return Pointer(BS.Pointee, Field, Field); } /// Subtract the given offset from the current Base and Offset @@ -197,7 +180,7 @@ public: [[nodiscard]] Pointer atFieldSub(unsigned Off) const { assert(Offset >= Off); unsigned O = Offset - Off; - return Pointer(asBlockPointer().Pointee, O, O); + return Pointer(BS.Pointee, O, O); } /// Restricts the scope of an array element pointer. @@ -209,15 +192,15 @@ public: if (isZero() || isUnknownSizeArray()) return *this; - unsigned Base = asBlockPointer().Base; + unsigned Base = BS.Base; // Pointer to an array of base types - enter block. if (Base == RootPtrMark) - return Pointer(asBlockPointer().Pointee, sizeof(InlineDescriptor), + return Pointer(BS.Pointee, sizeof(InlineDescriptor), Offset == 0 ? Offset : PastEndMark); // Pointer is one past end - magic offset marks that. if (isOnePastEnd()) - return Pointer(asBlockPointer().Pointee, Base, PastEndMark); + return Pointer(BS.Pointee, Base, PastEndMark); if (Offset != Base) { // If we're pointing to a primitive array element, there's nothing to do. @@ -225,7 +208,7 @@ public: return *this; // Pointer is to a composite array element - enter it. if (Offset != Base) - return Pointer(asBlockPointer().Pointee, Offset, Offset); + return Pointer(BS.Pointee, Offset, Offset); } // Otherwise, we're pointing to a non-array element or @@ -236,7 +219,7 @@ public: /// Expands a pointer to the containing array, undoing narrowing. [[nodiscard]] Pointer expand() const { assert(isBlockPointer()); - Block *Pointee = asBlockPointer().Pointee; + Block *Pointee = BS.Pointee; if (isElementPastEnd()) { // Revert to an outer one-past-end pointer. @@ -245,19 +228,18 @@ public: Adjust = sizeof(InitMapPtr); else Adjust = sizeof(InlineDescriptor); - return Pointer(Pointee, asBlockPointer().Base, - asBlockPointer().Base + getSize() + Adjust); + return Pointer(Pointee, BS.Base, BS.Base + getSize() + Adjust); } // Do not step out of array elements. - if (asBlockPointer().Base != Offset) + if (BS.Base != Offset) return *this; if (isRoot()) - return Pointer(Pointee, asBlockPointer().Base, asBlockPointer().Base); + return Pointer(Pointee, BS.Base, BS.Base); // Step into the containing array, if inside one. - unsigned Next = asBlockPointer().Base - getInlineDesc()->Offset; + unsigned Next = BS.Base - getInlineDesc()->Offset; const Descriptor *Desc = (Next == Pointee->getDescriptor()->getMetadataSize()) ? getDeclDesc() @@ -270,19 +252,19 @@ public: /// Checks if the pointer is null. bool isZero() const { if (isBlockPointer()) - return asBlockPointer().Pointee == nullptr; + return BS.Pointee == nullptr; if (isFunctionPointer()) - return asFunctionPointer().isZero(); + return Fn.isZero(); if (isTypeidPointer()) return false; assert(isIntegralPointer()); - return asIntPointer().Value == 0 && Offset == 0; + return Int.Value == 0 && Offset == 0; } /// Checks if the pointer is live. bool isLive() const { if (!isBlockPointer()) return true; - return asBlockPointer().Pointee && !asBlockPointer().Pointee->IsDead; + return BS.Pointee && !BS.Pointee->isDead(); } /// Checks if the item is a field in an object. bool isField() const { @@ -295,13 +277,13 @@ public: /// Accessor for information about the declaration site. const Descriptor *getDeclDesc() const { if (isIntegralPointer()) - return asIntPointer().Desc; + return Int.Desc; if (isFunctionPointer() || isTypeidPointer()) return nullptr; assert(isBlockPointer()); - assert(asBlockPointer().Pointee); - return asBlockPointer().Pointee->Desc; + assert(BS.Pointee); + return BS.Pointee->Desc; } SourceLocation getDeclLoc() const { return getDeclDesc()->getLocation(); } @@ -310,37 +292,36 @@ public: if (isBlockPointer()) return getDeclDesc()->getSource(); if (isFunctionPointer()) { - const Function *F = asFunctionPointer().getFunction(); + const Function *F = Fn.getFunction(); return F ? F->getDecl() : DeclTy(); } assert(isIntegralPointer()); - return asIntPointer().Desc ? asIntPointer().Desc->getSource() : DeclTy(); + return Int.Desc ? Int.Desc->getSource() : DeclTy(); } /// Returns a pointer to the object of which this pointer is a field. [[nodiscard]] Pointer getBase() const { - if (asBlockPointer().Base == RootPtrMark) { + if (BS.Base == RootPtrMark) { assert(Offset == PastEndMark && "cannot get base of a block"); - return Pointer(asBlockPointer().Pointee, asBlockPointer().Base, 0); + return Pointer(BS.Pointee, BS.Base, 0); } - unsigned NewBase = asBlockPointer().Base - getInlineDesc()->Offset; - return Pointer(asBlockPointer().Pointee, NewBase, NewBase); + unsigned NewBase = BS.Base - getInlineDesc()->Offset; + return Pointer(BS.Pointee, NewBase, NewBase); } /// Returns the parent array. [[nodiscard]] Pointer getArray() const { - if (asBlockPointer().Base == RootPtrMark) { + if (BS.Base == RootPtrMark) { assert(Offset != 0 && Offset != PastEndMark && "not an array element"); - return Pointer(asBlockPointer().Pointee, asBlockPointer().Base, 0); + return Pointer(BS.Pointee, BS.Base, 0); } - assert(Offset != asBlockPointer().Base && "not an array element"); - return Pointer(asBlockPointer().Pointee, asBlockPointer().Base, - asBlockPointer().Base); + assert(Offset != BS.Base && "not an array element"); + return Pointer(BS.Pointee, BS.Base, BS.Base); } /// Accessors for information about the innermost field. const Descriptor *getFieldDesc() const { if (isIntegralPointer()) - return asIntPointer().Desc; + return Int.Desc; if (isRoot()) return getDeclDesc(); @@ -350,9 +331,11 @@ public: /// Returns the type of the innermost field. QualType getType() const { if (isTypeidPointer()) - return QualType(PointeeStorage.Typeid.TypeInfoType, 0); + return QualType(Typeid.TypeInfoType, 0); + if (isFunctionPointer()) + return Fn.getFunction()->getDecl()->getType(); - if (inPrimitiveArray() && Offset != asBlockPointer().Base) { + if (inPrimitiveArray() && Offset != BS.Base) { // Unfortunately, complex and vector types are not array types in clang, // but they are for us. if (const auto *AT = getFieldDesc()->getType()->getAsArrayTypeUnsafe()) @@ -365,19 +348,17 @@ public: return getFieldDesc()->getType(); } - [[nodiscard]] Pointer getDeclPtr() const { - return Pointer(asBlockPointer().Pointee); - } + [[nodiscard]] Pointer getDeclPtr() const { return Pointer(BS.Pointee); } /// Returns the element size of the innermost field. size_t elemSize() const { if (isIntegralPointer()) { - if (!asIntPointer().Desc) + if (!Int.Desc) return 1; - return asIntPointer().Desc->getElemSize(); + return Int.Desc->getElemSize(); } - if (asBlockPointer().Base == RootPtrMark) + if (BS.Base == RootPtrMark) return getDeclDesc()->getSize(); return getFieldDesc()->getElemSize(); } @@ -391,24 +372,22 @@ public: unsigned getOffset() const { assert(Offset != PastEndMark && "invalid offset"); assert(isBlockPointer()); - if (asBlockPointer().Base == RootPtrMark) + if (BS.Base == RootPtrMark) return Offset; unsigned Adjust = 0; - if (Offset != asBlockPointer().Base) { + if (Offset != BS.Base) { if (getFieldDesc()->ElemDesc) Adjust = sizeof(InlineDescriptor); else Adjust = sizeof(InitMapPtr); } - return Offset - asBlockPointer().Base - Adjust; + return Offset - BS.Base - Adjust; } /// Whether this array refers to an array, but not /// to the first element. - bool isArrayRoot() const { - return inArray() && Offset == asBlockPointer().Base; - } + bool isArrayRoot() const { return inArray() && Offset == BS.Base; } /// Checks if the innermost field is an array. bool inArray() const { @@ -417,7 +396,7 @@ public: return false; } bool inUnion() const { - if (isBlockPointer() && asBlockPointer().Base >= sizeof(InlineDescriptor)) + if (isBlockPointer() && BS.Base >= sizeof(InlineDescriptor)) return getInlineDesc()->InUnion; return false; }; @@ -439,7 +418,7 @@ public: if (!isBlockPointer()) return false; - const BlockPointer &BP = asBlockPointer(); + const BlockPointer &BP = BS; if (inArray() && BP.Base != Offset) return true; @@ -454,33 +433,32 @@ public: bool isRoot() const { if (isZero() || !isBlockPointer()) return true; - return (asBlockPointer().Base == - asBlockPointer().Pointee->getDescriptor()->getMetadataSize() || - asBlockPointer().Base == 0); + return (BS.Base == BS.Pointee->getDescriptor()->getMetadataSize() || + BS.Base == 0); } /// If this pointer has an InlineDescriptor we can use to initialize. bool canBeInitialized() const { if (!isBlockPointer()) return false; - return asBlockPointer().Pointee && asBlockPointer().Base > 0; + return BS.Pointee && BS.Base > 0; } [[nodiscard]] const BlockPointer &asBlockPointer() const { assert(isBlockPointer()); - return PointeeStorage.BS; + return BS; } [[nodiscard]] const IntPointer &asIntPointer() const { assert(isIntegralPointer()); - return PointeeStorage.Int; + return Int; } [[nodiscard]] const FunctionPointer &asFunctionPointer() const { assert(isFunctionPointer()); - return PointeeStorage.Fn; + return Fn; } [[nodiscard]] const TypeidPointer &asTypeidPointer() const { assert(isTypeidPointer()); - return PointeeStorage.Typeid; + return Typeid; } bool isBlockPointer() const { return StorageKind == Storage::Block; } @@ -505,29 +483,29 @@ public: /// Checks if the storage is extern. bool isExtern() const { if (isBlockPointer()) - return asBlockPointer().Pointee && asBlockPointer().Pointee->isExtern(); + return BS.Pointee && BS.Pointee->isExtern(); return false; } /// Checks if the storage is static. bool isStatic() const { if (!isBlockPointer()) return true; - assert(asBlockPointer().Pointee); - return asBlockPointer().Pointee->isStatic(); + assert(BS.Pointee); + return BS.Pointee->isStatic(); } /// Checks if the storage is temporary. bool isTemporary() const { if (isBlockPointer()) { - assert(asBlockPointer().Pointee); - return asBlockPointer().Pointee->isTemporary(); + assert(BS.Pointee); + return BS.Pointee->isTemporary(); } return false; } /// Checks if the storage has been dynamically allocated. bool isDynamic() const { if (isBlockPointer()) { - assert(asBlockPointer().Pointee); - return asBlockPointer().Pointee->isDynamic(); + assert(BS.Pointee); + return BS.Pointee->isDynamic(); } return false; } @@ -543,15 +521,13 @@ public: bool isWeak() const { if (isFunctionPointer()) - return asFunctionPointer().isWeak(); + return Fn.isWeak(); if (!isBlockPointer()) return false; assert(isBlockPointer()); - return asBlockPointer().Pointee->isWeak(); + return BS.Pointee->isWeak(); } - /// Checks if an object was initialized. - bool isInitialized() const; /// Checks if the object is active. bool isActive() const { if (!isBlockPointer()) @@ -568,10 +544,9 @@ public: if (!isBlockPointer()) return false; - if (!asBlockPointer().Pointee) - return false; - - return getDeclDesc()->isDummy(); + if (const Block *Pointee = BS.Pointee) + return Pointee->isDummy(); + return false; } /// Checks if an object or a subfield is mutable. @@ -594,10 +569,10 @@ public: } /// Returns the declaration ID. - std::optional<unsigned> getDeclID() const { + UnsignedOrNone getDeclID() const { if (isBlockPointer()) { - assert(asBlockPointer().Pointee); - return asBlockPointer().Pointee->getDeclID(); + assert(BS.Pointee); + return BS.Pointee->getDeclID(); } return std::nullopt; } @@ -605,9 +580,9 @@ public: /// Returns the byte offset from the start. uint64_t getByteOffset() const { if (isIntegralPointer()) - return asIntPointer().Value + Offset; + return Int.Value + Offset; if (isTypeidPointer()) - return reinterpret_cast<uintptr_t>(asTypeidPointer().TypePtr) + Offset; + return reinterpret_cast<uintptr_t>(Typeid.TypePtr) + Offset; if (isOnePastEnd()) return PastEndMark; return Offset; @@ -620,13 +595,13 @@ public: return getSize() / elemSize(); } - const Block *block() const { return asBlockPointer().Pointee; } + const Block *block() const { return BS.Pointee; } /// If backed by actual data (i.e. a block pointer), return /// an address to that data. const std::byte *getRawAddress() const { assert(isBlockPointer()); - return asBlockPointer().Pointee->rawData() + Offset; + return BS.Pointee->rawData() + Offset; } /// Returns the index into an array. @@ -638,8 +613,7 @@ public: return 0; // narrow()ed element in a composite array. - if (asBlockPointer().Base > sizeof(InlineDescriptor) && - asBlockPointer().Base == Offset) + if (BS.Base > sizeof(InlineDescriptor) && BS.Base == Offset) return 0; if (auto ElemSize = elemSize()) @@ -652,13 +626,13 @@ public: if (!isBlockPointer()) return false; - if (!asBlockPointer().Pointee) + if (!BS.Pointee) return false; if (isUnknownSizeArray()) return false; - return isPastEnd() || (getSize() == getOffset() && !isZeroSizeArray()); + return isPastEnd() || (getSize() == getOffset()); } /// Checks if the pointer points past the end of the object. @@ -666,7 +640,7 @@ public: if (isIntegralPointer()) return false; - return !isZero() && Offset > PointeeStorage.BS.Pointee->getSize(); + return !isZero() && Offset > BS.Pointee->getSize(); } /// Checks if the pointer is an out-of-bounds element pointer. @@ -685,16 +659,15 @@ public: template <typename T> T &deref() const { assert(isLive() && "Invalid pointer"); assert(isBlockPointer()); - assert(asBlockPointer().Pointee); + assert(BS.Pointee); assert(isDereferencable()); - assert(Offset + sizeof(T) <= - asBlockPointer().Pointee->getDescriptor()->getAllocSize()); + assert(Offset + sizeof(T) <= BS.Pointee->getDescriptor()->getAllocSize()); if (isArrayRoot()) - return *reinterpret_cast<T *>(asBlockPointer().Pointee->rawData() + - asBlockPointer().Base + sizeof(InitMapPtr)); + return *reinterpret_cast<T *>(BS.Pointee->rawData() + BS.Base + + sizeof(InitMapPtr)); - return *reinterpret_cast<T *>(asBlockPointer().Pointee->rawData() + Offset); + return *reinterpret_cast<T *>(BS.Pointee->rawData() + Offset); } /// Dereferences the element at index \p I. @@ -702,18 +675,17 @@ public: template <typename T> T &elem(unsigned I) const { assert(isLive() && "Invalid pointer"); assert(isBlockPointer()); - assert(asBlockPointer().Pointee); + assert(BS.Pointee); assert(isDereferencable()); assert(getFieldDesc()->isPrimitiveArray()); + assert(I < getFieldDesc()->getNumElems()); unsigned ElemByteOffset = I * getFieldDesc()->getElemSize(); - if (isArrayRoot()) - return *reinterpret_cast<T *>(asBlockPointer().Pointee->rawData() + - asBlockPointer().Base + sizeof(InitMapPtr) + - ElemByteOffset); + unsigned ReadOffset = BS.Base + sizeof(InitMapPtr) + ElemByteOffset; + assert(ReadOffset + sizeof(T) <= + BS.Pointee->getDescriptor()->getAllocSize()); - return *reinterpret_cast<T *>(asBlockPointer().Pointee->rawData() + Offset + - ElemByteOffset); + return *reinterpret_cast<T *>(BS.Pointee->rawData() + ReadOffset); } /// Whether this block can be read from at all. This is only true for @@ -733,6 +705,11 @@ public: /// used in situations where we *know* we have initialized *all* elements /// of a primtive array. void initializeAllElements() const; + /// Checks if an object was initialized. + bool isInitialized() const; + /// Like isInitialized(), but for primitive arrays. + bool isElementInitialized(unsigned Index) const; + bool allElementsInitialized() const; /// Activats a field. void activate() const; /// Deactivates an entire strurcutre. @@ -741,7 +718,7 @@ public: Lifetime getLifetime() const { if (!isBlockPointer()) return Lifetime::Started; - if (asBlockPointer().Base < sizeof(InlineDescriptor)) + if (BS.Base < sizeof(InlineDescriptor)) return Lifetime::Started; return getInlineDesc()->LifeState; } @@ -749,7 +726,7 @@ public: void endLifetime() const { if (!isBlockPointer()) return; - if (asBlockPointer().Base < sizeof(InlineDescriptor)) + if (BS.Base < sizeof(InlineDescriptor)) return; getInlineDesc()->LifeState = Lifetime::Ended; } @@ -757,7 +734,7 @@ public: void startLifetime() const { if (!isBlockPointer()) return; - if (asBlockPointer().Base < sizeof(InlineDescriptor)) + if (BS.Base < sizeof(InlineDescriptor)) return; getInlineDesc()->LifeState = Lifetime::Started; } @@ -805,14 +782,15 @@ private: friend class InterpState; friend struct InitMap; friend class DynamicAllocator; + friend class Program; /// Returns the embedded descriptor preceding a field. InlineDescriptor *getInlineDesc() const { assert(isBlockPointer()); - assert(asBlockPointer().Base != sizeof(GlobalInlineDescriptor)); - assert(asBlockPointer().Base <= asBlockPointer().Pointee->getSize()); - assert(asBlockPointer().Base >= sizeof(InlineDescriptor)); - return getDescriptor(asBlockPointer().Base); + assert(BS.Base != sizeof(GlobalInlineDescriptor)); + assert(BS.Base <= BS.Pointee->getSize()); + assert(BS.Base >= sizeof(InlineDescriptor)); + return getDescriptor(BS.Base); } /// Returns a descriptor at a given offset. @@ -820,8 +798,8 @@ private: assert(Offset != 0 && "Not a nested pointer"); assert(isBlockPointer()); assert(!isZero()); - return reinterpret_cast<InlineDescriptor *>( - asBlockPointer().Pointee->rawData() + Offset) - + return reinterpret_cast<InlineDescriptor *>(BS.Pointee->rawData() + + Offset) - 1; } @@ -829,8 +807,7 @@ private: InitMapPtr &getInitMap() const { assert(isBlockPointer()); assert(!isZero()); - return *reinterpret_cast<InitMapPtr *>(asBlockPointer().Pointee->rawData() + - asBlockPointer().Base); + return *reinterpret_cast<InitMapPtr *>(BS.Pointee->rawData() + BS.Base); } /// Offset into the storage. @@ -842,7 +819,7 @@ private: BlockPointer BS; FunctionPointer Fn; TypeidPointer Typeid; - } PointeeStorage; + }; }; inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Pointer &P) { diff --git a/clang/lib/AST/ByteCode/PrimType.h b/clang/lib/AST/ByteCode/PrimType.h index 724da93..54fd39a 100644 --- a/clang/lib/AST/ByteCode/PrimType.h +++ b/clang/lib/AST/ByteCode/PrimType.h @@ -31,7 +31,7 @@ template <bool Signed> class IntegralAP; template <unsigned Bits, bool Signed> class Integral; /// Enumeration of the primitive types of the VM. -enum PrimType : unsigned { +enum PrimType : uint8_t { PT_Sint8 = 0, PT_Uint8 = 1, PT_Sint16 = 2, @@ -51,14 +51,15 @@ enum PrimType : unsigned { // Like std::optional<PrimType>, but only sizeof(PrimType). class OptPrimType final { - unsigned V = ~0u; + static constexpr uint8_t None = 0xFF; + uint8_t V = None; public: OptPrimType() = default; OptPrimType(std::nullopt_t) {} OptPrimType(PrimType T) : V(static_cast<unsigned>(T)) {} - explicit constexpr operator bool() const { return V != ~0u; } + explicit constexpr operator bool() const { return V != None; } PrimType operator*() const { assert(operator bool()); return static_cast<PrimType>(V); @@ -85,6 +86,19 @@ inline constexpr bool isPtrType(PrimType T) { return T == PT_Ptr || T == PT_MemberPtr; } +inline constexpr bool isSignedType(PrimType T) { + switch (T) { + case PT_Sint8: + case PT_Sint16: + case PT_Sint32: + case PT_Sint64: + return true; + default: + return false; + } + return false; +} + enum class CastKind : uint8_t { Reinterpret, Volatile, @@ -258,14 +272,4 @@ static inline bool aligned(const void *P) { } \ } while (0) -#define COMPOSITE_TYPE_SWITCH(Expr, B, D) \ - do { \ - switch (Expr) { \ - TYPE_SWITCH_CASE(PT_Ptr, B) \ - default: { \ - D; \ - break; \ - } \ - } \ - } while (0) #endif diff --git a/clang/lib/AST/ByteCode/Program.cpp b/clang/lib/AST/ByteCode/Program.cpp index 4daa4ab..0be017e 100644 --- a/clang/lib/AST/ByteCode/Program.cpp +++ b/clang/lib/AST/ByteCode/Program.cpp @@ -101,7 +101,7 @@ unsigned Program::createGlobalString(const StringLiteral *S, const Expr *Base) { } } } - Ptr.initialize(); + Ptr.initializeAllElements(); return GlobalIndex; } @@ -164,8 +164,8 @@ unsigned Program::getOrCreateDummy(const DeclTy &D) { const auto *VD = cast<ValueDecl>(cast<const Decl *>(D)); IsWeak = VD->isWeak(); QT = VD->getType(); - if (const auto *RT = QT->getAs<ReferenceType>()) - QT = RT->getPointeeType(); + if (QT->isPointerOrReferenceType()) + QT = QT->getPointeeType(); } assert(!QT.isNull()); @@ -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; @@ -215,19 +213,31 @@ std::optional<unsigned> Program::createGlobal(const ValueDecl *VD, // Register all previous declarations as well. For extern blocks, just replace // the index with the new variable. - if (auto Idx = - createGlobal(VD, VD->getType(), IsStatic, IsExtern, IsWeak, Init)) { - for (const Decl *P = VD; P; P = P->getPreviousDecl()) { - unsigned &PIdx = GlobalIndices[P]; - if (P != VD) { - if (Globals[PIdx]->block()->isExtern()) - Globals[PIdx] = Globals[*Idx]; + std::optional<unsigned> Idx = + createGlobal(VD, VD->getType(), IsStatic, IsExtern, IsWeak, Init); + if (!Idx) + return std::nullopt; + + Global *NewGlobal = Globals[*Idx]; + for (const Decl *Redecl : VD->redecls()) { + unsigned &PIdx = GlobalIndices[Redecl]; + if (Redecl != VD) { + if (Block *RedeclBlock = Globals[PIdx]->block(); + RedeclBlock->isExtern()) { + Globals[PIdx] = NewGlobal; + // All pointers pointing to the previous extern decl now point to the + // new decl. + for (Pointer *Ptr = RedeclBlock->Pointers; Ptr; Ptr = Ptr->BS.Next) { + RedeclBlock->removePointer(Ptr); + Ptr->BS.Pointee = NewGlobal->block(); + NewGlobal->block()->addPointer(Ptr); + } } - PIdx = *Idx; } - return *Idx; + PIdx = *Idx; } - return std::nullopt; + + return *Idx; } std::optional<unsigned> Program::createGlobal(const Expr *E) { @@ -266,7 +276,7 @@ std::optional<unsigned> Program::createGlobal(const DeclTy &D, QualType Ty, Ctx.getEvalID(), getCurrentDecl(), Desc, IsStatic, IsExtern, IsWeak); G->block()->invokeCtor(); - // Initialize InlineDescriptor fields. + // Initialize GlobalInlineDescriptor fields. auto *GD = new (G->block()->rawData()) GlobalInlineDescriptor(); if (!Init) GD->InitState = GlobalInitState::NoInitializer; @@ -322,10 +332,9 @@ Record *Program::getOrCreateRecord(const RecordDecl *RD) { continue; // In error cases, the base might not be a RecordType. - const auto *RT = Spec.getType()->getAs<RecordType>(); - if (!RT) + const auto *BD = Spec.getType()->getAsCXXRecordDecl(); + if (!BD) return nullptr; - const RecordDecl *BD = RT->getDecl(); const Record *BR = getOrCreateRecord(BD); const Descriptor *Desc = GetBaseDesc(BD, BR); @@ -338,11 +347,7 @@ Record *Program::getOrCreateRecord(const RecordDecl *RD) { } for (const CXXBaseSpecifier &Spec : CD->vbases()) { - const auto *RT = Spec.getType()->getAs<RecordType>(); - if (!RT) - return nullptr; - - const RecordDecl *BD = RT->getDecl(); + const auto *BD = Spec.getType()->castAsCXXRecordDecl(); const Record *BR = getOrCreateRecord(BD); const Descriptor *Desc = GetBaseDesc(BD, BR); @@ -398,8 +403,8 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty, const Expr *Init) { // Classes and structures. - if (const auto *RT = Ty->getAs<RecordType>()) { - if (const auto *Record = getOrCreateRecord(RT->getDecl())) + if (const auto *RD = Ty->getAsRecordDecl()) { + if (const auto *Record = getOrCreateRecord(RD)) return allocateDescriptor(D, Record, MDSize, IsConst, IsTemporary, IsMutable, IsVolatile); return allocateDescriptor(D, MDSize); diff --git a/clang/lib/AST/ByteCode/Program.h b/clang/lib/AST/ByteCode/Program.h index 207ceef..90b48ee5 100644 --- a/clang/lib/AST/ByteCode/Program.h +++ b/clang/lib/AST/ByteCode/Program.h @@ -73,6 +73,10 @@ public: return Globals[Idx]->block(); } + bool isGlobalInitialized(unsigned Index) const { + return getPtrGlobal(Index).isInitialized(); + } + /// Finds a global's index. std::optional<unsigned> getGlobal(const ValueDecl *VD); std::optional<unsigned> getGlobal(const Expr *E); @@ -152,7 +156,7 @@ public: }; /// Returns the current declaration ID. - std::optional<unsigned> getCurrentDecl() const { + UnsignedOrNone getCurrentDecl() const { if (CurrentDeclaration == NoDeclaration) return std::nullopt; return CurrentDeclaration; @@ -172,9 +176,6 @@ private: /// List of anonymous functions. std::vector<std::unique_ptr<Function>> AnonFuncs; - /// Function relocation locations. - llvm::DenseMap<const FunctionDecl *, std::vector<unsigned>> Relocs; - /// Native pointers referenced by bytecode. std::vector<const void *> NativePointers; /// Cached native pointer indices. diff --git a/clang/lib/AST/ByteCode/Record.cpp b/clang/lib/AST/ByteCode/Record.cpp index 1d4ac71..c20ec18 100644 --- a/clang/lib/AST/ByteCode/Record.cpp +++ b/clang/lib/AST/ByteCode/Record.cpp @@ -50,10 +50,8 @@ 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(); + if (auto *RD = T->getAsCXXRecordDecl()) return BaseMap.lookup(RD); - } return nullptr; } diff --git a/clang/lib/AST/CXXInheritance.cpp b/clang/lib/AST/CXXInheritance.cpp index f037616..7a3e7ea 100644 --- a/clang/lib/AST/CXXInheritance.cpp +++ b/clang/lib/AST/CXXInheritance.cpp @@ -128,17 +128,11 @@ bool CXXRecordDecl::forallBases(ForallBasesCallback BaseMatches) const { const CXXRecordDecl *Record = this; while (true) { for (const auto &I : Record->bases()) { - const RecordType *Ty = I.getType()->getAs<RecordType>(); - if (!Ty) + const auto *Base = I.getType()->getAsCXXRecordDecl(); + if (!Base || !(Base->isBeingDefined() || Base->isCompleteDefinition())) return false; - - CXXRecordDecl *Base = - cast_if_present<CXXRecordDecl>(Ty->getDecl()->getDefinition()); - if (!Base || - (Base->isDependentContext() && - !Base->isCurrentInstantiation(Record))) { + if (Base->isDependentContext() && !Base->isCurrentInstantiation(Record)) return false; - } Queue.push_back(Base); if (!BaseMatches(Base)) @@ -196,7 +190,7 @@ bool CXXBasePaths::lookupInBases(ASTContext &Context, if (isDetectingVirtual() && DetectedVirtual == nullptr) { // If this is the first virtual we find, remember it. If it turns out // there is no base path here, we'll reset it later. - DetectedVirtual = BaseType->getAs<RecordType>(); + DetectedVirtual = BaseType->getAsCanonical<RecordType>(); SetVirtual = true; } } else { @@ -255,8 +249,7 @@ bool CXXBasePaths::lookupInBases(ASTContext &Context, const TemplateSpecializationType *TST = BaseSpec.getType()->getAs<TemplateSpecializationType>(); if (!TST) { - if (auto *RT = BaseSpec.getType()->getAs<RecordType>()) - BaseRecord = cast<CXXRecordDecl>(RT->getDecl()); + BaseRecord = BaseSpec.getType()->getAsCXXRecordDecl(); } else { TemplateName TN = TST->getTemplateName(); if (auto *TD = @@ -270,7 +263,7 @@ bool CXXBasePaths::lookupInBases(ASTContext &Context, BaseRecord = nullptr; } } else { - BaseRecord = cast<CXXRecordDecl>(BaseSpec.getType()->getAsRecordDecl()); + BaseRecord = BaseSpec.getType()->castAsCXXRecordDecl(); } if (BaseRecord && lookupInBases(Context, BaseRecord, BaseMatches, LookupInDependent)) { @@ -334,9 +327,7 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback BaseMatches, if (!PE.Base->isVirtual()) continue; - CXXRecordDecl *VBase = nullptr; - if (const RecordType *Record = PE.Base->getType()->getAs<RecordType>()) - VBase = cast<CXXRecordDecl>(Record->getDecl()); + auto *VBase = PE.Base->getType()->getAsCXXRecordDecl(); if (!VBase) break; @@ -345,10 +336,8 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback BaseMatches, // base is a subobject of any other path; if so, then the // declaration in this path are hidden by that patch. for (const CXXBasePath &HidingP : Paths) { - CXXRecordDecl *HidingClass = nullptr; - if (const RecordType *Record = - HidingP.back().Base->getType()->getAs<RecordType>()) - HidingClass = cast<CXXRecordDecl>(Record->getDecl()); + auto *HidingClass = + HidingP.back().Base->getType()->getAsCXXRecordDecl(); if (!HidingClass) break; @@ -404,7 +393,7 @@ bool CXXRecordDecl::hasMemberName(DeclarationName Name) const { CXXBasePaths Paths(false, false, false); return lookupInBases( [Name](const CXXBaseSpecifier *Specifier, CXXBasePath &Path) { - return findOrdinaryMember(Specifier->getType()->getAsCXXRecordDecl(), + return findOrdinaryMember(Specifier->getType()->castAsCXXRecordDecl(), Path, Name); }, Paths); @@ -467,8 +456,7 @@ void FinalOverriderCollector::Collect(const CXXRecordDecl *RD, = ++SubobjectCount[cast<CXXRecordDecl>(RD->getCanonicalDecl())]; for (const auto &Base : RD->bases()) { - if (const RecordType *RT = Base.getType()->getAs<RecordType>()) { - const CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(RT->getDecl()); + if (const auto *BaseDecl = Base.getType()->getAsCXXRecordDecl()) { 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/CommentLexer.cpp b/clang/lib/AST/CommentLexer.cpp index e19c232..a0903d0 100644 --- a/clang/lib/AST/CommentLexer.cpp +++ b/clang/lib/AST/CommentLexer.cpp @@ -214,7 +214,7 @@ bool isCommandNameStartCharacter(char C) { } bool isCommandNameCharacter(char C) { - return isAlphanumeric(C); + return isAsciiIdentifierContinue(C, false); } const char *skipCommandName(const char *BufferPtr, const char *BufferEnd) { 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..34367306 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -1604,17 +1604,20 @@ LinkageInfo LinkageComputer::getLVForDecl(const NamedDecl *D, // We have just computed the linkage for this decl. By induction we know // that all other computed linkages match, check that the one we just // computed also does. - NamedDecl *Old = nullptr; - for (auto *I : D->redecls()) { - auto *T = cast<NamedDecl>(I); - if (T == D) + // We can't assume the redecl chain is well formed at this point, + // so keep track of already visited declarations. + for (llvm::SmallPtrSet<const Decl *, 4> AlreadyVisited{D}; /**/; /**/) { + D = cast<NamedDecl>(const_cast<NamedDecl *>(D)->getNextRedeclarationImpl()); + if (!AlreadyVisited.insert(D).second) + break; + if (D->isInvalidDecl()) continue; - if (!T->isInvalidDecl() && T->hasCachedLinkage()) { - Old = T; + if (auto OldLinkage = D->getCachedLinkage(); + OldLinkage != Linkage::Invalid) { + assert(LV.getLinkage() == OldLinkage); break; } } - assert(!Old || Old->getCachedLinkage() == D->getCachedLinkage()); #endif return LV; @@ -1693,9 +1696,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 +1886,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()) @@ -2863,8 +2861,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()) + auto *D = getType()->getAsRecordDecl(); + if (!D || !D->hasFlexibleArrayMember()) return false; auto *List = dyn_cast<InitListExpr>(getInit()->IgnoreParens()); if (!List) @@ -2878,8 +2876,8 @@ 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()) + auto *RD = getType()->getAsRecordDecl(); + if (!RD || !RD->hasFlexibleArrayMember()) return CharUnits::Zero(); auto *List = dyn_cast<InitListExpr>(getInit()->IgnoreParens()); if (!List || List->getNumInits() == 0) @@ -2889,7 +2887,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()) @@ -2990,8 +2988,11 @@ bool ParmVarDecl::isDestroyedInCallee() const { // FIXME: isParamDestroyedInCallee() should probably imply // isDestructedType() - const auto *RT = getType()->getAs<RecordType>(); - if (RT && RT->getDecl()->isParamDestroyedInCallee() && + const auto *RT = getType()->getAsCanonical<RecordType>(); + if (RT && + RT->getOriginalDecl() + ->getDefinitionOrSelf() + ->isParamDestroyedInCallee() && getType().isDestructedType()) return true; @@ -3502,7 +3503,7 @@ bool FunctionDecl::isUsableAsGlobalAllocationFunctionInConstantEvaluation( while (const auto *TD = T->getAs<TypedefType>()) T = TD->getDecl()->getUnderlyingType(); const IdentifierInfo *II = - T->castAs<EnumType>()->getDecl()->getIdentifier(); + T->castAsCanonical<EnumType>()->getOriginalDecl()->getIdentifier(); if (II && II->isStr("__hot_cold_t")) Consume(); } @@ -4652,8 +4653,8 @@ bool FieldDecl::isAnonymousStructOrUnion() const { if (!isImplicit() || getDeclName()) return false; - if (const auto *Record = getType()->getAs<RecordType>()) - return Record->getDecl()->isAnonymousStructOrUnion(); + if (const auto *Record = getType()->getAsCanonical<RecordType>()) + return Record->getOriginalDecl()->isAnonymousStructOrUnion(); return false; } @@ -4710,10 +4711,10 @@ bool FieldDecl::isZeroSize(const ASTContext &Ctx) const { return false; // -- is not of class type, or - const auto *RT = getType()->getAs<RecordType>(); + const auto *RT = getType()->getAsCanonical<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; @@ -4733,7 +4734,7 @@ bool FieldDecl::isZeroSize(const ASTContext &Ctx) const { // MS ABI: has nonzero size if it is a class type with class type fields, // whether or not they have nonzero size return !llvm::any_of(CXXRD->fields(), [](const FieldDecl *Field) { - return Field->getType()->getAs<RecordType>(); + return Field->getType()->isRecordType(); }); } @@ -4836,10 +4837,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 +4864,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 +4907,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 +4951,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 +5017,7 @@ EnumDecl *EnumDecl::getTemplateInstantiationPattern() const { EnumDecl *ED = getInstantiatedFromMemberEnum(); while (auto *NewED = ED->getInstantiatedFromMemberEnum()) ED = NewED; - return getDefinitionOrSelf(ED); + return ::getDefinitionOrSelf(ED); } } @@ -5125,21 +5107,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 { @@ -5162,8 +5138,8 @@ 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()) + const RecordType *RT = FD->getType()->getAsCanonical<RecordType>(); + if (RT && RT->getOriginalDecl()->isOrContainsUnion()) return true; } } @@ -5294,9 +5270,8 @@ const FieldDecl *RecordDecl::findFirstNamedDataMember() const { if (I->getIdentifier()) return I; - if (const auto *RT = I->getType()->getAs<RecordType>()) - if (const FieldDecl *NamedDataMember = - RT->getDecl()->findFirstNamedDataMember()) + if (const auto *RD = I->getType()->getAsRecordDecl()) + if (const FieldDecl *NamedDataMember = RD->findFirstNamedDataMember()) return NamedDataMember; } @@ -5658,14 +5633,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 +5649,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..aa1f5a1 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()) { @@ -227,8 +216,7 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, // Skip dependent types; we can't do any checking on them now. if (BaseType->isDependentType()) continue; - auto *BaseClassDecl = - cast<CXXRecordDecl>(BaseType->castAs<RecordType>()->getDecl()); + auto *BaseClassDecl = BaseType->castAsCXXRecordDecl(); // C++2a [class]p7: // A standard-layout class is a class that: @@ -1217,9 +1205,8 @@ void CXXRecordDecl::addedMember(Decl *D) { // those because they are always unnamed. bool IsZeroSize = Field->isZeroSize(Context); - if (const auto *RecordTy = T->getAs<RecordType>()) { - auto *FieldRec = cast<CXXRecordDecl>(RecordTy->getDecl()); - if (FieldRec->getDefinition()) { + if (auto *FieldRec = T->getAsCXXRecordDecl()) { + if (FieldRec->isBeingDefined() || FieldRec->isCompleteDefinition()) { addedClassSubobject(FieldRec); // We may need to perform overload resolution to determine whether a @@ -1448,6 +1435,13 @@ void CXXRecordDecl::addedMember(Decl *D) { data().StructuralIfLiteral = false; } + // If this type contains any address discriminated values we should + // have already indicated that the only special member functions that + // can possibly be trivial are the default constructor and destructor. + if (T.hasAddressDiscriminatedPointerAuth()) + data().HasTrivialSpecialMembers &= + SMF_DefaultConstructor | SMF_Destructor; + // C++14 [meta.unary.prop]p4: // T is a class type [...] with [...] no non-static data members other // than subobjects of zero size @@ -1918,14 +1912,14 @@ static void CollectVisibleConversions( // Collect information recursively from any base classes. for (const auto &I : Record->bases()) { - const auto *RT = I.getType()->getAs<RecordType>(); - if (!RT) continue; + const auto *Base = I.getType()->getAsCXXRecordDecl(); + if (!Base) + continue; AccessSpecifier BaseAccess = CXXRecordDecl::MergeAccess(Access, I.getAccessSpecifier()); bool BaseInVirtual = InVirtual || I.isVirtual(); - auto *Base = cast<CXXRecordDecl>(RT->getDecl()); CollectVisibleConversions(Context, Base, BaseInVirtual, BaseAccess, *HiddenTypes, Output, VOutput, HiddenVBaseCs); } @@ -1960,12 +1954,13 @@ static void CollectVisibleConversions(ASTContext &Context, // Recursively collect conversions from base classes. for (const auto &I : Record->bases()) { - const auto *RT = I.getType()->getAs<RecordType>(); - if (!RT) continue; + const auto *Base = I.getType()->getAsCXXRecordDecl(); + if (!Base) + continue; - CollectVisibleConversions(Context, cast<CXXRecordDecl>(RT->getDecl()), - I.isVirtual(), I.getAccessSpecifier(), - HiddenTypes, Output, VBaseCs, HiddenVBaseCs); + CollectVisibleConversions(Context, Base, I.isVirtual(), + I.getAccessSpecifier(), HiddenTypes, Output, + VBaseCs, HiddenVBaseCs); } // Add any unhidden conversions provided by virtual bases. @@ -2125,11 +2120,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 +2153,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 +2289,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 +2301,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 +2313,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()->castAsCanonical<RecordType>()->getOriginalDecl()); if (BaseDecl->isAbstract()) return true; } @@ -2457,10 +2474,9 @@ CXXMethodDecl::getCorrespondingMethodInClass(const CXXRecordDecl *RD, }; for (const auto &I : RD->bases()) { - const RecordType *RT = I.getType()->getAs<RecordType>(); - if (!RT) + const auto *Base = I.getType()->getAsCXXRecordDecl(); + if (!Base) continue; - const auto *Base = cast<CXXRecordDecl>(RT->getDecl()); 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() {} @@ -3429,13 +3437,12 @@ SourceRange UsingDecl::getSourceRange() const { void UsingEnumDecl::anchor() {} UsingEnumDecl *UsingEnumDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation UL, - SourceLocation EL, + SourceLocation UL, SourceLocation EL, SourceLocation NL, TypeSourceInfo *EnumType) { - assert(isa<EnumDecl>(EnumType->getType()->getAsTagDecl())); return new (C, DC) - UsingEnumDecl(DC, EnumType->getType()->getAsTagDecl()->getDeclName(), UL, EL, NL, EnumType); + UsingEnumDecl(DC, EnumType->getType()->castAsEnumDecl()->getDeclName(), + UL, EL, NL, EnumType); } UsingEnumDecl *UsingEnumDecl::CreateDeserialized(ASTContext &C, 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..3162857 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -307,8 +307,9 @@ bool TemplateDecl::hasAssociatedConstraints() const { bool TemplateDecl::isTypeAlias() const { switch (getKind()) { case TemplateDecl::TypeAliasTemplate: - case TemplateDecl::BuiltinTemplate: return true; + case TemplateDecl::BuiltinTemplate: + return !cast<BuiltinTemplateDecl>(this)->isPackProducingBuiltinTemplate(); default: return false; }; @@ -632,7 +633,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 +653,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; } //===----------------------------------------------------------------------===// @@ -736,15 +730,15 @@ void TemplateTypeParmDecl::setDefaultArgument( } unsigned TemplateTypeParmDecl::getDepth() const { - return getTypeForDecl()->castAs<TemplateTypeParmType>()->getDepth(); + return dyn_cast<TemplateTypeParmType>(getTypeForDecl())->getDepth(); } unsigned TemplateTypeParmDecl::getIndex() const { - return getTypeForDecl()->castAs<TemplateTypeParmType>()->getIndex(); + return dyn_cast<TemplateTypeParmType>(getTypeForDecl())->getIndex(); } bool TemplateTypeParmDecl::isParameterPack() const { - return getTypeForDecl()->castAs<TemplateTypeParmType>()->isParameterPack(); + return dyn_cast<TemplateTypeParmType>(getTypeForDecl())->isParameterPack(); } void TemplateTypeParmDecl::setTypeConstraint( @@ -998,7 +992,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 +1001,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 +1170,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 +1188,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 { @@ -1600,6 +1599,16 @@ BuiltinTemplateDecl::BuiltinTemplateDecl(const ASTContext &C, DeclContext *DC, createBuiltinTemplateParameterList(C, DC, BTK)), BTK(BTK) {} +bool BuiltinTemplateDecl::isPackProducingBuiltinTemplate() const { + return getBuiltinTemplateKind() == clang::BTK__builtin_dedup_pack; +} + +bool clang::isPackProducingBuiltinTemplateName(TemplateName N) { + auto *T = dyn_cast_or_null<BuiltinTemplateDecl>( + N.getAsTemplateDecl(/*IgnoreDeduced=*/true)); + return T && T->isPackProducingBuiltinTemplate(); +} + TemplateParamObjectDecl *TemplateParamObjectDecl::Create(const ASTContext &C, QualType T, const APValue &V) { diff --git a/clang/lib/AST/DeclarationName.cpp b/clang/lib/AST/DeclarationName.cpp index ae5fcf6..55f5a99 100644 --- a/clang/lib/AST/DeclarationName.cpp +++ b/clang/lib/AST/DeclarationName.cpp @@ -113,14 +113,15 @@ static void printCXXConstructorDestructorName(QualType ClassType, PrintingPolicy Policy) { // We know we're printing C++ here. Ensure we print types properly. Policy.adjustForCPlusPlus(); + Policy.SuppressScope = true; - if (const RecordType *ClassRec = ClassType->getAs<RecordType>()) { - ClassRec->getDecl()->printName(OS, Policy); + if (const RecordType *ClassRec = ClassType->getAsCanonical<RecordType>()) { + ClassRec->getOriginalDecl()->printName(OS, Policy); return; } if (Policy.SuppressTemplateArgsInCXXConstructors) { - if (auto *InjTy = ClassType->getAs<InjectedClassNameType>()) { - InjTy->getDecl()->printName(OS, Policy); + if (auto *InjTy = ClassType->getAsCanonical<InjectedClassNameType>()) { + InjTy->getOriginalDecl()->printName(OS, Policy); return; } } @@ -184,7 +185,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..cdff160 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -74,9 +74,7 @@ const CXXRecordDecl *Expr::getBestDynamicClassType() const { if (DerivedType->isDependentType()) return nullptr; - const RecordType *Ty = DerivedType->castAs<RecordType>(); - Decl *D = Ty->getDecl(); - return cast<CXXRecordDecl>(D); + return DerivedType->castAsCXXRecordDecl(); } const Expr *Expr::skipRValueSubobjectAdjustments( @@ -91,8 +89,7 @@ const Expr *Expr::skipRValueSubobjectAdjustments( CE->getCastKind() == CK_UncheckedDerivedToBase) && E->getType()->isRecordType()) { E = CE->getSubExpr(); - const auto *Derived = - cast<CXXRecordDecl>(E->getType()->castAs<RecordType>()->getDecl()); + const auto *Derived = E->getType()->castAsCXXRecordDecl(); Adjustments.push_back(SubobjectAdjustment(CE, Derived)); continue; } @@ -268,7 +265,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,8 +2028,7 @@ CXXBaseSpecifier **CastExpr::path_buffer() { const FieldDecl *CastExpr::getTargetFieldForToUnionCast(QualType unionType, QualType opType) { - auto RD = unionType->castAs<RecordType>()->getDecl(); - return getTargetFieldForToUnionCast(RD, opType); + return getTargetFieldForToUnionCast(unionType->castAsRecordDecl(), opType); } const FieldDecl *CastExpr::getTargetFieldForToUnionCast(const RecordDecl *RD, @@ -2399,6 +2395,7 @@ EmbedExpr::EmbedExpr(const ASTContext &Ctx, SourceLocation Loc, setDependence(ExprDependence::None); FakeChildNode = IntegerLiteral::Create( Ctx, llvm::APInt::getZero(Ctx.getTypeSize(getType())), getType(), Loc); + assert(getType()->isSignedIntegerType() && "IntTy should be signed"); } InitListExpr::InitListExpr(const ASTContext &C, SourceLocation lbraceloc, @@ -2774,23 +2771,22 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc, case UserDefinedLiteralClass: { // If this is a direct call, get the callee. const CallExpr *CE = cast<CallExpr>(this); - if (const Decl *FD = CE->getCalleeDecl()) { - // If the callee has attribute pure, const, or warn_unused_result, warn - // about it. void foo() { strlen("bar"); } should warn. - // - // Note: If new cases are added here, DiagnoseUnusedExprResult should be - // updated to match for QoI. - if (CE->hasUnusedResultAttr(Ctx) || - FD->hasAttr<PureAttr>() || FD->hasAttr<ConstAttr>()) { - WarnE = this; - Loc = CE->getCallee()->getBeginLoc(); - R1 = CE->getCallee()->getSourceRange(); - - if (unsigned NumArgs = CE->getNumArgs()) - R2 = SourceRange(CE->getArg(0)->getBeginLoc(), - CE->getArg(NumArgs - 1)->getEndLoc()); - return true; - } + // If the callee has attribute pure, const, or warn_unused_result, warn + // about it. void foo() { strlen("bar"); } should warn. + // Note: If new cases are added here, DiagnoseUnusedExprResult should be + // updated to match for QoI. + const Decl *FD = CE->getCalleeDecl(); + bool PureOrConst = + FD && (FD->hasAttr<PureAttr>() || FD->hasAttr<ConstAttr>()); + if (CE->hasUnusedResultAttr(Ctx) || PureOrConst) { + WarnE = this; + Loc = getBeginLoc(); + R1 = getSourceRange(); + + if (unsigned NumArgs = CE->getNumArgs()) + R2 = SourceRange(CE->getArg(0)->getBeginLoc(), + CE->getArg(NumArgs - 1)->getEndLoc()); + return true; } return false; } @@ -2803,32 +2799,20 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc, case CXXTemporaryObjectExprClass: case CXXConstructExprClass: { - if (const CXXRecordDecl *Type = getType()->getAsCXXRecordDecl()) { - const auto *WarnURAttr = Type->getAttr<WarnUnusedResultAttr>(); - if (Type->hasAttr<WarnUnusedAttr>() || - (WarnURAttr && WarnURAttr->IsCXX11NoDiscard())) { - WarnE = this; - Loc = getBeginLoc(); - R1 = getSourceRange(); - return true; - } - } - const auto *CE = cast<CXXConstructExpr>(this); - if (const CXXConstructorDecl *Ctor = CE->getConstructor()) { - const auto *WarnURAttr = Ctor->getAttr<WarnUnusedResultAttr>(); - if (WarnURAttr && WarnURAttr->IsCXX11NoDiscard()) { - WarnE = this; - Loc = getBeginLoc(); - R1 = getSourceRange(); - - if (unsigned NumArgs = CE->getNumArgs()) - R2 = SourceRange(CE->getArg(0)->getBeginLoc(), - CE->getArg(NumArgs - 1)->getEndLoc()); - return true; - } - } + const CXXRecordDecl *Type = getType()->getAsCXXRecordDecl(); + if ((Type && Type->hasAttr<WarnUnusedAttr>()) || + CE->hasUnusedResultAttr(Ctx)) { + WarnE = this; + Loc = getBeginLoc(); + R1 = getSourceRange(); + + if (unsigned NumArgs = CE->getNumArgs()) + R2 = SourceRange(CE->getArg(0)->getBeginLoc(), + CE->getArg(NumArgs - 1)->getEndLoc()); + return true; + } return false; } @@ -3221,7 +3205,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 +3391,7 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef, if (ILE->getType()->isRecordType()) { unsigned ElementNo = 0; - RecordDecl *RD = ILE->getType()->castAs<RecordType>()->getDecl(); + auto *RD = ILE->getType()->castAsRecordDecl(); // In C++17, bases were added to the list of members used by aggregate // initialization. @@ -3541,6 +3525,56 @@ bool CallExpr::isBuiltinAssumeFalse(const ASTContext &Ctx) const { Arg->EvaluateAsBooleanCondition(ArgVal, Ctx) && !ArgVal; } +const AllocSizeAttr *CallExpr::getCalleeAllocSizeAttr() const { + if (const FunctionDecl *DirectCallee = getDirectCallee()) + return DirectCallee->getAttr<AllocSizeAttr>(); + if (const Decl *IndirectCallee = getCalleeDecl()) + return IndirectCallee->getAttr<AllocSizeAttr>(); + return nullptr; +} + +std::optional<llvm::APInt> +CallExpr::evaluateBytesReturnedByAllocSizeCall(const ASTContext &Ctx) const { + const AllocSizeAttr *AllocSize = getCalleeAllocSizeAttr(); + + assert(AllocSize && AllocSize->getElemSizeParam().isValid()); + unsigned SizeArgNo = AllocSize->getElemSizeParam().getASTIndex(); + unsigned BitsInSizeT = Ctx.getTypeSize(Ctx.getSizeType()); + if (getNumArgs() <= SizeArgNo) + return std::nullopt; + + auto EvaluateAsSizeT = [&](const Expr *E, llvm::APSInt &Into) { + Expr::EvalResult ExprResult; + if (E->isValueDependent() || + !E->EvaluateAsInt(ExprResult, Ctx, Expr::SE_AllowSideEffects)) + return false; + Into = ExprResult.Val.getInt(); + if (Into.isNegative() || !Into.isIntN(BitsInSizeT)) + return false; + Into = Into.zext(BitsInSizeT); + return true; + }; + + llvm::APSInt SizeOfElem; + if (!EvaluateAsSizeT(getArg(SizeArgNo), SizeOfElem)) + return std::nullopt; + + if (!AllocSize->getNumElemsParam().isValid()) + return SizeOfElem; + + llvm::APSInt NumberOfElems; + unsigned NumArgNo = AllocSize->getNumElemsParam().getASTIndex(); + if (!EvaluateAsSizeT(getArg(NumArgNo), NumberOfElems)) + return std::nullopt; + + bool Overflow; + llvm::APInt BytesAvailable = SizeOfElem.umul_ov(NumberOfElems, Overflow); + if (Overflow) + return std::nullopt; + + return BytesAvailable; +} + bool CallExpr::isCallToStdMove() const { return getBuiltinCallee() == Builtin::BImove; } @@ -4050,8 +4084,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 3679327..b4f1e76 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -114,15 +114,6 @@ namespace { return Ctx.getLValueReferenceType(E->getType()); } - /// Given a CallExpr, try to get the alloc_size attribute. May return null. - static const AllocSizeAttr *getAllocSizeAttr(const CallExpr *CE) { - if (const FunctionDecl *DirectCallee = CE->getDirectCallee()) - return DirectCallee->getAttr<AllocSizeAttr>(); - if (const Decl *IndirectCallee = CE->getCalleeDecl()) - return IndirectCallee->getAttr<AllocSizeAttr>(); - return nullptr; - } - /// Attempts to unwrap a CallExpr (with an alloc_size attribute) from an Expr. /// This will look through a single cast. /// @@ -142,7 +133,7 @@ namespace { E = Cast->getSubExpr()->IgnoreParens(); if (const auto *CE = dyn_cast<CallExpr>(E)) - return getAllocSizeAttr(CE) ? CE : nullptr; + return CE->getCalleeAllocSizeAttr() ? CE : nullptr; return nullptr; } @@ -401,7 +392,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 +2614,7 @@ static bool CheckEvaluationResult(CheckEvaluationResultKind CERK, Value.getUnionValue(), Kind, Value.getUnionField(), CheckedTemps); } if (Value.isStruct()) { - RecordDecl *RD = Type->castAs<RecordType>()->getDecl(); + auto *RD = Type->castAsRecordDecl(); if (const CXXRecordDecl *CD = dyn_cast<CXXRecordDecl>(RD)) { unsigned BaseIndex = 0; for (const CXXBaseSpecifier &BS : CD->bases()) { @@ -4109,7 +4100,8 @@ 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->castAsCanonical<RecordType>()->getOriginalDecl(); if (RD->isUnion()) { const FieldDecl *UnionField = O->getUnionField(); if (!UnionField || @@ -4144,7 +4136,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 +6355,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 +6381,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 +6878,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 +7786,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 = @@ -7982,8 +7975,9 @@ static bool checkBitCastConstexprEligibilityType(SourceLocation Loc, // so its layout is unspecified. For now, we'll simply treat these cases // as unsupported (this should only be possible with OpenCL bool vectors // whose element count isn't a multiple of the byte size). - Info->FFDiag(Loc, diag::note_constexpr_bit_cast_invalid_vector) - << QualType(VTy, 0) << EltSize << NElts << Ctx.getCharWidth(); + if (Info) + Info->FFDiag(Loc, diag::note_constexpr_bit_cast_invalid_vector) + << QualType(VTy, 0) << EltSize << NElts << Ctx.getCharWidth(); return false; } @@ -7992,8 +7986,9 @@ static bool checkBitCastConstexprEligibilityType(SourceLocation Loc, // The layout for x86_fp80 vectors seems to be handled very inconsistently // by both clang and LLVM, so for now we won't allow bit_casts involving // it in a constexpr context. - Info->FFDiag(Loc, diag::note_constexpr_bit_cast_unsupported_type) - << EltTy; + if (Info) + Info->FFDiag(Loc, diag::note_constexpr_bit_cast_unsupported_type) + << EltTy; return false; } } @@ -8528,7 +8523,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 +8584,9 @@ 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->castAsCanonical<RecordType>()->getOriginalDecl() == + 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 +8813,9 @@ 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->castAsCanonical<RecordType>()->getOriginalDecl() == + FD->getParent()->getCanonicalDecl() && + "record / field mismatch"); (void)BaseTy; if (!HandleLValueMember(this->Info, E, Result, FD)) return false; @@ -9257,8 +9254,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())); @@ -9460,57 +9457,6 @@ bool LValueExprEvaluator::VisitBinAssign(const BinaryOperator *E) { // Pointer Evaluation //===----------------------------------------------------------------------===// -/// Attempts to compute the number of bytes available at the pointer -/// returned by a function with the alloc_size attribute. Returns true if we -/// were successful. Places an unsigned number into `Result`. -/// -/// This expects the given CallExpr to be a call to a function with an -/// alloc_size attribute. -static bool getBytesReturnedByAllocSizeCall(const ASTContext &Ctx, - const CallExpr *Call, - llvm::APInt &Result) { - const AllocSizeAttr *AllocSize = getAllocSizeAttr(Call); - - assert(AllocSize && AllocSize->getElemSizeParam().isValid()); - unsigned SizeArgNo = AllocSize->getElemSizeParam().getASTIndex(); - unsigned BitsInSizeT = Ctx.getTypeSize(Ctx.getSizeType()); - if (Call->getNumArgs() <= SizeArgNo) - return false; - - auto EvaluateAsSizeT = [&](const Expr *E, APSInt &Into) { - Expr::EvalResult ExprResult; - if (!E->EvaluateAsInt(ExprResult, Ctx, Expr::SE_AllowSideEffects)) - return false; - Into = ExprResult.Val.getInt(); - if (Into.isNegative() || !Into.isIntN(BitsInSizeT)) - return false; - Into = Into.zext(BitsInSizeT); - return true; - }; - - APSInt SizeOfElem; - if (!EvaluateAsSizeT(Call->getArg(SizeArgNo), SizeOfElem)) - return false; - - if (!AllocSize->getNumElemsParam().isValid()) { - Result = std::move(SizeOfElem); - return true; - } - - APSInt NumberOfElems; - unsigned NumArgNo = AllocSize->getNumElemsParam().getASTIndex(); - if (!EvaluateAsSizeT(Call->getArg(NumArgNo), NumberOfElems)) - return false; - - bool Overflow; - llvm::APInt BytesAvailable = SizeOfElem.umul_ov(NumberOfElems, Overflow); - if (Overflow) - return false; - - Result = std::move(BytesAvailable); - return true; -} - /// Convenience function. LVal's base must be a call to an alloc_size /// function. static bool getBytesReturnedByAllocSizeCall(const ASTContext &Ctx, @@ -9520,7 +9466,13 @@ static bool getBytesReturnedByAllocSizeCall(const ASTContext &Ctx, "Can't get the size of a non alloc_size function"); const auto *Base = LVal.getLValueBase().get<const Expr *>(); const CallExpr *CE = tryUnwrapAllocSizeCall(Base); - return getBytesReturnedByAllocSizeCall(Ctx, CE, Result); + std::optional<llvm::APInt> Size = + CE->evaluateBytesReturnedByAllocSizeCall(Ctx); + if (!Size) + return false; + + Result = std::move(*Size); + return true; } /// Attempts to evaluate the given LValueBase as the result of a call to @@ -10011,7 +9963,7 @@ bool PointerExprEvaluator::visitNonBuiltinCallExpr(const CallExpr *E) { if (ExprEvaluatorBaseTy::VisitCallExpr(E)) return true; - if (!(InvalidBaseOK && getAllocSizeAttr(E))) + if (!(InvalidBaseOK && E->getCalleeAllocSizeAttr())) return false; Result.setInvalid(E); @@ -10818,7 +10770,7 @@ static bool HandleClassZeroInitialization(EvalInfo &Info, const Expr *E, } bool RecordExprEvaluator::ZeroInitialization(const Expr *E, QualType T) { - const RecordDecl *RD = T->castAs<RecordType>()->getDecl(); + const auto *RD = T->castAsRecordDecl(); if (RD->isInvalidDecl()) return false; if (RD->isUnion()) { // C++11 [dcl.init]p5: If T is a (possibly cv-qualified) union type, the @@ -10887,8 +10839,7 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) { bool RecordExprEvaluator::VisitCXXParenListOrInitListExpr( const Expr *ExprToVisit, ArrayRef<Expr *> Args) { - const RecordDecl *RD = - ExprToVisit->getType()->castAs<RecordType>()->getDecl(); + const auto *RD = ExprToVisit->getType()->castAsRecordDecl(); if (RD->isInvalidDecl()) return false; const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD); auto *CXXRD = dyn_cast<CXXRecordDecl>(RD); @@ -11036,10 +10987,6 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E, bool ZeroInit = E->requiresZeroInitialization(); if (CheckTrivialDefaultConstructor(Info, E->getExprLoc(), FD, ZeroInit)) { - // If we've already performed zero-initialization, we're already done. - if (Result.hasValue()) - return true; - if (ZeroInit) return ZeroInitialization(E, T); @@ -11116,7 +11063,7 @@ bool RecordExprEvaluator::VisitCXXStdInitializerListExpr( Result = APValue(APValue::UninitStruct(), 0, 2); Array.moveInto(Result.getStructField(0)); - RecordDecl *Record = E->getType()->castAs<RecordType>()->getDecl(); + auto *Record = E->getType()->castAsRecordDecl(); RecordDecl::field_iterator Field = Record->field_begin(); assert(Field != Record->field_end() && Info.Ctx.hasSameType(Field->getType()->getPointeeType(), @@ -11302,6 +11249,24 @@ static bool EvaluateVector(const Expr* E, APValue& Result, EvalInfo &Info) { return VectorExprEvaluator(Info, Result).Visit(E); } +static llvm::APInt ConvertBoolVectorToInt(const APValue &Val) { + assert(Val.isVector() && "expected vector APValue"); + unsigned NumElts = Val.getVectorLength(); + + // Each element is one bit, so create an integer with NumElts bits. + llvm::APInt Result(NumElts, 0); + + for (unsigned I = 0; I < NumElts; ++I) { + const APValue &Elt = Val.getVectorElt(I); + assert(Elt.isInt() && "expected integer element in bool vector"); + + if (Elt.getInt().getBoolValue()) + Result.setBit(I); + } + + return Result; +} + bool VectorExprEvaluator::VisitCastExpr(const CastExpr *E) { const VectorType *VTy = E->getType()->castAs<VectorType>(); unsigned NElts = VTy->getNumElements(); @@ -11627,30 +11592,424 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) { return Success(APValue(ResultElements.data(), ResultElements.size()), E); } + case Builtin::BI__builtin_elementwise_abs: { + APValue Source; + if (!EvaluateAsRValue(Info, E->getArg(0), Source)) + return false; + + QualType DestEltTy = E->getType()->castAs<VectorType>()->getElementType(); + unsigned SourceLen = Source.getVectorLength(); + SmallVector<APValue, 4> ResultElements; + ResultElements.reserve(SourceLen); + + for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) { + APValue CurrentEle = Source.getVectorElt(EltNum); + APValue Val = DestEltTy->isFloatingType() + ? APValue(llvm::abs(CurrentEle.getFloat())) + : APValue(APSInt( + CurrentEle.getInt().abs(), + DestEltTy->isUnsignedIntegerOrEnumerationType())); + ResultElements.push_back(Val); + } + + 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: + case clang::X86::BI__builtin_ia32_psllv2di: + case clang::X86::BI__builtin_ia32_psllv4di: + case clang::X86::BI__builtin_ia32_psllv4si: + case clang::X86::BI__builtin_ia32_psllv8si: + case clang::X86::BI__builtin_ia32_psrav4si: + case clang::X86::BI__builtin_ia32_psrav8si: + case clang::X86::BI__builtin_ia32_psrlv2di: + case clang::X86::BI__builtin_ia32_psrlv4di: + case clang::X86::BI__builtin_ia32_psrlv4si: + case clang::X86::BI__builtin_ia32_psrlv8si: + + case clang::X86::BI__builtin_ia32_psllwi128: + case clang::X86::BI__builtin_ia32_pslldi128: + case clang::X86::BI__builtin_ia32_psllqi128: + case clang::X86::BI__builtin_ia32_psllwi256: + case clang::X86::BI__builtin_ia32_pslldi256: + case clang::X86::BI__builtin_ia32_psllqi256: + case clang::X86::BI__builtin_ia32_psllwi512: + case clang::X86::BI__builtin_ia32_pslldi512: + case clang::X86::BI__builtin_ia32_psllqi512: + + case clang::X86::BI__builtin_ia32_psrlwi128: + case clang::X86::BI__builtin_ia32_psrldi128: + case clang::X86::BI__builtin_ia32_psrlqi128: + case clang::X86::BI__builtin_ia32_psrlwi256: + case clang::X86::BI__builtin_ia32_psrldi256: + case clang::X86::BI__builtin_ia32_psrlqi256: + case clang::X86::BI__builtin_ia32_psrlwi512: + case clang::X86::BI__builtin_ia32_psrldi512: + case clang::X86::BI__builtin_ia32_psrlqi512: + + case clang::X86::BI__builtin_ia32_psrawi128: + case clang::X86::BI__builtin_ia32_psradi128: + case clang::X86::BI__builtin_ia32_psraqi128: + case clang::X86::BI__builtin_ia32_psrawi256: + case clang::X86::BI__builtin_ia32_psradi256: + case clang::X86::BI__builtin_ia32_psraqi256: + case clang::X86::BI__builtin_ia32_psrawi512: + case clang::X86::BI__builtin_ia32_psradi512: + case clang::X86::BI__builtin_ia32_psraqi512: { + APValue SourceLHS, SourceRHS; if (!EvaluateAsRValue(Info, E->getArg(0), SourceLHS) || !EvaluateAsRValue(Info, E->getArg(1), SourceRHS)) return false; QualType DestEltTy = E->getType()->castAs<VectorType>()->getElementType(); + bool DestUnsigned = DestEltTy->isUnsignedIntegerOrEnumerationType(); unsigned SourceLen = SourceLHS.getVectorLength(); SmallVector<APValue, 4> ResultElements; ResultElements.reserve(SourceLen); for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) { APSInt LHS = SourceLHS.getVectorElt(EltNum).getInt(); + + if (SourceRHS.isInt()) { + const unsigned LaneBitWidth = LHS.getBitWidth(); + const unsigned ShiftAmount = SourceRHS.getInt().getZExtValue(); + + switch (E->getBuiltinCallee()) { + case clang::X86::BI__builtin_ia32_psllwi128: + case clang::X86::BI__builtin_ia32_psllwi256: + case clang::X86::BI__builtin_ia32_psllwi512: + case clang::X86::BI__builtin_ia32_pslldi128: + case clang::X86::BI__builtin_ia32_pslldi256: + case clang::X86::BI__builtin_ia32_pslldi512: + case clang::X86::BI__builtin_ia32_psllqi128: + case clang::X86::BI__builtin_ia32_psllqi256: + case clang::X86::BI__builtin_ia32_psllqi512: + if (ShiftAmount >= LaneBitWidth) { + ResultElements.push_back( + APValue(APSInt(APInt::getZero(LaneBitWidth), DestUnsigned))); + } else { + ResultElements.push_back( + APValue(APSInt(LHS.shl(ShiftAmount), DestUnsigned))); + } + break; + case clang::X86::BI__builtin_ia32_psrlwi128: + case clang::X86::BI__builtin_ia32_psrlwi256: + case clang::X86::BI__builtin_ia32_psrlwi512: + case clang::X86::BI__builtin_ia32_psrldi128: + case clang::X86::BI__builtin_ia32_psrldi256: + case clang::X86::BI__builtin_ia32_psrldi512: + case clang::X86::BI__builtin_ia32_psrlqi128: + case clang::X86::BI__builtin_ia32_psrlqi256: + case clang::X86::BI__builtin_ia32_psrlqi512: + if (ShiftAmount >= LaneBitWidth) { + ResultElements.push_back( + APValue(APSInt(APInt::getZero(LaneBitWidth), DestUnsigned))); + } else { + ResultElements.push_back( + APValue(APSInt(LHS.lshr(ShiftAmount), DestUnsigned))); + } + break; + case clang::X86::BI__builtin_ia32_psrawi128: + case clang::X86::BI__builtin_ia32_psrawi256: + case clang::X86::BI__builtin_ia32_psrawi512: + case clang::X86::BI__builtin_ia32_psradi128: + case clang::X86::BI__builtin_ia32_psradi256: + case clang::X86::BI__builtin_ia32_psradi512: + case clang::X86::BI__builtin_ia32_psraqi128: + case clang::X86::BI__builtin_ia32_psraqi256: + case clang::X86::BI__builtin_ia32_psraqi512: + ResultElements.push_back( + APValue(APSInt(LHS.ashr(std::min(ShiftAmount, LaneBitWidth - 1)), + DestUnsigned))); + break; + default: + llvm_unreachable("Unexpected builtin callee"); + } + continue; + } APSInt RHS = SourceRHS.getVectorElt(EltNum).getInt(); switch (E->getBuiltinCallee()) { case Builtin::BI__builtin_elementwise_add_sat: ResultElements.push_back(APValue( APSInt(LHS.isSigned() ? LHS.sadd_sat(RHS) : LHS.uadd_sat(RHS), - DestEltTy->isUnsignedIntegerOrEnumerationType()))); + DestUnsigned))); break; case Builtin::BI__builtin_elementwise_sub_sat: ResultElements.push_back(APValue( APSInt(LHS.isSigned() ? LHS.ssub_sat(RHS) : LHS.usub_sat(RHS), + DestUnsigned))); + 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; + case clang::X86::BI__builtin_ia32_psllv2di: + case clang::X86::BI__builtin_ia32_psllv4di: + case clang::X86::BI__builtin_ia32_psllv4si: + case clang::X86::BI__builtin_ia32_psllv8si: + if (RHS.uge(RHS.getBitWidth())) { + ResultElements.push_back( + APValue(APSInt(APInt::getZero(RHS.getBitWidth()), DestUnsigned))); + break; + } + ResultElements.push_back( + APValue(APSInt(LHS.shl(RHS.getZExtValue()), DestUnsigned))); + break; + case clang::X86::BI__builtin_ia32_psrav4si: + case clang::X86::BI__builtin_ia32_psrav8si: + if (RHS.uge(RHS.getBitWidth())) { + ResultElements.push_back( + APValue(APSInt(LHS.ashr(RHS.getBitWidth() - 1), DestUnsigned))); + break; + } + ResultElements.push_back( + APValue(APSInt(LHS.ashr(RHS.getZExtValue()), DestUnsigned))); + break; + case clang::X86::BI__builtin_ia32_psrlv2di: + case clang::X86::BI__builtin_ia32_psrlv4di: + case clang::X86::BI__builtin_ia32_psrlv4si: + case clang::X86::BI__builtin_ia32_psrlv8si: + if (RHS.uge(RHS.getBitWidth())) { + ResultElements.push_back( + APValue(APSInt(APInt::getZero(RHS.getBitWidth()), DestUnsigned))); + break; + } + ResultElements.push_back( + APValue(APSInt(LHS.lshr(RHS.getZExtValue()), DestUnsigned))); + break; + } + } + + return Success(APValue(ResultElements.data(), ResultElements.size()), E); + } + case clang::X86::BI__builtin_ia32_pmuldq128: + case clang::X86::BI__builtin_ia32_pmuldq256: + case clang::X86::BI__builtin_ia32_pmuldq512: + case clang::X86::BI__builtin_ia32_pmuludq128: + case clang::X86::BI__builtin_ia32_pmuludq256: + case clang::X86::BI__builtin_ia32_pmuludq512: { + APValue SourceLHS, SourceRHS; + if (!EvaluateAsRValue(Info, E->getArg(0), SourceLHS) || + !EvaluateAsRValue(Info, E->getArg(1), SourceRHS)) + return false; + + unsigned SourceLen = SourceLHS.getVectorLength(); + SmallVector<APValue, 4> ResultElements; + ResultElements.reserve(SourceLen / 2); + + for (unsigned EltNum = 0; EltNum < SourceLen; EltNum += 2) { + APSInt LHS = SourceLHS.getVectorElt(EltNum).getInt(); + APSInt RHS = SourceRHS.getVectorElt(EltNum).getInt(); + + switch (E->getBuiltinCallee()) { + case clang::X86::BI__builtin_ia32_pmuludq128: + case clang::X86::BI__builtin_ia32_pmuludq256: + case clang::X86::BI__builtin_ia32_pmuludq512: + ResultElements.push_back( + APValue(APSInt(llvm::APIntOps::muluExtended(LHS, RHS), true))); + break; + case clang::X86::BI__builtin_ia32_pmuldq128: + case clang::X86::BI__builtin_ia32_pmuldq256: + case clang::X86::BI__builtin_ia32_pmuldq512: + ResultElements.push_back( + APValue(APSInt(llvm::APIntOps::mulsExtended(LHS, RHS), false))); + break; + } + } + + return Success(APValue(ResultElements.data(), ResultElements.size()), E); + } + case clang::X86::BI__builtin_ia32_vprotbi: + case clang::X86::BI__builtin_ia32_vprotdi: + case clang::X86::BI__builtin_ia32_vprotqi: + case clang::X86::BI__builtin_ia32_vprotwi: + case clang::X86::BI__builtin_ia32_prold128: + case clang::X86::BI__builtin_ia32_prold256: + case clang::X86::BI__builtin_ia32_prold512: + case clang::X86::BI__builtin_ia32_prolq128: + case clang::X86::BI__builtin_ia32_prolq256: + case clang::X86::BI__builtin_ia32_prolq512: { + APValue SourceLHS, SourceRHS; + if (!EvaluateAsRValue(Info, E->getArg(0), SourceLHS) || + !EvaluateAsRValue(Info, E->getArg(1), SourceRHS)) + return false; + + QualType DestEltTy = E->getType()->castAs<VectorType>()->getElementType(); + bool DestUnsigned = DestEltTy->isUnsignedIntegerOrEnumerationType(); + unsigned SourceLen = SourceLHS.getVectorLength(); + SmallVector<APValue, 4> ResultElements; + ResultElements.reserve(SourceLen); + + APSInt RHS = SourceRHS.getInt(); + + for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) { + const APSInt &LHS = SourceLHS.getVectorElt(EltNum).getInt(); + ResultElements.push_back(APValue(APSInt(LHS.rotl(RHS), DestUnsigned))); + } + + return Success(APValue(ResultElements.data(), ResultElements.size()), E); + } + case clang::X86::BI__builtin_ia32_prord128: + case clang::X86::BI__builtin_ia32_prord256: + case clang::X86::BI__builtin_ia32_prord512: + case clang::X86::BI__builtin_ia32_prorq128: + case clang::X86::BI__builtin_ia32_prorq256: + case clang::X86::BI__builtin_ia32_prorq512: { + APValue SourceLHS, SourceRHS; + if (!EvaluateAsRValue(Info, E->getArg(0), SourceLHS) || + !EvaluateAsRValue(Info, E->getArg(1), SourceRHS)) + return false; + + QualType DestEltTy = E->getType()->castAs<VectorType>()->getElementType(); + bool DestUnsigned = DestEltTy->isUnsignedIntegerOrEnumerationType(); + unsigned SourceLen = SourceLHS.getVectorLength(); + SmallVector<APValue, 4> ResultElements; + ResultElements.reserve(SourceLen); + + APSInt RHS = SourceRHS.getInt(); + + for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) { + const APSInt &LHS = SourceLHS.getVectorElt(EltNum).getInt(); + ResultElements.push_back(APValue(APSInt(LHS.rotr(RHS), DestUnsigned))); + } + + return Success(APValue(ResultElements.data(), ResultElements.size()), E); + } + case Builtin::BI__builtin_elementwise_max: + case Builtin::BI__builtin_elementwise_min: { + APValue SourceLHS, SourceRHS; + if (!EvaluateAsRValue(Info, E->getArg(0), SourceLHS) || + !EvaluateAsRValue(Info, E->getArg(1), SourceRHS)) + return false; + + QualType DestEltTy = E->getType()->castAs<VectorType>()->getElementType(); + + if (!DestEltTy->isIntegerType()) + return false; + + unsigned SourceLen = SourceLHS.getVectorLength(); + SmallVector<APValue, 4> ResultElements; + ResultElements.reserve(SourceLen); + + for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) { + APSInt LHS = SourceLHS.getVectorElt(EltNum).getInt(); + APSInt RHS = SourceRHS.getVectorElt(EltNum).getInt(); + switch (E->getBuiltinCallee()) { + case Builtin::BI__builtin_elementwise_max: + ResultElements.push_back( + APValue(APSInt(std::max(LHS, RHS), + DestEltTy->isUnsignedIntegerOrEnumerationType()))); + break; + case Builtin::BI__builtin_elementwise_min: + ResultElements.push_back( + APValue(APSInt(std::min(LHS, RHS), + DestEltTy->isUnsignedIntegerOrEnumerationType()))); + break; + } + } + + return Success(APValue(ResultElements.data(), ResultElements.size()), E); + } + case X86::BI__builtin_ia32_selectb_128: + case X86::BI__builtin_ia32_selectb_256: + case X86::BI__builtin_ia32_selectb_512: + case X86::BI__builtin_ia32_selectw_128: + case X86::BI__builtin_ia32_selectw_256: + case X86::BI__builtin_ia32_selectw_512: + case X86::BI__builtin_ia32_selectd_128: + case X86::BI__builtin_ia32_selectd_256: + case X86::BI__builtin_ia32_selectd_512: + case X86::BI__builtin_ia32_selectq_128: + case X86::BI__builtin_ia32_selectq_256: + case X86::BI__builtin_ia32_selectq_512: + case X86::BI__builtin_ia32_selectph_128: + case X86::BI__builtin_ia32_selectph_256: + case X86::BI__builtin_ia32_selectph_512: + case X86::BI__builtin_ia32_selectpbf_128: + case X86::BI__builtin_ia32_selectpbf_256: + case X86::BI__builtin_ia32_selectpbf_512: + case X86::BI__builtin_ia32_selectps_128: + case X86::BI__builtin_ia32_selectps_256: + case X86::BI__builtin_ia32_selectps_512: + case X86::BI__builtin_ia32_selectpd_128: + case X86::BI__builtin_ia32_selectpd_256: + case X86::BI__builtin_ia32_selectpd_512: { + // AVX512 predicated move: "Result = Mask[] ? LHS[] : RHS[]". + APValue SourceMask, SourceLHS, SourceRHS; + if (!EvaluateAsRValue(Info, E->getArg(0), SourceMask) || + !EvaluateAsRValue(Info, E->getArg(1), SourceLHS) || + !EvaluateAsRValue(Info, E->getArg(2), SourceRHS)) + return false; + + APSInt Mask = SourceMask.getInt(); + unsigned SourceLen = SourceLHS.getVectorLength(); + SmallVector<APValue, 4> ResultElements; + ResultElements.reserve(SourceLen); + + for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) { + const APValue &LHS = SourceLHS.getVectorElt(EltNum); + const APValue &RHS = SourceRHS.getVectorElt(EltNum); + ResultElements.push_back(Mask[EltNum] ? LHS : RHS); + } + + return Success(APValue(ResultElements.data(), ResultElements.size()), E); + } + case Builtin::BI__builtin_elementwise_ctlz: + case Builtin::BI__builtin_elementwise_cttz: { + APValue SourceLHS; + std::optional<APValue> Fallback; + if (!EvaluateAsRValue(Info, E->getArg(0), SourceLHS)) + return false; + if (E->getNumArgs() > 1) { + APValue FallbackTmp; + if (!EvaluateAsRValue(Info, E->getArg(1), FallbackTmp)) + return false; + Fallback = FallbackTmp; + } + + QualType DestEltTy = E->getType()->castAs<VectorType>()->getElementType(); + unsigned SourceLen = SourceLHS.getVectorLength(); + SmallVector<APValue, 4> ResultElements; + ResultElements.reserve(SourceLen); + + for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) { + APSInt LHS = SourceLHS.getVectorElt(EltNum).getInt(); + if (!LHS) { + // Without a fallback, a zero element is undefined + if (!Fallback) { + Info.FFDiag(E, diag::note_constexpr_countzeroes_zero) + << /*IsTrailing=*/(E->getBuiltinCallee() == + Builtin::BI__builtin_elementwise_cttz); + return false; + } + ResultElements.push_back(Fallback->getVectorElt(EltNum)); + continue; + } + switch (E->getBuiltinCallee()) { + case Builtin::BI__builtin_elementwise_ctlz: + ResultElements.push_back(APValue( + APSInt(APInt(Info.Ctx.getIntWidth(DestEltTy), LHS.countl_zero()), + DestEltTy->isUnsignedIntegerOrEnumerationType()))); + break; + case Builtin::BI__builtin_elementwise_cttz: + ResultElements.push_back(APValue( + APSInt(APInt(Info.Ctx.getIntWidth(DestEltTy), LHS.countr_zero()), DestEltTy->isUnsignedIntegerOrEnumerationType()))); break; } @@ -11658,6 +12017,28 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) { return Success(APValue(ResultElements.data(), ResultElements.size()), E); } + + case Builtin::BI__builtin_elementwise_fma: { + APValue SourceX, SourceY, SourceZ; + if (!EvaluateAsRValue(Info, E->getArg(0), SourceX) || + !EvaluateAsRValue(Info, E->getArg(1), SourceY) || + !EvaluateAsRValue(Info, E->getArg(2), SourceZ)) + return false; + + unsigned SourceLen = SourceX.getVectorLength(); + SmallVector<APValue> ResultElements; + ResultElements.reserve(SourceLen); + llvm::RoundingMode RM = getActiveRoundingMode(getEvalInfo(), E); + for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) { + const APFloat &X = SourceX.getVectorElt(EltNum).getFloat(); + const APFloat &Y = SourceY.getVectorElt(EltNum).getFloat(); + const APFloat &Z = SourceZ.getVectorElt(EltNum).getFloat(); + APFloat Result(X); + (void)Result.fusedMultiplyAdd(Y, Z, RM); + ResultElements.push_back(APValue(Result)); + } + return Success(APValue(ResultElements.data(), ResultElements.size()), E); + } } } @@ -12889,7 +13270,7 @@ 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->castAsRecordDecl()->hasFlexibleArrayMember()) if (const auto *V = LV.getLValueBase().dyn_cast<const ValueDecl *>()) if (const auto *VD = dyn_cast<VarDecl>(V)) if (VD->hasInit()) @@ -13210,15 +13591,24 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, case Builtin::BI__builtin_clzll: case Builtin::BI__builtin_clzs: case Builtin::BI__builtin_clzg: + case Builtin::BI__builtin_elementwise_ctlz: case Builtin::BI__lzcnt16: // Microsoft variants of count leading-zeroes case Builtin::BI__lzcnt: case Builtin::BI__lzcnt64: { APSInt Val; - if (!EvaluateInteger(E->getArg(0), Val, Info)) + if (E->getArg(0)->getType()->isExtVectorBoolType()) { + APValue Vec; + if (!EvaluateVector(E->getArg(0), Vec, Info)) + return false; + Val = ConvertBoolVectorToInt(Vec); + } else if (!EvaluateInteger(E->getArg(0), Val, Info)) { return false; + } std::optional<APSInt> Fallback; - if (BuiltinOp == Builtin::BI__builtin_clzg && E->getNumArgs() > 1) { + if ((BuiltinOp == Builtin::BI__builtin_clzg || + BuiltinOp == Builtin::BI__builtin_elementwise_ctlz) && + E->getNumArgs() > 1) { APSInt FallbackTemp; if (!EvaluateInteger(E->getArg(1), FallbackTemp, Info)) return false; @@ -13236,6 +13626,11 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, BuiltinOp != Builtin::BI__lzcnt && BuiltinOp != Builtin::BI__lzcnt64; + if (BuiltinOp == Builtin::BI__builtin_elementwise_ctlz) { + Info.FFDiag(E, diag::note_constexpr_countzeroes_zero) + << /*IsTrailing=*/false; + } + if (ZeroIsUndefined) return Error(E); } @@ -13290,13 +13685,22 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, case Builtin::BI__builtin_ctzl: case Builtin::BI__builtin_ctzll: case Builtin::BI__builtin_ctzs: - case Builtin::BI__builtin_ctzg: { + case Builtin::BI__builtin_ctzg: + case Builtin::BI__builtin_elementwise_cttz: { APSInt Val; - if (!EvaluateInteger(E->getArg(0), Val, Info)) + if (E->getArg(0)->getType()->isExtVectorBoolType()) { + APValue Vec; + if (!EvaluateVector(E->getArg(0), Vec, Info)) + return false; + Val = ConvertBoolVectorToInt(Vec); + } else if (!EvaluateInteger(E->getArg(0), Val, Info)) { return false; + } std::optional<APSInt> Fallback; - if (BuiltinOp == Builtin::BI__builtin_ctzg && E->getNumArgs() > 1) { + if ((BuiltinOp == Builtin::BI__builtin_ctzg || + BuiltinOp == Builtin::BI__builtin_elementwise_cttz) && + E->getNumArgs() > 1) { APSInt FallbackTemp; if (!EvaluateInteger(E->getArg(1), FallbackTemp, Info)) return false; @@ -13307,6 +13711,10 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, if (Fallback) return Success(*Fallback, E); + if (BuiltinOp == Builtin::BI__builtin_elementwise_cttz) { + Info.FFDiag(E, diag::note_constexpr_countzeroes_zero) + << /*IsTrailing=*/true; + } return Error(E); } @@ -13319,6 +13727,14 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, return Success(Operand, E); } + case Builtin::BI__builtin_elementwise_abs: { + APSInt Val; + if (!EvaluateInteger(E->getArg(0), Val, Info)) + return false; + + return Success(Val.abs(), E); + } + case Builtin::BI__builtin_expect: case Builtin::BI__builtin_expect_with_probability: return Visit(E->getArg(0)); @@ -13494,8 +13910,14 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, case Builtin::BI__popcnt: case Builtin::BI__popcnt64: { APSInt Val; - if (!EvaluateInteger(E->getArg(0), Val, Info)) + if (E->getArg(0)->getType()->isExtVectorBoolType()) { + APValue Vec; + if (!EvaluateVector(E->getArg(0), Vec, Info)) + return false; + Val = ConvertBoolVectorToInt(Vec); + } else if (!EvaluateInteger(E->getArg(0), Val, Info)) { return false; + } return Success(Val.popcount(), E); } @@ -13552,7 +13974,24 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, APInt Result = LHS.isSigned() ? LHS.ssub_sat(RHS) : LHS.usub_sat(RHS); return Success(APSInt(Result, !LHS.isSigned()), E); } + case Builtin::BI__builtin_elementwise_max: { + APSInt LHS, RHS; + if (!EvaluateInteger(E->getArg(0), LHS, Info) || + !EvaluateInteger(E->getArg(1), RHS, Info)) + return false; + + APInt Result = std::max(LHS, RHS); + return Success(APSInt(Result, !LHS.isSigned()), E); + } + case Builtin::BI__builtin_elementwise_min: { + APSInt LHS, RHS; + if (!EvaluateInteger(E->getArg(0), LHS, Info) || + !EvaluateInteger(E->getArg(1), RHS, Info)) + return false; + APInt Result = std::min(LHS, RHS); + return Success(APSInt(Result, !LHS.isSigned()), E); + } case Builtin::BIstrlen: case Builtin::BIwcslen: // A call to strlen is not a constant expression. @@ -15086,6 +15525,13 @@ bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr( const auto *VAT = Info.Ctx.getAsVariableArrayType(Ty); assert(VAT); if (VAT->getElementType()->isArrayType()) { + // Variable array size expression could be missing (e.g. int a[*][10]) In + // that case, it can't be a constant expression. + if (!VAT->getSizeExpr()) { + Info.FFDiag(E->getBeginLoc()); + return false; + } + std::optional<APSInt> Res = VAT->getSizeExpr()->getIntegerConstantExpr(Info.Ctx); if (Res) { @@ -15133,10 +15579,9 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *OOE) { case OffsetOfNode::Field: { FieldDecl *MemberDecl = ON.getField(); - const RecordType *RT = CurrentType->getAs<RecordType>(); - if (!RT) + const auto *RD = CurrentType->getAsRecordDecl(); + if (!RD) return Error(OOE); - RecordDecl *RD = RT->getDecl(); if (RD->isInvalidDecl()) return false; const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD); unsigned i = MemberDecl->getFieldIndex(); @@ -15155,21 +15600,20 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *OOE) { return Error(OOE); // Find the layout of the class whose base we are looking into. - const RecordType *RT = CurrentType->getAs<RecordType>(); - if (!RT) + const auto *RD = CurrentType->getAsCXXRecordDecl(); + if (!RD) return Error(OOE); - RecordDecl *RD = RT->getDecl(); if (RD->isInvalidDecl()) return false; const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD); // Find the base class itself. CurrentType = BaseSpec->getType(); - const RecordType *BaseRT = CurrentType->getAs<RecordType>(); - if (!BaseRT) + const auto *BaseRD = CurrentType->getAsCXXRecordDecl(); + if (!BaseRD) return Error(OOE); // Add the offset to the base. - Result += RL.getBaseClassOffset(cast<CXXRecordDecl>(BaseRT->getDecl())); + Result += RL.getBaseClassOffset(BaseRD); break; } } @@ -15347,8 +15791,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 auto *ED = DestType->getAsEnumDecl(); // Check that the value is within the range of the enumeration values. // // This corressponds to [expr.static.cast]p10 which says: @@ -15792,6 +16235,7 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) { return Error(E); return true; + case Builtin::BI__builtin_elementwise_abs: case Builtin::BI__builtin_fabs: case Builtin::BI__builtin_fabsf: case Builtin::BI__builtin_fabsl: @@ -15878,6 +16322,21 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) { Result = minimumnum(Result, RHS); return true; } + + case Builtin::BI__builtin_elementwise_fma: { + if (!E->getArg(0)->isPRValue() || !E->getArg(1)->isPRValue() || + !E->getArg(2)->isPRValue()) { + return false; + } + APFloat SourceY(0.), SourceZ(0.); + if (!EvaluateFloat(E->getArg(0), Result, Info) || + !EvaluateFloat(E->getArg(1), SourceY, Info) || + !EvaluateFloat(E->getArg(2), SourceZ, Info)) + return false; + llvm::RoundingMode RM = getActiveRoundingMode(getEvalInfo(), E); + (void)Result.fusedMultiplyAdd(SourceY, SourceZ, RM); + return true; + } } } @@ -17606,7 +18065,10 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { // it is an ICE or not. const auto *VAT = Ctx.getAsVariableArrayType(ArgTy); if (VAT->getElementType()->isArrayType()) - return CheckICE(VAT->getSizeExpr(), Ctx); + // Variable array size expression could be missing (e.g. int a[*][10]) + // In that case, it can't be a constant expression. + return VAT->getSizeExpr() ? CheckICE(VAT->getSizeExpr(), Ctx) + : ICEDiag(IK_NotICE, E->getBeginLoc()); // Otherwise, this is a regular VLA, which is definitely not an ICE. return ICEDiag(IK_NotICE, E->getBeginLoc()); @@ -18010,7 +18472,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..d4cb89b 100644 --- a/clang/lib/AST/FormatString.cpp +++ b/clang/lib/AST/FormatString.cpp @@ -413,14 +413,14 @@ ArgType::matchesType(ASTContext &C, QualType argTy) const { return Match; case AnyCharTy: { - if (const auto *ETy = argTy->getAs<EnumType>()) { + if (const auto *ED = argTy->getAsEnumDecl()) { // 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()) + if (!ED->isComplete()) return NoMatch; - if (ETy->isUnscopedEnumerationType()) - argTy = ETy->getDecl()->getIntegerType(); + if (!ED->isScoped()) + argTy = ED->getIntegerType(); } if (const auto *BT = argTy->getAs<BuiltinType>()) { @@ -462,14 +462,14 @@ ArgType::matchesType(ASTContext &C, QualType argTy) const { return matchesSizeTPtrdiffT(C, argTy, T); } - if (const EnumType *ETy = argTy->getAs<EnumType>()) { + if (const auto *ED = argTy->getAsEnumDecl()) { // 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()) + if (!ED->isComplete()) argTy = C.IntTy; - else if (ETy->isUnscopedEnumerationType()) - argTy = ETy->getDecl()->getIntegerType(); + else if (!ED->isScoped()) + argTy = ED->getIntegerType(); } if (argTy->isSaturatedFixedPointType()) @@ -653,7 +653,7 @@ ArgType::matchesType(ASTContext &C, QualType argTy) const { // to Objective-C objects. Since the compiler doesn't know which // structs can be toll-free bridged, we just accept them all. QualType pointee = PT->getPointeeType(); - if (pointee->getAsStructureType() || pointee->isVoidType()) + if (pointee->isStructureType() || pointee->isVoidType()) return Match; } return NoMatch; diff --git a/clang/lib/AST/InheritViz.cpp b/clang/lib/AST/InheritViz.cpp index 1dafed8..3c4a5a8 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 = cast<CXXRecordDecl>( + Type->castAsCanonical<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..adef158 100644 --- a/clang/lib/AST/ItaniumCXXABI.cpp +++ b/clang/lib/AST/ItaniumCXXABI.cpp @@ -42,10 +42,9 @@ 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 *RD = VD.getType()->castAsRecordDecl(); + 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..ffadfce 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,7 @@ 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 auto *RD = VD->getType()->castAsRecordDecl(); // Itanium C++ ABI 5.1.2: // @@ -2167,49 +2166,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()); - 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)); + case NestedNameSpecifier::Kind::Namespace: + mangleName(Qualifier.getAsNamespaceAndPrefix().Namespace->getNamespace()); 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 +2241,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; @@ -2470,6 +2441,13 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty, case Type::CountAttributed: llvm_unreachable("type is illegal as a nested name specifier"); + case Type::SubstBuiltinTemplatePack: + // FIXME: not clear how to mangle this! + // template <class T...> class A { + // template <class U...> void foo(__builtin_dedup_pack<T...>(*)(U) x...); + // }; + Out << "_SUBSTBUILTINPACK_"; + break; case Type::SubstTemplateTypeParmPack: // FIXME: not clear how to mangle this! // template <class T...> class A { @@ -2525,7 +2503,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 +2565,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 +2588,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 +3815,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 +3852,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); @@ -3924,6 +3895,14 @@ void CXXNameMangler::mangleType(const SubstTemplateTypeParmPackType *T) { Out << "_SUBSTPACK_"; } +void CXXNameMangler::mangleType(const SubstBuiltinTemplatePackType *T) { + // FIXME: not clear how to mangle this! + // template <class T...> class A { + // template <class U...> void foo(__builtin_dedup_pack<T...>(*)(U) x...); + // }; + Out << "_SUBSTBUILTINPACK_"; +} + // <type> ::= P <type> # pointer-to void CXXNameMangler::mangleType(const PointerType *T) { Out << 'P'; @@ -4471,7 +4450,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) { @@ -4746,8 +4726,8 @@ 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()) + while (const auto *RT = Base->getType()->getAsCanonical<RecordType>()) { + if (!RT->getOriginalDecl()->isAnonymousStructOrUnion()) break; const auto *ME = dyn_cast<MemberExpr>(Base); if (!ME) @@ -4768,9 +4748,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 +4759,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 +5209,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 +5834,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 +6508,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 +6875,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 +6985,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) { @@ -7022,8 +6994,8 @@ static bool hasMangledSubstitutionQualifiers(QualType T) { bool CXXNameMangler::mangleSubstitution(QualType T) { if (!hasMangledSubstitutionQualifiers(T)) { - if (const RecordType *RT = T->getAs<RecordType>()) - return mangleSubstitution(RT->getDecl()); + if (const auto *RD = T->getAsCXXRecordDecl()) + return mangleSubstitution(RD); } uintptr_t TypePtr = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr()); @@ -7059,12 +7031,12 @@ bool CXXNameMangler::isSpecializedAs(QualType S, llvm::StringRef Name, if (S.isNull()) return false; - const RecordType *RT = S->getAs<RecordType>(); + const RecordType *RT = S->getAsCanonical<RecordType>(); if (!RT) return false; const ClassTemplateSpecializationDecl *SD = - dyn_cast<ClassTemplateSpecializationDecl>(RT->getDecl()); + dyn_cast<ClassTemplateSpecializationDecl>(RT->getOriginalDecl()); if (!SD || !SD->getIdentifier()->isStr(Name)) return false; @@ -7193,8 +7165,8 @@ bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) { void CXXNameMangler::addSubstitution(QualType T) { if (!hasMangledSubstitutionQualifiers(T)) { - if (const RecordType *RT = T->getAs<RecordType>()) { - addSubstitution(RT->getDecl()); + if (const auto *RD = T->getAsCXXRecordDecl()) { + addSubstitution(RD); return; } } diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp index 64ddb1e..ca8e2af 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()->castAsCanonical<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..2ac38a2 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,13 +3246,17 @@ void MicrosoftCXXNameMangler::mangleTagTypeKind(TagTypeKind TTK) { } void MicrosoftCXXNameMangler::mangleType(const EnumType *T, Qualifiers, SourceRange) { - mangleType(cast<TagType>(T)->getDecl()); + mangleType(cast<TagType>(T)->getOriginalDecl()); } void MicrosoftCXXNameMangler::mangleType(const RecordType *T, Qualifiers, SourceRange) { - mangleType(cast<TagType>(T)->getDecl()); + mangleType(cast<TagType>(T)->getOriginalDecl()); } void MicrosoftCXXNameMangler::mangleType(const TagDecl *TD) { + // MSVC chooses the tag kind of the definition if it exists, otherwise it + // always picks the first declaration. + const auto *Def = TD->getDefinition(); + TD = Def ? Def : TD->getFirstDecl(); mangleTagTypeKind(TD->getTagKind()); mangleName(TD); } @@ -3384,6 +3387,11 @@ void MicrosoftCXXNameMangler::mangleType(const SubstTemplateTypeParmPackType *T, Error(Range.getBegin(), "substituted parameter pack") << Range; } +void MicrosoftCXXNameMangler::mangleType(const SubstBuiltinTemplatePackType *T, + Qualifiers, SourceRange Range) { + Error(Range.getBegin(), "substituted builtin template pack") << Range; +} + // <type> ::= <pointer-type> // <pointer-type> ::= E? <pointer-cvr-qualifiers> <cvr-qualifiers> <type> // # the E is required for 64-bit non-static pointers 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 fe20004..9a9ede4 100644 --- a/clang/lib/AST/OpenACCClause.cpp +++ b/clang/lib/AST/OpenACCClause.cpp @@ -506,11 +506,13 @@ OpenACCDeviceTypeClause *OpenACCDeviceTypeClause::Create( OpenACCReductionClause *OpenACCReductionClause::Create( const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc, OpenACCReductionOperator Operator, ArrayRef<Expr *> VarList, + ArrayRef<OpenACCReductionRecipe> Recipes, SourceLocation EndLoc) { void *Mem = C.Allocate( - OpenACCReductionClause::totalSizeToAlloc<Expr *>(VarList.size())); - return new (Mem) - OpenACCReductionClause(BeginLoc, LParenLoc, Operator, VarList, EndLoc); + OpenACCReductionClause::totalSizeToAlloc<Expr *, OpenACCReductionRecipe>( + VarList.size(), Recipes.size())); + return new (Mem) OpenACCReductionClause(BeginLoc, LParenLoc, Operator, + VarList, Recipes, EndLoc); } OpenACCAutoClause *OpenACCAutoClause::Create(const ASTContext &C, diff --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp index de8b599..0930ca2 100644 --- a/clang/lib/AST/OpenMPClause.cpp +++ b/clang/lib/AST/OpenMPClause.cpp @@ -104,6 +104,8 @@ const OMPClauseWithPreInit *OMPClauseWithPreInit::get(const OMPClause *C) { return static_cast<const OMPFilterClause *>(C); case OMPC_ompx_dyn_cgroup_mem: return static_cast<const OMPXDynCGroupMemClause *>(C); + case OMPC_message: + return static_cast<const OMPMessageClause *>(C); case OMPC_default: case OMPC_proc_bind: case OMPC_safelen: @@ -158,7 +160,6 @@ const OMPClauseWithPreInit *OMPClauseWithPreInit::get(const OMPClause *C) { case OMPC_self_maps: case OMPC_at: case OMPC_severity: - case OMPC_message: case OMPC_device_type: case OMPC_match: case OMPC_nontemporal: @@ -1963,8 +1964,10 @@ void OMPClausePrinter::VisitOMPSeverityClause(OMPSeverityClause *Node) { } void OMPClausePrinter::VisitOMPMessageClause(OMPMessageClause *Node) { - OS << "message(\"" - << cast<StringLiteral>(Node->getMessageString())->getString() << "\")"; + OS << "message("; + if (Expr *E = Node->getMessageString()) + E->printPretty(OS, nullptr, Policy); + OS << ")"; } void OMPClausePrinter::VisitOMPScheduleClause(OMPScheduleClause *Node) { @@ -2350,17 +2353,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 +2375,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 +2396,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 +2508,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..8555504 100644 --- a/clang/lib/AST/PrintfFormatString.cpp +++ b/clang/lib/AST/PrintfFormatString.cpp @@ -793,8 +793,8 @@ 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(); + if (const auto *ED = QT->getAsEnumDecl()) + QT = ED->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..4b312c5 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -204,15 +204,13 @@ void EmptySubobjectMap::ComputeEmptySubobjectSizes() { // Check the fields. for (const FieldDecl *FD : Class->fields()) { - const RecordType *RT = - Context.getBaseElementType(FD->getType())->getAs<RecordType>(); - - // We only care about record types. - if (!RT) + // We only care about records. + const auto *MemberDecl = + Context.getBaseElementType(FD->getType())->getAsCXXRecordDecl(); + if (!MemberDecl) continue; CharUnits EmptySize; - const CXXRecordDecl *MemberDecl = RT->getAsCXXRecordDecl(); const ASTRecordLayout &Layout = Context.getASTRecordLayout(MemberDecl); if (MemberDecl->isEmpty()) { // If the class decl is empty, get its size. @@ -433,11 +431,10 @@ EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const FieldDecl *FD, // If we have an array type we need to look at every element. if (const ConstantArrayType *AT = Context.getAsConstantArrayType(T)) { QualType ElemTy = Context.getBaseElementType(AT); - const RecordType *RT = ElemTy->getAs<RecordType>(); - if (!RT) + const auto *RD = ElemTy->getAsCXXRecordDecl(); + if (!RD) return true; - const CXXRecordDecl *RD = RT->getAsCXXRecordDecl(); const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); uint64_t NumElements = Context.getConstantArrayElementCount(AT); @@ -533,11 +530,10 @@ void EmptySubobjectMap::UpdateEmptyFieldSubobjects( // If we have an array type we need to update every element. if (const ConstantArrayType *AT = Context.getAsConstantArrayType(T)) { QualType ElemTy = Context.getBaseElementType(AT); - const RecordType *RT = ElemTy->getAs<RecordType>(); - if (!RT) + const auto *RD = ElemTy->getAsCXXRecordDecl(); + if (!RD) return; - const CXXRecordDecl *RD = RT->getAsCXXRecordDecl(); const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); uint64_t NumElements = Context.getConstantArrayElementCount(AT); @@ -2011,9 +2007,8 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D, CTy->getElementType()->castAs<BuiltinType>()); } 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."); + } else if (const RecordType *RT = BaseTy->getAsCanonical<RecordType>()) { + const RecordDecl *RD = RT->getOriginalDecl(); const ASTRecordLayout &FieldRecord = Context.getASTRecordLayout(RD); PreferredAlign = FieldRecord.getPreferredAlignment(); } @@ -2128,7 +2123,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 +2189,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 +2207,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 +2301,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 +2310,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) } } @@ -2712,9 +2707,10 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo( // alignment when it is applied to bitfields. Info.Alignment = std::max(Info.Alignment, FieldRequiredAlignment); else { - if (auto RT = - FD->getType()->getBaseElementTypeUnsafe()->getAs<RecordType>()) { - auto const &Layout = Context.getASTRecordLayout(RT->getDecl()); + if (const auto *RT = FD->getType() + ->getBaseElementTypeUnsafe() + ->getAsCanonical<RecordType>()) { + auto const &Layout = Context.getASTRecordLayout(RT->getOriginalDecl()); EndsWithZeroSizedObject = Layout.endsWithZeroSizedObject(); FieldRequiredAlignment = std::max(FieldRequiredAlignment, Layout.getRequiredAlignment()); @@ -3273,7 +3269,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 +3627,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()) @@ -3696,8 +3692,8 @@ static void DumpRecordLayout(raw_ostream &OS, const RecordDecl *RD, Offset + C.toCharUnitsFromBits(LocalFieldOffsetInBits); // Recursively dump fields of record type. - if (auto RT = Field->getType()->getAs<RecordType>()) { - DumpRecordLayout(OS, RT->getDecl(), C, FieldOffset, IndentLevel, + if (const auto *RD = Field->getType()->getAsRecordDecl()) { + DumpRecordLayout(OS, RD, C, FieldOffset, IndentLevel, Field->getName().data(), /*PrintSizeInfo=*/false, /*IncludeVirtualBases=*/true); @@ -3781,7 +3777,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..41cf71a 100644 --- a/clang/lib/AST/ScanfFormatString.cpp +++ b/clang/lib/AST/ScanfFormatString.cpp @@ -430,11 +430,11 @@ bool ScanfSpecifier::fixType(QualType QT, QualType RawQT, QualType PT = QT->getPointeeType(); // If it's an enum, get its underlying type. - if (const EnumType *ETy = PT->getAs<EnumType>()) { + if (const auto *ED = PT->getAsEnumDecl()) { // Don't try to fix incomplete enums. - if (!ETy->getDecl()->isComplete()) + 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 0297f9c..2035fa7 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); - } } }; } @@ -441,37 +440,37 @@ public: #define GEN_CLANG_CLAUSE_CLASS #define CLAUSE_CLASS(Enum, Str, Class) void Visit##Class(const Class *C); #include "llvm/Frontend/OpenMP/OMP.inc" - void VistOMPClauseWithPreInit(const OMPClauseWithPreInit *C); - void VistOMPClauseWithPostUpdate(const OMPClauseWithPostUpdate *C); + void VisitOMPClauseWithPreInit(const OMPClauseWithPreInit *C); + void VisitOMPClauseWithPostUpdate(const OMPClauseWithPostUpdate *C); }; -void OMPClauseProfiler::VistOMPClauseWithPreInit( +void OMPClauseProfiler::VisitOMPClauseWithPreInit( const OMPClauseWithPreInit *C) { if (auto *S = C->getPreInitStmt()) Profiler->VisitStmt(S); } -void OMPClauseProfiler::VistOMPClauseWithPostUpdate( +void OMPClauseProfiler::VisitOMPClauseWithPostUpdate( const OMPClauseWithPostUpdate *C) { - VistOMPClauseWithPreInit(C); + VisitOMPClauseWithPreInit(C); if (auto *E = C->getPostUpdateExpr()) Profiler->VisitStmt(E); } void OMPClauseProfiler::VisitOMPIfClause(const OMPIfClause *C) { - VistOMPClauseWithPreInit(C); + VisitOMPClauseWithPreInit(C); if (C->getCondition()) Profiler->VisitStmt(C->getCondition()); } void OMPClauseProfiler::VisitOMPFinalClause(const OMPFinalClause *C) { - VistOMPClauseWithPreInit(C); + VisitOMPClauseWithPreInit(C); if (C->getCondition()) Profiler->VisitStmt(C->getCondition()); } void OMPClauseProfiler::VisitOMPNumThreadsClause(const OMPNumThreadsClause *C) { - VistOMPClauseWithPreInit(C); + VisitOMPClauseWithPreInit(C); if (C->getNumThreads()) Profiler->VisitStmt(C->getNumThreads()); } @@ -527,13 +526,13 @@ void OMPClauseProfiler::VisitOMPDetachClause(const OMPDetachClause *C) { } void OMPClauseProfiler::VisitOMPNovariantsClause(const OMPNovariantsClause *C) { - VistOMPClauseWithPreInit(C); + VisitOMPClauseWithPreInit(C); if (C->getCondition()) Profiler->VisitStmt(C->getCondition()); } void OMPClauseProfiler::VisitOMPNocontextClause(const OMPNocontextClause *C) { - VistOMPClauseWithPreInit(C); + VisitOMPClauseWithPreInit(C); if (C->getCondition()) Profiler->VisitStmt(C->getCondition()); } @@ -569,7 +568,7 @@ void OMPClauseProfiler::VisitOMPMessageClause(const OMPMessageClause *C) { } void OMPClauseProfiler::VisitOMPScheduleClause(const OMPScheduleClause *C) { - VistOMPClauseWithPreInit(C); + VisitOMPClauseWithPreInit(C); if (auto *S = C->getChunkSize()) Profiler->VisitStmt(S); } @@ -647,7 +646,7 @@ void OMPClauseProfiler::VisitOMPDestroyClause(const OMPDestroyClause *C) { } void OMPClauseProfiler::VisitOMPFilterClause(const OMPFilterClause *C) { - VistOMPClauseWithPreInit(C); + VisitOMPClauseWithPreInit(C); if (C->getThreadID()) Profiler->VisitStmt(C->getThreadID()); } @@ -670,7 +669,7 @@ void OMPClauseProfiler::VisitOMPPrivateClause(const OMPPrivateClause *C) { void OMPClauseProfiler::VisitOMPFirstprivateClause(const OMPFirstprivateClause *C) { VisitOMPClauseList(C); - VistOMPClauseWithPreInit(C); + VisitOMPClauseWithPreInit(C); for (auto *E : C->private_copies()) { if (E) Profiler->VisitStmt(E); @@ -683,7 +682,7 @@ OMPClauseProfiler::VisitOMPFirstprivateClause(const OMPFirstprivateClause *C) { void OMPClauseProfiler::VisitOMPLastprivateClause(const OMPLastprivateClause *C) { VisitOMPClauseList(C); - VistOMPClauseWithPostUpdate(C); + VisitOMPClauseWithPostUpdate(C); for (auto *E : C->source_exprs()) { if (E) Profiler->VisitStmt(E); @@ -706,7 +705,7 @@ void OMPClauseProfiler::VisitOMPReductionClause( C->getQualifierLoc().getNestedNameSpecifier()); Profiler->VisitName(C->getNameInfo().getName()); VisitOMPClauseList(C); - VistOMPClauseWithPostUpdate(C); + VisitOMPClauseWithPostUpdate(C); for (auto *E : C->privates()) { if (E) Profiler->VisitStmt(E); @@ -744,7 +743,7 @@ void OMPClauseProfiler::VisitOMPTaskReductionClause( C->getQualifierLoc().getNestedNameSpecifier()); Profiler->VisitName(C->getNameInfo().getName()); VisitOMPClauseList(C); - VistOMPClauseWithPostUpdate(C); + VisitOMPClauseWithPostUpdate(C); for (auto *E : C->privates()) { if (E) Profiler->VisitStmt(E); @@ -768,7 +767,7 @@ void OMPClauseProfiler::VisitOMPInReductionClause( C->getQualifierLoc().getNestedNameSpecifier()); Profiler->VisitName(C->getNameInfo().getName()); VisitOMPClauseList(C); - VistOMPClauseWithPostUpdate(C); + VisitOMPClauseWithPostUpdate(C); for (auto *E : C->privates()) { if (E) Profiler->VisitStmt(E); @@ -792,7 +791,7 @@ void OMPClauseProfiler::VisitOMPInReductionClause( } void OMPClauseProfiler::VisitOMPLinearClause(const OMPLinearClause *C) { VisitOMPClauseList(C); - VistOMPClauseWithPostUpdate(C); + VisitOMPClauseWithPostUpdate(C); for (auto *E : C->privates()) { if (E) Profiler->VisitStmt(E); @@ -874,25 +873,25 @@ void OMPClauseProfiler::VisitOMPAllocateClause(const OMPAllocateClause *C) { } void OMPClauseProfiler::VisitOMPNumTeamsClause(const OMPNumTeamsClause *C) { VisitOMPClauseList(C); - VistOMPClauseWithPreInit(C); + VisitOMPClauseWithPreInit(C); } void OMPClauseProfiler::VisitOMPThreadLimitClause( const OMPThreadLimitClause *C) { VisitOMPClauseList(C); - VistOMPClauseWithPreInit(C); + VisitOMPClauseWithPreInit(C); } void OMPClauseProfiler::VisitOMPPriorityClause(const OMPPriorityClause *C) { - VistOMPClauseWithPreInit(C); + VisitOMPClauseWithPreInit(C); if (C->getPriority()) Profiler->VisitStmt(C->getPriority()); } void OMPClauseProfiler::VisitOMPGrainsizeClause(const OMPGrainsizeClause *C) { - VistOMPClauseWithPreInit(C); + VisitOMPClauseWithPreInit(C); if (C->getGrainsize()) Profiler->VisitStmt(C->getGrainsize()); } void OMPClauseProfiler::VisitOMPNumTasksClause(const OMPNumTasksClause *C) { - VistOMPClauseWithPreInit(C); + VisitOMPClauseWithPreInit(C); if (C->getNumTasks()) Profiler->VisitStmt(C->getNumTasks()); } @@ -953,7 +952,7 @@ void OMPClauseProfiler::VisitOMPOrderClause(const OMPOrderClause *C) {} void OMPClauseProfiler::VisitOMPBindClause(const OMPBindClause *C) {} void OMPClauseProfiler::VisitOMPXDynCGroupMemClause( const OMPXDynCGroupMemClause *C) { - VistOMPClauseWithPreInit(C); + VisitOMPClauseWithPreInit(C); if (Expr *Size = C->getSize()) Profiler->VisitStmt(Size); } @@ -1230,7 +1229,7 @@ void StmtProfiler::VisitOMPDistributeDirective( void OMPClauseProfiler::VisitOMPDistScheduleClause( const OMPDistScheduleClause *C) { - VistOMPClauseWithPreInit(C); + VisitOMPClauseWithPreInit(C); if (auto *S = C->getChunkSize()) Profiler->VisitStmt(S); } @@ -2749,6 +2748,14 @@ void OpenACCClauseProfiler::VisitGangClause(const OpenACCGangClause &Clause) { void OpenACCClauseProfiler::VisitReductionClause( const OpenACCReductionClause &Clause) { VisitClauseWithVarList(Clause); + + for (auto &Recipe : Clause.getRecipes()) { + Profiler.VisitDecl(Recipe.RecipeDecl); + // TODO: OpenACC: Make sure we remember to update this when we figure out + // what we're adding for the operation recipe, in the meantime, a static + // assert will make sure we don't add something. + static_assert(sizeof(OpenACCReductionRecipe) == sizeof(int *)); + } } void OpenACCClauseProfiler::VisitBindClause(const OpenACCBindClause &Clause) { diff --git a/clang/lib/AST/TemplateBase.cpp b/clang/lib/AST/TemplateBase.cpp index 7a0f740..76f96fb 100644 --- a/clang/lib/AST/TemplateBase.cpp +++ b/clang/lib/AST/TemplateBase.cpp @@ -56,8 +56,8 @@ static void printIntegral(const TemplateArgument &TemplArg, raw_ostream &Out, const llvm::APSInt &Val = TemplArg.getAsIntegral(); if (Policy.UseEnumerators) { - if (const EnumType *ET = T->getAs<EnumType>()) { - for (const EnumConstantDecl *ECD : ET->getDecl()->enumerators()) { + if (const auto *ED = T->getAsEnumDecl()) { + for (const EnumConstantDecl *ECD : ED->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..f2cb15d 100644 --- a/clang/lib/AST/TemplateName.cpp +++ b/clang/lib/AST/TemplateName.cpp @@ -293,6 +293,21 @@ DependentTemplateName *TemplateName::getAsDependentTemplateName() const { return Storage.dyn_cast<DependentTemplateName *>(); } +std::tuple<NestedNameSpecifier, bool> +TemplateName::getQualifierAndTemplateKeyword() const { + for (std::optional<TemplateName> Cur = *this; Cur; + Cur = Cur->desugar(/*IgnoreDeduced=*/true)) { + if (DependentTemplateName *N = Cur->getAsDependentTemplateName()) + return {N->getQualifier(), N->hasTemplateKeyword()}; + if (QualifiedTemplateName *N = Cur->getAsQualifiedTemplateName()) + return {N->getQualifier(), N->hasTemplateKeyword()}; + if (Cur->getAsSubstTemplateTemplateParm() || + Cur->getAsSubstTemplateTemplateParmPack()) + break; + } + return {std::nullopt, false}; +} + UsingShadowDecl *TemplateName::getAsUsingShadowDecl() const { if (Decl *D = Storage.dyn_cast<Decl *>()) if (UsingShadowDecl *USD = dyn_cast<UsingShadowDecl>(D)) @@ -303,24 +318,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 +375,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 +443,26 @@ void TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy, Template = cast<TemplateDecl>(Template->getCanonicalDecl()); if (handleAnonymousTTP(Template, OS)) return; - if (Qual == Qualified::None) - OS << *Template; - else - Template->printQualifiedName(OS, Policy); + if (Qual == Qualified::None || isa<TemplateTemplateParmDecl>(Template) || + Policy.SuppressScope) { + if (IdentifierInfo *II = Template->getIdentifier(); + Policy.CleanUglifiedParameters && II && + isa<TemplateTemplateParmDecl>(Template)) + OS << II->deuglifiedName(); + else + OS << *Template; + } 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 "; @@ -458,12 +475,7 @@ void TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy, if (handleAnonymousTTP(UTD, OS)) return; - if (IdentifierInfo *II = UTD->getIdentifier(); - Policy.CleanUglifiedParameters && II && - isa<TemplateTemplateParmDecl>(UTD)) - OS << II->deuglifiedName(); - else - OS << *UTD; + OS << *UTD; } else if (DependentTemplateName *DTN = getAsDependentTemplateName()) { DTN->print(OS, Policy); } else if (SubstTemplateTemplateParmStorage *subst = diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index 6b524cf..9dca5cf 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()->castAsCanonical<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..3432810 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -109,12 +109,12 @@ 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(); - else if (ty->isEnumeralType()) - ND = ty->castAs<EnumType>()->getDecl(); + if (const auto *TT = ty->getAs<TagType>()) + ND = TT->getOriginalDecl(); else if (ty->getTypeClass() == Type::Typedef) ND = ty->castAs<TypedefType>()->getDecl(); else if (ty->isArrayType()) @@ -670,61 +670,59 @@ const Type *Type::getUnqualifiedDesugaredType() const { } bool Type::isClassType() const { - if (const auto *RT = getAs<RecordType>()) - return RT->getDecl()->isClass(); + if (const auto *RT = getAsCanonical<RecordType>()) + return RT->getOriginalDecl()->isClass(); return false; } bool Type::isStructureType() const { - if (const auto *RT = getAs<RecordType>()) - return RT->getDecl()->isStruct(); + if (const auto *RT = getAsCanonical<RecordType>()) + return RT->getOriginalDecl()->isStruct(); return false; } bool Type::isStructureTypeWithFlexibleArrayMember() const { - const auto *RT = getAs<RecordType>(); + const auto *RT = getAsCanonical<RecordType>(); if (!RT) return false; - const auto *Decl = RT->getDecl(); + const auto *Decl = RT->getOriginalDecl(); if (!Decl->isStruct()) return false; - return Decl->hasFlexibleArrayMember(); + return Decl->getDefinitionOrSelf()->hasFlexibleArrayMember(); } bool Type::isObjCBoxableRecordType() const { - if (const auto *RT = getAs<RecordType>()) - return RT->getDecl()->hasAttr<ObjCBoxableAttr>(); + if (const auto *RD = getAsRecordDecl()) + return RD->hasAttr<ObjCBoxableAttr>(); return false; } bool Type::isInterfaceType() const { - if (const auto *RT = getAs<RecordType>()) - return RT->getDecl()->isInterface(); + if (const auto *RT = getAsCanonical<RecordType>()) + return RT->getOriginalDecl()->isInterface(); return false; } bool Type::isStructureOrClassType() const { - if (const auto *RT = getAs<RecordType>()) { - RecordDecl *RD = RT->getDecl(); - return RD->isStruct() || RD->isClass() || RD->isInterface(); - } + if (const auto *RT = getAsCanonical<RecordType>()) + return RT->getOriginalDecl()->isStructureOrClass(); return false; } bool Type::isVoidPointerType() const { - if (const auto *PT = getAs<PointerType>()) + if (const auto *PT = getAsCanonical<PointerType>()) return PT->getPointeeType()->isVoidType(); return false; } bool Type::isUnionType() const { - if (const auto *RT = getAs<RecordType>()) - return RT->getDecl()->isUnion(); + if (const auto *RT = getAsCanonical<RecordType>()) + return RT->getOriginalDecl()->isUnion(); return false; } bool Type::isComplexType() const { - if (const auto *CT = dyn_cast<ComplexType>(CanonicalType)) + if (const auto *CT = getAsCanonical<ComplexType>()) return CT->getElementType()->isFloatingType(); return false; } @@ -735,8 +733,8 @@ bool Type::isComplexIntegerType() const { } bool Type::isScopedEnumeralType() const { - if (const auto *ET = getAs<EnumType>()) - return ET->getDecl()->isScoped(); + if (const auto *ET = getAsCanonical<EnumType>()) + return ET->getOriginalDecl()->isScoped(); return false; } @@ -770,13 +768,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 +787,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 +1270,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()) @@ -1626,7 +1621,7 @@ bool QualType::UseExcessPrecision(const ASTContext &Ctx) { switch (BT->getKind()) { case BuiltinType::Kind::Float16: { const TargetInfo &TI = Ctx.getTargetInfo(); - if (TI.hasFloat16Type() && !TI.hasLegalHalfType() && + if (TI.hasFloat16Type() && !TI.hasFastHalfType() && Ctx.getLangOpts().getFloat16ExcessPrecision() != Ctx.getLangOpts().ExcessPrecisionKind::FPP_None) return true; @@ -1913,34 +1908,13 @@ const ObjCObjectPointerType *Type::getAsObjCInterfacePointerType() const { const CXXRecordDecl *Type::getPointeeCXXRecordDecl() const { QualType PointeeType; - if (const auto *PT = getAs<PointerType>()) + if (const auto *PT = getAsCanonical<PointerType>()) PointeeType = PT->getPointeeType(); - else if (const auto *RT = getAs<ReferenceType>()) + else if (const auto *RT = getAsCanonical<ReferenceType>()) PointeeType = RT->getPointeeType(); else return nullptr; - - if (const auto *RT = PointeeType->getAs<RecordType>()) - return dyn_cast<CXXRecordDecl>(RT->getDecl()); - - return nullptr; -} - -CXXRecordDecl *Type::getAsCXXRecordDecl() const { - return dyn_cast_or_null<CXXRecordDecl>(getAsTagDecl()); -} - -RecordDecl *Type::getAsRecordDecl() const { - return dyn_cast_or_null<RecordDecl>(getAsTagDecl()); -} - -TagDecl *Type::getAsTagDecl() const { - if (const auto *TT = getAs<TagType>()) - return TT->getDecl(); - if (const auto *Injected = getAs<InjectedClassNameType>()) - return Injected->getDecl(); - - return nullptr; + return PointeeType->getAsCXXRecordDecl(); } const TemplateSpecializationType * @@ -1951,6 +1925,33 @@ Type::getAsNonAliasTemplateSpecializationType() const { return TST; } +NestedNameSpecifier Type::getPrefix() const { + switch (getTypeClass()) { + case Type::DependentName: + return cast<DependentNameType>(this)->getQualifier(); + case Type::TemplateSpecialization: + return cast<TemplateSpecializationType>(this) + ->getTemplateName() + .getQualifier(); + 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 +1990,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 +2111,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 +2128,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; } @@ -2213,11 +2210,12 @@ bool Type::isSignedIntegerType() const { if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType)) return BT->isSignedInteger(); - if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) { + if (const auto *ED = getAsEnumDecl()) { // 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(); + if (!ED->isComplete() || ED->isScoped()) + return false; + return ED->getIntegerType()->isSignedIntegerType(); } if (const auto *IT = dyn_cast<BitIntType>(CanonicalType)) @@ -2232,9 +2230,11 @@ 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 *ED = getAsEnumDecl()) { + if (!ED->isComplete()) + return false; + return ED->getIntegerType()->isSignedIntegerType(); + } if (const auto *IT = dyn_cast<BitIntType>(CanonicalType)) return IT->isSigned(); @@ -2258,11 +2258,12 @@ bool Type::isUnsignedIntegerType() const { if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType)) return BT->isUnsignedInteger(); - if (const auto *ET = dyn_cast<EnumType>(CanonicalType)) { + if (const auto *ED = getAsEnumDecl()) { // 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(); + if (!ED->isComplete() || ED->isScoped()) + return false; + return ED->getIntegerType()->isUnsignedIntegerType(); } if (const auto *IT = dyn_cast<BitIntType>(CanonicalType)) @@ -2277,9 +2278,11 @@ 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 *ED = getAsEnumDecl()) { + if (!ED->isComplete()) + return false; + return ED->getIntegerType()->isUnsignedIntegerType(); + } if (const auto *IT = dyn_cast<BitIntType>(CanonicalType)) return IT->isUnsigned(); @@ -2328,8 +2331,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,24 +2342,24 @@ 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(); } 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(); - } + if (const auto *ED = getAsEnumDecl()) + return ED->isComplete() && ED->getIntegerType()->isBooleanType(); if (const auto *IT = dyn_cast<BitIntType>(CanonicalType)) return IT->getNumBits() == 1; return isBooleanType(); @@ -2385,7 +2390,7 @@ 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(T->castAsEnumDecl()->isComplete()); return STK_Integral; } else if (const auto *CT = dyn_cast<ComplexType>(T)) { if (CT->getElementType()->isRealFloatingType()) @@ -2409,7 +2414,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())) return ClassDecl->isAggregate(); return true; @@ -2443,7 +2449,7 @@ bool Type::isIncompleteType(NamedDecl **Def) const { // be completed. return isVoidType(); case Enum: { - EnumDecl *EnumD = cast<EnumType>(CanonicalType)->getDecl(); + auto *EnumD = castAsEnumDecl(); if (Def) *Def = EnumD; return !EnumD->isComplete(); @@ -2451,13 +2457,13 @@ 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(); + auto *Rec = castAsRecordDecl(); if (Def) *Def = Rec; return !Rec->isCompleteDefinition(); } case InjectedClassName: { - CXXRecordDecl *Rec = cast<InjectedClassNameType>(CanonicalType)->getDecl(); + auto *Rec = castAsCXXRecordDecl(); if (!Rec->isBeingDefined()) return false; if (Def) @@ -2517,7 +2523,7 @@ bool Type::isAlwaysIncompleteType() const { // Forward declarations of structs, classes, enums, and unions could be later // completed in a compilation unit by providing a type definition. - if (getAsTagDecl()) + if (isa<TagType>(CanonicalType)) return false; // Other types are incompletable. @@ -2715,6 +2721,11 @@ bool QualType::isCXX98PODType(const ASTContext &Context) const { return false; QualType CanonicalType = getTypePtr()->CanonicalType; + + // Any type that is, or contains, address discriminated data is never POD. + if (Context.containsAddressDiscriminatedPointerAuth(CanonicalType)) + return false; + switch (CanonicalType->getTypeClass()) { // Everything not explicitly mentioned is not POD. default: @@ -2739,8 +2750,8 @@ bool QualType::isCXX98PODType(const ASTContext &Context) const { return true; case Type::Record: - if (const auto *ClassDecl = - dyn_cast<CXXRecordDecl>(cast<RecordType>(CanonicalType)->getDecl())) + if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>( + cast<RecordType>(CanonicalType)->getOriginalDecl())) return ClassDecl->isPOD(); // C struct/union is POD. @@ -2773,6 +2784,11 @@ bool QualType::isTrivialType(const ASTContext &Context) const { if (CanonicalType->isDependentType()) return false; + // Any type that is, or contains, address discriminated data is never a + // trivial type. + if (Context.containsAddressDiscriminatedPointerAuth(CanonicalType)) + return false; + // C++0x [basic.types]p9: // Scalar types, trivial class types, arrays of such types, and // cv-qualified versions of these types are collectively called trivial @@ -2781,22 +2797,22 @@ bool QualType::isTrivialType(const ASTContext &Context) const { // As an extension, Clang treats vector types as Scalar types. if (CanonicalType->isScalarType() || CanonicalType->isVectorType()) return true; - if (const auto *RT = CanonicalType->getAs<RecordType>()) { - if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) { - // 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 - // trivial. - // FIXME: We should merge this definition of triviality into - // CXXRecordDecl::isTrivial. Currently it computes the wrong thing. - return ClassDecl->hasTrivialDefaultConstructor() && - !ClassDecl->hasNonTrivialDefaultConstructor() && - ClassDecl->isTriviallyCopyable(); - } - return true; + if (const auto *ClassDecl = CanonicalType->getAsCXXRecordDecl()) { + // 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 + // trivial. + // FIXME: We should merge this definition of triviality into + // CXXRecordDecl::isTrivial. Currently it computes the wrong thing. + return ClassDecl->hasTrivialDefaultConstructor() && + !ClassDecl->hasNonTrivialDefaultConstructor() && + ClassDecl->isTriviallyCopyable(); } + if (isa<RecordType>(CanonicalType)) + return true; + // No other types can match. return false; } @@ -2840,15 +2856,13 @@ static bool isTriviallyCopyableTypeImpl(const QualType &type, if (CanonicalType->isMFloat8Type()) return true; - if (const auto *RT = CanonicalType->getAs<RecordType>()) { - if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) { - if (IsCopyConstructible) { + if (const auto *RD = CanonicalType->getAsRecordDecl()) { + if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>(RD)) { + if (IsCopyConstructible) return ClassDecl->isTriviallyCopyConstructible(); - } else { - return ClassDecl->isTriviallyCopyable(); - } + return ClassDecl->isTriviallyCopyable(); } - return !RT->getDecl()->isNonTrivialToPrimitiveCopy(); + return !RD->isNonTrivialToPrimitiveCopy(); } // No other types can match. return false; @@ -2870,6 +2884,12 @@ bool QualType::isBitwiseCloneableType(const ASTContext &Context) const { if (CanonicalType->isIncompleteType()) return false; + + // Any type that is, or contains, address discriminated data is never + // bitwise clonable. + if (Context.containsAddressDiscriminatedPointerAuth(CanonicalType)) + return false; + const auto *RD = CanonicalType->getAsRecordDecl(); // struct/union/class if (!RD) return true; @@ -2936,9 +2956,9 @@ bool QualType::isWebAssemblyFuncrefType() const { QualType::PrimitiveDefaultInitializeKind QualType::isNonTrivialToPrimitiveDefaultInitialize() const { - if (const auto *RT = - getTypePtr()->getBaseElementTypeUnsafe()->getAs<RecordType>()) - if (RT->getDecl()->isNonTrivialToPrimitiveDefaultInitialize()) + if (const auto *RD = + getTypePtr()->getBaseElementTypeUnsafe()->getAsRecordDecl()) + if (RD->isNonTrivialToPrimitiveDefaultInitialize()) return PDIK_Struct; switch (getQualifiers().getObjCLifetime()) { @@ -2952,9 +2972,9 @@ QualType::isNonTrivialToPrimitiveDefaultInitialize() const { } QualType::PrimitiveCopyKind QualType::isNonTrivialToPrimitiveCopy() const { - if (const auto *RT = - getTypePtr()->getBaseElementTypeUnsafe()->getAs<RecordType>()) - if (RT->getDecl()->isNonTrivialToPrimitiveCopy()) + if (const auto *RD = + getTypePtr()->getBaseElementTypeUnsafe()->getAsRecordDecl()) + if (RD->isNonTrivialToPrimitiveCopy()) return PCK_Struct; Qualifiers Qs = getQualifiers(); @@ -3011,7 +3031,7 @@ bool Type::isLiteralType(const ASTContext &Ctx) const { if (BaseTy->isReferenceType()) return true; // -- a class type that has all of the following properties: - if (const auto *RT = BaseTy->getAs<RecordType>()) { + if (const auto *RD = BaseTy->getAsRecordDecl()) { // -- a trivial destructor, // -- every constructor call and full-expression in the // brace-or-equal-initializers for non-static data members (if any) @@ -3022,7 +3042,7 @@ 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())) + if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>(RD)) return ClassDecl->isLiteral(); return true; @@ -3075,10 +3095,10 @@ bool Type::isStandardLayoutType() const { // As an extension, Clang treats vector types as Scalar types. 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()) - return false; + if (const auto *RD = BaseTy->getAsRecordDecl()) { + if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>(RD); + ClassDecl && !ClassDecl->isStandardLayout()) + return false; // Default to 'true' for non-C++ class types. // FIXME: This is a bit dubious, but plain C structs should trivially meet @@ -3115,11 +3135,15 @@ bool QualType::isCXX11PODType(const ASTContext &Context) const { if (BaseTy->isIncompleteType()) return false; + // Any type that is, or contains, address discriminated data is non-POD. + if (Context.containsAddressDiscriminatedPointerAuth(*this)) + return false; + // As an extension, Clang treats vector types as Scalar types. 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 *RD = BaseTy->getAsRecordDecl()) { + if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>(RD)) { // C++11 [class]p10: // A POD struct is a non-union class that is both a trivial class [...] if (!ClassDecl->isTrivial()) @@ -3158,18 +3182,20 @@ 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()) + if (const auto *ET = getAsCanonical<EnumType>()) { + const auto *ED = ET->getOriginalDecl(); + IdentifierInfo *II = ED->getIdentifier(); + if (II && II->isStr("align_val_t") && ED->isInStdNamespace()) return true; } return false; } bool Type::isStdByteType() const { - if (const auto *ET = getAs<EnumType>()) { - IdentifierInfo *II = ET->getDecl()->getIdentifier(); - if (II && II->isStr("byte") && ET->getDecl()->isInStdNamespace()) + if (const auto *ET = getAsCanonical<EnumType>()) { + const auto *ED = ET->getOriginalDecl(); + IdentifierInfo *II = ED->getIdentifier(); + if (II && II->isStr("byte") && ED->isInStdNamespace()) return true; } return false; @@ -3188,7 +3214,6 @@ bool Type::isSpecifierType() const { case TemplateTypeParm: case SubstTemplateTypeParm: case TemplateSpecialization: - case Elaborated: case DependentName: case DependentTemplateSpecialization: case ObjCInterface: @@ -3199,8 +3224,7 @@ bool Type::isSpecifierType() const { } } -ElaboratedTypeKeyword -TypeWithKeyword::getKeywordForTypeSpec(unsigned TypeSpec) { +ElaboratedTypeKeyword KeywordHelpers::getKeywordForTypeSpec(unsigned TypeSpec) { switch (TypeSpec) { default: return ElaboratedTypeKeyword::None; @@ -3219,7 +3243,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 +3261,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 +3278,7 @@ TypeWithKeyword::getKeywordForTagTypeKind(TagTypeKind Kind) { } TagTypeKind -TypeWithKeyword::getTagTypeKindForKeyword(ElaboratedTypeKeyword Keyword) { +KeywordHelpers::getTagTypeKindForKeyword(ElaboratedTypeKeyword Keyword) { switch (Keyword) { case ElaboratedTypeKeyword::Class: return TagTypeKind::Class; @@ -3273,7 +3297,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 +3312,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 +3362,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; @@ -3677,6 +3709,16 @@ FunctionProtoType::FunctionProtoType(QualType result, ArrayRef<QualType> params, FunctionTypeBits.HasExtraBitfields = false; } + // Propagate any extra attribute information. + if (epi.requiresFunctionProtoTypeExtraAttributeInfo()) { + auto &ExtraAttrInfo = *getTrailingObjects<FunctionTypeExtraAttributeInfo>(); + ExtraAttrInfo.CFISalt = epi.ExtraAttributeInfo.CFISalt; + + // Also set the bit in FunctionTypeExtraBitfields. + auto &ExtraBits = *getTrailingObjects<FunctionTypeExtraBitfields>(); + ExtraBits.HasExtraAttributeInfo = true; + } + if (epi.requiresFunctionProtoTypeArmAttributes()) { auto &ArmTypeAttrs = *getTrailingObjects<FunctionTypeArmAttributes>(); ArmTypeAttrs = FunctionTypeArmAttributes(); @@ -3894,7 +3936,8 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result, // This is followed by the ext info: // int // Finally we have a trailing return type flag (bool) - // combined with AArch64 SME Attributes, to save space: + // combined with AArch64 SME Attributes and extra attribute info, to save + // space: // int // combined with any FunctionEffects // @@ -3929,6 +3972,7 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result, } epi.ExtInfo.Profile(ID); + epi.ExtraAttributeInfo.Profile(ID); unsigned EffectCount = epi.FunctionEffects.size(); bool HasConds = !epi.FunctionEffects.Conditions.empty(); @@ -4011,34 +4055,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 +4275,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 *>())); +} -bool TagType::isBeingDefined() const { return getDecl()->isBeingDefined(); } +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(); +} + +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,13 +4355,15 @@ 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; FieldTy = FieldTy.getCanonicalType(); - if (const auto *FieldRecTy = FieldTy->getAs<RecordType>()) { + if (const auto *FieldRecTy = FieldTy->getAsCanonical<RecordType>()) { if (!llvm::is_contained(RecordTypeList, FieldRecTy)) RecordTypeList.push_back(FieldRecTy); } @@ -4253,6 +4373,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 +4467,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(); } @@ -4393,17 +4516,45 @@ void SubstTemplateTypeParmType::Profile(llvm::FoldingSetNodeID &ID, ID.AddBoolean(Final); } +SubstPackType::SubstPackType(TypeClass Derived, QualType Canon, + const TemplateArgument &ArgPack) + : Type(Derived, Canon, + TypeDependence::DependentInstantiation | + TypeDependence::UnexpandedPack), + Arguments(ArgPack.pack_begin()) { + assert(llvm::all_of( + ArgPack.pack_elements(), + [](auto &P) { return P.getKind() == TemplateArgument::Type; }) && + "non-type argument to SubstPackType?"); + SubstPackTypeBits.NumArgs = ArgPack.pack_size(); +} + +TemplateArgument SubstPackType::getArgumentPack() const { + return TemplateArgument(llvm::ArrayRef(Arguments, getNumArgs())); +} + +void SubstPackType::Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getArgumentPack()); +} + +void SubstPackType::Profile(llvm::FoldingSetNodeID &ID, + const TemplateArgument &ArgPack) { + ID.AddInteger(ArgPack.pack_size()); + for (const auto &P : ArgPack.pack_elements()) + ID.AddPointer(P.getAsType().getAsOpaquePtr()); +} + SubstTemplateTypeParmPackType::SubstTemplateTypeParmPackType( QualType Canon, Decl *AssociatedDecl, unsigned Index, bool Final, const TemplateArgument &ArgPack) - : Type(SubstTemplateTypeParmPack, Canon, - TypeDependence::DependentInstantiation | - TypeDependence::UnexpandedPack), - Arguments(ArgPack.pack_begin()), + : SubstPackType(SubstTemplateTypeParmPack, Canon, ArgPack), AssociatedDeclAndFinal(AssociatedDecl, Final) { - SubstTemplateTypeParmPackTypeBits.Index = Index; - SubstTemplateTypeParmPackTypeBits.NumArgs = ArgPack.pack_size(); assert(AssociatedDecl != nullptr); + + SubstPackTypeBits.SubstTemplTypeParmPackIndex = Index; + assert(getNumArgs() == ArgPack.pack_size() && + "Parent bitfields in SubstPackType were overwritten." + "Check NumSubstPackTypeBits."); } Decl *SubstTemplateTypeParmPackType::getAssociatedDecl() const { @@ -4423,10 +4574,6 @@ IdentifierInfo *SubstTemplateTypeParmPackType::getIdentifier() const { return getReplacedParameter()->getIdentifier(); } -TemplateArgument SubstTemplateTypeParmPackType::getArgumentPack() const { - return TemplateArgument(llvm::ArrayRef(Arguments, getNumArgs())); -} - void SubstTemplateTypeParmPackType::Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getAssociatedDecl(), getIndex(), getFinal(), getArgumentPack()); } @@ -4438,11 +4585,13 @@ void SubstTemplateTypeParmPackType::Profile(llvm::FoldingSetNodeID &ID, ID.AddPointer(AssociatedDecl); ID.AddInteger(Index); ID.AddBoolean(Final); - ID.AddInteger(ArgPack.pack_size()); - for (const auto &P : ArgPack.pack_elements()) - ID.AddPointer(P.getAsType().getAsOpaquePtr()); + SubstPackType::Profile(ID, ArgPack); } +SubstBuiltinTemplatePackType::SubstBuiltinTemplatePackType( + QualType Canon, const TemplateArgument &ArgPack) + : SubstPackType(SubstBuiltinTemplatePack, Canon, ArgPack) {} + bool TemplateSpecializationType::anyDependentTemplateArguments( const TemplateArgumentListInfo &Args, ArrayRef<TemplateArgument> Converted) { @@ -4466,17 +4615,28 @@ bool TemplateSpecializationType::anyInstantiationDependentTemplateArguments( return false; } +static TypeDependence +getTemplateSpecializationTypeDependence(QualType Underlying, TemplateName T) { + TypeDependence D = Underlying.isNull() + ? TypeDependence::DependentInstantiation + : toSemanticDependence(Underlying->getDependence()); + D |= toTypeDependence(T.getDependence()) & TypeDependence::UnexpandedPack; + if (isPackProducingBuiltinTemplateName(T)) { + if (Underlying.isNull()) // Dependent, will produce a pack on substitution. + D |= TypeDependence::UnexpandedPack; + else + D |= (Underlying->getDependence() & TypeDependence::UnexpandedPack); + } + return D; +} + 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(), + getTemplateSpecializationTypeDependence(Underlying, T)), Template(T) { TemplateSpecializationTypeBits.NumArgs = Args.size(); TemplateSpecializationTypeBits.TypeAlias = IsAlias; @@ -4522,6 +4682,12 @@ QualType TemplateSpecializationType::getAliasedType() const { return *reinterpret_cast<const QualType *>(template_arguments().end()); } +bool clang::TemplateSpecializationType::isSugared() const { + return !isDependentType() || isCurrentInstantiation() || isTypeAlias() || + (isPackProducingBuiltinTemplateName(Template) && + isa<SubstBuiltinTemplatePackType>(*getCanonicalTypeInternal())); +} + void TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx) { Profile(ID, Template, template_arguments(), @@ -4699,7 +4865,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 +4893,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 +4975,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 +4992,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; @@ -4938,6 +5103,7 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const { case Type::UnaryTransform: case Type::TemplateTypeParm: case Type::SubstTemplateTypeParmPack: + case Type::SubstBuiltinTemplatePack: case Type::DependentName: case Type::DependentTemplateSpecialization: case Type::Auto: @@ -5014,7 +5180,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)) @@ -5201,7 +5367,7 @@ bool Type::isObjCARCBridgableType() const { /// Determine whether the given type T is a "bridgeable" C type. bool Type::isCARCBridgableType() const { - const auto *Pointer = getAs<PointerType>(); + const auto *Pointer = getAsCanonical<PointerType>(); if (!Pointer) return false; @@ -5211,15 +5377,19 @@ 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>(); + if (const auto *RT = getAsCanonical<RecordType>()) + 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>(); + if (const auto *RT = getAsCanonical<RecordType>()) + return RT->getOriginalDecl() + ->getMostRecentDecl() + ->hasAttr<CUDADeviceBuiltinTextureTypeAttr>(); return false; } @@ -5246,6 +5416,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(); @@ -5282,8 +5461,7 @@ QualType::DestructionKind QualType::isDestructedTypeImpl(QualType type) { return DK_objc_weak_lifetime; } - if (const auto *RT = type->getBaseElementTypeUnsafe()->getAs<RecordType>()) { - const RecordDecl *RD = RT->getDecl(); + if (const auto *RD = type->getBaseElementTypeUnsafe()->getAsRecordDecl()) { 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()) @@ -5301,16 +5479,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 +5496,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..3e9597f 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,76 @@ 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) { + + auto [Qualifier, HasTemplateKeyword] = + getTypePtr()->getTemplateName().getQualifierAndTemplateKeyword(); + + SourceLocation ElaboratedKeywordLoc = + getTypePtr()->getKeyword() != ElaboratedTypeKeyword::None + ? Loc + : SourceLocation(); + + NestedNameSpecifierLoc QualifierLoc; + if (Qualifier) { + NestedNameSpecifierLocBuilder Builder; + Builder.MakeTrivial(Context, Qualifier, Loc); + QualifierLoc = Builder.getWithLocInContext(Context); + } + + TemplateArgumentListInfo TAL(Loc, Loc); + set(ElaboratedKeywordLoc, QualifierLoc, + /*TemplateKeywordLoc=*/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 +809,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 +858,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 +879,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..54ca42d 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,9 +230,9 @@ 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::SubstBuiltinTemplatePack: case Type::DeducedTemplateSpecialization: case Type::TemplateSpecialization: case Type::InjectedClassName: @@ -504,11 +504,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 +1207,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 +1371,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 +1536,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 +1641,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 +1659,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(); @@ -1640,6 +1732,15 @@ void TypePrinter::printSubstTemplateTypeParmAfter( printAfter(T->getReplacementType(), OS); } +void TypePrinter::printSubstBuiltinTemplatePackBefore( + const SubstBuiltinTemplatePackType *T, raw_ostream &OS) { + IncludeStrongLifetimeRAII Strong(Policy); + OS << "type-pack"; +} + +void TypePrinter::printSubstBuiltinTemplatePackAfter( + const SubstBuiltinTemplatePackType *T, raw_ostream &OS) {} + void TypePrinter::printSubstTemplateTypeParmPackBefore( const SubstTemplateTypeParmPackType *T, raw_ostream &OS) { @@ -1671,6 +1772,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 +1785,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 +1807,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 +1828,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); } @@ -2129,6 +2164,9 @@ void TypePrinter::printAttributedAfter(const AttributedType *T, case attr::ExtVectorType: OS << "ext_vector_type"; break; + case attr::CFISalt: + OS << "cfi_salt(\"" << cast<CFISaltAttr>(T->getAttr())->getSalt() << "\")"; + break; } OS << "))"; } @@ -2344,7 +2382,7 @@ static bool isSubstitutedType(ASTContext &Ctx, QualType T, QualType Pattern, return true; // A type parameter matches its argument. - if (auto *TTPT = Pattern->getAs<TemplateTypeParmType>()) { + if (auto *TTPT = Pattern->getAsCanonical<TemplateTypeParmType>()) { if (TTPT->getDepth() == Depth && TTPT->getIndex() < Args.size() && Args[TTPT->getIndex()].getKind() == TemplateArgument::Type) { QualType SubstArg = Ctx.getQualifiedType( diff --git a/clang/lib/AST/VTTBuilder.cpp b/clang/lib/AST/VTTBuilder.cpp index de01184..89b58b5 100644 --- a/clang/lib/AST/VTTBuilder.cpp +++ b/clang/lib/AST/VTTBuilder.cpp @@ -63,9 +63,7 @@ void VTTBuilder::LayoutSecondaryVTTs(BaseSubobject Base) { if (I.isVirtual()) continue; - const auto *BaseDecl = - cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl()); - + const auto *BaseDecl = I.getType()->castAsCXXRecordDecl(); const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD); CharUnits BaseOffset = Base.getBaseOffset() + Layout.getBaseClassOffset(BaseDecl); @@ -89,8 +87,7 @@ VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base, return; for (const auto &I : RD->bases()) { - const auto *BaseDecl = - cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl()); + const auto *BaseDecl = I.getType()->castAsCXXRecordDecl(); // Itanium C++ ABI 2.6.2: // Secondary virtual pointers are present for all bases with either @@ -153,8 +150,7 @@ VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base, void VTTBuilder::LayoutVirtualVTTs(const CXXRecordDecl *RD, VisitedVirtualBasesSetTy &VBases) { for (const auto &I : RD->bases()) { - const auto *BaseDecl = - cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl()); + const auto *BaseDecl = I.getType()->castAsCXXRecordDecl(); // 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); } |