https://github.com/mizvekov updated https://github.com/llvm/llvm-project/pull/132441
>From 0793555771f9855a12c267eb4f2de1341a8556d1 Mon Sep 17 00:00:00 2001 From: Matheus Izvekov <mizve...@gmail.com> Date: Mon, 30 May 2022 01:46:31 +0200 Subject: [PATCH] [clang] Template Specialization Resugaring - TypeDecl This is the introductory patch for a larger work which intends to solve the long standing C++ issue with losing type sugar when acessing template specializations. The well known example here is specializing a template with `std::string`, but getting diagnostics related to `std::basic_string<char>` instead. This implements a transform which, upon member access, propagates type sugar from the naming context into the accessed entity. It also implements a single use of this transform, resugaring access to TypeDecls. For more details and discussion see: https://discourse.llvm.org/t/rfc-improving-diagnostics-with-template-specialization-resugaring/64294 This is ready for review, although maybe not finished and there is some more stuff that could be done either here or in follow ups. * Its worth exploring if a global resugaring cache is worthwhile, besides the current operational cache. A global cache would be more expensive to index, so there is a tradeoff, and maybe should be used of the whole result of the operation, while keeping the existing cache for sub-results. * It would be ideal if the transform could live in ASTContext instead of Sema. There are a few dependencies that would have to be tackled. * Template arguments deduced for partial specializations. * Some kinds of type adjustments currently require Sema. Differential Revision: https://reviews.llvm.org/D127695 --- .../readability/QualifiedAutoCheck.cpp | 2 +- clang/include/clang/AST/ASTContext.h | 13 +- clang/include/clang/AST/Type.h | 11 +- clang/include/clang/Sema/Sema.h | 8 +- clang/lib/AST/ASTContext.cpp | 17 +- clang/lib/Sema/SemaCXXScopeSpec.cpp | 5 +- clang/lib/Sema/SemaCoroutine.cpp | 1 + clang/lib/Sema/SemaDecl.cpp | 9 +- clang/lib/Sema/SemaDeclCXX.cpp | 2 +- clang/lib/Sema/SemaTemplate.cpp | 735 +++++++++++++++++- clang/lib/Sema/SemaTemplateDeduction.cpp | 6 +- clang/lib/Sema/SemaType.cpp | 10 +- ...openmp-begin-declare-variant_reference.cpp | 4 +- clang/test/AST/ast-dump-template-name.cpp | 8 +- clang/test/CXX/temp/temp.param/p15-cxx0x.cpp | 4 +- clang/test/Sema/Resugar/resugar-types.cpp | 209 +++++ .../iterator/TestIteratorFromStdModule.py | 6 +- 17 files changed, 1004 insertions(+), 46 deletions(-) create mode 100644 clang/test/Sema/Resugar/resugar-types.cpp diff --git a/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp b/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp index e843c593a92cc..679fbd75d2479 100644 --- a/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp @@ -126,7 +126,7 @@ void QualifiedAutoCheck::registerMatchers(MatchFinder *Finder) { auto UnlessFunctionType = unless(hasUnqualifiedDesugaredType(functionType())); auto IsAutoDeducedToPointer = [](const auto &...InnerMatchers) { return autoType(hasDeducedType( - hasUnqualifiedDesugaredType(pointerType(pointee(InnerMatchers...))))); + hasCanonicalType(pointerType(pointee(InnerMatchers...))))); }; Finder->addMatcher( diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index d2529fbba68e0..a7d318d894811 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -1319,8 +1319,6 @@ class ASTContext : public RefCountedBase<ASTContext> { QualType getTypeDeclTypeSlow(const TypeDecl *Decl) const; - QualType getPipeType(QualType T, bool ReadOnly) const; - public: /// Return the uniqued reference to the type for an address space /// qualified type with the specified type and address space. @@ -1500,6 +1498,9 @@ class ASTContext : public RefCountedBase<ASTContext> { /// blocks. QualType getBlockDescriptorType() const; + // Return a pipe type for the specified type. + QualType getPipeType(QualType T, bool ReadOnly) const; + /// Return a read_only pipe type for the specified type. QualType getReadPipeType(QualType T) const; @@ -1897,10 +1898,10 @@ class ASTContext : public RefCountedBase<ASTContext> { /// C++11 decltype. QualType getDecltypeType(Expr *e, QualType UnderlyingType) const; - QualType getPackIndexingType(QualType Pattern, Expr *IndexExpr, - bool FullySubstituted = false, - ArrayRef<QualType> Expansions = {}, - int Index = -1) const; + QualType getPackIndexingType( + QualType Pattern, Expr *IndexExpr, bool FullySubstituted = false, + ArrayRef<QualType> Expansions = {}, + std::optional<unsigned> SelectedIndex = std::nullopt) const; /// Unary type transforms QualType getUnaryTransformType(QualType BaseType, QualType UnderlyingType, diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 3451284913d12..8c42f5b6ecf0d 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -643,10 +643,10 @@ class Qualifiers { void addQualifiers(Qualifiers Q) { // If the other set doesn't have any non-boolean qualifiers, just // bit-or it in. - if (!(Q.Mask & ~CVRMask)) + if (!(Q.Mask & ~CVRUMask)) Mask |= Q.Mask; else { - Mask |= (Q.Mask & CVRMask); + Mask |= (Q.Mask & CVRUMask); if (Q.hasAddressSpace()) addAddressSpace(Q.getAddressSpace()); if (Q.hasObjCGCAttr()) @@ -662,10 +662,10 @@ class Qualifiers { void removeQualifiers(Qualifiers Q) { // If the other set doesn't have any non-boolean qualifiers, just // bit-and the inverse in. - if (!(Q.Mask & ~CVRMask)) + if (!(Q.Mask & ~CVRUMask)) Mask &= ~Q.Mask; else { - Mask &= ~(Q.Mask & CVRMask); + Mask &= ~(Q.Mask & CVRUMask); if (getObjCGCAttr() == Q.getObjCGCAttr()) removeObjCGCAttr(); if (getObjCLifetime() == Q.getObjCLifetime()) @@ -805,12 +805,13 @@ class Qualifiers { static constexpr uint64_t UMask = 0x8; static constexpr uint64_t UShift = 3; + static constexpr uint64_t CVRUMask = CVRMask | UMask; static constexpr uint64_t GCAttrMask = 0x30; static constexpr uint64_t GCAttrShift = 4; static constexpr uint64_t LifetimeMask = 0x1C0; static constexpr uint64_t LifetimeShift = 6; static constexpr uint64_t AddressSpaceMask = - ~(CVRMask | UMask | GCAttrMask | LifetimeMask); + ~(CVRUMask | GCAttrMask | LifetimeMask); static constexpr uint64_t AddressSpaceShift = 9; static constexpr uint64_t PtrAuthShift = 32; static constexpr uint64_t PtrAuthMask = uint64_t(0xffffffff) << PtrAuthShift; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index a62562bb134f5..945ff5e2c2ca6 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -3193,7 +3193,8 @@ class Sema final : public SemaBase { /// Returns the TypeDeclType for the given type declaration, /// as ASTContext::getTypeDeclType would, but /// performs the required semantic checks for name lookup of said entity. - QualType getTypeDeclType(DeclContext *LookupCtx, DiagCtorKind DCK, + QualType getTypeDeclType(const NestedNameSpecifier *NNS, + DeclContext *LookupCtx, DiagCtorKind DCK, TypeDecl *TD, SourceLocation NameLoc); /// If the identifier refers to a type name within this scope, @@ -13985,6 +13986,8 @@ class Sema final : public SemaBase { FunctionDecl *SubstSpaceshipAsEqualEqual(CXXRecordDecl *RD, FunctionDecl *Spaceship); + QualType resugar(const NestedNameSpecifier *NNS, QualType T); + /// Performs template instantiation for all implicit template /// instantiations we have seen until this point. void PerformPendingInstantiations(bool LocalOnly = false, @@ -14984,7 +14987,8 @@ class Sema final : public SemaBase { /// wasn't specified explicitly. This handles method types formed from /// function type typedefs and typename template arguments. void adjustMemberFunctionCC(QualType &T, bool HasThisPointer, - bool IsCtorOrDtor, SourceLocation Loc); + bool IsCtorOrDtor, bool IsDeduced, + SourceLocation Loc); // Check if there is an explicit attribute, but only look through parens. // The intent is to look for an attribute on the current declarator, but not diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index e9d90002ef4ea..d2ea298c79f07 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -6391,13 +6391,14 @@ QualType ASTContext::getDecltypeType(Expr *e, QualType UnderlyingType) const { return QualType(dt, 0); } -QualType ASTContext::getPackIndexingType(QualType Pattern, Expr *IndexExpr, - bool FullySubstituted, - ArrayRef<QualType> Expansions, - int Index) const { +QualType +ASTContext::getPackIndexingType(QualType Pattern, Expr *IndexExpr, + bool FullySubstituted, + ArrayRef<QualType> Expansions, + std::optional<unsigned> SelectedIndex) const { QualType Canonical; - if (FullySubstituted && Index != -1) { - Canonical = getCanonicalType(Expansions[Index]); + if (FullySubstituted && SelectedIndex) { + Canonical = getCanonicalType(Expansions[*SelectedIndex]); } else { llvm::FoldingSetNodeID ID; PackIndexingType::Profile(ID, *this, Pattern.getCanonicalType(), IndexExpr, @@ -14067,9 +14068,7 @@ static QualType getCommonNonSugarTypeNode(ASTContext &Ctx, const Type *X, 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)); + return Ctx.getPipeType(getCommonElementType(Ctx, PX, PY), PX->isReadOnly()); } case Type::TemplateTypeParm: { const auto *TX = cast<TemplateTypeParmType>(X), diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp index e010fd61a34c8..1085639dcb355 100644 --- a/clang/lib/Sema/SemaCXXScopeSpec.cpp +++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -643,8 +643,9 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo, return false; } - QualType T = - Context.getTypeDeclType(cast<TypeDecl>(SD->getUnderlyingDecl())); + QualType T = resugar( + SS.getScopeRep(), + Context.getTypeDeclType(cast<TypeDecl>(SD->getUnderlyingDecl()))); if (T->isEnumeralType()) Diag(IdInfo.IdentifierLoc, diag::warn_cxx98_compat_enum_nested_name_spec); diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp index 6f873cafa98fd..75364a3b2c8b5 100644 --- a/clang/lib/Sema/SemaCoroutine.cpp +++ b/clang/lib/Sema/SemaCoroutine.cpp @@ -113,6 +113,7 @@ static QualType lookupPromiseType(Sema &S, const FunctionDecl *FD, } // The promise type is required to be a class type. QualType PromiseType = S.Context.getTypeDeclType(Promise); + // FIXME: resugar PromiseType. auto buildElaboratedType = [&]() { auto *NNS = NestedNameSpecifier::Create(S.Context, nullptr, S.getStdNamespace()); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 9b7b3f856cc55..a51698950b660 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -139,7 +139,8 @@ class TypeNameValidatorCCC final : public CorrectionCandidateCallback { } // end anonymous namespace -QualType Sema::getTypeDeclType(DeclContext *LookupCtx, DiagCtorKind DCK, +QualType Sema::getTypeDeclType(const NestedNameSpecifier *NNS, + DeclContext *LookupCtx, DiagCtorKind DCK, TypeDecl *TD, SourceLocation NameLoc) { auto *LookupRD = dyn_cast_or_null<CXXRecordDecl>(LookupCtx); auto *FoundRD = dyn_cast<CXXRecordDecl>(TD); @@ -156,7 +157,7 @@ QualType Sema::getTypeDeclType(DeclContext *LookupCtx, DiagCtorKind DCK, DiagnoseUseOfDecl(TD, NameLoc); MarkAnyDeclReferenced(TD->getLocation(), TD, /*OdrUse=*/false); - return Context.getTypeDeclType(TD); + return resugar(NNS, Context.getTypeDeclType(TD)); } namespace { @@ -534,7 +535,7 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc, // C++ [class.qual]p2: A lookup that would find the injected-class-name // instead names the constructors of the class, except when naming a class. // This is ill-formed when we're not actually forming a ctor or dtor name. - T = getTypeDeclType(LookupCtx, + T = getTypeDeclType(SS ? SS->getScopeRep() : nullptr, LookupCtx, IsImplicitTypename ? DiagCtorKind::Implicit : DiagCtorKind::None, TD, NameLoc); @@ -9865,7 +9866,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (D.isFirstDeclarationOfMember()) adjustMemberFunctionCC( R, !(D.isStaticMember() || D.isExplicitObjectMemberFunction()), - D.isCtorOrDtor(), D.getIdentifierLoc()); + D.isCtorOrDtor(), /*IsDeduced=*/false, D.getIdentifierLoc()); bool isFriend = false; FunctionTemplateDecl *FunctionTemplate = nullptr; diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 171a266494f82..928bf47285490 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -1246,7 +1246,7 @@ static QualType getTupleLikeElementType(Sema &S, SourceLocation Loc, S.Diag(R.getRepresentativeDecl()->getLocation(), diag::note_declared_at); return QualType(); } - + // FIXME: resugar return S.Context.getTypeDeclType(TD); } diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index dbc5a721ee8d0..5652b4548895a 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -18,6 +18,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/TemplateName.h" +#include "clang/AST/TypeOrdering.h" #include "clang/AST/TypeVisitor.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/DiagnosticSema.h" @@ -93,6 +94,738 @@ unsigned Sema::getTemplateDepth(Scope *S) const { return Depth; } +namespace { + +class NameMap { + llvm::DenseMap<const Decl *, ArrayRef<TemplateArgument>> Map; + + void insert(const Decl *AssociatedDecl, ArrayRef<TemplateArgument> Args) { + assert(!Args.empty()); + Map.try_emplace(AssociatedDecl->getCanonicalDecl(), Args); + } + +public: + NameMap() = default; + + const TemplateArgument *getArgument(const Decl *AssociatedDecl, + unsigned Index, + std::optional<unsigned> PackIndex) const { + auto It = Map.find(AssociatedDecl); + if (It == Map.end()) + return nullptr; + ArrayRef<TemplateArgument> Args = It->second; + assert(Index < Args.size()); + const TemplateArgument &Arg = Args[Index]; + if (!PackIndex) + return &Arg; + ArrayRef<TemplateArgument> PackArgs = Arg.getPackAsArray(); + assert(*PackIndex < PackArgs.size()); + return &PackArgs[PackArgs.size() - 1 - *PackIndex]; + } + + void insert(Sema &SemaRef, const Type *T) { + const Type *CanonT = T->getCanonicalTypeInternal().getTypePtr(); + if (auto TC = CanonT->getTypeClass(); TC != Type::Record) { + assert(TC == Type::Enum || TC == Type::InjectedClassName || + T->isDependentType()); + return; + } + const auto *TS = T->getAsNonAliasTemplateSpecializationType(); + if (!TS) + return; + auto *CTSD = cast<ClassTemplateSpecializationDecl>( + cast<RecordType>(CanonT)->getDecl()); + auto PU = CTSD->getInstantiatedFrom(); + if (PU.isNull()) + return; + + ArrayRef<TemplateArgument> Args = TS->getConvertedArguments(); + auto *CTPSD = PU.dyn_cast<ClassTemplatePartialSpecializationDecl *>(); + if (!CTPSD) + return insert(CTSD, Args); + // FIXME: Don't deduce partial specialization args on resugaring. + TemplateParameterList *TPL = CTPSD->getTemplateParameters(); + TemplateDeductionInfo Info(SourceLocation(), TPL->getDepth()); + [[maybe_unused]] TemplateDeductionResult Res = + SemaRef.DeduceTemplateArguments(CTPSD, Args, Info); + assert(Res == TemplateDeductionResult::Success); + insert(CTSD, Info.takeSugared()->asArray()); + } + + void insert(Sema &SemaRef, const NestedNameSpecifier *NNS) { + for (/**/; NNS; NNS = NNS->getPrefix()) { + switch (NNS->getKind()) { + case NestedNameSpecifier::Global: + case NestedNameSpecifier::Namespace: + case NestedNameSpecifier::NamespaceAlias: + case NestedNameSpecifier::Super: + return; + case NestedNameSpecifier::Identifier: + continue; + case NestedNameSpecifier::TypeSpec: + insert(SemaRef, NNS->getAsType()); + continue; + } + llvm_unreachable("Unknown NestedNameSpecifier Kind"); + } + } + + bool empty() const { return Map.empty(); } +}; + +class Resugarer { + Sema &SemaRef; + const NameMap *Names; + llvm::DenseMap<QualType, QualType> CacheTypes; + +public: + Resugarer(Sema &SemaRef, const NameMap &Names) + : SemaRef(SemaRef), Names(&Names) {} + + template <class T> + SmallVector<T, 4> transform(ArrayRef<T> Es, bool &Changed) { + SmallVector<T, 4> TransformedEs(Es); + for (auto &E : TransformedEs) + E = transform(E, Changed); + return TransformedEs; + } + + NestedNameSpecifier *transform(NestedNameSpecifier *NNS, bool &OutChanged) { + if (!NNS) + return NNS; + + bool Changed = false; + switch (NNS->getKind()) { + case NestedNameSpecifier::Global: + case NestedNameSpecifier::Namespace: + case NestedNameSpecifier::NamespaceAlias: + case NestedNameSpecifier::Super: + return NNS; + case NestedNameSpecifier::Identifier: { + NestedNameSpecifier *Prefix = transform(NNS->getPrefix(), Changed); + if (!Changed) + return NNS; + OutChanged = true; + return NestedNameSpecifier::Create(SemaRef.Context, Prefix, + NNS->getAsIdentifier()); + } + case NestedNameSpecifier::TypeSpec: { + const Type *T = + transform(QualType(NNS->getAsType(), 0), Changed).getTypePtr(); + NestedNameSpecifier *Prefix; + if (const auto *ET = dyn_cast<ElaboratedType>(T)) { + Prefix = transform(ET->getQualifier(), Changed); + T = ET->getNamedType().getTypePtr(); + } else { + Prefix = transform(NNS->getPrefix(), Changed); + } + if (!Changed) + return NNS; + OutChanged = true; + return NestedNameSpecifier::Create(SemaRef.Context, Prefix, T); + } + } + llvm_unreachable("Unknown NestedNameSpecifier Kind"); + } + + TemplateName transform(TemplateName TN, bool &OutChanged) { + auto build = [&](TemplateName NewTN) { + assert(SemaRef.Context.hasSameTemplateName(TN, NewTN)); + OutChanged = true; + return NewTN; + }; + + bool Changed = false; + switch (TN.getKind()) { + case TemplateName::AssumedTemplate: + case TemplateName::OverloadedTemplate: + case TemplateName::Template: + case TemplateName::UsingTemplate: + return TN; + case TemplateName::DeducedTemplate: { + const auto *DTN = TN.getAsDeducedTemplateName(); + TemplateName Underlying = transform(DTN->getUnderlying(), Changed); + DefaultArguments DefaultArgs = DTN->getDefaultArguments(); + auto Args = transform(DefaultArgs.Args, Changed); + DefaultArgs.Args = Args; + if (!Changed) + return TN; + return build( + SemaRef.Context.getDeducedTemplateName(Underlying, DefaultArgs)); + } + case TemplateName::DependentTemplate: { + const auto *DTN = TN.getAsDependentTemplateName(); + NestedNameSpecifier *NNS = transform(DTN->getQualifier(), Changed); + if (!Changed) + return TN; + return build(SemaRef.Context.getDependentTemplateName( + {NNS, DTN->getName(), DTN->hasTemplateKeyword()})); + } + case TemplateName::QualifiedTemplate: { + const auto *QTN = TN.getAsQualifiedTemplateName(); + NestedNameSpecifier *NNS = transform(QTN->getQualifier(), Changed); + TemplateName UTN = transform(QTN->getUnderlyingTemplate(), Changed); + if (!Changed) + return TN; + return build(SemaRef.Context.getQualifiedTemplateName( + NNS, QTN->hasTemplateKeyword(), UTN)); + } + case TemplateName::SubstTemplateTemplateParm: { + const auto *STN = TN.getAsSubstTemplateTemplateParm(); + TemplateName RTN; + if (STN->getFinal()) { + RTN = transform(STN->getReplacement(), Changed); + if (!Changed) + return TN; + } else { + const TemplateArgument *Arg = Names->getArgument( + STN->getAssociatedDecl(), STN->getIndex(), STN->getPackIndex()); + if (!Arg) + return TN; + RTN = Arg->getAsTemplate(); + } + return build(SemaRef.Context.getSubstTemplateTemplateParm( + RTN, STN->getAssociatedDecl(), STN->getIndex(), STN->getPackIndex(), + /*Final=*/true)); + } + case TemplateName::SubstTemplateTemplateParmPack: { + const auto *STNP = TN.getAsSubstTemplateTemplateParmPack(); + TemplateArgument Pack = transform(STNP->getArgumentPack(), Changed); + if (!Changed) + return TN; + return build(SemaRef.Context.getSubstTemplateTemplateParmPack( + Pack, STNP->getAssociatedDecl(), STNP->getIndex(), STNP->getFinal())); + } + } + llvm_unreachable("Unhandled TemplateName kind"); + } + + QualType buildType(QualType Orig, const Type *Ty, Qualifiers Quals) { + QualType NewT = SemaRef.Context.getQualifiedType(Ty, Quals); + assert(SemaRef.Context.hasSameType(Orig, NewT)); + CacheTypes.find(Orig)->second = NewT; + return NewT; + } + + QualType transform(QualType TT, bool &OutChanged) { + if (TT.isNull() || TT.isCanonical()) + return TT; + + if (auto [It, Created] = CacheTypes.try_emplace(TT, TT); !Created) { + QualType NewT = It->second; + OutChanged |= (NewT != TT); + return NewT; + } + + SplitQualType ST = TT.split(); + auto build = [&](QualType T) { + OutChanged = true; + return buildType(TT, T.getTypePtr(), ST.Quals); + }; + + bool Changed = false; + switch (ST.Ty->getTypeClass()) { + case Type::Adjusted: { + const auto *T = cast<AdjustedType>(ST.Ty); + QualType OT = transform(T->getOriginalType(), Changed); + // FIXME: Handle AdjustedType. + if (!Changed) + return TT; + return build(SemaRef.Context.getAdjustedType(OT, T->getAdjustedType())); + } + case Type::Atomic: { + const auto *T = cast<AtomicType>(ST.Ty); + QualType VT = transform(T->getValueType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getAtomicType(VT)); + } + case Type::Attributed: { + const auto *T = cast<AttributedType>(ST.Ty); + QualType MT = transform(T->getModifiedType(), Changed); + // FIXME: Handle EquivalentType. + if (!Changed) + return TT; + return build(SemaRef.Context.getAttributedType(T->getAttrKind(), MT, + T->getEquivalentType())); + } + case Type::Auto: { + const auto *T = cast<AutoType>(ST.Ty); + auto Args = transform(T->getTypeConstraintArguments(), Changed); + QualType DT = transform(T->getDeducedType(), Changed); + if (!Changed) + return TT; + return build( + SemaRef.Context.getAutoType(DT, T->getKeyword(), DT.isNull(), + T->containsUnexpandedParameterPack(), + T->getTypeConstraintConcept(), Args)); + } + case Type::BitInt: + return TT; + case Type::BlockPointer: { + const auto *T = cast<BlockPointerType>(ST.Ty); + QualType PT = transform(T->getPointeeType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getBlockPointerType(PT)); + } + case Type::Builtin: + return TT; + case Type::BTFTagAttributed: { + const auto *T = cast<BTFTagAttributedType>(ST.Ty); + QualType WT = transform(T->getWrappedType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getBTFTagAttributedType(T->getAttr(), WT)); + } + case Type::Complex: { + const auto *T = cast<ComplexType>(ST.Ty); + QualType ET = transform(T->getElementType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getComplexType(ET)); + } + case Type::ConstantArray: { + const auto *T = cast<ConstantArrayType>(ST.Ty); + QualType ET = transform(T->getElementType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getConstantArrayType( + ET, T->getSize(), T->getSizeExpr(), T->getSizeModifier(), + T->getIndexTypeCVRQualifiers())); + } + case Type::ConstantMatrix: { + const auto *T = cast<ConstantMatrixType>(ST.Ty); + QualType ET = transform(T->getElementType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getConstantMatrixType(ET, T->getNumRows(), + T->getNumColumns())); + } + case Type::Decltype: { + const auto *T = cast<DecltypeType>(ST.Ty); + QualType UT = transform(T->getUnderlyingType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getDecltypeType(T->getUnderlyingExpr(), UT)); + } + case Type::Decayed: { + const auto *T = cast<DecayedType>(ST.Ty); + QualType OT = transform(T->getOriginalType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getDecayedType(OT)); + } + case Type::DeducedTemplateSpecialization: { + const auto *T = cast<DeducedTemplateSpecializationType>(ST.Ty); + TemplateName TN = transform(T->getTemplateName(), Changed); + QualType DT = transform(T->getDeducedType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getDeducedTemplateSpecializationType( + TN, DT, DT.isNull())); + } + case Type::DependentAddressSpace: { + const auto *T = cast<DependentAddressSpaceType>(ST.Ty); + QualType PT = transform(T->getPointeeType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getDependentAddressSpaceType( + PT, T->getAddrSpaceExpr(), T->getAttributeLoc())); + } + case Type::DependentBitInt: + return TT; + case Type::DependentName: { + const auto *T = cast<DependentNameType>(ST.Ty); + NestedNameSpecifier *NNS = transform(T->getQualifier(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getDependentNameType(T->getKeyword(), NNS, + T->getIdentifier())); + } + case Type::DependentSizedArray: { + const auto *T = cast<DependentSizedArrayType>(ST.Ty); + QualType ET = transform(T->getElementType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getDependentSizedArrayType( + ET, T->getSizeExpr(), T->getSizeModifier(), + T->getIndexTypeCVRQualifiers(), T->getBracketsRange())); + } + case Type::DependentSizedExtVector: { + const auto *T = cast<DependentSizedExtVectorType>(ST.Ty); + QualType ET = transform(T->getElementType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getDependentSizedExtVectorType( + ET, T->getSizeExpr(), T->getAttributeLoc())); + } + case Type::DependentSizedMatrix: { + const auto *T = cast<DependentSizedMatrixType>(ST.Ty); + QualType ET = transform(T->getElementType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getDependentSizedMatrixType( + ET, T->getRowExpr(), T->getColumnExpr(), T->getAttributeLoc())); + } + case Type::DependentVector: { + const auto *T = cast<DependentVectorType>(ST.Ty); + QualType ET = transform(T->getElementType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getDependentVectorType( + ET, T->getSizeExpr(), T->getAttributeLoc(), T->getVectorKind())); + } + case Type::DependentTemplateSpecialization: { + const auto *T = cast<DependentTemplateSpecializationType>(ST.Ty); + const DependentTemplateStorage &S = T->getDependentTemplateName(); + auto SpecArgs = transform(T->template_arguments(), Changed); + NestedNameSpecifier *NNS = transform(S.getQualifier(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getDependentTemplateSpecializationType( + T->getKeyword(), {NNS, S.getName(), S.hasTemplateKeyword()}, + SpecArgs)); + } + case Type::Elaborated: { + const auto *T = cast<ElaboratedType>(ST.Ty); + NestedNameSpecifier *NNS = transform(T->getQualifier(), Changed); + QualType NT = transform(T->getNamedType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getElaboratedType(T->getKeyword(), NNS, NT, + T->getOwnedTagDecl())); + } + case Type::Enum: + // FIXME: Resugar. + return TT; + case Type::ExtVector: { + const auto *T = cast<ExtVectorType>(ST.Ty); + QualType ET = transform(T->getElementType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getExtVectorType(ET, T->getNumElements())); + } + case Type::FunctionNoProto: { + const auto *T = cast<FunctionNoProtoType>(ST.Ty); + QualType RT = transform(T->getReturnType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getFunctionNoProtoType(RT, T->getExtInfo())); + } + case Type::FunctionProto: { + const auto *T = cast<FunctionProtoType>(ST.Ty); + FunctionProtoType::ExtProtoInfo EPI = T->getExtProtoInfo(); + QualType RT = transform(T->getReturnType(), Changed); + auto Ps = transform(T->param_types(), Changed); + auto Es = transform(EPI.ExceptionSpec.Exceptions, Changed); + if (!Changed) + return TT; + EPI.ExceptionSpec.Exceptions = Es; + return build(SemaRef.Context.getFunctionType(RT, Ps, EPI)); + } + case Type::IncompleteArray: { + const auto *T = cast<IncompleteArrayType>(ST.Ty); + QualType ET = transform(T->getElementType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getIncompleteArrayType( + ET, T->getSizeModifier(), T->getIndexTypeCVRQualifiers())); + } + case Type::InjectedClassName: { + const auto *T = cast<InjectedClassNameType>(ST.Ty); + QualType TST = transform(T->getInjectedSpecializationType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getInjectedClassNameType(T->getDecl(), TST)); + } + case Type::LValueReference: { + const auto *T = cast<LValueReferenceType>(ST.Ty); + QualType PT = transform(T->getPointeeTypeAsWritten(), Changed); + if (!Changed) + return TT; + return build( + SemaRef.Context.getLValueReferenceType(PT, T->isSpelledAsLValue())); + } + case Type::MacroQualified: { + const auto *T = cast<MacroQualifiedType>(ST.Ty); + QualType UT = transform(T->getUnderlyingType(), Changed); + if (!Changed) + return TT; + return build( + SemaRef.Context.getMacroQualifiedType(UT, T->getMacroIdentifier())); + } + case Type::MemberPointer: { + const auto *T = cast<MemberPointerType>(ST.Ty); + NestedNameSpecifier *Qualifier = transform(T->getQualifier(), Changed); + QualType PT = transform(T->getPointeeType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getMemberPointerType( + PT, Qualifier, T->getMostRecentCXXRecordDecl())); + } + case Type::ObjCInterface: + return TT; + case Type::ObjCObject: { + const auto *T = cast<ObjCObjectType>(ST.Ty); + QualType BT = transform(T->getBaseType(), Changed); + auto Args = transform(T->getTypeArgs(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getObjCObjectType( + BT, Args, T->getProtocols(), T->isKindOfType())); + } + case Type::ObjCObjectPointer: { + const auto *T = cast<ObjCObjectPointerType>(ST.Ty); + QualType PT = transform(T->getPointeeType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getObjCObjectPointerType(PT)); + } + case Type::ObjCTypeParam: + return TT; + case Type::PackExpansion: { + const auto *T = cast<PackExpansionType>(ST.Ty); + QualType P = transform(T->getPattern(), Changed); + if (!Changed) + return TT; + return build( + SemaRef.Context.getPackExpansionType(P, T->getNumExpansions())); + } + case Type::Paren: { + const auto *T = cast<ParenType>(ST.Ty); + QualType IT = transform(T->getInnerType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getParenType(IT)); + } + case Type::Pipe: { + const auto *T = cast<PipeType>(ST.Ty); + QualType ET = transform(T->getElementType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getPipeType(ET, T->isReadOnly())); + } + case Type::Pointer: { + const auto *T = cast<PointerType>(ST.Ty); + QualType PT = transform(T->getPointeeType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getPointerType(PT)); + } + case Type::Record: + return TT; + case Type::RValueReference: { + const auto *T = cast<RValueReferenceType>(ST.Ty); + QualType PT = transform(T->getPointeeTypeAsWritten(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getRValueReferenceType(PT)); + } + case Type::SubstTemplateTypeParm: { + const auto *T = cast<SubstTemplateTypeParmType>(ST.Ty); + QualType RT; + if (T->getFinal()) { + RT = transform(T->getReplacementType(), Changed); + if (!Changed) + return TT; + } else { + const TemplateArgument *Arg = Names->getArgument( + T->getAssociatedDecl(), T->getIndex(), T->getPackIndex()); + if (!Arg) + return TT; + RT = Arg->getAsType(); + } + return build(SemaRef.Context.getSubstTemplateTypeParmType( + RT, T->getAssociatedDecl(), T->getIndex(), T->getPackIndex(), + /*Final=*/true)); + } + case Type::SubstTemplateTypeParmPack: { + const auto *T = cast<SubstTemplateTypeParmPackType>(ST.Ty); + TemplateArgument P = transform(T->getArgumentPack(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getSubstTemplateTypeParmPackType( + T->getAssociatedDecl(), T->getIndex(), T->getFinal(), P)); + } + case Type::TemplateTypeParm: + return TT; + case Type::TemplateSpecialization: { + const auto *T = cast<TemplateSpecializationType>(ST.Ty); + TemplateName TN = transform(T->getTemplateName(), Changed); + auto SpecArgs = transform(T->getSpecifiedArguments(), Changed); + auto ConvertedArgs = transform(T->getConvertedArguments(), Changed); + QualType UT = T->desugar(); + if (T->isTypeAlias()) + UT = transform(UT, Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getTemplateSpecializationType( + TN, SpecArgs, ConvertedArgs, + /*CanonicalConvertedArgs=*/std::nullopt, UT)); + } + case Type::Typedef: { + const auto *T = cast<TypedefType>(ST.Ty); + QualType Underlying = transform(T->desugar(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getTypedefType(T->getDecl(), Underlying)); + } + case Type::TypeOfExpr: + // FIXME: Resugar. + return TT; + case Type::TypeOf: { + const auto *T = cast<TypeOfType>(ST.Ty); + QualType UT = transform(T->getUnmodifiedType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getTypeOfType(UT, T->getKind())); + } + case Type::UnaryTransform: { + const auto *T = cast<UnaryTransformType>(ST.Ty); + QualType UT = transform(T->getUnderlyingType(), Changed); + if (!Changed) + return TT; + // FIXME: Handle BaseType. + return build(SemaRef.Context.getUnaryTransformType(T->getBaseType(), UT, + T->getUTTKind())); + } + case Type::UnresolvedUsing: + return TT; + case Type::Using: { + const auto *T = cast<UsingType>(ST.Ty); + QualType Underlying = transform(T->desugar(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getUsingType(T->getFoundDecl(), Underlying)); + } + case Type::VariableArray: { + const auto *T = cast<VariableArrayType>(ST.Ty); + QualType ET = transform(T->getElementType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getVariableArrayType( + ET, T->getSizeExpr(), T->getSizeModifier(), + T->getIndexTypeCVRQualifiers(), T->getBracketsRange())); + } + case Type::Vector: { + const auto *T = cast<VectorType>(ST.Ty); + QualType ET = transform(T->getElementType(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getVectorType(ET, T->getNumElements(), + T->getVectorKind())); + } + case Type::ArrayParameter: { + const auto *T = cast<ArrayParameterType>(ST.Ty); + QualType Ty = + transform(T->getConstantArrayType(SemaRef.Context), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getArrayParameterType(Ty)); + } + case Type::CountAttributed: { + const auto *T = cast<CountAttributedType>(ST.Ty); + QualType Ty = transform(T->desugar(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getCountAttributedType( + Ty, T->getCountExpr(), T->isCountInBytes(), T->isOrNull(), + T->getCoupledDecls())); + } + case Type::HLSLAttributedResource: + return TT; + case Type::PackIndexing: { + const auto *T = cast<PackIndexingType>(ST.Ty); + QualType Pattern = transform(T->getPattern(), Changed); + auto Expansions = transform(T->getExpansions(), Changed); + if (!Changed) + return TT; + return build(SemaRef.Context.getPackIndexingType( + Pattern, T->getIndexExpr(), T->isFullySubstituted(), Expansions, + T->getSelectedIndex())); + } + } + llvm_unreachable("Unhandled TypeClass"); + } + + TemplateArgument transform(TemplateArgument A, bool &OutChanged) { + bool Changed = false; + switch (auto Kind = A.getKind()) { + case TemplateArgument::Null: + llvm_unreachable("Unexpected Null TemplateArgument"); + case TemplateArgument::Pack: { + ArrayRef<TemplateArgument> PackArray = A.getPackAsArray(); + if (PackArray.empty()) + return A; + auto Pack = PackArray.copy(SemaRef.Context); + for (auto &PA : Pack) + PA = transform(PA, Changed); + if (!Changed) + return A; + OutChanged = true; + return TemplateArgument(Pack); + } + case TemplateArgument::Integral: + case TemplateArgument::NullPtr: + case TemplateArgument::Declaration: + case TemplateArgument::StructuralValue: { + QualType T = transform(A.getNonTypeTemplateArgumentType(), Changed); + if (!Changed) + return A; + OutChanged = true; + switch (A.getKind()) { + case TemplateArgument::Integral: + return TemplateArgument(SemaRef.Context, A.getAsIntegral(), T); + case TemplateArgument::NullPtr: + return TemplateArgument(T, /*IsNullPtr=*/true); + case TemplateArgument::Declaration: + return TemplateArgument(A.getAsDecl(), T); + case TemplateArgument::StructuralValue: + return TemplateArgument(SemaRef.Context, T, A.getAsStructuralValue()); + default: + llvm_unreachable("Not handled case"); + } + } + case TemplateArgument::Type: { + QualType T = transform(A.getAsType(), Changed); + if (!Changed) + return A; + OutChanged = true; + return TemplateArgument(T); + } + case TemplateArgument::Template: + case TemplateArgument::TemplateExpansion: { + TemplateName TN = transform(A.getAsTemplateOrTemplatePattern(), Changed); + if (!Changed) + return A; + OutChanged = true; + return Kind == TemplateArgument::Template + ? TemplateArgument(TN) + : TemplateArgument(TN, A.getNumTemplateExpansions()); + } + case TemplateArgument::Expression: + // FIXME: convert the type of these. + return A; + } + llvm_unreachable("Unexpected TemplateArgument kind"); + } +}; +} // namespace + +QualType Sema::resugar(const NestedNameSpecifier *NNS, QualType T) { + if (NNS == nullptr) + return T; + + NameMap Names; + Names.insert(*this, NNS); + if (Names.empty()) + return T; + + bool Changed = false; + return Resugarer(*this, Names).transform(T, Changed); +} + /// \brief Determine whether the declaration found is acceptable as the name /// of a template and, if so, return that template declaration. Otherwise, /// returns null. @@ -10929,7 +11662,7 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, // // FIXME: That's not strictly true: mem-initializer-id lookup does not // ignore functions, but that appears to be an oversight. - QualType T = getTypeDeclType(Ctx, + QualType T = getTypeDeclType(SS.getScopeRep(), Ctx, Keyword == ElaboratedTypeKeyword::Typename ? DiagCtorKind::Typename : DiagCtorKind::None, diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 76d388062b664..0faf9cb405b09 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -2091,11 +2091,13 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( QualType PPT = MPP->getPointeeType(); if (PPT->isFunctionType()) S.adjustMemberFunctionCC(PPT, /*HasThisPointer=*/false, - /*IsCtorOrDtor=*/false, Info.getLocation()); + /*IsCtorOrDtor=*/false, /*IsDeduced=*/true, + Info.getLocation()); QualType APT = MPA->getPointeeType(); if (APT->isFunctionType()) S.adjustMemberFunctionCC(APT, /*HasThisPointer=*/false, - /*IsCtorOrDtor=*/false, Info.getLocation()); + /*IsCtorOrDtor=*/false, /*IsDeduced=*/true, + Info.getLocation()); unsigned SubTDF = TDF & TDF_IgnoreQualifiers; if (auto Result = DeduceTemplateArgumentsByTypeMatch( diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 5dfd102f340f5..277045c5606bb 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -2739,7 +2739,8 @@ QualType Sema::BuildMemberPointerType(QualType T, const CXXScopeSpec &SS, (Entity.getNameKind() == DeclarationName::CXXConstructorName) || (Entity.getNameKind() == DeclarationName::CXXDestructorName); if (T->isFunctionType()) - adjustMemberFunctionCC(T, /*HasThisPointer=*/true, IsCtorOrDtor, Loc); + adjustMemberFunctionCC(T, /*HasThisPointer=*/true, IsCtorOrDtor, + /*IsDeduced=*/false, Loc); return Context.getMemberPointerType(T, SS.getScopeRep(), Cls); } @@ -8123,7 +8124,8 @@ bool Sema::hasExplicitCallingConv(QualType T) { } void Sema::adjustMemberFunctionCC(QualType &T, bool HasThisPointer, - bool IsCtorOrDtor, SourceLocation Loc) { + bool IsCtorOrDtor, bool IsDeduced, + SourceLocation Loc) { FunctionTypeUnwrapper Unwrapped(*this, T); const FunctionType *FT = Unwrapped.get(); bool IsVariadic = (isa<FunctionProtoType>(FT) && @@ -8155,7 +8157,7 @@ void Sema::adjustMemberFunctionCC(QualType &T, bool HasThisPointer, if (CurCC != DefaultCC) return; - if (hasExplicitCallingConv(T)) + if (!IsDeduced && hasExplicitCallingConv(T)) return; } @@ -9701,7 +9703,7 @@ QualType Sema::BuildPackIndexingType(QualType Pattern, Expr *IndexExpr, } return Context.getPackIndexingType(Pattern, IndexExpr, FullySubstituted, - Expansions, Index.value_or(-1)); + Expansions, Index); } static QualType GetEnumUnderlyingType(Sema &S, QualType BaseType, diff --git a/clang/test/AST/ast-dump-openmp-begin-declare-variant_reference.cpp b/clang/test/AST/ast-dump-openmp-begin-declare-variant_reference.cpp index 1937a5d1c3eb3..de1cd14fc2f26 100644 --- a/clang/test/AST/ast-dump-openmp-begin-declare-variant_reference.cpp +++ b/clang/test/AST/ast-dump-openmp-begin-declare-variant_reference.cpp @@ -195,7 +195,7 @@ int test(float &&f, short &&s) { // CHECK-NEXT: | | | `-ElaboratedType [[ADDR_47:0x[a-z0-9]*]] 'typename remove_reference<float &>::type' sugar // CHECK-NEXT: | | | `-TypedefType [[ADDR_48:0x[a-z0-9]*]] 'remove_reference<float &>::type' sugar // CHECK-NEXT: | | | |-Typedef [[ADDR_10]] 'type' -// CHECK-NEXT: | | | `-SubstTemplateTypeParmType [[ADDR_11]] 'float' sugar class depth 0 index 0 _Tp +// CHECK-NEXT: | | | `-SubstTemplateTypeParmType [[ADDR_195:0x[a-z0-9]*]] 'float' sugar class depth 0 index 0 _Tp final // CHECK-NEXT: | | | |-ClassTemplateSpecialization [[ADDR_6]] 'remove_reference' // CHECK-NEXT: | | | `-BuiltinType [[ADDR_8]] 'float' // CHECK-NEXT: | | `-ReturnStmt [[ADDR_49:0x[a-z0-9]*]] <line:13:3, col:33> @@ -212,7 +212,7 @@ int test(float &&f, short &&s) { // CHECK-NEXT: | | `-ElaboratedType [[ADDR_57:0x[a-z0-9]*]] 'typename remove_reference<short &>::type' sugar // CHECK-NEXT: | | `-TypedefType [[ADDR_58:0x[a-z0-9]*]] 'remove_reference<short &>::type' sugar // CHECK-NEXT: | | |-Typedef [[ADDR_18]] 'type' -// CHECK-NEXT: | | `-SubstTemplateTypeParmType [[ADDR_19]] 'short' sugar class depth 0 index 0 _Tp +// CHECK-NEXT: | | `-SubstTemplateTypeParmType [[ADDR_196:0x[a-z0-9]*]] 'short' sugar class depth 0 index 0 _Tp final // CHECK-NEXT: | | |-ClassTemplateSpecialization [[ADDR_14]] 'remove_reference' // CHECK-NEXT: | | `-BuiltinType [[ADDR_16]] 'short' // CHECK-NEXT: | `-ReturnStmt [[ADDR_59:0x[a-z0-9]*]] <line:13:3, col:33> diff --git a/clang/test/AST/ast-dump-template-name.cpp b/clang/test/AST/ast-dump-template-name.cpp index acacdac857954..245ae7c102753 100644 --- a/clang/test/AST/ast-dump-template-name.cpp +++ b/clang/test/AST/ast-dump-template-name.cpp @@ -53,8 +53,8 @@ namespace subst { // CHECK-NEXT: `-TemplateSpecializationType // CHECK-NEXT: |-name: 'C':'subst::B<subst::A>::C' qualified // CHECK-NEXT: | `-ClassTemplateDecl {{.+}} C -// CHECK-NEXT: |-TemplateArgument template 'subst::A' subst index 0 -// CHECK-NEXT: | |-parameter: TemplateTemplateParmDecl {{.+}} depth 0 index 0 TT{{$}} -// CHECK-NEXT: | |-associated ClassTemplateSpecialization {{.+}} 'B'{{$}} -// CHECK-NEXT: | `-replacement: +// CHECK-NEXT: |-TemplateArgument template 'A':'subst::A' subst index 0 final +// CHECK-NEXT: | |-parameter: TemplateTemplateParmDecl {{.+}} col:36 depth 0 index 0 TT +// CHECK-NEXT: | |-associated ClassTemplateSpecialization {{.+}} 'B' +// CHECK-NEXT: | `-replacement: 'A':'subst::A' qualified // CHECK-NEXT: | `-ClassTemplateDecl {{.+}} A{{$}} diff --git a/clang/test/CXX/temp/temp.param/p15-cxx0x.cpp b/clang/test/CXX/temp/temp.param/p15-cxx0x.cpp index 83144a494937b..556bc10eef5af 100644 --- a/clang/test/CXX/temp/temp.param/p15-cxx0x.cpp +++ b/clang/test/CXX/temp/temp.param/p15-cxx0x.cpp @@ -97,14 +97,14 @@ template<unsigned N, typename...Ts> struct drop { using T1 = take<3, int, char, double, long>::type; // expected-note {{previous}} // FIXME: Desguar the types on the RHS in this diagnostic. // desired-error {{'types<void, void, void, void>' vs 'types<int, char, double, (no argument)>'}} -using T1 = types<void, void, void, void>; // expected-error {{'types<void, void, void, void>' vs 'types<typename inner<_>::type, typename inner<_>::type, typename inner<_>::type, (no argument)>'}} +using T1 = types<void, void, void, void>; // expected-error {{'types<void, void, void, void>' vs 'types<typename template inner<_>::type, typename template inner<_>::type, typename template inner<_>::type, (no argument)>}} using D1 = drop<3, int, char, double, long>::type; using D1 = types<long>; using T2 = take<4, int, char, double, long>::type; // expected-note {{previous}} // FIXME: Desguar the types on the RHS in this diagnostic. // desired-error {{'types<void, void, void, void>' vs 'types<int, char, double, long>'}} -using T2 = types<void, void, void, void>; // expected-error {{'types<void, void, void, void>' vs 'types<typename inner<_>::type, typename inner<_>::type, typename inner<_>::type, typename inner<_>::type>'}} +using T2 = types<void, void, void, void>; // expected-error {{'types<void, void, void, void>' vs 'types<typename template inner<_>::type, typename template inner<_>::type, typename template inner<_>::type, typename template inner<_>::type>'}} using T2 = types<int, char, double, long>; using D2 = drop<4, int, char, double, long>::type; using D2 = types<>; diff --git a/clang/test/Sema/Resugar/resugar-types.cpp b/clang/test/Sema/Resugar/resugar-types.cpp new file mode 100644 index 0000000000000..baa3b4ed65f20 --- /dev/null +++ b/clang/test/Sema/Resugar/resugar-types.cpp @@ -0,0 +1,209 @@ +// RUN: %clang_cc1 -std=c++2b -fms-extensions -verify %s +// expected-no-diagnostics + +static constexpr int alignment = 64; // Suitable large alignment. + +struct Baz {}; +using Bar [[gnu::aligned(alignment)]] = Baz; +using Int [[gnu::aligned(alignment)]] = int; + +#define TEST(X) static_assert(alignof(X) == alignment) +#define TEST_NOT(X) static_assert(alignof(X) != alignment) + +// Sanity checks. +TEST_NOT(Baz); +TEST(Bar); + +namespace t1 { +template <class T> struct foo { using type = T; }; +template <class U> struct foo<U &> { using type = U; }; + +TEST(typename foo<Bar>::type); +TEST(typename foo<Bar &>::type); +} // namespace t1 + +namespace t2 { +template <int, class T> struct foo1 { using type = T; }; +template <class T> struct foo2 { using type = typename foo1<1, T>::type; }; +TEST(typename foo2<Bar>::type); +} // namespace t2 + +namespace t3 { +template <class T> struct foo1 { + template <int, class U> struct foo2 { using type1 = T; }; + using type2 = typename foo2<1, int>::type1; +}; +TEST(typename foo1<Bar>::type2); +} // namespace t3 + +namespace t4 { +template <class T> struct foo { + template <class U> using type1 = T; + using type2 = type1<int>; +}; +TEST(typename foo<Bar>::type2); +} // namespace t4 + +namespace t5 { +template <class T> struct foo { + template <int, class U> using type1 = U; + using type2 = type1<1, T>; +}; +TEST(typename foo<Bar>::type2); +} // namespace t5 + +namespace t6 { +template <class T> struct foo1 { + template <int, class U> struct foo2 { using type = U; }; + using type2 = typename foo2<1, T>::type; +}; +TEST(typename foo1<Bar>::type2); +}; // namespace t6 + +namespace t7 { +template <class T> struct foo { + template <int, class U> using type1 = U; +}; +using type2 = typename foo<int>::template type1<1, Bar>; +TEST(type2); +} // namespace t7 + +namespace t8 { +template <class T> struct foo { + using type1 = T; +}; +template <class T, class> using type2 = T; +using type3 = typename type2<foo<Bar>, int>::type1; +TEST(type3); +} // namespace t8 + +namespace t9 { +template <class A, class B> struct Y { + using type1 = A; + using type2 = B; +}; +template <class C, class D> using Z = Y<C, D>; +template <class E> struct foo { + template <class F> using apply = Z<F, E>; +}; +using T1 = foo<Bar>::apply<char>; +TEST_NOT(T1::type1); +TEST_NOT(T1::type2); // FIXME: Needs resugaring on the pattern of template type aliases. + +using T2 = foo<int>::apply<Bar>; +TEST(T2::type1); +TEST_NOT(T2::type2); +} // namespace t9 + +namespace t10 { +template <class A1, class A2> struct Y { + using type1 = A1; + using type2 = A2; +}; +template <typename... Bs> using Z = Y<Bs...>; +template <typename... Cs> struct foo { + template <typename... Ds> using bind = Z<Ds..., Cs...>; +}; +using T1 = foo<Bar>::bind<char>; +TEST_NOT(T1::type1); +TEST_NOT(T1::type2); // FIXME: Needs resugaring on the pattern of template type aliases. + +using T2 = foo<int>::bind<Bar>; +TEST(T2::type1); +TEST_NOT(T2::type2); +} // namespace t10 + +namespace t11 { +template <class A1, class A2 = A1> struct A { using type1 = A2; }; +TEST(A<Bar>::type1); +} // namespace t11 + +namespace t12 { +template <class T> struct W { + template <class Z, template <class Z1, class Z2 = Z1, class Z3 = T> class TT> + struct X { + using type1 = TT<Z>; + }; +}; + +template <class Y1, class Y2, class Y3> struct Y { + using type2 = Y2; + using type3 = Y3; +}; + +using T1 = typename W<Bar>::X<Int, Y>::type1; +TEST(typename T1::type2); +TEST(typename T1::type3); +} // namespace t12 + +namespace t13 { +template <template <typename...> class C, typename... Us> struct foo { + template <typename... Ts> using bind = C<Ts..., Us...>; +}; +template <typename A1, typename A2> struct Y { + using type1 = A1; + using type2 = A2; +}; +template <typename... Ts> using Z = Y<Ts...>; + +using T1 = typename foo<Z, Bar>::template bind<int>; +TEST_NOT(typename T1::type1); +TEST_NOT(typename T1::type2); // FIXME: Needs resugaring on the pattern of template type aliases. + +using T2 = typename foo<Z, int>::template bind<Bar>; +TEST(typename T2::type1); +TEST_NOT(typename T2::type2); +} // namespace t13 + +namespace t14 { +template <int, class A1, class...> struct A { using B = A1; }; +template <class A2, class A3, class... A4> struct A<0, A2, A3, A4...> { + using B = typename A<0, A3, A4...>::B; +}; +using T1 = typename A<0, long, short, Bar>::B; +TEST(T1); +} // namespace t14 + +namespace t15 { +template <class T, T... Ints> struct foo { using type1 = T; }; +using type2 = typename __make_integer_seq<foo, Int, 1>::type1; +TEST(type2); +template <typename T, T N> using type3 = __make_integer_seq<foo, T, N>; +using type4 = type3<Int, 1>::type1; +TEST(type4); +} // namespace t15 + +namespace t16 { +template <class A1> struct A { + using type1 = A1; +}; +using type2 = __type_pack_element<0, A<Bar>>::type1; +TEST(type2); +} // namespace t16 + +namespace t17 { +template <class A1> struct A { + using type1 = A1; +}; +struct C : A<int> { + using A::type1; +}; +TEST(C::A<Bar>::type1); +TEST_NOT(C::A<int>::type1); +TEST(C::A<Int>::type1); +} // namespace t17 + +namespace t18 { +template <class A1> struct A; +template <class B1> struct B {}; +template <class C1> struct A<B<C1>> { + using type1 = C1; +}; +TEST(A<B<Bar>>::type1); +} // namespace t18 + +namespace t19 { +template <class T> struct A { using type = T&; }; + +TEST_NOT(A<Bar __unaligned>::type); +} // namespace t19 diff --git a/lldb/test/API/commands/expression/import-std-module/iterator/TestIteratorFromStdModule.py b/lldb/test/API/commands/expression/import-std-module/iterator/TestIteratorFromStdModule.py index 011906f33caef..8be253cb20cf5 100644 --- a/lldb/test/API/commands/expression/import-std-module/iterator/TestIteratorFromStdModule.py +++ b/lldb/test/API/commands/expression/import-std-module/iterator/TestIteratorFromStdModule.py @@ -22,7 +22,11 @@ def test(self): iter_type = "std::move_iterator<std::__wrap_iter<int *> >" self.expect_expr("move_begin", result_type=iter_type) - self.expect_expr("move_begin[0]", result_type="int", result_value="1") + self.expect_expr( + "move_begin[0]", + result_type="__libcpp_remove_reference_t<__reference>", + result_value="1", + ) self.expect_expr("move_begin + 3 == move_end", result_value="true") _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits