mizvekov retitled this revision from "[clang] Implement Template Specialization 
Resugaring" to "[clang] Template Specialization Resugaring - TypeDecl".
mizvekov edited the summary of this revision.
mizvekov updated this revision to Diff 472416.

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D127695/new/

https://reviews.llvm.org/D127695

Files:
  clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp
  clang/include/clang/AST/ASTContext.h
  clang/include/clang/AST/Type.h
  clang/include/clang/Sema/Sema.h
  clang/lib/AST/ASTContext.cpp
  clang/lib/Sema/SemaCXXScopeSpec.cpp
  clang/lib/Sema/SemaCoroutine.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/lib/Sema/SemaTemplate.cpp
  clang/lib/Sema/SemaTemplateDeduction.cpp
  clang/lib/Sema/SemaType.cpp
  clang/lib/StaticAnalyzer/Checkers/PointerSortingChecker.cpp
  clang/test/AST/ast-dump-openmp-begin-declare-variant_reference.cpp
  clang/test/Sema/Resugar/resugar-types.cpp
  libcxx/DELETE.ME
  
lldb/test/API/commands/expression/import-std-module/iterator/TestIteratorFromStdModule.py

Index: lldb/test/API/commands/expression/import-std-module/iterator/TestIteratorFromStdModule.py
===================================================================
--- lldb/test/API/commands/expression/import-std-module/iterator/TestIteratorFromStdModule.py
+++ lldb/test/API/commands/expression/import-std-module/iterator/TestIteratorFromStdModule.py
@@ -23,7 +23,7 @@
         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")
 
Index: libcxx/DELETE.ME
===================================================================
--- /dev/null
+++ libcxx/DELETE.ME
@@ -0,0 +1 @@
+D127695
Index: clang/test/Sema/Resugar/resugar-types.cpp
===================================================================
--- /dev/null
+++ 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
Index: clang/test/AST/ast-dump-openmp-begin-declare-variant_reference.cpp
===================================================================
--- clang/test/AST/ast-dump-openmp-begin-declare-variant_reference.cpp
+++ clang/test/AST/ast-dump-openmp-begin-declare-variant_reference.cpp
@@ -195,9 +195,7 @@
 // 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 @@
 // 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 &'
Index: clang/lib/StaticAnalyzer/Checkers/PointerSortingChecker.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/PointerSortingChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/PointerSortingChecker.cpp
@@ -79,12 +79,9 @@
                     );
 
   // Match only if the container has pointer-type elements.
-  auto IteratesPointerEltsM = hasArgument(0,
-                                hasType(cxxRecordDecl(has(
-                                  fieldDecl(hasType(hasCanonicalType(
-                                    pointsTo(hasCanonicalType(pointerType()))
-                                  )))
-                              ))));
+  auto IteratesPointerEltsM = hasArgument(
+      0, hasType(hasCanonicalType(hasDeclaration(cxxRecordDecl(has(fieldDecl(
+             hasType(hasCanonicalType(pointsTo(pointerType()))))))))));
 
   auto PointerSortM = traverse(
       TK_AsIs,
Index: clang/lib/Sema/SemaType.cpp
===================================================================
--- clang/lib/Sema/SemaType.cpp
+++ clang/lib/Sema/SemaType.cpp
@@ -3067,7 +3067,8 @@
       (Entity.getNameKind() == DeclarationName::CXXConstructorName) ||
       (Entity.getNameKind() == DeclarationName::CXXDestructorName);
   if (T->isFunctionType())
-    adjustMemberFunctionCC(T, /*IsStatic=*/false, IsCtorOrDtor, Loc);
+    adjustMemberFunctionCC(T, /*IsStatic=*/false, /*isDeduced=*/false,
+                           IsCtorOrDtor, Loc);
 
   return Context.getMemberPointerType(T, Class.getTypePtr());
 }
@@ -7907,7 +7908,7 @@
 }
 
 void Sema::adjustMemberFunctionCC(QualType &T, bool IsStatic, bool IsCtorOrDtor,
-                                  SourceLocation Loc) {
+                                  bool isDeduced, SourceLocation Loc) {
   FunctionTypeUnwrapper Unwrapped(*this, T);
   const FunctionType *FT = Unwrapped.get();
   bool IsVariadic = (isa<FunctionProtoType>(FT) &&
@@ -7938,7 +7939,7 @@
     if (CurCC != DefaultCC || DefaultCC == ToCC)
       return;
 
-    if (hasExplicitCallingConv(T))
+    if (!isDeduced && hasExplicitCallingConv(T))
       return;
   }
 
Index: clang/lib/Sema/SemaTemplateDeduction.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateDeduction.cpp
+++ clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -1889,11 +1889,13 @@
       QualType PPT = MPP->getPointeeType();
       if (PPT->isFunctionType())
         S.adjustMemberFunctionCC(PPT, /*IsStatic=*/true,
-                                 /*IsCtorOrDtor=*/false, Info.getLocation());
+                                 /*IsCtorOrDtor=*/false, /*isDeduced=*/true,
+                                 Info.getLocation());
       QualType APT = MPA->getPointeeType();
       if (APT->isFunctionType())
         S.adjustMemberFunctionCC(APT, /*IsStatic=*/true,
-                                 /*IsCtorOrDtor=*/false, Info.getLocation());
+                                 /*IsCtorOrDtor=*/false, /*isDeduced=*/true,
+                                 Info.getLocation());
 
       unsigned SubTDF = TDF & TDF_IgnoreQualifiers;
       if (auto Result = DeduceTemplateArgumentsByTypeMatch(
Index: clang/lib/Sema/SemaTemplate.cpp
===================================================================
--- clang/lib/Sema/SemaTemplate.cpp
+++ clang/lib/Sema/SemaTemplate.cpp
@@ -91,6 +91,684 @@
   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,
+                                      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]] Sema::TemplateDeductionResult Res =
+        SemaRef.DeduceTemplateArguments(
+            CTPSD,
+            TemplateArgumentList(TemplateArgumentList::OnStackType{}, Args),
+            Info);
+    assert(Res == Sema::TDK_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::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);
+      QualType CT = transform(QualType(T->getClass(), 0), Changed);
+      QualType PT = transform(T->getPointeeType(), Changed);
+      if (!Changed)
+        return TT;
+      return build(SemaRef.Context.getMemberPointerType(PT, CT.getTypePtr()));
+    }
+    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->template_arguments(), 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=*/None, 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()));
+    }
+    }
+    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: {
+      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);
+      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.
@@ -11012,7 +11690,7 @@
       // 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,
+          SS.getScopeRep(), Ctx,
           Keyword == ETK_Typename ? DiagCtorKind::Typename : DiagCtorKind::None,
           Type, IILoc);
       // We found a type. Build an ElaboratedType, since the
Index: clang/lib/Sema/SemaDeclCXX.cpp
===================================================================
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -1139,7 +1139,7 @@
       S.Diag(R.getRepresentativeDecl()->getLocation(), diag::note_declared_at);
     return QualType();
   }
-
+  // FIXME: resugar
   return S.Context.getTypeDeclType(TD);
 }
 
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -169,7 +169,8 @@
   return false;
 }
 
-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);
@@ -186,7 +187,7 @@
 
   DiagnoseUseOfDecl(TD, NameLoc);
   MarkAnyDeclReferenced(TD->getLocation(), TD, /*OdrUse=*/false);
-  return Context.getTypeDeclType(TD);
+  return resugar(NNS, Context.getTypeDeclType(TD));
 }
 
 namespace {
@@ -556,7 +557,7 @@
     // 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);
@@ -9555,7 +9556,7 @@
 
   if (D.isFirstDeclarationOfMember())
     adjustMemberFunctionCC(R, D.isStaticMember(), D.isCtorOrDtor(),
-                           D.getIdentifierLoc());
+                           /*isDeduced=*/false, D.getIdentifierLoc());
 
   bool isFriend = false;
   FunctionTemplateDecl *FunctionTemplate = nullptr;
Index: clang/lib/Sema/SemaCoroutine.cpp
===================================================================
--- clang/lib/Sema/SemaCoroutine.cpp
+++ clang/lib/Sema/SemaCoroutine.cpp
@@ -115,6 +115,7 @@
   }
   // 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, CoroNamespace);
Index: clang/lib/Sema/SemaCXXScopeSpec.cpp
===================================================================
--- clang/lib/Sema/SemaCXXScopeSpec.cpp
+++ clang/lib/Sema/SemaCXXScopeSpec.cpp
@@ -734,8 +734,9 @@
       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);
Index: clang/lib/AST/ASTContext.cpp
===================================================================
--- clang/lib/AST/ASTContext.cpp
+++ clang/lib/AST/ASTContext.cpp
@@ -12842,9 +12842,7 @@
   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),
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -2567,7 +2567,8 @@
   bool isSimpleTypeSpecifier(tok::TokenKind Kind) const;
 
   enum class DiagCtorKind { None, Implicit, Typename };
-  QualType getTypeDeclType(DeclContext *LookupCtx, DiagCtorKind DCK,
+  QualType getTypeDeclType(const NestedNameSpecifier *NNS,
+                           DeclContext *LookupCtx, DiagCtorKind DCK,
                            TypeDecl *TD, SourceLocation NameLoc);
 
   ParsedType getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
@@ -4663,8 +4664,9 @@
   /// Adjust the calling convention of a method to be the ABI default if it
   /// wasn't specified explicitly.  This handles method types formed from
   /// function type typedefs and typename template arguments.
+  /// For deduced types, don't suppress the adjusment even for explicit CC.
   void adjustMemberFunctionCC(QualType &T, bool IsStatic, bool IsCtorOrDtor,
-                              SourceLocation Loc);
+                              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
@@ -9784,6 +9786,8 @@
     }
   };
 
+  QualType resugar(const NestedNameSpecifier *NNS, QualType T);
+
   void PerformPendingInstantiations(bool LocalOnly = false);
 
   TypeSourceInfo *SubstType(TypeSourceInfo *T,
Index: clang/include/clang/AST/Type.h
===================================================================
--- clang/include/clang/AST/Type.h
+++ clang/include/clang/AST/Type.h
@@ -443,10 +443,10 @@
   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())
@@ -460,10 +460,10 @@
   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())
@@ -615,6 +615,7 @@
 
   static const uint32_t UMask = 0x8;
   static const uint32_t UShift = 3;
+  static const uint32_t CVRUMask = CVRMask | UMask;
   static const uint32_t GCAttrMask = 0x30;
   static const uint32_t GCAttrShift = 4;
   static const uint32_t LifetimeMask = 0x1C0;
Index: clang/include/clang/AST/ASTContext.h
===================================================================
--- clang/include/clang/AST/ASTContext.h
+++ clang/include/clang/AST/ASTContext.h
@@ -1238,8 +1238,6 @@
 
   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.
@@ -1383,6 +1381,9 @@
   /// 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;
 
Index: clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp
===================================================================
--- clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp
@@ -128,7 +128,7 @@
   auto UnlessFunctionType = unless(hasUnqualifiedDesugaredType(functionType()));
   auto IsAutoDeducedToPointer = [](const auto &...InnerMatchers) {
     return autoType(hasDeducedType(
-        hasUnqualifiedDesugaredType(pointerType(pointee(InnerMatchers...)))));
+        hasCanonicalType(pointerType(pointee(InnerMatchers...)))));
   };
 
   Finder->addMatcher(
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D127695: [clang] T... Matheus Izvekov via Phabricator via cfe-commits

Reply via email to