diff options
Diffstat (limited to 'clang/lib/AST/ASTContext.cpp')
-rw-r--r-- | clang/lib/AST/ASTContext.cpp | 1683 |
1 files changed, 1359 insertions, 324 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index cfd7bf604542..2884fe660422 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -71,8 +71,6 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/FoldingSet.h" -#include "llvm/ADT/None.h" -#include "llvm/ADT/Optional.h" #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" @@ -94,6 +92,7 @@ #include <cstdlib> #include <map> #include <memory> +#include <optional> #include <string> #include <tuple> #include <utility> @@ -298,6 +297,9 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const { return nullptr; const FileID File = SourceMgr.getDecomposedLoc(DeclLoc).first; + if (!File.isValid()) { + return nullptr; + } const auto CommentsInThisFile = Comments.getCommentsInFile(File); if (!CommentsInThisFile || CommentsInThisFile->empty()) return nullptr; @@ -693,7 +695,11 @@ ASTContext::CanonicalTemplateTemplateParm::Profile(llvm::FoldingSetNodeID &ID, if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) { ID.AddInteger(1); ID.AddBoolean(NTTP->isParameterPack()); + const Expr *TC = NTTP->getPlaceholderTypeConstraint(); + ID.AddBoolean(TC != nullptr); ID.AddPointer(NTTP->getType().getCanonicalType().getAsOpaquePtr()); + if (TC) + TC->Profile(ID, C, /*Canonical=*/true); if (NTTP->isExpandedParameterPack()) { ID.AddBoolean(true); ID.AddInteger(NTTP->getNumExpansionTypes()); @@ -754,15 +760,19 @@ canonicalizeImmediatelyDeclaredConstraint(const ASTContext &C, Expr *IDC, NewConverted.push_back(ConstrainedType); llvm::append_range(NewConverted, OldConverted.drop_front(1)); } + auto *CSD = ImplicitConceptSpecializationDecl::Create( + C, CSE->getNamedConcept()->getDeclContext(), + CSE->getNamedConcept()->getLocation(), NewConverted); + Expr *NewIDC = ConceptSpecializationExpr::Create( - C, CSE->getNamedConcept(), NewConverted, nullptr, - CSE->isInstantiationDependent(), CSE->containsUnexpandedParameterPack()); + C, CSE->getNamedConcept(), CSD, nullptr, CSE->isInstantiationDependent(), + CSE->containsUnexpandedParameterPack()); if (auto *OrigFold = dyn_cast<CXXFoldExpr>(IDC)) NewIDC = new (C) CXXFoldExpr( - OrigFold->getType(), /*Callee*/nullptr, SourceLocation(), NewIDC, + OrigFold->getType(), /*Callee*/ nullptr, SourceLocation(), NewIDC, BinaryOperatorKind::BO_LAnd, SourceLocation(), /*RHS=*/nullptr, - SourceLocation(), /*NumExpansions=*/None); + SourceLocation(), /*NumExpansions=*/std::nullopt); return NewIDC; } @@ -786,23 +796,18 @@ ASTContext::getCanonicalTemplateTemplateParmDecl( PEnd = Params->end(); P != PEnd; ++P) { if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(*P)) { - TemplateTypeParmDecl *NewTTP = TemplateTypeParmDecl::Create(*this, - getTranslationUnitDecl(), SourceLocation(), SourceLocation(), + TemplateTypeParmDecl *NewTTP = TemplateTypeParmDecl::Create( + *this, getTranslationUnitDecl(), SourceLocation(), SourceLocation(), TTP->getDepth(), TTP->getIndex(), nullptr, false, TTP->isParameterPack(), TTP->hasTypeConstraint(), - TTP->isExpandedParameterPack() ? - llvm::Optional<unsigned>(TTP->getNumExpansionParameters()) : None); + TTP->isExpandedParameterPack() + ? std::optional<unsigned>(TTP->getNumExpansionParameters()) + : std::nullopt); if (const auto *TC = TTP->getTypeConstraint()) { QualType ParamAsArgument(NewTTP->getTypeForDecl(), 0); Expr *NewIDC = canonicalizeImmediatelyDeclaredConstraint( *this, TC->getImmediatelyDeclaredConstraint(), ParamAsArgument); - TemplateArgumentListInfo CanonArgsAsWritten; - if (auto *Args = TC->getTemplateArgsAsWritten()) - for (const auto &ArgLoc : Args->arguments()) - CanonArgsAsWritten.addArgument( - TemplateArgumentLoc(ArgLoc.getArgument(), - TemplateArgumentLocInfo())); NewTTP->setTypeConstraint( NestedNameSpecifierLoc(), DeclarationNameInfo(TC->getNamedConcept()->getDeclName(), @@ -924,38 +929,6 @@ ParentMapContext &ASTContext::getParentMapContext() { return *ParentMapCtx.get(); } -static const LangASMap *getAddressSpaceMap(const TargetInfo &T, - const LangOptions &LOpts) { - if (LOpts.FakeAddressSpaceMap) { - // The fake address space map must have a distinct entry for each - // language-specific address space. - static const unsigned FakeAddrSpaceMap[] = { - 0, // Default - 1, // opencl_global - 3, // opencl_local - 2, // opencl_constant - 0, // opencl_private - 4, // opencl_generic - 5, // opencl_global_device - 6, // opencl_global_host - 7, // cuda_device - 8, // cuda_constant - 9, // cuda_shared - 1, // sycl_global - 5, // sycl_global_device - 6, // sycl_global_host - 3, // sycl_local - 0, // sycl_private - 10, // ptr32_sptr - 11, // ptr32_uptr - 12 // ptr64 - }; - return &FakeAddrSpaceMap; - } else { - return &T.getAddressSpaceMap(); - } -} - static bool isAddrSpaceMapManglingEnabled(const TargetInfo &TI, const LangOptions &LangOpts) { switch (LangOpts.getAddressSpaceMapMangling()) { @@ -1133,7 +1106,7 @@ ASTContext::getModulesWithMergedDefinition(const NamedDecl *Def) { auto MergedIt = MergedDefModules.find(cast<NamedDecl>(Def->getCanonicalDecl())); if (MergedIt == MergedDefModules.end()) - return None; + return std::nullopt; return MergedIt->second; } @@ -1191,7 +1164,7 @@ void ASTContext::addLazyModuleInitializers(Module *M, ArrayRef<uint32_t> IDs) { ArrayRef<Decl *> ASTContext::getModuleInitializers(Module *M) { auto It = ModuleInitializers.find(M); if (It == ModuleInitializers.end()) - return None; + return std::nullopt; auto *Inits = It->second; Inits->resolve(*this); @@ -1286,7 +1259,6 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target, this->AuxTarget = AuxTarget; ABI.reset(createCXXABI(Target)); - AddrSpaceMap = getAddressSpaceMap(Target, LangOpts); AddrSpaceMapMangling = isAddrSpaceMapManglingEnabled(Target, LangOpts); // C99 6.2.5p19. @@ -1873,7 +1845,7 @@ static getConstantArrayInfoInChars(const ASTContext &Context, uint64_t Width = EltInfo.Width.getQuantity() * Size; unsigned Align = EltInfo.Align.getQuantity(); if (!Context.getTargetInfo().getCXXABI().isMicrosoft() || - Context.getTargetInfo().getPointerWidth(0) == 64) + Context.getTargetInfo().getPointerWidth(LangAS::Default) == 64) Width = llvm::alignTo(Width, Align); return TypeInfoChars(CharUnits::fromQuantity(Width), CharUnits::fromQuantity(Align), @@ -1892,6 +1864,44 @@ TypeInfoChars ASTContext::getTypeInfoInChars(QualType T) const { return getTypeInfoInChars(T.getTypePtr()); } +bool ASTContext::isPromotableIntegerType(QualType T) const { + // HLSL doesn't promote all small integer types to int, it + // just uses the rank-based promotion rules for all types. + if (getLangOpts().HLSL) + return false; + + if (const auto *BT = T->getAs<BuiltinType>()) + switch (BT->getKind()) { + case BuiltinType::Bool: + case BuiltinType::Char_S: + case BuiltinType::Char_U: + case BuiltinType::SChar: + case BuiltinType::UChar: + case BuiltinType::Short: + case BuiltinType::UShort: + case BuiltinType::WChar_S: + case BuiltinType::WChar_U: + case BuiltinType::Char8: + case BuiltinType::Char16: + case BuiltinType::Char32: + return true; + default: + return false; + } + + // 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()) + return false; + + return true; + } + + return false; +} + bool ASTContext::isAlignmentRequired(const Type *T) const { return getTypeInfo(T).AlignRequirement != AlignRequirementKind::None; } @@ -1946,7 +1956,7 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { uint64_t Width = 0; unsigned Align = 8; AlignRequirementKind AlignRequirement = AlignRequirementKind::None; - unsigned AS = 0; + LangAS AS = LangAS::Default; switch (T->getTypeClass()) { #define TYPE(Class, Base) #define ABSTRACT_TYPE(Class, Base) @@ -1981,7 +1991,7 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { Align = EltInfo.Align; AlignRequirement = EltInfo.AlignRequirement; if (!getTargetInfo().getCXXABI().isMicrosoft() || - getTargetInfo().getPointerWidth(0) == 64) + getTargetInfo().getPointerWidth(LangAS::Default) == 64) Width = llvm::alignTo(Width, Align); break; } @@ -2082,7 +2092,7 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { case BuiltinType::Int128: case BuiltinType::UInt128: Width = 128; - Align = 128; // int128_t is 128-bit aligned on all targets. + Align = Target->getInt128Align(); break; case BuiltinType::ShortAccum: case BuiltinType::UShortAccum: @@ -2181,14 +2191,15 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { } break; case BuiltinType::NullPtr: - Width = Target->getPointerWidth(0); // C++ 3.9.1p11: sizeof(nullptr_t) - Align = Target->getPointerAlign(0); // == sizeof(void*) + // C++ 3.9.1p11: sizeof(nullptr_t) == sizeof(void*) + Width = Target->getPointerWidth(LangAS::Default); + Align = Target->getPointerAlign(LangAS::Default); break; case BuiltinType::ObjCId: case BuiltinType::ObjCClass: case BuiltinType::ObjCSel: - Width = Target->getPointerWidth(0); - Align = Target->getPointerAlign(0); + Width = Target->getPointerWidth(LangAS::Default); + Align = Target->getPointerAlign(LangAS::Default); break; case BuiltinType::OCLSampler: case BuiltinType::OCLEvent: @@ -2201,8 +2212,7 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ case BuiltinType::Id: #include "clang/Basic/OpenCLExtensionTypes.def" - AS = getTargetAddressSpace( - Target->getOpenCLTypeAddrSpace(getOpenCLTypeKind(T))); + AS = Target->getOpenCLTypeAddrSpace(getOpenCLTypeKind(T)); Width = Target->getPointerWidth(AS); Align = Target->getPointerAlign(AS); break; @@ -2247,11 +2257,11 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { } break; case Type::ObjCObjectPointer: - Width = Target->getPointerWidth(0); - Align = Target->getPointerAlign(0); + Width = Target->getPointerWidth(LangAS::Default); + Align = Target->getPointerAlign(LangAS::Default); break; case Type::BlockPointer: - AS = getTargetAddressSpace(cast<BlockPointerType>(T)->getPointeeType()); + AS = cast<BlockPointerType>(T)->getPointeeType().getAddressSpace(); Width = Target->getPointerWidth(AS); Align = Target->getPointerAlign(AS); break; @@ -2259,12 +2269,12 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { case Type::RValueReference: // alignof and sizeof should never enter this code path here, so we go // the pointer route. - AS = getTargetAddressSpace(cast<ReferenceType>(T)->getPointeeType()); + AS = cast<ReferenceType>(T)->getPointeeType().getAddressSpace(); Width = Target->getPointerWidth(AS); Align = Target->getPointerAlign(AS); break; case Type::Pointer: - AS = getTargetAddressSpace(cast<PointerType>(T)->getPointeeType()); + AS = cast<PointerType>(T)->getPointeeType().getAddressSpace(); Width = Target->getPointerWidth(AS); Align = Target->getPointerAlign(AS); break; @@ -2367,12 +2377,12 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { return getTypeInfo(cast<UsingType>(T)->desugar().getTypePtr()); case Type::Typedef: { - const TypedefNameDecl *Typedef = cast<TypedefType>(T)->getDecl(); - TypeInfo Info = getTypeInfo(Typedef->getUnderlyingType().getTypePtr()); + const auto *TT = cast<TypedefType>(T); + TypeInfo Info = getTypeInfo(TT->desugar().getTypePtr()); // If the typedef has an aligned attribute on it, it overrides any computed // alignment we have. This violates the GCC documentation (which says that // attribute(aligned) can only round up) but matches its implementation. - if (unsigned AttrAlign = Typedef->getMaxAlignment()) { + if (unsigned AttrAlign = TT->getDecl()->getMaxAlignment()) { Align = AttrAlign; AlignRequirement = AlignRequirementKind::RequiredByTypedef; } else { @@ -2421,8 +2431,8 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { break; case Type::Pipe: - Width = Target->getPointerWidth(getTargetAddressSpace(LangAS::opencl_global)); - Align = Target->getPointerAlign(getTargetAddressSpace(LangAS::opencl_global)); + Width = Target->getPointerWidth(LangAS::opencl_global); + Align = Target->getPointerAlign(LangAS::opencl_global); break; } @@ -2485,7 +2495,7 @@ CharUnits ASTContext::getTypeAlignInChars(const Type *T) const { } /// getTypeUnadjustedAlignInChars - Return the ABI-specified alignment of a -/// type, in characters, before alignment adustments. This method does +/// type, in characters, before alignment adjustments. This method does /// not work on incomplete types. CharUnits ASTContext::getTypeUnadjustedAlignInChars(QualType T) const { return toCharUnitsFromBits(getTypeUnadjustedAlign(T)); @@ -2682,11 +2692,11 @@ static int64_t getSubobjectOffset(const CXXRecordDecl *RD, return Context.toBits(Layout.getBaseClassOffset(RD)); } -static llvm::Optional<int64_t> +static std::optional<int64_t> structHasUniqueObjectRepresentations(const ASTContext &Context, const RecordDecl *RD); -static llvm::Optional<int64_t> +static std::optional<int64_t> getSubobjectSizeInBits(const FieldDecl *Field, const ASTContext &Context) { if (Field->getType()->isRecordType()) { const RecordDecl *RD = Field->getType()->getAsRecordDecl(); @@ -2699,7 +2709,7 @@ getSubobjectSizeInBits(const FieldDecl *Field, const ASTContext &Context) { bool IsBitIntType = Field->getType()->isBitIntType(); if (!Field->getType()->isReferenceType() && !IsBitIntType && !Context.hasUniqueObjectRepresentations(Field->getType())) - return llvm::None; + return std::nullopt; int64_t FieldSizeInBits = Context.toBits(Context.getTypeSizeInChars(Field->getType())); @@ -2708,43 +2718,43 @@ getSubobjectSizeInBits(const FieldDecl *Field, const ASTContext &Context) { if (IsBitIntType) { if ((unsigned)BitfieldSize > cast<BitIntType>(Field->getType())->getNumBits()) - return llvm::None; + return std::nullopt; } else if (BitfieldSize > FieldSizeInBits) { - return llvm::None; + return std::nullopt; } FieldSizeInBits = BitfieldSize; } else if (IsBitIntType && !Context.hasUniqueObjectRepresentations(Field->getType())) { - return llvm::None; + return std::nullopt; } return FieldSizeInBits; } -static llvm::Optional<int64_t> +static std::optional<int64_t> getSubobjectSizeInBits(const CXXRecordDecl *RD, const ASTContext &Context) { return structHasUniqueObjectRepresentations(Context, RD); } template <typename RangeT> -static llvm::Optional<int64_t> structSubobjectsHaveUniqueObjectRepresentations( +static std::optional<int64_t> structSubobjectsHaveUniqueObjectRepresentations( const RangeT &Subobjects, int64_t CurOffsetInBits, const ASTContext &Context, const clang::ASTRecordLayout &Layout) { for (const auto *Subobject : Subobjects) { - llvm::Optional<int64_t> SizeInBits = + std::optional<int64_t> SizeInBits = getSubobjectSizeInBits(Subobject, Context); if (!SizeInBits) - return llvm::None; + return std::nullopt; if (*SizeInBits != 0) { int64_t Offset = getSubobjectOffset(Subobject, Context, Layout); if (Offset != CurOffsetInBits) - return llvm::None; + return std::nullopt; CurOffsetInBits += *SizeInBits; } } return CurOffsetInBits; } -static llvm::Optional<int64_t> +static std::optional<int64_t> structHasUniqueObjectRepresentations(const ASTContext &Context, const RecordDecl *RD) { assert(!RD->isUnion() && "Must be struct/class type"); @@ -2753,7 +2763,7 @@ structHasUniqueObjectRepresentations(const ASTContext &Context, int64_t CurOffsetInBits = 0; if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>(RD)) { if (ClassDecl->isDynamicClass()) - return llvm::None; + return std::nullopt; SmallVector<CXXRecordDecl *, 4> Bases; for (const auto &Base : ClassDecl->bases()) { @@ -2766,19 +2776,19 @@ structHasUniqueObjectRepresentations(const ASTContext &Context, return Layout.getBaseClassOffset(L) < Layout.getBaseClassOffset(R); }); - llvm::Optional<int64_t> OffsetAfterBases = + std::optional<int64_t> OffsetAfterBases = structSubobjectsHaveUniqueObjectRepresentations(Bases, CurOffsetInBits, Context, Layout); if (!OffsetAfterBases) - return llvm::None; + return std::nullopt; CurOffsetInBits = *OffsetAfterBases; } - llvm::Optional<int64_t> OffsetAfterFields = + std::optional<int64_t> OffsetAfterFields = structSubobjectsHaveUniqueObjectRepresentations( RD->fields(), CurOffsetInBits, Context, Layout); if (!OffsetAfterFields) - return llvm::None; + return std::nullopt; CurOffsetInBits = *OffsetAfterFields; return CurOffsetInBits; @@ -2839,7 +2849,7 @@ bool ASTContext::hasUniqueObjectRepresentations(QualType Ty) const { if (Record->isUnion()) return unionHasUniqueObjectRepresentations(*this, Record); - Optional<int64_t> StructSize = + std::optional<int64_t> StructSize = structHasUniqueObjectRepresentations(*this, Record); return StructSize && *StructSize == static_cast<int64_t>(getTypeSize(Ty)); @@ -3001,6 +3011,18 @@ ASTContext::getASTObjCImplementationLayout( return getObjCLayout(D->getClassInterface(), D); } +static auto getCanonicalTemplateArguments(const ASTContext &C, + ArrayRef<TemplateArgument> Args, + bool &AnyNonCanonArgs) { + SmallVector<TemplateArgument, 16> CanonArgs(Args); + for (auto &Arg : CanonArgs) { + TemplateArgument OrigArg = Arg; + Arg = C.getCanonicalTemplateArgument(Arg); + AnyNonCanonArgs |= !Arg.structurallyEquals(OrigArg); + } + return CanonArgs; +} + //===----------------------------------------------------------------------===// // Type creation/memoization methods //===----------------------------------------------------------------------===// @@ -3204,9 +3226,9 @@ bool ASTContext::hasSameFunctionTypeIgnoringExceptionSpec(QualType T, QualType ASTContext::getFunctionTypeWithoutPtrSizes(QualType T) { if (const auto *Proto = T->getAs<FunctionProtoType>()) { QualType RetTy = removePtrSizeAddrSpace(Proto->getReturnType()); - SmallVector<QualType, 16> Args(Proto->param_types()); + SmallVector<QualType, 16> Args(Proto->param_types().size()); for (unsigned i = 0, n = Args.size(); i != n; ++i) - Args[i] = removePtrSizeAddrSpace(Args[i]); + Args[i] = removePtrSizeAddrSpace(Proto->param_types()[i]); return getFunctionType(RetTy, Args, Proto->getExtProtoInfo()); } @@ -3329,6 +3351,26 @@ QualType ASTContext::getAdjustedType(QualType Orig, QualType New) const { return QualType(AT, 0); } +QualType ASTContext::getDecayedType(QualType Orig, QualType Decayed) const { + llvm::FoldingSetNodeID ID; + AdjustedType::Profile(ID, Orig, Decayed); + void *InsertPos = nullptr; + AdjustedType *AT = AdjustedTypes.FindNodeOrInsertPos(ID, InsertPos); + if (AT) + return QualType(AT, 0); + + QualType Canonical = getCanonicalType(Decayed); + + // Get the new insert position for the node we care about. + AT = AdjustedTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(!AT && "Shouldn't be in the map!"); + + AT = new (*this, TypeAlignment) DecayedType(Orig, Decayed, Canonical); + Types.push_back(AT); + AdjustedTypes.InsertNode(AT, InsertPos); + return QualType(AT, 0); +} + QualType ASTContext::getDecayedType(QualType T) const { assert((T->isArrayType() || T->isFunctionType()) && "T does not decay"); @@ -3349,23 +3391,7 @@ QualType ASTContext::getDecayedType(QualType T) const { if (T->isFunctionType()) Decayed = getPointerType(T); - llvm::FoldingSetNodeID ID; - AdjustedType::Profile(ID, T, Decayed); - void *InsertPos = nullptr; - AdjustedType *AT = AdjustedTypes.FindNodeOrInsertPos(ID, InsertPos); - if (AT) - return QualType(AT, 0); - - QualType Canonical = getCanonicalType(Decayed); - - // Get the new insert position for the node we care about. - AT = AdjustedTypes.FindNodeOrInsertPos(ID, InsertPos); - assert(!AT && "Shouldn't be in the map!"); - - AT = new (*this, TypeAlignment) DecayedType(T, Decayed, Canonical); - Types.push_back(AT); - AdjustedTypes.InsertNode(AT, InsertPos); - return QualType(AT, 0); + return getDecayedType(T, Decayed); } /// getBlockPointerType - Return the uniqued reference to the type for @@ -3541,6 +3567,7 @@ QualType ASTContext::getConstantArrayType(QualType EltTy, // is instantiation-dependent, this won't be a canonical type either, so fill // in the canonical type field. QualType Canon; + // FIXME: Check below should look for qualifiers behind sugar. if (!EltTy.isCanonical() || EltTy.hasLocalQualifiers() || SizeExpr) { SplitQualType canonSplit = getCanonicalType(EltTy).split(); Canon = getConstantArrayType(QualType(canonSplit.Ty, 0), ArySize, nullptr, @@ -3716,6 +3743,7 @@ QualType ASTContext::getVariableArrayType(QualType EltTy, QualType Canon; // Be sure to pull qualifiers off the element type. + // FIXME: Check below should look for qualifiers behind sugar. if (!EltTy.isCanonical() || EltTy.hasLocalQualifiers()) { SplitQualType canonSplit = getCanonicalType(EltTy).split(); Canon = getVariableArrayType(QualType(canonSplit.Ty, 0), NumElts, ASM, @@ -3818,6 +3846,7 @@ QualType ASTContext::getIncompleteArrayType(QualType elementType, // qualifiers off the element type. QualType canon; + // FIXME: Check below should look for qualifiers behind sugar. if (!elementType.isCanonical() || elementType.hasLocalQualifiers()) { SplitQualType canonSplit = getCanonicalType(elementType).split(); canon = getIncompleteArrayType(QualType(canonSplit.Ty, 0), @@ -4009,7 +4038,11 @@ QualType ASTContext::getScalableVectorType(QualType EltTy, /// the specified element type and size. VectorType must be a built-in type. QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts, VectorType::VectorKind VecKind) const { - assert(vecType->isBuiltinType()); + assert(vecType->isBuiltinType() || + (vecType->isBitIntType() && + // Only support _BitInt elements with byte-sized power of 2 NumBits. + llvm::isPowerOf2_32(vecType->getAs<BitIntType>()->getNumBits()) && + vecType->getAs<BitIntType>()->getNumBits() >= 8)); // Check if we've already instantiated a vector of this type. llvm::FoldingSetNodeID ID; @@ -4077,9 +4110,13 @@ ASTContext::getDependentVectorType(QualType VecType, Expr *SizeExpr, /// getExtVectorType - Return the unique reference to an extended vector type of /// the specified element type and size. VectorType must be a built-in type. -QualType -ASTContext::getExtVectorType(QualType vecType, unsigned NumElts) const { - assert(vecType->isBuiltinType() || vecType->isDependentType()); +QualType ASTContext::getExtVectorType(QualType vecType, + unsigned NumElts) const { + assert(vecType->isBuiltinType() || vecType->isDependentType() || + (vecType->isBitIntType() && + // Only support _BitInt elements with byte-sized power of 2 NumBits. + llvm::isPowerOf2_32(vecType->getAs<BitIntType>()->getNumBits()) && + vecType->getAs<BitIntType>()->getNumBits() >= 8)); // Check if we've already instantiated a vector of this type. llvm::FoldingSetNodeID ID; @@ -4420,7 +4457,7 @@ QualType ASTContext::getFunctionTypeInternal( case EST_Unparsed: case EST_Unevaluated: case EST_Uninstantiated: // We don't know yet. It shouldn't matter what we pick here; no-one // should ever look at this. - LLVM_FALLTHROUGH; + [[fallthrough]]; case EST_None: case EST_MSAny: case EST_NoexceptFalse: CanonicalEPI.ExceptionSpec.Type = EST_None; break; @@ -4626,34 +4663,60 @@ QualType ASTContext::getTypeDeclTypeSlow(const TypeDecl *Decl) const { /// specified typedef name decl. QualType ASTContext::getTypedefType(const TypedefNameDecl *Decl, QualType Underlying) const { - if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0); + if (!Decl->TypeForDecl) { + if (Underlying.isNull()) + Underlying = Decl->getUnderlyingType(); + auto *NewType = new (*this, TypeAlignment) TypedefType( + Type::Typedef, Decl, QualType(), getCanonicalType(Underlying)); + Decl->TypeForDecl = NewType; + Types.push_back(NewType); + return QualType(NewType, 0); + } + if (Underlying.isNull() || Decl->getUnderlyingType() == Underlying) + return QualType(Decl->TypeForDecl, 0); + assert(hasSameType(Decl->getUnderlyingType(), Underlying)); - if (Underlying.isNull()) - Underlying = Decl->getUnderlyingType(); - QualType Canonical = getCanonicalType(Underlying); - auto *newType = new (*this, TypeAlignment) - TypedefType(Type::Typedef, Decl, Underlying, Canonical); - Decl->TypeForDecl = newType; - Types.push_back(newType); - return QualType(newType, 0); + llvm::FoldingSetNodeID ID; + TypedefType::Profile(ID, Decl, Underlying); + + 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); + } + + void *Mem = + Allocate(TypedefType::totalSizeToAlloc<QualType>(true), TypeAlignment); + auto *NewType = new (Mem) TypedefType(Type::Typedef, Decl, Underlying, + getCanonicalType(Underlying)); + TypedefTypes.InsertNode(NewType, InsertPos); + Types.push_back(NewType); + return QualType(NewType, 0); } QualType ASTContext::getUsingType(const UsingShadowDecl *Found, QualType Underlying) const { llvm::FoldingSetNodeID ID; - UsingType::Profile(ID, Found); + UsingType::Profile(ID, Found, Underlying); void *InsertPos = nullptr; - UsingType *T = UsingTypes.FindNodeOrInsertPos(ID, InsertPos); - if (T) + if (UsingType *T = UsingTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(T, 0); - assert(!Underlying.hasLocalQualifiers()); - assert(Underlying == getTypeDeclType(cast<TypeDecl>(Found->getTargetDecl()))); - QualType Canon = Underlying.getCanonicalType(); + const Type *TypeForDecl = + cast<TypeDecl>(Found->getTargetDecl())->getTypeForDecl(); - UsingType *NewType = - new (*this, TypeAlignment) UsingType(Found, Underlying, Canon); + assert(!Underlying.hasLocalQualifiers()); + QualType Canon = Underlying->getCanonicalTypeInternal(); + assert(TypeForDecl->getCanonicalTypeInternal() == Canon); + + if (Underlying.getTypePtr() == TypeForDecl) + Underlying = QualType(); + void *Mem = + Allocate(UsingType::totalSizeToAlloc<QualType>(!Underlying.isNull()), + TypeAlignment); + UsingType *NewType = new (Mem) UsingType(Found, Underlying, Canon); Types.push_back(NewType); UsingTypes.InsertNode(NewType, InsertPos); return QualType(NewType, 0); @@ -4742,21 +4805,22 @@ QualType ASTContext::getBTFTagAttributedType(const BTFTypeTagAttr *BTFAttr, } /// Retrieve a substitution-result type. -QualType -ASTContext::getSubstTemplateTypeParmType(const TemplateTypeParmType *Parm, - QualType Replacement) const { - assert(Replacement.isCanonical() - && "replacement types must always be canonical"); - +QualType ASTContext::getSubstTemplateTypeParmType( + QualType Replacement, Decl *AssociatedDecl, unsigned Index, + std::optional<unsigned> PackIndex) const { llvm::FoldingSetNodeID ID; - SubstTemplateTypeParmType::Profile(ID, Parm, Replacement); + SubstTemplateTypeParmType::Profile(ID, Replacement, AssociatedDecl, Index, + PackIndex); void *InsertPos = nullptr; - SubstTemplateTypeParmType *SubstParm - = SubstTemplateTypeParmTypes.FindNodeOrInsertPos(ID, InsertPos); + SubstTemplateTypeParmType *SubstParm = + SubstTemplateTypeParmTypes.FindNodeOrInsertPos(ID, InsertPos); if (!SubstParm) { - SubstParm = new (*this, TypeAlignment) - SubstTemplateTypeParmType(Parm, Replacement); + void *Mem = Allocate(SubstTemplateTypeParmType::totalSizeToAlloc<QualType>( + !Replacement.isCanonical()), + TypeAlignment); + SubstParm = new (Mem) SubstTemplateTypeParmType(Replacement, AssociatedDecl, + Index, PackIndex); Types.push_back(SubstParm); SubstTemplateTypeParmTypes.InsertNode(SubstParm, InsertPos); } @@ -4765,34 +4829,38 @@ ASTContext::getSubstTemplateTypeParmType(const TemplateTypeParmType *Parm, } /// Retrieve a -QualType ASTContext::getSubstTemplateTypeParmPackType( - const TemplateTypeParmType *Parm, - const TemplateArgument &ArgPack) { +QualType +ASTContext::getSubstTemplateTypeParmPackType(Decl *AssociatedDecl, + unsigned Index, bool Final, + const TemplateArgument &ArgPack) { #ifndef NDEBUG - for (const auto &P : ArgPack.pack_elements()) { - assert(P.getKind() == TemplateArgument::Type &&"Pack contains a non-type"); - assert(P.getAsType().isCanonical() && "Pack contains non-canonical type"); - } + for (const auto &P : ArgPack.pack_elements()) + assert(P.getKind() == TemplateArgument::Type && "Pack contains a non-type"); #endif llvm::FoldingSetNodeID ID; - SubstTemplateTypeParmPackType::Profile(ID, Parm, ArgPack); + SubstTemplateTypeParmPackType::Profile(ID, AssociatedDecl, Index, Final, + ArgPack); void *InsertPos = nullptr; - if (SubstTemplateTypeParmPackType *SubstParm - = SubstTemplateTypeParmPackTypes.FindNodeOrInsertPos(ID, InsertPos)) + if (SubstTemplateTypeParmPackType *SubstParm = + SubstTemplateTypeParmPackTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(SubstParm, 0); QualType Canon; - if (!Parm->isCanonicalUnqualified()) { - Canon = getCanonicalType(QualType(Parm, 0)); - Canon = getSubstTemplateTypeParmPackType(cast<TemplateTypeParmType>(Canon), - ArgPack); - SubstTemplateTypeParmPackTypes.FindNodeOrInsertPos(ID, InsertPos); + { + TemplateArgument CanonArgPack = getCanonicalTemplateArgument(ArgPack); + if (!AssociatedDecl->isCanonicalDecl() || + !CanonArgPack.structurallyEquals(ArgPack)) { + Canon = getSubstTemplateTypeParmPackType( + AssociatedDecl->getCanonicalDecl(), Index, Final, CanonArgPack); + [[maybe_unused]] const auto *Nothing = + SubstTemplateTypeParmPackTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(!Nothing); + } } - auto *SubstParm - = new (*this, TypeAlignment) SubstTemplateTypeParmPackType(Parm, Canon, - ArgPack); + auto *SubstParm = new (*this, TypeAlignment) SubstTemplateTypeParmPackType( + Canon, AssociatedDecl, Index, Final, ArgPack); Types.push_back(SubstParm); SubstTemplateTypeParmPackTypes.InsertNode(SubstParm, InsertPos); return QualType(SubstParm, 0); @@ -4838,7 +4906,8 @@ ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name, QualType Underlying) const { assert(!Name.getAsDependentTemplateName() && "No dependent template names here!"); - QualType TST = getTemplateSpecializationType(Name, Args, Underlying); + QualType TST = + getTemplateSpecializationType(Name, Args.arguments(), Underlying); TypeSourceInfo *DI = CreateTypeSourceInfo(TST); TemplateSpecializationTypeLoc TL = @@ -4854,14 +4923,14 @@ ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name, QualType ASTContext::getTemplateSpecializationType(TemplateName Template, - const TemplateArgumentListInfo &Args, + ArrayRef<TemplateArgumentLoc> Args, QualType Underlying) const { assert(!Template.getAsDependentTemplateName() && "No dependent template names here!"); SmallVector<TemplateArgument, 4> ArgVec; ArgVec.reserve(Args.size()); - for (const TemplateArgumentLoc &Arg : Args.arguments()) + for (const TemplateArgumentLoc &Arg : Args) ArgVec.push_back(Arg.getArgument()); return getTemplateSpecializationType(Template, ArgVec, Underlying); @@ -4887,8 +4956,8 @@ ASTContext::getTemplateSpecializationType(TemplateName Template, if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) Template = QTN->getUnderlyingTemplate(); - bool IsTypeAlias = - isa_and_nonnull<TypeAliasTemplateDecl>(Template.getAsTemplateDecl()); + const auto *TD = Template.getAsTemplateDecl(); + bool IsTypeAlias = TD && TD->isTypeAlias(); QualType CanonType; if (!Underlying.isNull()) CanonType = getCanonicalType(Underlying); @@ -4916,23 +4985,6 @@ ASTContext::getTemplateSpecializationType(TemplateName Template, return QualType(Spec, 0); } -static bool -getCanonicalTemplateArguments(const ASTContext &C, - ArrayRef<TemplateArgument> OrigArgs, - SmallVectorImpl<TemplateArgument> &CanonArgs) { - bool AnyNonCanonArgs = false; - unsigned NumArgs = OrigArgs.size(); - CanonArgs.resize(NumArgs); - for (unsigned I = 0; I != NumArgs; ++I) { - const TemplateArgument &OrigArg = OrigArgs[I]; - TemplateArgument &CanonArg = CanonArgs[I]; - CanonArg = C.getCanonicalTemplateArgument(OrigArg); - if (!CanonArg.structurallyEquals(OrigArg)) - AnyNonCanonArgs = true; - } - return AnyNonCanonArgs; -} - QualType ASTContext::getCanonicalTemplateSpecializationType( TemplateName Template, ArrayRef<TemplateArgument> Args) const { assert(!Template.getAsDependentTemplateName() && @@ -4944,8 +4996,9 @@ QualType ASTContext::getCanonicalTemplateSpecializationType( // Build the canonical template specialization type. TemplateName CanonTemplate = getCanonicalTemplateName(Template); - SmallVector<TemplateArgument, 4> CanonArgs; - ::getCanonicalTemplateArguments(*this, Args, CanonArgs); + bool AnyNonCanonArgs = false; + auto CanonArgs = + ::getCanonicalTemplateArguments(*this, Args, AnyNonCanonArgs); // Determine whether this canonical template specialization type already // exists. @@ -5065,12 +5118,9 @@ QualType ASTContext::getDependentNameType(ElaboratedTypeKeyword Keyword, return QualType(T, 0); } -QualType -ASTContext::getDependentTemplateSpecializationType( - ElaboratedTypeKeyword Keyword, - NestedNameSpecifier *NNS, - const IdentifierInfo *Name, - const TemplateArgumentListInfo &Args) const { +QualType ASTContext::getDependentTemplateSpecializationType( + ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, + const IdentifierInfo *Name, ArrayRef<TemplateArgumentLoc> Args) const { // TODO: avoid this copy SmallVector<TemplateArgument, 16> ArgCopy; for (unsigned I = 0, E = Args.size(); I != E; ++I) @@ -5102,9 +5152,9 @@ ASTContext::getDependentTemplateSpecializationType( ElaboratedTypeKeyword CanonKeyword = Keyword; if (Keyword == ETK_None) CanonKeyword = ETK_Typename; - SmallVector<TemplateArgument, 16> CanonArgs; - bool AnyNonCanonArgs = - ::getCanonicalTemplateArguments(*this, Args, CanonArgs); + bool AnyNonCanonArgs = false; + auto CanonArgs = + ::getCanonicalTemplateArguments(*this, Args, AnyNonCanonArgs); QualType Canon; if (AnyNonCanonArgs || CanonNNS != NNS || CanonKeyword != Keyword) { @@ -5113,7 +5163,9 @@ ASTContext::getDependentTemplateSpecializationType( CanonArgs); // Find the insert position again. - DependentTemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos); + [[maybe_unused]] auto *Nothing = + DependentTemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(!Nothing && "canonical type broken"); } void *Mem = Allocate((sizeof(DependentTemplateSpecializationType) + @@ -5131,7 +5183,7 @@ TemplateArgument ASTContext::getInjectedTemplateArg(NamedDecl *Param) { if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) { QualType ArgType = getTypeDeclType(TTP); if (TTP->isParameterPack()) - ArgType = getPackExpansionType(ArgType, None); + ArgType = getPackExpansionType(ArgType, std::nullopt); Arg = TemplateArgument(ArgType); } else if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) { @@ -5144,17 +5196,17 @@ TemplateArgument ASTContext::getInjectedTemplateArg(NamedDecl *Param) { if (T->isRecordType()) T.addConst(); Expr *E = new (*this) DeclRefExpr( - *this, NTTP, /*enclosing*/ false, T, + *this, NTTP, /*RefersToEnclosingVariableOrCapture*/ false, T, Expr::getValueKindForType(NTTP->getType()), NTTP->getLocation()); if (NTTP->isParameterPack()) - E = new (*this) PackExpansionExpr(DependentTy, E, NTTP->getLocation(), - None); + E = new (*this) + PackExpansionExpr(DependentTy, E, NTTP->getLocation(), std::nullopt); Arg = TemplateArgument(E); } else { auto *TTP = cast<TemplateTemplateParmDecl>(Param); if (TTP->isParameterPack()) - Arg = TemplateArgument(TemplateName(TTP), Optional<unsigned>()); + Arg = TemplateArgument(TemplateName(TTP), std::optional<unsigned>()); else Arg = TemplateArgument(TemplateName(TTP)); } @@ -5175,7 +5227,7 @@ ASTContext::getInjectedTemplateArgs(const TemplateParameterList *Params, } QualType ASTContext::getPackExpansionType(QualType Pattern, - Optional<unsigned> NumExpansions, + std::optional<unsigned> NumExpansions, bool ExpectPackInType) { assert((!ExpectPackInType || Pattern->containsUnexpandedParameterPack()) && "Pack expansions must expand one or more parameter packs"); @@ -5243,7 +5295,7 @@ QualType ASTContext::getObjCObjectType(QualType BaseType, ObjCProtocolDecl * const *Protocols, unsigned NumProtocols) const { return getObjCObjectType(BaseType, {}, - llvm::makeArrayRef(Protocols, NumProtocols), + llvm::ArrayRef(Protocols, NumProtocols), /*isKindOf=*/false); } @@ -5565,30 +5617,31 @@ QualType ASTContext::getObjCInterfaceType(const ObjCInterfaceDecl *Decl, /// multiple declarations that refer to "typeof(x)" all contain different /// DeclRefExpr's. This doesn't effect the type checker, since it operates /// on canonical type's (which are always unique). -QualType ASTContext::getTypeOfExprType(Expr *tofExpr) const { +QualType ASTContext::getTypeOfExprType(Expr *tofExpr, TypeOfKind Kind) const { TypeOfExprType *toe; if (tofExpr->isTypeDependent()) { llvm::FoldingSetNodeID ID; - DependentTypeOfExprType::Profile(ID, *this, tofExpr); + DependentTypeOfExprType::Profile(ID, *this, tofExpr, + Kind == TypeOfKind::Unqualified); void *InsertPos = nullptr; - DependentTypeOfExprType *Canon - = DependentTypeOfExprTypes.FindNodeOrInsertPos(ID, InsertPos); + DependentTypeOfExprType *Canon = + DependentTypeOfExprTypes.FindNodeOrInsertPos(ID, InsertPos); if (Canon) { // We already have a "canonical" version of an identical, dependent // typeof(expr) type. Use that as our canonical type. - toe = new (*this, TypeAlignment) TypeOfExprType(tofExpr, - QualType((TypeOfExprType*)Canon, 0)); + toe = new (*this, TypeAlignment) + TypeOfExprType(tofExpr, Kind, QualType((TypeOfExprType *)Canon, 0)); } else { // Build a new, canonical typeof(expr) type. - Canon - = new (*this, TypeAlignment) DependentTypeOfExprType(*this, tofExpr); + Canon = new (*this, TypeAlignment) + DependentTypeOfExprType(*this, tofExpr, Kind); DependentTypeOfExprTypes.InsertNode(Canon, InsertPos); toe = Canon; } } else { QualType Canonical = getCanonicalType(tofExpr->getType()); - toe = new (*this, TypeAlignment) TypeOfExprType(tofExpr, Canonical); + toe = new (*this, TypeAlignment) TypeOfExprType(tofExpr, Kind, Canonical); } Types.push_back(toe); return QualType(toe, 0); @@ -5599,9 +5652,10 @@ QualType ASTContext::getTypeOfExprType(Expr *tofExpr) const { /// memory savings. Since typeof(t) is fairly uncommon, space shouldn't be /// an issue. This doesn't affect the type checker, since it operates /// on canonical types (which are always unique). -QualType ASTContext::getTypeOfType(QualType tofType) const { +QualType ASTContext::getTypeOfType(QualType tofType, TypeOfKind Kind) const { QualType Canonical = getCanonicalType(tofType); - auto *tot = new (*this, TypeAlignment) TypeOfType(tofType, Canonical); + auto *tot = + new (*this, TypeAlignment) TypeOfType(tofType, Canonical, Kind); Types.push_back(tot); return QualType(tot, 0); } @@ -5707,9 +5761,6 @@ QualType ASTContext::getAutoTypeInternal( !TypeConstraintConcept && !IsDependent) return getAutoDeductType(); - if (TypeConstraintConcept) - TypeConstraintConcept = TypeConstraintConcept->getCanonicalDecl(); - // Look in the folding set for an existing type. void *InsertPos = nullptr; llvm::FoldingSetNodeID ID; @@ -5720,18 +5771,15 @@ QualType ASTContext::getAutoTypeInternal( QualType Canon; if (!IsCanon) { - if (DeducedType.isNull()) { - SmallVector<TemplateArgument, 4> CanonArgs; - bool AnyNonCanonArgs = - ::getCanonicalTemplateArguments(*this, TypeConstraintArgs, CanonArgs); - if (AnyNonCanonArgs) { - Canon = getAutoTypeInternal(QualType(), Keyword, IsDependent, IsPack, - TypeConstraintConcept, CanonArgs, true); - // Find the insert position again. - AutoTypes.FindNodeOrInsertPos(ID, InsertPos); - } - } else { + if (!DeducedType.isNull()) { Canon = DeducedType.getCanonicalType(); + } else if (TypeConstraintConcept) { + Canon = getAutoTypeInternal(QualType(), Keyword, IsDependent, IsPack, + nullptr, {}, true); + // Find the insert position again. + [[maybe_unused]] auto *Nothing = + AutoTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(!Nothing && "canonical type broken"); } } @@ -5892,14 +5940,14 @@ QualType ASTContext::getUIntPtrType() const { /// getPointerDiffType - Return the unique type for "ptrdiff_t" (C99 7.17) /// defined in <stddef.h>. Pointer - pointer requires this (C99 6.5.6p9). QualType ASTContext::getPointerDiffType() const { - return getFromTargetType(Target->getPtrDiffType(0)); + return getFromTargetType(Target->getPtrDiffType(LangAS::Default)); } /// Return the unique unsigned counterpart of "ptrdiff_t" /// integer type. The standard (C11 7.21.6.1p7) refers to this type /// in the definition of %tu format specifier. QualType ASTContext::getUnsignedPointerDiffType() const { - return getFromTargetType(Target->getUnsignedPtrDiffType(0)); + return getFromTargetType(Target->getUnsignedPtrDiffType(LangAS::Default)); } /// Return the unique type for "pid_t" defined in @@ -6199,13 +6247,13 @@ ASTContext::getCanonicalTemplateName(const TemplateName &Name) const { } case TemplateName::SubstTemplateTemplateParmPack: { - SubstTemplateTemplateParmPackStorage *subst - = Name.getAsSubstTemplateTemplateParmPack(); - TemplateTemplateParmDecl *canonParameter - = getCanonicalTemplateTemplateParmDecl(subst->getParameterPack()); - TemplateArgument canonArgPack - = getCanonicalTemplateArgument(subst->getArgumentPack()); - return getSubstTemplateTemplateParmPack(canonParameter, canonArgPack); + SubstTemplateTemplateParmPackStorage *subst = + Name.getAsSubstTemplateTemplateParmPack(); + TemplateArgument canonArgPack = + getCanonicalTemplateArgument(subst->getArgumentPack()); + return getSubstTemplateTemplateParmPack( + canonArgPack, subst->getAssociatedDecl()->getCanonicalDecl(), + subst->getFinal(), subst->getIndex()); } } @@ -6287,7 +6335,9 @@ bool ASTContext::isSameTemplateParameter(const NamedDecl *X, if (auto *TX = dyn_cast<NonTypeTemplateParmDecl>(X)) { auto *TY = cast<NonTypeTemplateParmDecl>(Y); return TX->isParameterPack() == TY->isParameterPack() && - TX->getASTContext().hasSameType(TX->getType(), TY->getType()); + TX->getASTContext().hasSameType(TX->getType(), TY->getType()) && + isSameConstraintExpr(TX->getPlaceholderTypeConstraint(), + TY->getPlaceholderTypeConstraint()); } auto *TX = cast<TemplateTemplateParmDecl>(X); @@ -6407,8 +6457,8 @@ static bool hasSameOverloadableAttrs(const FunctionDecl *A, auto BEnableIfAttrs = B->specific_attrs<EnableIfAttr>(); for (auto Pair : zip_longest(AEnableIfAttrs, BEnableIfAttrs)) { - Optional<EnableIfAttr *> Cand1A = std::get<0>(Pair); - Optional<EnableIfAttr *> Cand2A = std::get<1>(Pair); + std::optional<EnableIfAttr *> Cand1A = std::get<0>(Pair); + std::optional<EnableIfAttr *> Cand2A = std::get<1>(Pair); // Return false if the number of enable_if attributes is different. if (!Cand1A || !Cand2A) @@ -6428,6 +6478,31 @@ static bool hasSameOverloadableAttrs(const FunctionDecl *A, return true; } +bool ASTContext::FriendsDifferByConstraints(const FunctionDecl *X, + const FunctionDecl *Y) const { + // If these aren't friends, then they aren't friends that differ by + // constraints. + if (!X->getFriendObjectKind() || !Y->getFriendObjectKind()) + return false; + + // If the two functions share lexical declaration context, they are not in + // separate instantations, and thus in the same scope. + if (X->getLexicalDeclContext() == Y->getLexicalDeclContext()) + return false; + + if (!X->getDescribedFunctionTemplate()) { + assert(!Y->getDescribedFunctionTemplate() && + "How would these be the same if they aren't both templates?"); + + // If these friends don't have constraints, they aren't constrained, and + // thus don't fall under temp.friend p9. Else the simple presence of a + // constraint makes them unique. + return X->getTrailingRequiresClause(); + } + + return X->FriendConstraintRefersToEnclosingTemplate(); +} + bool ASTContext::isSameEntity(const NamedDecl *X, const NamedDecl *Y) const { if (X == Y) return true; @@ -6508,6 +6583,10 @@ bool ASTContext::isSameEntity(const NamedDecl *X, const NamedDecl *Y) const { FuncY->getTrailingRequiresClause())) return false; + // Constrained friends are different in certain cases, see: [temp.friend]p9. + if (FriendsDifferByConstraints(FuncX, FuncY)) + return false; + auto GetTypeAsWritten = [](const FunctionDecl *FD) { // Map to the first declaration that we've already merged into this one. // The TSI of redeclarations might not match (due to calling conventions @@ -6660,7 +6739,7 @@ ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) const { case TemplateArgument::Declaration: { auto *D = cast<ValueDecl>(Arg.getAsDecl()->getCanonicalDecl()); - return TemplateArgument(D, Arg.getParamTypeForDecl()); + return TemplateArgument(D, getCanonicalType(Arg.getParamTypeForDecl())); } case TemplateArgument::NullPtr: @@ -6682,17 +6761,13 @@ ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) const { return TemplateArgument(getCanonicalType(Arg.getAsType())); case TemplateArgument::Pack: { - if (Arg.pack_size() == 0) + bool AnyNonCanonArgs = false; + auto CanonArgs = ::getCanonicalTemplateArguments( + *this, Arg.pack_elements(), AnyNonCanonArgs); + if (!AnyNonCanonArgs) return Arg; - - auto *CanonArgs = new (*this) TemplateArgument[Arg.pack_size()]; - unsigned Idx = 0; - for (TemplateArgument::pack_iterator A = Arg.pack_begin(), - AEnd = Arg.pack_end(); - A != AEnd; (void)++A, ++Idx) - CanonArgs[Idx] = getCanonicalTemplateArgument(*A); - - return TemplateArgument(llvm::makeArrayRef(CanonArgs, Arg.pack_size())); + return TemplateArgument::CreatePackCopy(const_cast<ASTContext &>(*this), + CanonArgs); } } @@ -6864,7 +6939,7 @@ QualType ASTContext::getArrayDecayedType(QualType Ty) const { PrettyArrayType->getIndexTypeQualifiers()); // int x[_Nullable] -> int * _Nullable - if (auto Nullability = Ty->getNullability(*this)) { + if (auto Nullability = Ty->getNullability()) { Result = const_cast<ASTContext *>(this)->getAttributedType( AttributedType::getNullabilityAttrKind(*Nullability), Result, Result); } @@ -6901,6 +6976,21 @@ ASTContext::getConstantArrayElementCount(const ConstantArrayType *CA) const { return ElementCount; } +uint64_t ASTContext::getArrayInitLoopExprElementCount( + const ArrayInitLoopExpr *AILE) const { + if (!AILE) + return 0; + + uint64_t ElementCount = 1; + + do { + ElementCount *= AILE->getArraySize().getZExtValue(); + AILE = dyn_cast<ArrayInitLoopExpr>(AILE->getSubExpr()); + } while (AILE); + + return ElementCount; +} + /// getFloatingRank - Return a relative rank for floating point types. /// This routine will assert if passed a built-in type that isn't a float. static FloatingRank getFloatingRank(QualType T) { @@ -6976,6 +7066,21 @@ unsigned ASTContext::getIntegerRank(const Type *T) const { case BuiltinType::Int128: case BuiltinType::UInt128: return 7 + (getIntWidth(Int128Ty) << 3); + + // "The ranks of char8_t, char16_t, char32_t, and wchar_t equal the ranks of + // their underlying types" [c++20 conv.rank] + case BuiltinType::Char8: + return getIntegerRank(UnsignedCharTy.getTypePtr()); + case BuiltinType::Char16: + return getIntegerRank( + getFromTargetType(Target->getChar16Type()).getTypePtr()); + case BuiltinType::Char32: + return getIntegerRank( + getFromTargetType(Target->getChar32Type()).getTypePtr()); + case BuiltinType::WChar_S: + case BuiltinType::WChar_U: + return getIntegerRank( + getFromTargetType(Target->getWCharType()).getTypePtr()); } } @@ -7041,7 +7146,7 @@ QualType ASTContext::isPromotableBitField(Expr *E) const { /// integer type. QualType ASTContext::getPromotedIntegerType(QualType Promotable) const { assert(!Promotable.isNull()); - assert(Promotable->isPromotableIntegerType()); + assert(isPromotableIntegerType(Promotable)); if (const auto *ET = Promotable->getAs<EnumType>()) return ET->getDecl()->getPromotionType(); @@ -7061,12 +7166,11 @@ QualType ASTContext::getPromotedIntegerType(QualType Promotable) const { uint64_t FromSize = getTypeSize(BT); QualType PromoteTypes[] = { IntTy, UnsignedIntTy, LongTy, UnsignedLongTy, LongLongTy, UnsignedLongLongTy }; - for (size_t Idx = 0; Idx < llvm::array_lengthof(PromoteTypes); ++Idx) { - uint64_t ToSize = getTypeSize(PromoteTypes[Idx]); + for (const auto &PT : PromoteTypes) { + uint64_t ToSize = getTypeSize(PT); if (FromSize < ToSize || - (FromSize == ToSize && - FromIsSigned == PromoteTypes[Idx]->isSignedIntegerType())) - return PromoteTypes[Idx]; + (FromSize == ToSize && FromIsSigned == PT->isSignedIntegerType())) + return PT; } llvm_unreachable("char type should fit into long long"); } @@ -7551,7 +7655,7 @@ std::string ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr) const { // FIXME: There might(should) be a better way of doing this computation! CharUnits PtrSize = getTypeSizeInChars(VoidPtrTy); CharUnits ParmOffset = PtrSize; - for (auto PI : Decl->parameters()) { + for (auto *PI : Decl->parameters()) { QualType PType = PI->getType(); CharUnits sz = getObjCEncodingTypeSize(PType); if (sz.isZero()) @@ -7566,7 +7670,7 @@ std::string ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr) const { // Argument types. ParmOffset = PtrSize; - for (auto PVDecl : Decl->parameters()) { + for (auto *PVDecl : Decl->parameters()) { QualType PType = PVDecl->getOriginalType(); if (const auto *AT = dyn_cast<ArrayType>(PType->getCanonicalTypeInternal())) { @@ -7595,7 +7699,7 @@ ASTContext::getObjCEncodingForFunctionDecl(const FunctionDecl *Decl) const { getObjCEncodingForType(Decl->getReturnType(), S); CharUnits ParmOffset; // Compute size of all parameters. - for (auto PI : Decl->parameters()) { + for (auto *PI : Decl->parameters()) { QualType PType = PI->getType(); CharUnits sz = getObjCEncodingTypeSize(PType); if (sz.isZero()) @@ -7609,7 +7713,7 @@ ASTContext::getObjCEncodingForFunctionDecl(const FunctionDecl *Decl) const { ParmOffset = CharUnits::Zero(); // Argument types. - for (auto PVDecl : Decl->parameters()) { + for (auto *PVDecl : Decl->parameters()) { QualType PType = PVDecl->getOriginalType(); if (const auto *AT = dyn_cast<ArrayType>(PType->getCanonicalTypeInternal())) { @@ -7816,7 +7920,7 @@ ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD, /// 'l' or 'L' , but not always. For typedefs, we need to use /// 'i' or 'I' instead if encoding a struct field, or a pointer! void ASTContext::getLegacyIntegralTypeEncoding (QualType &PointeeTy) const { - if (isa<TypedefType>(PointeeTy.getTypePtr())) { + if (PointeeTy->getAs<TypedefType>()) { if (const auto *BT = PointeeTy->getAs<BuiltinType>()) { if (BT->getKind() == BuiltinType::ULong && getIntWidth(PointeeTy) == 32) PointeeTy = UnsignedIntTy; @@ -8104,7 +8208,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S, // pointee gets emitted _before_ the '^'. The read-only qualifier of // the pointer itself gets ignored, _unless_ we are looking at a typedef! // Also, do not emit the 'r' for anything but the outermost type! - if (isa<TypedefType>(T.getTypePtr())) { + if (T->getAs<TypedefType>()) { if (Options.IsOutermostType() && T.isConstQualified()) { isReadOnly = true; S += 'r'; @@ -8286,7 +8390,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S, return; } // TODO: Double check to make sure this intentionally falls through. - LLVM_FALLTHROUGH; + [[fallthrough]]; } case Type::ObjCInterface: { @@ -8641,9 +8745,9 @@ CreateAArch64ABIBuiltinVaListDecl(const ASTContext *Context) { // namespace std { struct __va_list { auto *NS = NamespaceDecl::Create( const_cast<ASTContext &>(*Context), Context->getTranslationUnitDecl(), - /*Inline*/ false, SourceLocation(), SourceLocation(), + /*Inline=*/false, SourceLocation(), SourceLocation(), &Context->Idents.get("std"), - /*PrevDecl*/ nullptr); + /*PrevDecl=*/nullptr, /*Nested=*/false); NS->setImplicit(); VaListTagDecl->setDeclContext(NS); } @@ -8830,9 +8934,9 @@ CreateAAPCSABIBuiltinVaListDecl(const ASTContext *Context) { NamespaceDecl *NS; NS = NamespaceDecl::Create(const_cast<ASTContext &>(*Context), Context->getTranslationUnitDecl(), - /*Inline*/false, SourceLocation(), + /*Inline=*/false, SourceLocation(), SourceLocation(), &Context->Idents.get("std"), - /*PrevDecl*/ nullptr); + /*PrevDecl=*/nullptr, /*Nested=*/false); NS->setImplicit(); VaListDecl->setDeclContext(NS); } @@ -9020,6 +9124,10 @@ TypedefDecl *ASTContext::getBuiltinMSVaListDecl() const { } bool ASTContext::canBuiltinBeRedeclared(const FunctionDecl *FD) const { + // Allow redecl custom type checking builtin for HLSL. + if (LangOpts.HLSL && FD->getBuiltinID() != Builtin::NotBuiltin && + BuiltinInfo.hasCustomTypechecking(FD->getBuiltinID())) + return true; return BuiltinInfo.canBeRedeclared(FD->getBuiltinID()); } @@ -9158,18 +9266,20 @@ ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS, return TemplateName(QTN); } -TemplateName -ASTContext::getSubstTemplateTemplateParm(TemplateTemplateParmDecl *param, - TemplateName replacement) const { +TemplateName ASTContext::getSubstTemplateTemplateParm( + TemplateName Replacement, Decl *AssociatedDecl, unsigned Index, + std::optional<unsigned> PackIndex) const { llvm::FoldingSetNodeID ID; - SubstTemplateTemplateParmStorage::Profile(ID, param, replacement); + SubstTemplateTemplateParmStorage::Profile(ID, Replacement, AssociatedDecl, + Index, PackIndex); void *insertPos = nullptr; SubstTemplateTemplateParmStorage *subst = SubstTemplateTemplateParms.FindNodeOrInsertPos(ID, insertPos); if (!subst) { - subst = new (*this) SubstTemplateTemplateParmStorage(param, replacement); + subst = new (*this) SubstTemplateTemplateParmStorage( + Replacement, AssociatedDecl, Index, PackIndex); SubstTemplateTemplateParms.InsertNode(subst, insertPos); } @@ -9177,20 +9287,21 @@ ASTContext::getSubstTemplateTemplateParm(TemplateTemplateParmDecl *param, } TemplateName -ASTContext::getSubstTemplateTemplateParmPack(TemplateTemplateParmDecl *Param, - const TemplateArgument &ArgPack) const { +ASTContext::getSubstTemplateTemplateParmPack(const TemplateArgument &ArgPack, + Decl *AssociatedDecl, + unsigned Index, bool Final) const { auto &Self = const_cast<ASTContext &>(*this); llvm::FoldingSetNodeID ID; - SubstTemplateTemplateParmPackStorage::Profile(ID, Self, Param, ArgPack); + SubstTemplateTemplateParmPackStorage::Profile(ID, Self, ArgPack, + AssociatedDecl, Index, Final); void *InsertPos = nullptr; SubstTemplateTemplateParmPackStorage *Subst = SubstTemplateTemplateParmPacks.FindNodeOrInsertPos(ID, InsertPos); if (!Subst) { - Subst = new (*this) SubstTemplateTemplateParmPackStorage(Param, - ArgPack.pack_size(), - ArgPack.pack_begin()); + Subst = new (*this) SubstTemplateTemplateParmPackStorage( + ArgPack.pack_elements(), AssociatedDecl, Index, Final); SubstTemplateTemplateParmPacks.InsertNode(Subst, InsertPos); } @@ -9707,7 +9818,7 @@ void getIntersectionOfProtocols(ASTContext &Context, llvm::SmallPtrSet<ObjCProtocolDecl *, 8> LHSProtocolSet; // Start with the protocol qualifiers. - for (auto proto : LHS->quals()) { + for (auto *proto : LHS->quals()) { Context.CollectInheritedProtocols(proto, LHSProtocolSet); } @@ -9718,7 +9829,7 @@ void getIntersectionOfProtocols(ASTContext &Context, llvm::SmallPtrSet<ObjCProtocolDecl *, 8> RHSProtocolSet; // Start with the protocol qualifiers. - for (auto proto : RHS->quals()) { + for (auto *proto : RHS->quals()) { Context.CollectInheritedProtocols(proto, RHSProtocolSet); } @@ -9726,7 +9837,7 @@ void getIntersectionOfProtocols(ASTContext &Context, Context.CollectInheritedProtocols(RHS->getInterface(), RHSProtocolSet); // Compute the intersection of the collected protocol sets. - for (auto proto : LHSProtocolSet) { + for (auto *proto : LHSProtocolSet) { if (RHSProtocolSet.count(proto)) IntersectionSet.push_back(proto); } @@ -10077,7 +10188,8 @@ QualType ASTContext::mergeFunctionParameterTypes(QualType lhs, QualType rhs, QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, bool OfBlockPointer, bool Unqualified, - bool AllowCXX) { + bool AllowCXX, + bool IsConditionalOperator) { const auto *lbase = lhs->castAs<FunctionType>(); const auto *rbase = rhs->castAs<FunctionType>(); const auto *lproto = dyn_cast<FunctionProtoType>(lbase); @@ -10140,9 +10252,27 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, if (lbaseInfo.getNoCfCheck() != rbaseInfo.getNoCfCheck()) return {}; - // FIXME: some uses, e.g. conditional exprs, really want this to be 'both'. - bool NoReturn = lbaseInfo.getNoReturn() || rbaseInfo.getNoReturn(); - + // When merging declarations, it's common for supplemental information like + // attributes to only be present in one of the declarations, and we generally + // want type merging to preserve the union of information. So a merged + // function type should be noreturn if it was noreturn in *either* operand + // type. + // + // But for the conditional operator, this is backwards. The result of the + // operator could be either operand, and its type should conservatively + // reflect that. So a function type in a composite type is noreturn only + // if it's noreturn in *both* operand types. + // + // Arguably, noreturn is a kind of subtype, and the conditional operator + // ought to produce the most specific common supertype of its operand types. + // That would differ from this rule in contravariant positions. However, + // neither C nor C++ generally uses this kind of subtype reasoning. Also, + // as a practical matter, it would only affect C code that does abstraction of + // higher-order functions (taking noreturn callbacks!), which is uncommon to + // say the least. So we use the simpler rule. + bool NoReturn = IsConditionalOperator + ? lbaseInfo.getNoReturn() && rbaseInfo.getNoReturn() + : lbaseInfo.getNoReturn() || rbaseInfo.getNoReturn(); if (lbaseInfo.getNoReturn() != NoReturn) allLTypes = false; if (rbaseInfo.getNoReturn() != NoReturn) @@ -10235,7 +10365,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, return {}; } - if (paramTy->isPromotableIntegerType() || + if (isPromotableIntegerType(paramTy) || getCanonicalType(paramTy).getUnqualifiedType() == FloatTy) return {}; } @@ -10275,9 +10405,9 @@ static QualType mergeEnumWithInteger(ASTContext &Context, const EnumType *ET, return {}; } -QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, - bool OfBlockPointer, - bool Unqualified, bool BlockReturnType) { +QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, bool OfBlockPointer, + bool Unqualified, bool BlockReturnType, + bool IsConditionalOperator) { // For C++ we will not reach this code with reference types (see below), // for OpenMP variant call overloading we might. // @@ -10517,7 +10647,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, const ConstantArrayType* CAT) -> std::pair<bool,llvm::APInt> { if (VAT) { - Optional<llvm::APSInt> TheInt; + std::optional<llvm::APSInt> TheInt; Expr *E = VAT->getSizeExpr(); if (E && (TheInt = E->getIntegerConstantExpr(*this))) return std::make_pair(true, *TheInt); @@ -10570,7 +10700,8 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, ArrayType::ArraySizeModifier(), 0); } case Type::FunctionNoProto: - return mergeFunctionTypes(LHS, RHS, OfBlockPointer, Unqualified); + return mergeFunctionTypes(LHS, RHS, OfBlockPointer, Unqualified, + /*AllowCXX=*/false, IsConditionalOperator); case Type::Record: case Type::Enum: return {}; @@ -10778,7 +10909,8 @@ unsigned ASTContext::getIntWidth(QualType T) const { } QualType ASTContext::getCorrespondingUnsignedType(QualType T) const { - assert((T->hasSignedIntegerRepresentation() || T->isSignedFixedPointType()) && + assert((T->hasIntegerRepresentation() || T->isEnumeralType() || + T->isFixedPointType()) && "Unexpected type"); // Turn <4 x signed int> -> <4 x unsigned int> @@ -10796,8 +10928,11 @@ QualType ASTContext::getCorrespondingUnsignedType(QualType T) const { T = ETy->getDecl()->getIntegerType(); switch (T->castAs<BuiltinType>()->getKind()) { + case BuiltinType::Char_U: + // Plain `char` is mapped to `unsigned char` even if it's already unsigned case BuiltinType::Char_S: case BuiltinType::SChar: + case BuiltinType::Char8: return UnsignedCharTy; case BuiltinType::Short: return UnsignedShortTy; @@ -10811,7 +10946,7 @@ QualType ASTContext::getCorrespondingUnsignedType(QualType T) const { return UnsignedInt128Ty; // wchar_t is special. It is either signed or not, but when it's signed, // there's no matching "unsigned wchar_t". Therefore we return the unsigned - // version of it's underlying type instead. + // version of its underlying type instead. case BuiltinType::WChar_S: return getUnsignedWCharType(); @@ -10840,13 +10975,16 @@ QualType ASTContext::getCorrespondingUnsignedType(QualType T) const { case BuiltinType::SatLongFract: return SatUnsignedLongFractTy; default: - llvm_unreachable("Unexpected signed integer or fixed point type"); + assert((T->hasUnsignedIntegerRepresentation() || + T->isUnsignedFixedPointType()) && + "Unexpected signed integer or fixed point type"); + return T; } } QualType ASTContext::getCorrespondingSignedType(QualType T) const { - assert((T->hasUnsignedIntegerRepresentation() || - T->isUnsignedFixedPointType()) && + assert((T->hasIntegerRepresentation() || T->isEnumeralType() || + T->isFixedPointType()) && "Unexpected type"); // Turn <4 x unsigned int> -> <4 x signed int> @@ -10864,8 +11002,11 @@ QualType ASTContext::getCorrespondingSignedType(QualType T) const { T = ETy->getDecl()->getIntegerType(); switch (T->castAs<BuiltinType>()->getKind()) { + case BuiltinType::Char_S: + // Plain `char` is mapped to `signed char` even if it's already signed case BuiltinType::Char_U: case BuiltinType::UChar: + case BuiltinType::Char8: return SignedCharTy; case BuiltinType::UShort: return ShortTy; @@ -10879,7 +11020,7 @@ QualType ASTContext::getCorrespondingSignedType(QualType T) const { return Int128Ty; // wchar_t is special. It is either unsigned or not, but when it's unsigned, // there's no matching "signed wchar_t". Therefore we return the signed - // version of it's underlying type instead. + // version of its underlying type instead. case BuiltinType::WChar_U: return getSignedWCharType(); @@ -10908,7 +11049,10 @@ QualType ASTContext::getCorrespondingSignedType(QualType T) const { case BuiltinType::SatULongFract: return SatLongFractTy; default: - llvm_unreachable("Unexpected unsigned integer or fixed point type"); + assert( + (T->hasSignedIntegerRepresentation() || T->isSignedFixedPointType()) && + "Unexpected signed integer or fixed point type"); + return T; } } @@ -11673,7 +11817,7 @@ void ASTContext::forEachMultiversionedFunctionVersion( FD->getDeclContext()->getRedeclContext()->lookup(FD->getDeclName())) { FunctionDecl *CurFD = CurDecl->getAsFunction()->getMostRecentDecl(); if (CurFD && hasSameType(CurFD->getType(), FD->getType()) && - std::end(SeenDecls) == llvm::find(SeenDecls, CurFD)) { + !llvm::is_contained(SeenDecls, CurFD)) { SeenDecls.insert(CurFD); Pred(CurFD); } @@ -11775,10 +11919,10 @@ MangleContext *ASTContext::createDeviceMangleContext(const TargetInfo &T) { case TargetCXXABI::XL: return ItaniumMangleContext::create( *this, getDiagnostics(), - [](ASTContext &, const NamedDecl *ND) -> llvm::Optional<unsigned> { + [](ASTContext &, const NamedDecl *ND) -> std::optional<unsigned> { if (const auto *RD = dyn_cast<CXXRecordDecl>(ND)) return RD->getDeviceLambdaManglingNumber(); - return llvm::None; + return std::nullopt; }, /*IsAux=*/true); case TargetCXXABI::Microsoft: @@ -12082,25 +12226,885 @@ uint64_t ASTContext::getTargetNullPointerValue(QualType QT) const { return getTargetInfo().getNullPointerValue(AS); } -unsigned ASTContext::getTargetAddressSpace(QualType T) const { - // Return the address space for the type. If the type is a - // function type without an address space qualifier, the - // program address space is used. Otherwise, the target picks - // the best address space based on the type information - return T->isFunctionType() && !T.hasAddressSpace() - ? getTargetInfo().getProgramAddressSpace() - : getTargetAddressSpace(T.getQualifiers()); +unsigned ASTContext::getTargetAddressSpace(LangAS AS) const { + return getTargetInfo().getTargetAddressSpace(AS); } -unsigned ASTContext::getTargetAddressSpace(Qualifiers Q) const { - return getTargetAddressSpace(Q.getAddressSpace()); +bool ASTContext::hasSameExpr(const Expr *X, const Expr *Y) const { + if (X == Y) + return true; + if (!X || !Y) + return false; + llvm::FoldingSetNodeID IDX, IDY; + X->Profile(IDX, *this, /*Canonical=*/true); + Y->Profile(IDY, *this, /*Canonical=*/true); + return IDX == IDY; } -unsigned ASTContext::getTargetAddressSpace(LangAS AS) const { - if (isTargetAddressSpace(AS)) - return toTargetAddressSpace(AS); +// The getCommon* helpers return, for given 'same' X and Y entities given as +// inputs, another entity which is also the 'same' as the inputs, but which +// is closer to the canonical form of the inputs, each according to a given +// criteria. +// The getCommon*Checked variants are 'null inputs not-allowed' equivalents of +// the regular ones. + +static Decl *getCommonDecl(Decl *X, Decl *Y) { + if (!declaresSameEntity(X, Y)) + return nullptr; + for (const Decl *DX : X->redecls()) { + // If we reach Y before reaching the first decl, that means X is older. + if (DX == Y) + return X; + // If we reach the first decl, then Y is older. + if (DX->isFirstDecl()) + return Y; + } + llvm_unreachable("Corrupt redecls chain"); +} + +template <class T, std::enable_if_t<std::is_base_of_v<Decl, T>, bool> = true> +static T *getCommonDecl(T *X, T *Y) { + return cast_or_null<T>( + getCommonDecl(const_cast<Decl *>(cast_or_null<Decl>(X)), + const_cast<Decl *>(cast_or_null<Decl>(Y)))); +} + +template <class T, std::enable_if_t<std::is_base_of_v<Decl, T>, bool> = true> +static T *getCommonDeclChecked(T *X, T *Y) { + return cast<T>(getCommonDecl(const_cast<Decl *>(cast<Decl>(X)), + const_cast<Decl *>(cast<Decl>(Y)))); +} + +static TemplateName getCommonTemplateName(ASTContext &Ctx, TemplateName X, + TemplateName Y) { + if (X.getAsVoidPointer() == Y.getAsVoidPointer()) + return X; + // FIXME: There are cases here where we could find a common template name + // with more sugar. For example one could be a SubstTemplateTemplate* + // replacing the other. + TemplateName CX = Ctx.getCanonicalTemplateName(X); + if (CX.getAsVoidPointer() != + Ctx.getCanonicalTemplateName(Y).getAsVoidPointer()) + return TemplateName(); + return CX; +} + +static TemplateName +getCommonTemplateNameChecked(ASTContext &Ctx, TemplateName X, TemplateName Y) { + TemplateName R = getCommonTemplateName(Ctx, X, Y); + assert(R.getAsVoidPointer() != nullptr); + return R; +} + +static auto getCommonTypes(ASTContext &Ctx, ArrayRef<QualType> Xs, + ArrayRef<QualType> Ys, bool Unqualified = false) { + assert(Xs.size() == Ys.size()); + SmallVector<QualType, 8> Rs(Xs.size()); + for (size_t I = 0; I < Rs.size(); ++I) + Rs[I] = Ctx.getCommonSugaredType(Xs[I], Ys[I], Unqualified); + return Rs; +} + +template <class T> +static SourceLocation getCommonAttrLoc(const T *X, const T *Y) { + return X->getAttributeLoc() == Y->getAttributeLoc() ? X->getAttributeLoc() + : SourceLocation(); +} + +static TemplateArgument getCommonTemplateArgument(ASTContext &Ctx, + const TemplateArgument &X, + const TemplateArgument &Y) { + if (X.getKind() != Y.getKind()) + return TemplateArgument(); + + switch (X.getKind()) { + case TemplateArgument::ArgKind::Type: + if (!Ctx.hasSameType(X.getAsType(), Y.getAsType())) + return TemplateArgument(); + return TemplateArgument( + Ctx.getCommonSugaredType(X.getAsType(), Y.getAsType())); + case TemplateArgument::ArgKind::NullPtr: + if (!Ctx.hasSameType(X.getNullPtrType(), Y.getNullPtrType())) + return TemplateArgument(); + return TemplateArgument( + Ctx.getCommonSugaredType(X.getNullPtrType(), Y.getNullPtrType()), + /*Unqualified=*/true); + case TemplateArgument::ArgKind::Expression: + if (!Ctx.hasSameType(X.getAsExpr()->getType(), Y.getAsExpr()->getType())) + return TemplateArgument(); + // FIXME: Try to keep the common sugar. + return X; + case TemplateArgument::ArgKind::Template: { + TemplateName TX = X.getAsTemplate(), TY = Y.getAsTemplate(); + TemplateName CTN = ::getCommonTemplateName(Ctx, TX, TY); + if (!CTN.getAsVoidPointer()) + return TemplateArgument(); + return TemplateArgument(CTN); + } + case TemplateArgument::ArgKind::TemplateExpansion: { + TemplateName TX = X.getAsTemplateOrTemplatePattern(), + TY = Y.getAsTemplateOrTemplatePattern(); + TemplateName CTN = ::getCommonTemplateName(Ctx, TX, TY); + if (!CTN.getAsVoidPointer()) + return TemplateName(); + auto NExpX = X.getNumTemplateExpansions(); + assert(NExpX == Y.getNumTemplateExpansions()); + return TemplateArgument(CTN, NExpX); + } + default: + // FIXME: Handle the other argument kinds. + return X; + } +} + +static bool getCommonTemplateArguments(ASTContext &Ctx, + SmallVectorImpl<TemplateArgument> &R, + ArrayRef<TemplateArgument> Xs, + ArrayRef<TemplateArgument> Ys) { + if (Xs.size() != Ys.size()) + return true; + R.resize(Xs.size()); + for (size_t I = 0; I < R.size(); ++I) { + R[I] = getCommonTemplateArgument(Ctx, Xs[I], Ys[I]); + if (R[I].isNull()) + return true; + } + return false; +} + +static auto getCommonTemplateArguments(ASTContext &Ctx, + ArrayRef<TemplateArgument> Xs, + ArrayRef<TemplateArgument> Ys) { + SmallVector<TemplateArgument, 8> R; + bool Different = getCommonTemplateArguments(Ctx, R, Xs, Ys); + assert(!Different); + (void)Different; + return R; +} + +template <class T> +static ElaboratedTypeKeyword getCommonTypeKeyword(const T *X, const T *Y) { + return X->getKeyword() == Y->getKeyword() ? X->getKeyword() + : ElaboratedTypeKeyword::ETK_None; +} + +template <class T> +static NestedNameSpecifier *getCommonNNS(ASTContext &Ctx, const T *X, + const T *Y) { + // FIXME: Try to keep the common NNS sugar. + return X->getQualifier() == Y->getQualifier() + ? X->getQualifier() + : Ctx.getCanonicalNestedNameSpecifier(X->getQualifier()); +} + +template <class T> +static QualType getCommonElementType(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, + Qualifiers &QX, const T *Y, + Qualifiers &QY) { + QualType EX = X->getElementType(), EY = Y->getElementType(); + QualType R = Ctx.getCommonSugaredType(EX, EY, + /*Unqualified=*/true); + Qualifiers RQ = R.getQualifiers(); + QX += EX.getQualifiers() - RQ; + QY += EY.getQualifiers() - RQ; + return R; +} + +template <class T> +static QualType getCommonPointeeType(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) { + assert(Ctx.hasSameExpr(X->getSizeExpr(), Y->getSizeExpr())); + return X->getSizeExpr(); +} + +static auto getCommonSizeModifier(const ArrayType *X, const ArrayType *Y) { + assert(X->getSizeModifier() == Y->getSizeModifier()); + return X->getSizeModifier(); +} + +static auto getCommonIndexTypeCVRQualifiers(const ArrayType *X, + const ArrayType *Y) { + assert(X->getIndexTypeCVRQualifiers() == Y->getIndexTypeCVRQualifiers()); + return X->getIndexTypeCVRQualifiers(); +} + +// Merges two type lists such that the resulting vector will contain +// 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) { + llvm::DenseMap<QualType, unsigned> Found; + for (auto Ts : {X, Y}) { + for (QualType T : Ts) { + auto Res = Found.try_emplace(Ctx.getCanonicalType(T), Out.size()); + if (!Res.second) { + QualType &U = Out[Res.first->second]; + U = Ctx.getCommonSugaredType(U, T); + } else { + Out.emplace_back(T); + } + } + } +} + +FunctionProtoType::ExceptionSpecInfo +ASTContext::mergeExceptionSpecs(FunctionProtoType::ExceptionSpecInfo ESI1, + FunctionProtoType::ExceptionSpecInfo ESI2, + SmallVectorImpl<QualType> &ExceptionTypeStorage, + bool AcceptDependent) { + ExceptionSpecificationType EST1 = ESI1.Type, EST2 = ESI2.Type; + + // If either of them can throw anything, that is the result. + for (auto I : {EST_None, EST_MSAny, EST_NoexceptFalse}) { + if (EST1 == I) + return ESI1; + if (EST2 == I) + return ESI2; + } + + // If either of them is non-throwing, the result is the other. + for (auto I : + {EST_NoThrow, EST_DynamicNone, EST_BasicNoexcept, EST_NoexceptTrue}) { + if (EST1 == I) + return ESI2; + if (EST2 == I) + return ESI1; + } + + // If we're left with value-dependent computed noexcept expressions, we're + // stuck. Before C++17, we can just drop the exception specification entirely, + // since it's not actually part of the canonical type. And this should never + // happen in C++17, because it would mean we were computing the composite + // pointer type of dependent types, which should never happen. + if (EST1 == EST_DependentNoexcept || EST2 == EST_DependentNoexcept) { + assert(AcceptDependent && + "computing composite pointer type of dependent types"); + return FunctionProtoType::ExceptionSpecInfo(); + } + + // Switch over the possibilities so that people adding new values know to + // update this function. + switch (EST1) { + case EST_None: + case EST_DynamicNone: + case EST_MSAny: + case EST_BasicNoexcept: + case EST_DependentNoexcept: + case EST_NoexceptFalse: + case EST_NoexceptTrue: + case EST_NoThrow: + llvm_unreachable("These ESTs should be handled above"); + + case EST_Dynamic: { + // This is the fun case: both exception specifications are dynamic. Form + // the union of the two lists. + assert(EST2 == EST_Dynamic && "other cases should already be handled"); + mergeTypeLists(*this, ExceptionTypeStorage, ESI1.Exceptions, + ESI2.Exceptions); + FunctionProtoType::ExceptionSpecInfo Result(EST_Dynamic); + Result.Exceptions = ExceptionTypeStorage; + return Result; + } + + case EST_Unevaluated: + case EST_Uninstantiated: + case EST_Unparsed: + llvm_unreachable("shouldn't see unresolved exception specifications here"); + } + + llvm_unreachable("invalid ExceptionSpecificationType"); +} + +static QualType getCommonNonSugarTypeNode(ASTContext &Ctx, const Type *X, + Qualifiers &QX, const Type *Y, + Qualifiers &QY) { + Type::TypeClass TC = X->getTypeClass(); + assert(TC == Y->getTypeClass()); + switch (TC) { +#define UNEXPECTED_TYPE(Class, Kind) \ + case Type::Class: \ + llvm_unreachable("Unexpected " Kind ": " #Class); + +#define NON_CANONICAL_TYPE(Class, Base) UNEXPECTED_TYPE(Class, "non-canonical") +#define TYPE(Class, Base) +#include "clang/AST/TypeNodes.inc" + +#define SUGAR_FREE_TYPE(Class) UNEXPECTED_TYPE(Class, "sugar-free") + SUGAR_FREE_TYPE(Builtin) + SUGAR_FREE_TYPE(Decltype) + SUGAR_FREE_TYPE(DeducedTemplateSpecialization) + SUGAR_FREE_TYPE(DependentBitInt) + SUGAR_FREE_TYPE(Enum) + SUGAR_FREE_TYPE(BitInt) + SUGAR_FREE_TYPE(ObjCInterface) + SUGAR_FREE_TYPE(Record) + SUGAR_FREE_TYPE(SubstTemplateTypeParmPack) + SUGAR_FREE_TYPE(UnresolvedUsing) +#undef SUGAR_FREE_TYPE +#define NON_UNIQUE_TYPE(Class) UNEXPECTED_TYPE(Class, "non-unique") + NON_UNIQUE_TYPE(TypeOfExpr) + NON_UNIQUE_TYPE(VariableArray) +#undef NON_UNIQUE_TYPE + + UNEXPECTED_TYPE(TypeOf, "sugar") + +#undef UNEXPECTED_TYPE + + case Type::Auto: { + const auto *AX = cast<AutoType>(X), *AY = cast<AutoType>(Y); + assert(AX->getDeducedType().isNull()); + assert(AY->getDeducedType().isNull()); + assert(AX->getKeyword() == AY->getKeyword()); + assert(AX->isInstantiationDependentType() == + AY->isInstantiationDependentType()); + auto As = getCommonTemplateArguments(Ctx, AX->getTypeConstraintArguments(), + AY->getTypeConstraintArguments()); + return Ctx.getAutoType(QualType(), AX->getKeyword(), + AX->isInstantiationDependentType(), + AX->containsUnexpandedParameterPack(), + getCommonDeclChecked(AX->getTypeConstraintConcept(), + AY->getTypeConstraintConcept()), + As); + } + case Type::IncompleteArray: { + const auto *AX = cast<IncompleteArrayType>(X), + *AY = cast<IncompleteArrayType>(Y); + return Ctx.getIncompleteArrayType( + getCommonArrayElementType(Ctx, AX, QX, AY, QY), + getCommonSizeModifier(AX, AY), getCommonIndexTypeCVRQualifiers(AX, AY)); + } + case Type::DependentSizedArray: { + const auto *AX = cast<DependentSizedArrayType>(X), + *AY = cast<DependentSizedArrayType>(Y); + return Ctx.getDependentSizedArrayType( + getCommonArrayElementType(Ctx, AX, QX, AY, QY), + getCommonSizeExpr(Ctx, AX, AY), getCommonSizeModifier(AX, AY), + getCommonIndexTypeCVRQualifiers(AX, AY), + AX->getBracketsRange() == AY->getBracketsRange() + ? AX->getBracketsRange() + : SourceRange()); + } + case Type::ConstantArray: { + const auto *AX = cast<ConstantArrayType>(X), + *AY = cast<ConstantArrayType>(Y); + assert(AX->getSize() == AY->getSize()); + const Expr *SizeExpr = Ctx.hasSameExpr(AX->getSizeExpr(), AY->getSizeExpr()) + ? AX->getSizeExpr() + : nullptr; + return Ctx.getConstantArrayType( + getCommonArrayElementType(Ctx, AX, QX, AY, QY), AX->getSize(), SizeExpr, + getCommonSizeModifier(AX, AY), getCommonIndexTypeCVRQualifiers(AX, AY)); + } + case Type::Atomic: { + const auto *AX = cast<AtomicType>(X), *AY = cast<AtomicType>(Y); + return Ctx.getAtomicType( + Ctx.getCommonSugaredType(AX->getValueType(), AY->getValueType())); + } + case Type::Complex: { + const auto *CX = cast<ComplexType>(X), *CY = cast<ComplexType>(Y); + return Ctx.getComplexType(getCommonArrayElementType(Ctx, CX, QX, CY, QY)); + } + case Type::Pointer: { + const auto *PX = cast<PointerType>(X), *PY = cast<PointerType>(Y); + return Ctx.getPointerType(getCommonPointeeType(Ctx, PX, PY)); + } + case Type::BlockPointer: { + const auto *PX = cast<BlockPointerType>(X), *PY = cast<BlockPointerType>(Y); + return Ctx.getBlockPointerType(getCommonPointeeType(Ctx, PX, PY)); + } + case Type::ObjCObjectPointer: { + const auto *PX = cast<ObjCObjectPointerType>(X), + *PY = cast<ObjCObjectPointerType>(Y); + return Ctx.getObjCObjectPointerType(getCommonPointeeType(Ctx, PX, PY)); + } + case Type::MemberPointer: { + const auto *PX = cast<MemberPointerType>(X), + *PY = cast<MemberPointerType>(Y); + return Ctx.getMemberPointerType( + getCommonPointeeType(Ctx, PX, PY), + Ctx.getCommonSugaredType(QualType(PX->getClass(), 0), + QualType(PY->getClass(), 0)) + .getTypePtr()); + } + case Type::LValueReference: { + const auto *PX = cast<LValueReferenceType>(X), + *PY = cast<LValueReferenceType>(Y); + // FIXME: Preserve PointeeTypeAsWritten. + return Ctx.getLValueReferenceType(getCommonPointeeType(Ctx, PX, PY), + PX->isSpelledAsLValue() || + PY->isSpelledAsLValue()); + } + case Type::RValueReference: { + const auto *PX = cast<RValueReferenceType>(X), + *PY = cast<RValueReferenceType>(Y); + // FIXME: Preserve PointeeTypeAsWritten. + return Ctx.getRValueReferenceType(getCommonPointeeType(Ctx, PX, PY)); + } + case Type::DependentAddressSpace: { + const auto *PX = cast<DependentAddressSpaceType>(X), + *PY = cast<DependentAddressSpaceType>(Y); + assert(Ctx.hasSameExpr(PX->getAddrSpaceExpr(), PY->getAddrSpaceExpr())); + return Ctx.getDependentAddressSpaceType(getCommonPointeeType(Ctx, PX, PY), + PX->getAddrSpaceExpr(), + getCommonAttrLoc(PX, PY)); + } + case Type::FunctionNoProto: { + const auto *FX = cast<FunctionNoProtoType>(X), + *FY = cast<FunctionNoProtoType>(Y); + assert(FX->getExtInfo() == FY->getExtInfo()); + return Ctx.getFunctionNoProtoType( + Ctx.getCommonSugaredType(FX->getReturnType(), FY->getReturnType()), + FX->getExtInfo()); + } + case Type::FunctionProto: { + const auto *FX = cast<FunctionProtoType>(X), + *FY = cast<FunctionProtoType>(Y); + FunctionProtoType::ExtProtoInfo EPIX = FX->getExtProtoInfo(), + EPIY = FY->getExtProtoInfo(); + assert(EPIX.ExtInfo == EPIY.ExtInfo); + assert(EPIX.ExtParameterInfos == EPIY.ExtParameterInfos); + assert(EPIX.RefQualifier == EPIY.RefQualifier); + assert(EPIX.TypeQuals == EPIY.TypeQuals); + assert(EPIX.Variadic == EPIY.Variadic); + + // FIXME: Can we handle an empty EllipsisLoc? + // Use emtpy EllipsisLoc if X and Y differ. + + EPIX.HasTrailingReturn = EPIX.HasTrailingReturn && EPIY.HasTrailingReturn; + + QualType R = + Ctx.getCommonSugaredType(FX->getReturnType(), FY->getReturnType()); + auto P = getCommonTypes(Ctx, FX->param_types(), FY->param_types(), + /*Unqualified=*/true); + + SmallVector<QualType, 8> Exceptions; + EPIX.ExceptionSpec = Ctx.mergeExceptionSpecs( + EPIX.ExceptionSpec, EPIY.ExceptionSpec, Exceptions, true); + return Ctx.getFunctionType(R, P, EPIX); + } + case Type::ObjCObject: { + const auto *OX = cast<ObjCObjectType>(X), *OY = cast<ObjCObjectType>(Y); + assert( + std::equal(OX->getProtocols().begin(), OX->getProtocols().end(), + OY->getProtocols().begin(), OY->getProtocols().end(), + [](const ObjCProtocolDecl *P0, const ObjCProtocolDecl *P1) { + return P0->getCanonicalDecl() == P1->getCanonicalDecl(); + }) && + "protocol lists must be the same"); + auto TAs = getCommonTypes(Ctx, OX->getTypeArgsAsWritten(), + OY->getTypeArgsAsWritten()); + return Ctx.getObjCObjectType( + Ctx.getCommonSugaredType(OX->getBaseType(), OY->getBaseType()), TAs, + OX->getProtocols(), + OX->isKindOfTypeAsWritten() && OY->isKindOfTypeAsWritten()); + } + case Type::ConstantMatrix: { + const auto *MX = cast<ConstantMatrixType>(X), + *MY = cast<ConstantMatrixType>(Y); + assert(MX->getNumRows() == MY->getNumRows()); + assert(MX->getNumColumns() == MY->getNumColumns()); + return Ctx.getConstantMatrixType(getCommonElementType(Ctx, MX, MY), + MX->getNumRows(), MX->getNumColumns()); + } + case Type::DependentSizedMatrix: { + const auto *MX = cast<DependentSizedMatrixType>(X), + *MY = cast<DependentSizedMatrixType>(Y); + assert(Ctx.hasSameExpr(MX->getRowExpr(), MY->getRowExpr())); + assert(Ctx.hasSameExpr(MX->getColumnExpr(), MY->getColumnExpr())); + return Ctx.getDependentSizedMatrixType( + getCommonElementType(Ctx, MX, MY), MX->getRowExpr(), + MX->getColumnExpr(), getCommonAttrLoc(MX, MY)); + } + case Type::Vector: { + const auto *VX = cast<VectorType>(X), *VY = cast<VectorType>(Y); + assert(VX->getNumElements() == VY->getNumElements()); + assert(VX->getVectorKind() == VY->getVectorKind()); + return Ctx.getVectorType(getCommonElementType(Ctx, VX, VY), + VX->getNumElements(), VX->getVectorKind()); + } + case Type::ExtVector: { + const auto *VX = cast<ExtVectorType>(X), *VY = cast<ExtVectorType>(Y); + assert(VX->getNumElements() == VY->getNumElements()); + return Ctx.getExtVectorType(getCommonElementType(Ctx, VX, VY), + VX->getNumElements()); + } + case Type::DependentSizedExtVector: { + const auto *VX = cast<DependentSizedExtVectorType>(X), + *VY = cast<DependentSizedExtVectorType>(Y); + return Ctx.getDependentSizedExtVectorType(getCommonElementType(Ctx, VX, VY), + getCommonSizeExpr(Ctx, VX, VY), + getCommonAttrLoc(VX, VY)); + } + case Type::DependentVector: { + const auto *VX = cast<DependentVectorType>(X), + *VY = cast<DependentVectorType>(Y); + assert(VX->getVectorKind() == VY->getVectorKind()); + return Ctx.getDependentVectorType( + getCommonElementType(Ctx, VX, VY), getCommonSizeExpr(Ctx, VX, VY), + getCommonAttrLoc(VX, VY), VX->getVectorKind()); + } + 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())); + } + case Type::TemplateSpecialization: { + const auto *TX = cast<TemplateSpecializationType>(X), + *TY = cast<TemplateSpecializationType>(Y); + auto As = getCommonTemplateArguments(Ctx, TX->template_arguments(), + TY->template_arguments()); + return Ctx.getTemplateSpecializationType( + ::getCommonTemplateNameChecked(Ctx, TX->getTemplateName(), + TY->getTemplateName()), + As, X->getCanonicalTypeInternal()); + } + case Type::DependentName: { + const auto *NX = cast<DependentNameType>(X), + *NY = cast<DependentNameType>(Y); + assert(NX->getIdentifier() == NY->getIdentifier()); + return Ctx.getDependentNameType( + getCommonTypeKeyword(NX, NY), getCommonNNS(Ctx, NX, NY), + NX->getIdentifier(), NX->getCanonicalTypeInternal()); + } + case Type::DependentTemplateSpecialization: { + const auto *TX = cast<DependentTemplateSpecializationType>(X), + *TY = cast<DependentTemplateSpecializationType>(Y); + assert(TX->getIdentifier() == TY->getIdentifier()); + auto As = getCommonTemplateArguments(Ctx, TX->template_arguments(), + TY->template_arguments()); + return Ctx.getDependentTemplateSpecializationType( + getCommonTypeKeyword(TX, TY), getCommonNNS(Ctx, TX, TY), + TX->getIdentifier(), As); + } + case Type::UnaryTransform: { + const auto *TX = cast<UnaryTransformType>(X), + *TY = cast<UnaryTransformType>(Y); + assert(TX->getUTTKind() == TY->getUTTKind()); + return Ctx.getUnaryTransformType( + Ctx.getCommonSugaredType(TX->getBaseType(), TY->getBaseType()), + Ctx.getCommonSugaredType(TX->getUnderlyingType(), + TY->getUnderlyingType()), + TX->getUTTKind()); + } + case Type::PackExpansion: { + const auto *PX = cast<PackExpansionType>(X), + *PY = cast<PackExpansionType>(Y); + assert(PX->getNumExpansions() == PY->getNumExpansions()); + return Ctx.getPackExpansionType( + Ctx.getCommonSugaredType(PX->getPattern(), PY->getPattern()), + PX->getNumExpansions(), false); + } + case Type::Pipe: { + const auto *PX = cast<PipeType>(X), *PY = cast<PipeType>(Y); + assert(PX->isReadOnly() == PY->isReadOnly()); + auto MP = PX->isReadOnly() ? &ASTContext::getReadPipeType + : &ASTContext::getWritePipeType; + return (Ctx.*MP)(getCommonElementType(Ctx, PX, PY)); + } + case Type::TemplateTypeParm: { + const auto *TX = cast<TemplateTypeParmType>(X), + *TY = cast<TemplateTypeParmType>(Y); + assert(TX->getDepth() == TY->getDepth()); + assert(TX->getIndex() == TY->getIndex()); + assert(TX->isParameterPack() == TY->isParameterPack()); + return Ctx.getTemplateTypeParmType( + TX->getDepth(), TX->getIndex(), TX->isParameterPack(), + getCommonDecl(TX->getDecl(), TY->getDecl())); + } + } + llvm_unreachable("Unknown Type Class"); +} + +static QualType getCommonSugarTypeNode(ASTContext &Ctx, const Type *X, + const Type *Y, + SplitQualType Underlying) { + Type::TypeClass TC = X->getTypeClass(); + if (TC != Y->getTypeClass()) + return QualType(); + switch (TC) { +#define UNEXPECTED_TYPE(Class, Kind) \ + case Type::Class: \ + llvm_unreachable("Unexpected " Kind ": " #Class); +#define TYPE(Class, Base) +#define DEPENDENT_TYPE(Class, Base) UNEXPECTED_TYPE(Class, "dependent") +#include "clang/AST/TypeNodes.inc" + +#define CANONICAL_TYPE(Class) UNEXPECTED_TYPE(Class, "canonical") + CANONICAL_TYPE(Atomic) + CANONICAL_TYPE(BitInt) + CANONICAL_TYPE(BlockPointer) + CANONICAL_TYPE(Builtin) + CANONICAL_TYPE(Complex) + CANONICAL_TYPE(ConstantArray) + CANONICAL_TYPE(ConstantMatrix) + CANONICAL_TYPE(Enum) + CANONICAL_TYPE(ExtVector) + CANONICAL_TYPE(FunctionNoProto) + CANONICAL_TYPE(FunctionProto) + CANONICAL_TYPE(IncompleteArray) + CANONICAL_TYPE(LValueReference) + CANONICAL_TYPE(MemberPointer) + CANONICAL_TYPE(ObjCInterface) + CANONICAL_TYPE(ObjCObject) + CANONICAL_TYPE(ObjCObjectPointer) + CANONICAL_TYPE(Pipe) + CANONICAL_TYPE(Pointer) + CANONICAL_TYPE(Record) + CANONICAL_TYPE(RValueReference) + CANONICAL_TYPE(VariableArray) + CANONICAL_TYPE(Vector) +#undef CANONICAL_TYPE + +#undef UNEXPECTED_TYPE + + case Type::Adjusted: { + const auto *AX = cast<AdjustedType>(X), *AY = cast<AdjustedType>(Y); + QualType OX = AX->getOriginalType(), OY = AY->getOriginalType(); + if (!Ctx.hasSameType(OX, OY)) + return QualType(); + // FIXME: It's inefficient to have to unify the original types. + return Ctx.getAdjustedType(Ctx.getCommonSugaredType(OX, OY), + Ctx.getQualifiedType(Underlying)); + } + case Type::Decayed: { + const auto *DX = cast<DecayedType>(X), *DY = cast<DecayedType>(Y); + QualType OX = DX->getOriginalType(), OY = DY->getOriginalType(); + if (!Ctx.hasSameType(OX, OY)) + return QualType(); + // FIXME: It's inefficient to have to unify the original types. + return Ctx.getDecayedType(Ctx.getCommonSugaredType(OX, OY), + Ctx.getQualifiedType(Underlying)); + } + case Type::Attributed: { + const auto *AX = cast<AttributedType>(X), *AY = cast<AttributedType>(Y); + AttributedType::Kind Kind = AX->getAttrKind(); + if (Kind != AY->getAttrKind()) + return QualType(); + QualType MX = AX->getModifiedType(), MY = AY->getModifiedType(); + if (!Ctx.hasSameType(MX, MY)) + return QualType(); + // FIXME: It's inefficient to have to unify the modified types. + return Ctx.getAttributedType(Kind, Ctx.getCommonSugaredType(MX, MY), + Ctx.getQualifiedType(Underlying)); + } + case Type::BTFTagAttributed: { + const auto *BX = cast<BTFTagAttributedType>(X); + const BTFTypeTagAttr *AX = BX->getAttr(); + // The attribute is not uniqued, so just compare the tag. + if (AX->getBTFTypeTag() != + cast<BTFTagAttributedType>(Y)->getAttr()->getBTFTypeTag()) + return QualType(); + return Ctx.getBTFTagAttributedType(AX, Ctx.getQualifiedType(Underlying)); + } + case Type::Auto: { + const auto *AX = cast<AutoType>(X), *AY = cast<AutoType>(Y); + + AutoTypeKeyword KW = AX->getKeyword(); + if (KW != AY->getKeyword()) + return QualType(); + + ConceptDecl *CD = ::getCommonDecl(AX->getTypeConstraintConcept(), + AY->getTypeConstraintConcept()); + SmallVector<TemplateArgument, 8> As; + if (CD && + getCommonTemplateArguments(Ctx, As, AX->getTypeConstraintArguments(), + AY->getTypeConstraintArguments())) + CD = nullptr; // The arguments differ, so make it unconstrained. + + // Both auto types can't be dependent, otherwise they wouldn't have been + // sugar. This implies they can't contain unexpanded packs either. + return Ctx.getAutoType(Ctx.getQualifiedType(Underlying), AX->getKeyword(), + /*IsDependent=*/false, /*IsPack=*/false, CD, As); + } + case Type::Decltype: + return QualType(); + 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), ::getCommonNNS(Ctx, EX, EY), + Ctx.getQualifiedType(Underlying), + ::getCommonDecl(EX->getOwnedTagDecl(), EY->getOwnedTagDecl())); + } + case Type::MacroQualified: { + const auto *MX = cast<MacroQualifiedType>(X), + *MY = cast<MacroQualifiedType>(Y); + const IdentifierInfo *IX = MX->getMacroIdentifier(); + if (IX != MY->getMacroIdentifier()) + return QualType(); + return Ctx.getMacroQualifiedType(Ctx.getQualifiedType(Underlying), IX); + } + case Type::SubstTemplateTypeParm: { + const auto *SX = cast<SubstTemplateTypeParmType>(X), + *SY = cast<SubstTemplateTypeParmType>(Y); + Decl *CD = + ::getCommonDecl(SX->getAssociatedDecl(), SY->getAssociatedDecl()); + if (!CD) + return QualType(); + unsigned Index = SX->getIndex(); + if (Index != SY->getIndex()) + return QualType(); + auto PackIndex = SX->getPackIndex(); + if (PackIndex != SY->getPackIndex()) + return QualType(); + return Ctx.getSubstTemplateTypeParmType(Ctx.getQualifiedType(Underlying), + CD, Index, PackIndex); + } + case Type::ObjCTypeParam: + // FIXME: Try to merge these. + return QualType(); + case Type::Paren: + return Ctx.getParenType(Ctx.getQualifiedType(Underlying)); + + case Type::TemplateSpecialization: { + const auto *TX = cast<TemplateSpecializationType>(X), + *TY = cast<TemplateSpecializationType>(Y); + TemplateName CTN = ::getCommonTemplateName(Ctx, TX->getTemplateName(), + TY->getTemplateName()); + if (!CTN.getAsVoidPointer()) + return QualType(); + SmallVector<TemplateArgument, 8> Args; + if (getCommonTemplateArguments(Ctx, Args, TX->template_arguments(), + TY->template_arguments())) + return QualType(); + return Ctx.getTemplateSpecializationType(CTN, Args, + 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)); + } + case Type::TypeOf: { + // The common sugar between two typeof expressions, where one is + // potentially a typeof_unqual and the other is not, we unify to the + // qualified type as that retains the most information along with the type. + // We only return a typeof_unqual type when both types are unqual types. + TypeOfKind Kind = TypeOfKind::Qualified; + if (cast<TypeOfType>(X)->getKind() == cast<TypeOfType>(Y)->getKind() && + cast<TypeOfType>(X)->getKind() == TypeOfKind::Unqualified) + Kind = TypeOfKind::Unqualified; + return Ctx.getTypeOfType(Ctx.getQualifiedType(Underlying), Kind); + } + case Type::TypeOfExpr: + return QualType(); + + case Type::UnaryTransform: { + const auto *UX = cast<UnaryTransformType>(X), + *UY = cast<UnaryTransformType>(Y); + UnaryTransformType::UTTKind KX = UX->getUTTKind(); + if (KX != UY->getUTTKind()) + return QualType(); + QualType BX = UX->getBaseType(), BY = UY->getBaseType(); + if (!Ctx.hasSameType(BX, BY)) + return QualType(); + // FIXME: It's inefficient to have to unify the base types. + return Ctx.getUnaryTransformType(Ctx.getCommonSugaredType(BX, BY), + Ctx.getQualifiedType(Underlying), KX); + } + case Type::Using: { + const auto *UX = cast<UsingType>(X), *UY = cast<UsingType>(Y); + const UsingShadowDecl *CD = + ::getCommonDecl(UX->getFoundDecl(), UY->getFoundDecl()); + if (!CD) + return QualType(); + return Ctx.getUsingType(CD, Ctx.getQualifiedType(Underlying)); + } + } + llvm_unreachable("Unhandled Type Class"); +} + +static auto unwrapSugar(SplitQualType &T, Qualifiers &QTotal) { + SmallVector<SplitQualType, 8> R; + while (true) { + QTotal += T.Quals; + QualType NT = T.Ty->getLocallyUnqualifiedSingleStepDesugaredType(); + if (NT == QualType(T.Ty, 0)) + break; + R.push_back(T); + T = NT.split(); + } + return R; +} + +QualType ASTContext::getCommonSugaredType(QualType X, QualType Y, + bool Unqualified) { + assert(Unqualified ? hasSameUnqualifiedType(X, Y) : hasSameType(X, Y)); + if (X == Y) + return X; + if (!Unqualified) { + if (X.isCanonical()) + return X; + if (Y.isCanonical()) + return Y; + } + + SplitQualType SX = X.split(), SY = Y.split(); + Qualifiers QX, QY; + // Desugar SX and SY, setting the sugar and qualifiers aside into Xs and Ys, + // until we reach their underlying "canonical nodes". Note these are not + // necessarily canonical types, as they may still have sugared properties. + // QX and QY will store the sum of all qualifiers in Xs and Ys respectively. + auto Xs = ::unwrapSugar(SX, QX), Ys = ::unwrapSugar(SY, QY); + if (SX.Ty != SY.Ty) { + // The canonical nodes differ. Build a common canonical node out of the two, + // unifying their sugar. This may recurse back here. + SX.Ty = + ::getCommonNonSugarTypeNode(*this, SX.Ty, QX, SY.Ty, QY).getTypePtr(); + } else { + // The canonical nodes were identical: We may have desugared too much. + // Add any common sugar back in. + while (!Xs.empty() && !Ys.empty() && Xs.back().Ty == Ys.back().Ty) { + QX -= SX.Quals; + QY -= SY.Quals; + SX = Xs.pop_back_val(); + SY = Ys.pop_back_val(); + } + } + if (Unqualified) + QX = Qualifiers::removeCommonQualifiers(QX, QY); else - return (*AddrSpaceMap)[(unsigned)AS]; + assert(QX == QY); + + // Even though the remaining sugar nodes in Xs and Ys differ, some may be + // related. Walk up these nodes, unifying them and adding the result. + while (!Xs.empty() && !Ys.empty()) { + auto Underlying = SplitQualType( + SX.Ty, Qualifiers::removeCommonQualifiers(SX.Quals, SY.Quals)); + SX = Xs.pop_back_val(); + SY = Ys.pop_back_val(); + SX.Ty = ::getCommonSugarTypeNode(*this, SX.Ty, SY.Ty, Underlying) + .getTypePtrOrNull(); + // Stop at the first pair which is unrelated. + if (!SX.Ty) { + SX.Ty = Underlying.Ty; + break; + } + QX -= Underlying.Quals; + }; + + // Add back the missing accumulated qualifiers, which were stripped off + // with the sugar nodes we could not unify. + QualType R = getQualifiedType(SX.Ty, QX); + assert(Unqualified ? hasSameUnqualifiedType(R, X) : hasSameType(R, X)); + return R; } QualType ASTContext::getCorrespondingSaturatedType(QualType Ty) const { @@ -12304,10 +13308,22 @@ QualType ASTContext::getCorrespondingSignedFixedPointType(QualType Ty) const { } } +std::vector<std::string> ASTContext::filterFunctionTargetVersionAttrs( + const TargetVersionAttr *TV) const { + assert(TV != nullptr); + llvm::SmallVector<StringRef, 8> Feats; + std::vector<std::string> ResFeats; + TV->getFeatures(Feats); + for (auto &Feature : Feats) + if (Target->validateCpuSupports(Feature.str())) + ResFeats.push_back("?" + Feature.str()); + return ResFeats; +} + ParsedTargetAttr ASTContext::filterFunctionTargetAttrs(const TargetAttr *TD) const { assert(TD != nullptr); - ParsedTargetAttr ParsedAttr = TD->parse(); + ParsedTargetAttr ParsedAttr = Target->parseTargetAttr(TD->getFeaturesStr()); llvm::erase_if(ParsedAttr.Features, [&](const std::string &Feat) { return !Target->isValidFeatureName(StringRef{Feat}.substr(1)); @@ -12341,9 +13357,8 @@ void ASTContext::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap, Target->getTargetOpts().FeaturesAsWritten.begin(), Target->getTargetOpts().FeaturesAsWritten.end()); - if (ParsedAttr.Architecture != "" && - Target->isValidCPUName(ParsedAttr.Architecture)) - TargetCPU = ParsedAttr.Architecture; + if (ParsedAttr.CPU != "" && Target->isValidCPUName(ParsedAttr.CPU)) + TargetCPU = ParsedAttr.CPU; // Now populate the feature map, first with the TargetCPU which is either // the default or a new one from the target attribute string. Then we'll use @@ -12363,12 +13378,32 @@ void ASTContext::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap, } else if (const auto *TC = FD->getAttr<TargetClonesAttr>()) { std::vector<std::string> Features; StringRef VersionStr = TC->getFeatureStr(GD.getMultiVersionIndex()); - if (VersionStr.startswith("arch=")) - TargetCPU = VersionStr.drop_front(sizeof("arch=") - 1); - else if (VersionStr != "default") - Features.push_back((StringRef{"+"} + VersionStr).str()); - + if (Target->getTriple().isAArch64()) { + // TargetClones for AArch64 + if (VersionStr != "default") { + SmallVector<StringRef, 1> VersionFeatures; + VersionStr.split(VersionFeatures, "+"); + for (auto &VFeature : VersionFeatures) { + VFeature = VFeature.trim(); + Features.push_back((StringRef{"?"} + VFeature).str()); + } + } + Features.insert(Features.begin(), + Target->getTargetOpts().FeaturesAsWritten.begin(), + Target->getTargetOpts().FeaturesAsWritten.end()); + } else { + if (VersionStr.startswith("arch=")) + TargetCPU = VersionStr.drop_front(sizeof("arch=") - 1); + else if (VersionStr != "default") + Features.push_back((StringRef{"+"} + VersionStr).str()); + } Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, Features); + } else if (const auto *TV = FD->getAttr<TargetVersionAttr>()) { + std::vector<std::string> Feats = filterFunctionTargetVersionAttrs(TV); + Feats.insert(Feats.begin(), + Target->getTargetOpts().FeaturesAsWritten.begin(), + Target->getTargetOpts().FeaturesAsWritten.end()); + Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, Feats); } else { FeatureMap = Target->getTargetOpts().FeatureMap; } |