[llvm-branch-commits] [clang] [clang-tools-extra] [lldb] [clang] Template Specialization Resugaring - TypeDecl (PR #132441)
Matheus Izvekov via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Fri Mar 21 11:43:37 PDT 2025
https://github.com/mizvekov updated https://github.com/llvm/llvm-project/pull/132441
>From 4571fada1ea055a845bf5c4eb3d1a20904f768c6 Mon Sep 17 00:00:00 2001
From: Matheus Izvekov <mizvekov at 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 | 722 +++++++++++++++++-
clang/lib/Sema/SemaTemplateDeduction.cpp | 6 +-
clang/lib/Sema/SemaType.cpp | 10 +-
...openmp-begin-declare-variant_reference.cpp | 8 +-
clang/test/AST/ast-dump-template-name.cpp | 7 +-
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, 989 insertions(+), 51 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 ef596f99262be..23d789d8466d3 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;
@@ -1901,10 +1902,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 642881f185c07..56ff0f853a799 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 e215f07e2bf0a..047ba88511dac 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,
@@ -13980,6 +13981,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,
@@ -14972,7 +14975,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 7a44fd4a5dd0e..79bdac607cc2a 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -6385,13 +6385,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,
@@ -14103,9 +14104,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 02cd699addd75..e8fe1cdd7336a 100644
--- a/clang/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp
@@ -644,8 +644,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 53536b0d14037..88d849b27db07 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 043e82414c052..aded29a9daf6d 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);
@@ -9872,7 +9873,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 c90ef04bbbe0a..330afbfa2d19d 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -1248,7 +1248,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 7fe38402300a9..0b26f79ea3bfc 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,725 @@ 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:
+ case NestedNameSpecifier::TypeSpecWithTemplate:
+ 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 (auto K = 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:
+ case NestedNameSpecifier::TypeSpecWithTemplate: {
+ 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,
+ K == NestedNameSpecifier::TypeSpecWithTemplate, 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->getOperator()));
+ }
+ 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();
+ const TemplateArgument *Arg = Names->getArgument(
+ STN->getAssociatedDecl(), STN->getIndex(), STN->getPackIndex());
+ if (!Arg)
+ return TN;
+ return build(Arg->getAsTemplate());
+ }
+ 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);
+ auto SpecArgs = transform(T->template_arguments(), Changed);
+ NestedNameSpecifier *NNS = transform(T->getQualifier(), Changed);
+ if (!Changed)
+ return TT;
+ return build(SemaRef.Context.getDependentTemplateSpecializationType(
+ T->getKeyword(), NNS, T->getIdentifier(), 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);
+ const auto *Arg = Names->getArgument(T->getAssociatedDecl(),
+ T->getIndex(), T->getPackIndex());
+ if (!Arg)
+ return TT;
+
+ SplitQualType Replacement = Arg->getAsType().split();
+ if (ST.Quals.hasObjCLifetime())
+ Replacement.Quals.removeObjCLifetime();
+ OutChanged = true;
+ return buildType(TT, Replacement.Ty, ST.Quals + Replacement.Quals);
+ }
+ 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.
@@ -10947,7 +11667,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 c0dda828d4977..c6e717fa6c5f6 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 59cd7ffadfeb4..664e4c8adcc39 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -2728,7 +2728,8 @@ QualType Sema::BuildMemberPointerType(QualType T,
(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, Qualifier, Cls);
}
@@ -8127,7 +8128,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) &&
@@ -8159,7 +8161,7 @@ void Sema::adjustMemberFunctionCC(QualType &T, bool HasThisPointer,
if (CurCC != DefaultCC)
return;
- if (hasExplicitCallingConv(T))
+ if (!IsDeduced && hasExplicitCallingConv(T))
return;
}
@@ -9711,7 +9713,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..791c753cb2cbc 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,9 +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: | | | |-ClassTemplateSpecialization [[ADDR_6]] 'remove_reference'
-// CHECK-NEXT: | | | `-BuiltinType [[ADDR_8]] 'float'
+// CHECK-NEXT: | | | `-BuiltinType [[ADDR_8]] 'float'
// CHECK-NEXT: | | `-ReturnStmt [[ADDR_49:0x[a-z0-9]*]] <line:13:3, col:33>
// CHECK-NEXT: | | `-CXXStaticCastExpr [[ADDR_50:0x[a-z0-9]*]] <col:10, col:33> '_Up':'float' xvalue static_cast<_Up &&> <NoOp>
// CHECK-NEXT: | | `-DeclRefExpr [[ADDR_51:0x[a-z0-9]*]] <col:30> 'float' {{.*}}ParmVar [[ADDR_43]] '__t' 'float &'
@@ -212,9 +210,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: | | |-ClassTemplateSpecialization [[ADDR_14]] 'remove_reference'
-// CHECK-NEXT: | | `-BuiltinType [[ADDR_16]] 'short'
+// CHECK-NEXT: | | `-BuiltinType [[ADDR_16]] 'short'
// CHECK-NEXT: | `-ReturnStmt [[ADDR_59:0x[a-z0-9]*]] <line:13:3, col:33>
// CHECK-NEXT: | `-CXXStaticCastExpr [[ADDR_60:0x[a-z0-9]*]] <col:10, col:33> '_Up':'short' xvalue static_cast<_Up &&> <NoOp>
// CHECK-NEXT: | `-DeclRefExpr [[ADDR_61:0x[a-z0-9]*]] <col:30> 'short' {{.*}}ParmVar [[ADDR_53]] '__t' 'short &'
diff --git a/clang/test/AST/ast-dump-template-name.cpp b/clang/test/AST/ast-dump-template-name.cpp
index acacdac857954..6fc3dcfc57b29 100644
--- a/clang/test/AST/ast-dump-template-name.cpp
+++ b/clang/test/AST/ast-dump-template-name.cpp
@@ -53,8 +53,5 @@ 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: | `-ClassTemplateDecl {{.+}} A{{$}}
+// CHECK-NEXT: |-TemplateArgument template '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")
More information about the llvm-branch-commits
mailing list