[llvm-branch-commits] [clang] WIP: [clang] Template Specialization Resugaring - Expressions (PR #132446)

Matheus Izvekov via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Thu Apr 3 11:14:27 PDT 2025


https://github.com/mizvekov updated https://github.com/llvm/llvm-project/pull/132446

>From df203b5f1795b8e2baebf40cea9ccfc1b19f2ea7 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] WIP: [clang] Template Specialization Resugaring - Expressions

This adds some additional users of the resugaring transform,
around expressions. This makes function calls work for example.

While probably not the largest patch in the series,
this could use some further splitting up.

Differential Revision: https://reviews.llvm.org/D137200
---
 clang/include/clang/Sema/Sema.h               |  16 +-
 clang/lib/Sema/SemaChecking.cpp               |  15 +-
 clang/lib/Sema/SemaCoroutine.cpp              |   2 +-
 clang/lib/Sema/SemaDecl.cpp                   |   1 +
 clang/lib/Sema/SemaDeclAttr.cpp               |   1 +
 clang/lib/Sema/SemaDeclCXX.cpp                |  14 +-
 clang/lib/Sema/SemaExpr.cpp                   |  30 ++-
 clang/lib/Sema/SemaExprMember.cpp             | 130 +++++-----
 clang/lib/Sema/SemaHLSL.cpp                   |   3 +-
 clang/lib/Sema/SemaInit.cpp                   |   5 +-
 clang/lib/Sema/SemaOverload.cpp               |  87 +++++--
 clang/lib/Sema/SemaTemplate.cpp               | 110 +++++++++
 clang/lib/Sema/SemaTemplateDeduction.cpp      |  15 +-
 clang/lib/Sema/TreeTransform.h                |   4 +-
 .../test/AST/ast-dump-for-range-lifetime.cpp  |  66 ++---
 clang/test/Analysis/cast-value-notes.cpp      |  38 +--
 clang/test/Analysis/cast-value-state-dump.cpp |   6 +-
 .../Analysis/lifetime-extended-regions.cpp    |   8 +-
 .../CXX/class.derived/class.abstract/p3.cpp   |   2 +-
 clang/test/CXX/drs/cwg23xx.cpp                |   4 +-
 clang/test/CXX/drs/cwg26xx.cpp                |   2 +-
 clang/test/CXX/drs/cwg4xx.cpp                 |   8 +-
 clang/test/CXX/drs/cwg6xx.cpp                 |   2 +-
 .../test/Misc/diag-template-diffing-cxx11.cpp |   6 +-
 clang/test/Sema/Resugar/resugar-expr.cpp      | 227 ++++++++++++++++++
 clang/test/SemaTemplate/attributes.cpp        |   3 +-
 clang/unittests/Tooling/StencilTest.cpp       |   3 +-
 27 files changed, 635 insertions(+), 173 deletions(-)
 create mode 100644 clang/test/Sema/Resugar/resugar-expr.cpp

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 8b7d651594f55..cb47d2a01b8e9 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -8756,7 +8756,8 @@ class Sema final : public SemaBase {
 
   ExprResult BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow,
                                      SourceLocation OpLoc,
-                                     const CXXScopeSpec &SS, FieldDecl *Field,
+                                     const NestedNameSpecifierLoc &NNS,
+                                     FieldDecl *Field, QualType FieldType,
                                      DeclAccessPair FoundDecl,
                                      const DeclarationNameInfo &MemberNameInfo);
 
@@ -8767,7 +8768,8 @@ class Sema final : public SemaBase {
       const CXXScopeSpec &SS, SourceLocation nameLoc,
       IndirectFieldDecl *indirectField,
       DeclAccessPair FoundDecl = DeclAccessPair::make(nullptr, AS_none),
-      Expr *baseObjectExpr = nullptr, SourceLocation opLoc = SourceLocation());
+      Expr *baseObjectExpr = nullptr, const Type *BaseType = nullptr,
+      SourceLocation opLoc = SourceLocation());
 
 private:
   void CheckMemberAccessOfNoDeref(const MemberExpr *E);
@@ -13999,6 +14001,16 @@ class Sema final : public SemaBase {
                                            FunctionDecl *Spaceship);
 
   QualType resugar(const NestedNameSpecifier *NNS, QualType T);
+  QualType resugar(const NestedNameSpecifier *NNS, NamedDecl *ND,
+                   ArrayRef<TemplateArgument> Args, QualType T);
+  QualType resugar(NamedDecl *ND, ArrayRef<TemplateArgument> Args, QualType T);
+  QualType resugar(const Type *Base, const NestedNameSpecifier *FieldNNS,
+                   QualType T);
+  QualType resugar(const Type *Base, const NestedNameSpecifier *FieldNNS,
+                   NamedDecl *ND, ArrayRef<TemplateArgument> Args, QualType T);
+  QualType resugar(const Type *Base, QualType T);
+  QualType resugar(const Type *Base, NamedDecl *ND,
+                   ArrayRef<TemplateArgument> Args, QualType T);
 
   /// Performs template instantiation for all implicit template
   /// instantiations we have seen until this point.
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index db61af1495793..974bf3b018c09 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -649,9 +649,11 @@ struct BuiltinDumpStructGenerator {
       if (!FD || FD->isUnnamedBitField() || FD->isAnonymousStructOrUnion())
         continue;
 
+      QualType FieldType = FD->getType();
+
       llvm::SmallString<20> Format = llvm::StringRef("%s%s %s ");
       llvm::SmallVector<Expr *, 5> Args = {FieldIndentArg,
-                                           getTypeString(FD->getType()),
+                                           getTypeString(FieldType),
                                            getStringLiteral(FD->getName())};
 
       if (FD->isBitField()) {
@@ -667,15 +669,16 @@ struct BuiltinDumpStructGenerator {
       ExprResult Field =
           IFD ? S.BuildAnonymousStructUnionMemberReference(
                     CXXScopeSpec(), Loc, IFD,
-                    DeclAccessPair::make(IFD, AS_public), RecordArg, Loc)
+                    DeclAccessPair::make(IFD, AS_public), RecordArg, nullptr,
+                    Loc)
               : S.BuildFieldReferenceExpr(
-                    RecordArg, RecordArgIsPtr, Loc, CXXScopeSpec(), FD,
-                    DeclAccessPair::make(FD, AS_public),
+                    RecordArg, RecordArgIsPtr, Loc, NestedNameSpecifierLoc(),
+                    FD, FieldType, DeclAccessPair::make(FD, AS_public),
                     DeclarationNameInfo(FD->getDeclName(), Loc));
       if (Field.isInvalid())
         return true;
 
-      auto *InnerRD = FD->getType()->getAsRecordDecl();
+      auto *InnerRD = FieldType->getAsRecordDecl();
       auto *InnerCXXRD = dyn_cast_or_null<CXXRecordDecl>(InnerRD);
       if (InnerRD && (!InnerCXXRD || InnerCXXRD->isAggregate())) {
         // Recursively print the values of members of aggregate record type.
@@ -684,7 +687,7 @@ struct BuiltinDumpStructGenerator {
           return true;
       } else {
         Format += " ";
-        if (appendFormatSpecifier(FD->getType(), Format)) {
+        if (appendFormatSpecifier(FieldType, Format)) {
           // We know how to print this field.
           Args.push_back(Field.get());
         } else {
diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp
index 8dffbca7463dd..fdfef96ee7ba6 100644
--- a/clang/lib/Sema/SemaCoroutine.cpp
+++ b/clang/lib/Sema/SemaCoroutine.cpp
@@ -286,7 +286,7 @@ static ExprResult buildCoroutineHandle(Sema &S, QualType PromiseType,
       S.BuildDeclarationNameExpr(SS, Found, /*NeedsADL=*/false);
   if (FromAddr.isInvalid())
     return ExprError();
-
+  // FIXME: resugar
   return S.BuildCallExpr(nullptr, FromAddr.get(), Loc, FramePtr, Loc);
 }
 
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index f28cb137552c0..5659f06e34b30 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -13122,6 +13122,7 @@ bool Sema::DeduceVariableDeclarationType(VarDecl *VDecl, bool DirectInit,
     return true;
   }
 
+  // FIXME: Set TypeSourceInfo?
   VDecl->setType(DeducedType);
   assert(VDecl->isLinkageValid());
 
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 88d5c66953b40..0aa51979fe370 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -3640,6 +3640,7 @@ static void handleCleanupAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
 
   // We're currently more strict than GCC about what function types we accept.
   // If this ever proves to be a problem it should be easy to fix.
+  // FIXME: resugar
   QualType Ty = S.Context.getPointerType(cast<VarDecl>(D)->getType());
   QualType ParamTy = FD->getParamDecl(0)->getType();
   if (S.CheckAssignmentConstraints(FD->getParamDecl(0)->getLocation(),
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index ed3b867aae1a0..0ed14abf6f8ac 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -1554,6 +1554,9 @@ static bool checkMemberDecomposition(Sema &S, ArrayRef<BindingDecl*> Bindings,
     if (FD->isUnnamedBitField())
       continue;
 
+    // FIXME: Avoid having to recreate the naming context for every field.
+    QualType FieldType = S.resugar(DecompType.getTypePtr(), FD->getType());
+
     // We have a real field to bind.
     assert(FlatBindingsItr != FlatBindings.end());
     BindingDecl *B = *(FlatBindingsItr++);
@@ -1568,7 +1571,7 @@ static bool checkMemberDecomposition(Sema &S, ArrayRef<BindingDecl*> Bindings,
     if (E.isInvalid())
       return true;
     E = S.BuildFieldReferenceExpr(E.get(), /*IsArrow*/ false, Loc,
-                                  CXXScopeSpec(), FD,
+                                  NestedNameSpecifierLoc(), FD, FieldType,
                                   DeclAccessPair::make(FD, FD->getAccess()),
                                   DeclarationNameInfo(FD->getDeclName(), Loc));
     if (E.isInvalid())
@@ -1582,7 +1585,7 @@ static bool checkMemberDecomposition(Sema &S, ArrayRef<BindingDecl*> Bindings,
     Qualifiers Q = DecompType.getQualifiers();
     if (FD->isMutable())
       Q.removeConst();
-    B->setBinding(S.BuildQualifiedType(FD->getType(), Loc, Q), E.get());
+    B->setBinding(S.BuildQualifiedType(FieldType, Loc, Q), E.get());
   }
 
   return false;
@@ -8606,10 +8609,13 @@ class DefaultedComparisonSynthesizer
 
     DeclAccessPair Found = DeclAccessPair::make(Field, Field->getAccess());
     DeclarationNameInfo NameInfo(Field->getDeclName(), Loc);
+    QualType FieldType = Field->getType();
     return {S.BuildFieldReferenceExpr(Obj.first.get(), /*IsArrow=*/false, Loc,
-                                      CXXScopeSpec(), Field, Found, NameInfo),
+                                      NestedNameSpecifierLoc(), Field,
+                                      FieldType, Found, NameInfo),
             S.BuildFieldReferenceExpr(Obj.second.get(), /*IsArrow=*/false, Loc,
-                                      CXXScopeSpec(), Field, Found, NameInfo)};
+                                      NestedNameSpecifierLoc(), Field,
+                                      FieldType, Found, NameInfo)};
   }
 
   // FIXME: When expanding a subobject, register a note in the code synthesis
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index dc0215f44137f..0077d8321ac88 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -3224,6 +3224,7 @@ ExprResult Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
   if (!NeedsADL && R.isSingleResult() &&
       !R.getAsSingle<FunctionTemplateDecl>() &&
       !ShouldLookupResultBeMultiVersionOverload(R))
+    // FIXME: get ConvertedArgs
     return BuildDeclarationNameExpr(SS, R.getLookupNameInfo(), R.getFoundDecl(),
                                     R.getRepresentativeDecl(), nullptr, nullptr,
                                     AcceptInvalidDecl);
@@ -3308,6 +3309,10 @@ ExprResult Sema::BuildDeclarationNameExpr(
   QualType type = VD->getType();
   if (type.isNull())
     return ExprError();
+  assert(!TemplateArgs || ConvertedArgs);
+  type = ConvertedArgs
+             ? resugar(SS.getScopeRep(), VD, ConvertedArgs->asArray(), type)
+             : resugar(SS.getScopeRep(), type);
   ExprValueKind valueKind = VK_PRValue;
 
   // In 'T ...V;', the type of the declaration 'V' is 'T...', but the type of
@@ -19895,10 +19900,30 @@ static void DoMarkVarDeclReferenced(
 
         // Re-set the member to trigger a recomputation of the dependence bits
         // for the expression.
-        if (auto *DRE = dyn_cast_or_null<DeclRefExpr>(E))
+        CXXScopeSpec SS;
+        if (auto *DRE = dyn_cast_or_null<DeclRefExpr>(E)) {
           DRE->setDecl(DRE->getDecl());
-        else if (auto *ME = dyn_cast_or_null<MemberExpr>(E))
+          SS.Adopt(DRE->getQualifierLoc());
+          assert(DRE->template_arguments().size() == 0 ||
+                 DRE->getConvertedArgs() != nullptr);
+          QualType T = DRE->getConvertedArgs()
+                           ? SemaRef.resugar(SS.getScopeRep(), DRE->getDecl(),
+                                             DRE->getConvertedArgs()->asArray(),
+                                             DRE->getType())
+                           : SemaRef.resugar(SS.getScopeRep(), DRE->getType());
+          DRE->setType(T);
+        } else if (auto *ME = dyn_cast_or_null<MemberExpr>(E)) {
           ME->setMemberDecl(ME->getMemberDecl());
+          SS.Adopt(ME->getQualifierLoc());
+          assert(ME->template_arguments().size() == 0 ||
+                 ME->getDeduced() != nullptr);
+          QualType T =
+              ME->getDeduced()
+                  ? SemaRef.resugar(SS.getScopeRep(), ME->getMemberDecl(),
+                                    ME->getDeduced()->asArray(), ME->getType())
+                  : SemaRef.resugar(SS.getScopeRep(), ME->getType());
+          ME->setType(T);
+        }
       } else if (FirstInstantiation) {
         SemaRef.PendingInstantiations
             .push_back(std::make_pair(Var, PointOfInstantiation));
@@ -21200,6 +21225,7 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) {
         SS.Adopt(DRE->getQualifierLoc());
         TemplateArgumentListInfo TemplateArgs;
         DRE->copyTemplateArgumentsInto(TemplateArgs);
+        // FIXME: resugar
         return BuildDeclRefExpr(
             FD, FD->getType(), VK_LValue, DRE->getNameInfo(),
             DRE->hasQualifier() ? &SS : nullptr, DRE->getFoundDecl(),
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index f6da4ec339adf..72ae475548e23 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -836,18 +836,14 @@ ExprResult Sema::BuildMemberReferenceExpr(
                                   false, ExtraArgs);
 }
 
-ExprResult
-Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS,
-                                               SourceLocation loc,
-                                               IndirectFieldDecl *indirectField,
-                                               DeclAccessPair foundDecl,
-                                               Expr *baseObjectExpr,
-                                               SourceLocation opLoc) {
+ExprResult Sema::BuildAnonymousStructUnionMemberReference(
+    const CXXScopeSpec &SS, SourceLocation loc,
+    IndirectFieldDecl *indirectField, DeclAccessPair foundDecl,
+    Expr *baseObjectExpr, const Type *BaseType, SourceLocation opLoc) {
   // First, build the expression that refers to the base object.
 
   // Case 1:  the base of the indirect field is not a field.
   VarDecl *baseVariable = indirectField->getVarDecl();
-  CXXScopeSpec EmptySS;
   if (baseVariable) {
     assert(baseVariable->getType()->isRecordType());
 
@@ -860,6 +856,7 @@ Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS,
 
     DeclarationNameInfo baseNameInfo(DeclarationName(), loc);
 
+    CXXScopeSpec EmptySS;
     ExprResult result
       = BuildDeclarationNameExpr(EmptySS, baseNameInfo, baseVariable);
     if (result.isInvalid()) return ExprError();
@@ -877,6 +874,8 @@ Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS,
   IndirectFieldDecl::chain_iterator
   FI = indirectField->chain_begin(), FEnd = indirectField->chain_end();
 
+  NestedNameSpecifierLoc NNS = SS.getWithLocInContext(Context);
+
   // Case 2: the base of the indirect field is a field and the user
   // wrote a member expression.
   if (!baseVariable) {
@@ -887,11 +886,16 @@ Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS,
     // Make a nameInfo that properly uses the anonymous name.
     DeclarationNameInfo memberNameInfo(field->getDeclName(), loc);
 
+    // FIXME: Avoid redundant setting of the naming scope with the loop below.
+    QualType FieldType =
+        BaseType ? resugar(BaseType, SS.getScopeRep(), field->getType())
+                 : field->getType();
+
     // Build the first member access in the chain with full information.
-    result =
-        BuildFieldReferenceExpr(result, baseObjectIsPointer, SourceLocation(),
-                                SS, field, foundDecl, memberNameInfo)
-            .get();
+    result = BuildFieldReferenceExpr(result, baseObjectIsPointer,
+                                     SourceLocation(), NNS, field, FieldType,
+                                     foundDecl, memberNameInfo)
+                 .get();
     if (!result)
       return ExprError();
   }
@@ -907,10 +911,15 @@ Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS,
     DeclAccessPair fakeFoundDecl =
         DeclAccessPair::make(field, field->getAccess());
 
+    QualType FieldType =
+        BaseType && FI == FEnd
+            ? resugar(BaseType, SS.getScopeRep(), field->getType())
+            : field->getType();
+
     result =
         BuildFieldReferenceExpr(result, /*isarrow*/ false, SourceLocation(),
-                                (FI == FEnd ? SS : EmptySS), field,
-                                fakeFoundDecl, memberNameInfo)
+                                (FI == FEnd ? NNS : NestedNameSpecifierLoc()),
+                                field, FieldType, fakeFoundDecl, memberNameInfo)
             .get();
   }
 
@@ -1154,10 +1163,14 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
     return ExprError();
 
   if (FieldDecl *FD = dyn_cast<FieldDecl>(MemberDecl)) {
+    assert(!TemplateArgs);
     if (ConvertBaseExprToGLValue())
       return ExprError();
-    return BuildFieldReferenceExpr(BaseExpr, IsArrow, OpLoc, SS, FD, FoundDecl,
-                                   MemberNameInfo);
+    NestedNameSpecifierLoc NNS = SS.getWithLocInContext(Context);
+    QualType FieldType =
+        resugar(BaseType.getTypePtr(), SS.getScopeRep(), FD->getType());
+    return BuildFieldReferenceExpr(BaseExpr, IsArrow, OpLoc, NNS, FD, FieldType,
+                                   FoundDecl, MemberNameInfo);
   }
 
   if (MSPropertyDecl *PD = dyn_cast<MSPropertyDecl>(MemberDecl)) {
@@ -1166,6 +1179,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
     // Note that this is slightly different behaviour from MSVC which doesn't
     // implement CWG2813 yet: MSVC might materialize an extra temporary if the
     // getter or setter function is an explicit object member function.
+    // FIXME: resugar these.
     return BuildMSPropertyRefExpr(*this, BaseExpr, IsArrow, SS, PD,
                                   MemberNameInfo);
   }
@@ -1175,23 +1189,28 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
       return ExprError();
     // We may have found a field within an anonymous union or struct
     // (C++ [class.union]).
-    return BuildAnonymousStructUnionMemberReference(SS, MemberLoc, FD,
-                                                    FoundDecl, BaseExpr,
-                                                    OpLoc);
+    return BuildAnonymousStructUnionMemberReference(
+        SS, MemberLoc, FD, FoundDecl, BaseExpr, BaseType.getTypePtr(), OpLoc);
   }
 
   // Static data member
   if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl)) {
+    assert(!TemplateArgs);
     if (ConvertBaseExprToDiscardedValue())
       return ExprError();
-    return BuildMemberExpr(BaseExpr, IsArrow, OpLoc,
-                           SS.getWithLocInContext(Context), TemplateKWLoc, Var,
+    NestedNameSpecifierLoc NNS = SS.getWithLocInContext(Context);
+    QualType VarType =
+        resugar(BaseType.getTypePtr(), SS.getScopeRep(), Var->getType());
+    return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, NNS, TemplateKWLoc, Var,
                            FoundDecl, /*HadMultipleCandidates=*/false,
-                           MemberNameInfo, Var->getType().getNonReferenceType(),
+                           MemberNameInfo, VarType.getNonReferenceType(),
                            VK_LValue, OK_Ordinary);
   }
 
   if (CXXMethodDecl *MemberFn = dyn_cast<CXXMethodDecl>(MemberDecl)) {
+    assert(!TemplateArgs);
+    NestedNameSpecifierLoc NNS = SS.getWithLocInContext(Context);
+
     ExprValueKind valueKind;
     QualType type;
     if (MemberFn->isInstance()) {
@@ -1205,23 +1224,27 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
       if (ConvertBaseExprToDiscardedValue())
         return ExprError();
       valueKind = VK_LValue;
-      type = MemberFn->getType();
+      type =
+          resugar(BaseType.getTypePtr(), SS.getScopeRep(), MemberFn->getType());
     }
 
-    return BuildMemberExpr(BaseExpr, IsArrow, OpLoc,
-                           SS.getWithLocInContext(Context), TemplateKWLoc,
+    return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, NNS, TemplateKWLoc,
                            MemberFn, FoundDecl, /*HadMultipleCandidates=*/false,
                            MemberNameInfo, type, valueKind, OK_Ordinary);
   }
   assert(!isa<FunctionDecl>(MemberDecl) && "member function not C++ method?");
 
   if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl)) {
+    assert(!TemplateArgs);
     if (ConvertBaseExprToDiscardedValue())
       return ExprError();
-    return BuildMemberExpr(
-        BaseExpr, IsArrow, OpLoc, SS.getWithLocInContext(Context),
-        TemplateKWLoc, Enum, FoundDecl, /*HadMultipleCandidates=*/false,
-        MemberNameInfo, Enum->getType(), VK_PRValue, OK_Ordinary);
+    NestedNameSpecifierLoc NNS = SS.getWithLocInContext(Context);
+    // FIXME: EnumType resugaring not implemented.
+    QualType EnumType =
+        resugar(BaseType.getTypePtr(), SS.getScopeRep(), Enum->getType());
+    return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, NNS, TemplateKWLoc, Enum,
+                           FoundDecl, /*HadMultipleCandidates=*/false,
+                           MemberNameInfo, EnumType, VK_PRValue, OK_Ordinary);
   }
 
   if (VarTemplateDecl *VarTempl = dyn_cast<VarTemplateDecl>(MemberDecl)) {
@@ -1250,10 +1273,12 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
     if (!Var->getTemplateSpecializationKind())
       Var->setTemplateSpecializationKind(TSK_ImplicitInstantiation, MemberLoc);
 
-    return BuildMemberExpr(BaseExpr, IsArrow, OpLoc,
-                           SS.getWithLocInContext(Context), TemplateKWLoc, Var,
+    NestedNameSpecifierLoc NNS = SS.getWithLocInContext(Context);
+    QualType VarType = resugar(BaseType.getTypePtr(), SS.getScopeRep(), Var,
+                               ConvertedArgs->asArray(), Var->getType());
+    return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, NNS, TemplateKWLoc, Var,
                            FoundDecl, /*HadMultipleCandidates=*/false,
-                           MemberNameInfo, Var->getType().getNonReferenceType(),
+                           MemberNameInfo, VarType.getNonReferenceType(),
                            VK_LValue, OK_Ordinary, TemplateArgs, ConvertedArgs);
   }
 
@@ -1866,11 +1891,10 @@ void Sema::CheckMemberAccessOfNoDeref(const MemberExpr *E) {
   }
 }
 
-ExprResult
-Sema::BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow,
-                              SourceLocation OpLoc, const CXXScopeSpec &SS,
-                              FieldDecl *Field, DeclAccessPair FoundDecl,
-                              const DeclarationNameInfo &MemberNameInfo) {
+ExprResult Sema::BuildFieldReferenceExpr(
+    Expr *BaseExpr, bool IsArrow, SourceLocation OpLoc,
+    const NestedNameSpecifierLoc &NNS, FieldDecl *Field, QualType FieldType,
+    DeclAccessPair FoundDecl, const DeclarationNameInfo &MemberNameInfo) {
   // x.a is an l-value if 'a' has a reference type. Otherwise:
   // x.a is an l-value/x-value/pr-value if the base is (and note
   //   that *x is always an l-value), except that if the base isn't
@@ -1887,9 +1911,8 @@ Sema::BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow,
     OK = OK_BitField;
 
   // Figure out the type of the member; see C99 6.5.2.3p3, C++ [expr.ref]
-  QualType MemberType = Field->getType();
-  if (const ReferenceType *Ref = MemberType->getAs<ReferenceType>()) {
-    MemberType = Ref->getPointeeType();
+  if (const ReferenceType *Ref = FieldType->getAs<ReferenceType>()) {
+    FieldType = Ref->getPointeeType();
     VK = VK_LValue;
   } else {
     QualType BaseType = BaseExpr->getType();
@@ -1904,22 +1927,21 @@ Sema::BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow,
     // except that 'mutable' members don't pick up 'const'.
     if (Field->isMutable()) BaseQuals.removeConst();
 
-    Qualifiers MemberQuals =
-        Context.getCanonicalType(MemberType).getQualifiers();
+    Qualifiers FieldQuals = Context.getCanonicalType(FieldType).getQualifiers();
 
-    assert(!MemberQuals.hasAddressSpace());
+    assert(!FieldQuals.hasAddressSpace());
 
-    Qualifiers Combined = BaseQuals + MemberQuals;
-    if (Combined != MemberQuals)
-      MemberType = Context.getQualifiedType(MemberType, Combined);
+    Qualifiers Combined = BaseQuals + FieldQuals;
+    if (Combined != FieldQuals)
+      FieldType = Context.getQualifiedType(FieldType, Combined);
 
     // Pick up NoDeref from the base in case we end up using AddrOf on the
     // result. E.g. the expression
     //     &someNoDerefPtr->pointerMember
     // should be a noderef pointer again.
     if (BaseType->hasAttr(attr::NoDeref))
-      MemberType =
-          Context.getAttributedType(attr::NoDeref, MemberType, MemberType);
+      FieldType =
+          Context.getAttributedType(attr::NoDeref, FieldType, FieldType);
   }
 
   auto isDefaultedSpecialMember = [this](const DeclContext *Ctx) {
@@ -1934,8 +1956,8 @@ Sema::BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow,
   if (!isDefaultedSpecialMember(CurContext))
     UnusedPrivateFields.remove(Field);
 
-  ExprResult Base = PerformObjectMemberConversion(BaseExpr, SS.getScopeRep(),
-                                                  FoundDecl, Field);
+  ExprResult Base = PerformObjectMemberConversion(
+      BaseExpr, NNS.getNestedNameSpecifier(), FoundDecl, Field);
   if (Base.isInvalid())
     return ExprError();
 
@@ -1950,10 +1972,10 @@ Sema::BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow,
     }
   }
 
-  return BuildMemberExpr(
-      Base.get(), IsArrow, OpLoc, SS.getWithLocInContext(Context),
-      /*TemplateKWLoc=*/SourceLocation(), Field, FoundDecl,
-      /*HadMultipleCandidates=*/false, MemberNameInfo, MemberType, VK, OK);
+  return BuildMemberExpr(Base.get(), IsArrow, OpLoc, NNS,
+                         /*TemplateKWLoc=*/SourceLocation(), Field, FoundDecl,
+                         /*HadMultipleCandidates=*/false, MemberNameInfo,
+                         FieldType, VK, OK);
 }
 
 ExprResult
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index fe600386e6fa9..63c486d64f628 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -3339,7 +3339,8 @@ static bool BuildInitializerList(Sema &S, ASTContext &Ctx, Expr *E,
         DeclAccessPair Found = DeclAccessPair::make(FD, FD->getAccess());
         DeclarationNameInfo NameInfo(FD->getDeclName(), E->getBeginLoc());
         ExprResult Res = S.BuildFieldReferenceExpr(
-            E, false, E->getBeginLoc(), CXXScopeSpec(), FD, Found, NameInfo);
+            E, false, E->getBeginLoc(), NestedNameSpecifierLoc(), FD,
+            FD->getType(), Found, NameInfo);
         if (Res.isInvalid())
           return false;
         if (!BuildInitializerList(S, Ctx, Res.get(), List, DestTypes))
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 370e7ca1d918c..78092638a543a 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -10262,12 +10262,13 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
     MarkFunctionReferenced(Kind.getLocation(), Best->Function);
     break;
   }
+  QualType RT = Best->Function->getReturnType();
+  // FIXME: resugar here
 
   // C++ [dcl.type.class.deduct]p1:
   //  The placeholder is replaced by the return type of the function selected
   //  by overload resolution for class template deduction.
-  QualType DeducedType =
-      SubstAutoType(TSInfo->getType(), Best->Function->getReturnType());
+  QualType DeducedType = SubstAutoType(TSInfo->getType(), RT);
   Diag(TSInfo->getTypeLoc().getBeginLoc(),
        diag::warn_cxx14_compat_class_template_argument_deduction)
       << TSInfo->getTypeLoc().getSourceRange() << 1 << DeducedType;
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 0e6191f406866..8f89e159cc964 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -2219,6 +2219,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
       // We were able to resolve the address of the overloaded function,
       // so we can convert to the type of that function.
       FromType = Fn->getType();
+      // FIXME: resugar
       SCS.setFromType(FromType);
 
       // we can sometimes resolve &foo<int> regardless of ToType, so check
@@ -5221,6 +5222,7 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
     const TemplateArgumentList *ConvertedArgs;
     if (FunctionDecl *Fn = S.ResolveAddressOfOverloadedFunction(
             Init, DeclType, false, Found, ConvertedArgs))
+      // FIXME: resugar
       T2 = Fn->getType();
   }
 
@@ -5712,6 +5714,7 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType,
         const TemplateArgumentList *ConvertedArgs;
         if (FunctionDecl *Fn = S.ResolveAddressOfOverloadedFunction(
                 Init, ToType, false, Found, ConvertedArgs))
+          // FIXME: resugar
           T2 = Fn->getType();
       }
 
@@ -13610,6 +13613,7 @@ bool Sema::resolveAndFixAddressOfSingleOverloadCandidate(
       FixOverloadedFunctionReference(E, DAP, Found, /*ConvertedArgs=*/{});
   if (Res.isInvalid())
     return false;
+  // FIXME: resugar
   Expr *Fixed = Res.get();
   if (DoFunctionPointerConversion && Fixed->getType()->isFunctionType())
     SrcExpr = DefaultFunctionArrayConversion(Fixed, /*Diagnose=*/false);
@@ -15790,13 +15794,28 @@ ExprResult Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
 
     MemExpr = cast<MemberExpr>(MemExprE->IgnoreParens());
   }
+  assert(Method && "Member call to something that isn't a method?");
 
-  QualType ResultType = Method->getReturnType();
-  ExprValueKind VK = Expr::getValueKindForType(ResultType);
-  ResultType = ResultType.getNonLValueExprType(Context);
+  QualType MethodType;
+  {
+    QualType BaseType = MemExpr->getBase()->getType();
+    if (MemExpr->isArrow())
+      BaseType = BaseType->castAs<PointerType>()->getPointeeType();
+    NestedNameSpecifierLoc NNS = MemExpr->getQualifierLoc();
+    // FIXME: Should we resugar the explicit template arguments as well?
+    const TemplateArgumentList *Deduced = MemExpr->getDeduced();
+    MethodType =
+        Deduced ? resugar(BaseType.getTypePtr(), NNS.getNestedNameSpecifier(),
+                          Method, Deduced->asArray(), Method->getType())
+                : resugar(BaseType.getTypePtr(), NNS.getNestedNameSpecifier(),
+                          Method->getType());
+  }
 
-  assert(Method && "Member call to something that isn't a method?");
-  const auto *Proto = Method->getType()->castAs<FunctionProtoType>();
+  const auto *Proto = MethodType->castAs<FunctionProtoType>();
+  QualType ReturnType = Proto->getReturnType();
+
+  ExprValueKind VK = Expr::getValueKindForType(ReturnType);
+  QualType ResultType = ReturnType.getNonLValueExprType(Context);
 
   CallExpr *TheCall = nullptr;
   llvm::SmallVector<Expr *, 8> NewArgs;
@@ -15828,8 +15847,7 @@ ExprResult Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
   }
 
   // Check for a valid return type.
-  if (CheckCallReturnType(Method->getReturnType(), MemExpr->getMemberLoc(),
-                          TheCall, Method))
+  if (CheckCallReturnType(ReturnType, MemExpr->getMemberLoc(), TheCall, Method))
     return BuildRecoveryExpr(ResultType);
 
   // Convert the rest of the arguments
@@ -16524,9 +16542,18 @@ Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
         // We have taken the address of a pointer to member
         // function. Perform the computation here so that we get the
         // appropriate pointer to member type.
-        QualType MemPtrType = Context.getMemberPointerType(
-            Fn->getType(), Qualifier,
-            cast<CXXRecordDecl>(Method->getDeclContext()));
+        // FIXME: get sugared class type
+        auto *Cls = cast<CXXRecordDecl>(Method->getDeclContext());
+        if (auto *RD = Qualifier->getAsRecordDecl();
+            Cls != RD && Cls->getCanonicalDecl() != RD->getCanonicalDecl())
+          // FIXME: Get type as written for the base class.
+          Qualifier = nullptr;
+        QualType Type =
+            Deduced ? resugar(Qualifier, Fn, Deduced->asArray(), Fn->getType())
+                    : resugar(Qualifier, Fn->getType());
+        QualType MemPtrType =
+            Context.getMemberPointerType(Type, Qualifier, Cls);
+
         // Under the MS ABI, lock down the inheritance model now.
         if (Context.getTargetInfo().getCXXABI().isMicrosoft())
           (void)isCompleteType(UnOp->getOperatorLoc(), MemPtrType);
@@ -16555,24 +16582,30 @@ Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
       ULE->copyTemplateArgumentsInto(TemplateArgsBuffer);
       TemplateArgs = &TemplateArgsBuffer;
     }
+    NestedNameSpecifierLoc NNS = ULE->getQualifierLoc();
 
-    QualType Type = Fn->getType();
     ExprValueKind ValueKind =
         getLangOpts().CPlusPlus && !Fn->hasCXXExplicitFunctionObjectParameter()
             ? VK_LValue
             : VK_PRValue;
 
     // FIXME: Duplicated from BuildDeclarationNameExpr.
-    if (unsigned BID = Fn->getBuiltinID()) {
-      if (!Context.BuiltinInfo.isDirectlyAddressable(BID)) {
+    QualType Type;
+    {
+      unsigned BID = Fn->getBuiltinID();
+      if (BID && !Context.BuiltinInfo.isDirectlyAddressable(BID)) {
         Type = Context.BuiltinFnTy;
         ValueKind = VK_PRValue;
+      } else {
+        Type = Deduced ? resugar(NNS.getNestedNameSpecifier(), Fn,
+                                 Deduced->asArray(), Fn->getType())
+                       : resugar(NNS.getNestedNameSpecifier(), Fn->getType());
       }
     }
 
     DeclRefExpr *DRE = BuildDeclRefExpr(
-        Fn, Type, ValueKind, ULE->getNameInfo(), ULE->getQualifierLoc(),
-        Found.getDecl(), ULE->getTemplateKeywordLoc(), TemplateArgs, Deduced);
+        Fn, Type, ValueKind, ULE->getNameInfo(), NNS, Found.getDecl(),
+        ULE->getTemplateKeywordLoc(), TemplateArgs, Deduced);
     DRE->setHadMultipleCandidates(ULE->getNumDecls() > 1);
     return DRE;
   }
@@ -16584,6 +16617,10 @@ Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
       MemExpr->copyTemplateArgumentsInto(TemplateArgsBuffer);
       TemplateArgs = &TemplateArgsBuffer;
     }
+    QualType BaseType = MemExpr->getBaseType();
+    const Type *BasePointeeType = BaseType->getPointeeType().getTypePtrOrNull();
+    if (!BasePointeeType)
+      BasePointeeType = BaseType.getTypePtr();
 
     Expr *Base;
 
@@ -16591,8 +16628,11 @@ Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
     // implicit member access, rewrite to a simple decl ref.
     if (MemExpr->isImplicitAccess()) {
       if (cast<CXXMethodDecl>(Fn)->isStatic()) {
+        QualType Type = Deduced ? resugar(BasePointeeType, Fn,
+                                          Deduced->asArray(), Fn->getType())
+                                : resugar(BasePointeeType, Fn->getType());
         DeclRefExpr *DRE = BuildDeclRefExpr(
-            Fn, Fn->getType(), VK_LValue, MemExpr->getNameInfo(),
+            Fn, Type, VK_LValue, MemExpr->getNameInfo(),
             MemExpr->getQualifierLoc(), Found.getDecl(),
             MemExpr->getTemplateKeywordLoc(), TemplateArgs, Deduced);
         DRE->setHadMultipleCandidates(MemExpr->getNumDecls() > 1);
@@ -16601,27 +16641,28 @@ Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
         SourceLocation Loc = MemExpr->getMemberLoc();
         if (MemExpr->getQualifier())
           Loc = MemExpr->getQualifierLoc().getBeginLoc();
-        Base =
-            BuildCXXThisExpr(Loc, MemExpr->getBaseType(), /*IsImplicit=*/true);
+        Base = BuildCXXThisExpr(Loc, BaseType, /*IsImplicit=*/true);
       }
     } else
       Base = MemExpr->getBase();
 
     ExprValueKind valueKind;
-    QualType type;
+    QualType Type;
     if (cast<CXXMethodDecl>(Fn)->isStatic()) {
       valueKind = VK_LValue;
-      type = Fn->getType();
+      Type = Deduced ? resugar(BasePointeeType, Fn, Deduced->asArray(),
+                               Fn->getType())
+                     : resugar(BasePointeeType, Fn->getType());
     } else {
       valueKind = VK_PRValue;
-      type = Context.BoundMemberTy;
+      Type = Context.BoundMemberTy;
     }
 
     return BuildMemberExpr(
         Base, MemExpr->isArrow(), MemExpr->getOperatorLoc(),
         MemExpr->getQualifierLoc(), MemExpr->getTemplateKeywordLoc(), Fn, Found,
-        /*HadMultipleCandidates=*/true, MemExpr->getMemberNameInfo(),
-        type, valueKind, OK_Ordinary, TemplateArgs);
+        /*HadMultipleCandidates=*/true, MemExpr->getMemberNameInfo(), Type,
+        valueKind, OK_Ordinary, TemplateArgs, Deduced);
   }
 
   llvm_unreachable("Invalid reference to overloaded function");
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 479fcc1f147a2..bb3eecbf60bb3 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -152,6 +152,40 @@ class NameMap {
     insert(CTSD, Info.takeSugared()->asArray());
   }
 
+  void insert(Sema &SemaRef, const NamedDecl *ND,
+              ArrayRef<TemplateArgument> Args) {
+    assert(ND != nullptr);
+    ND = cast<NamedDecl>(ND->getCanonicalDecl());
+    assert(Args.size() != 0);
+    switch (ND->getKind()) {
+    case Decl::Kind::CXXConversion:
+    case Decl::Kind::CXXMethod:
+    case Decl::Kind::Function: {
+      const auto *FD = cast<FunctionDecl>(ND);
+      assert(FD->getTemplatedKind() ==
+             FunctionDecl::TK_FunctionTemplateSpecialization);
+      return insert(FD->getPrimaryTemplate(), Args);
+    }
+    case Decl::Kind::VarTemplateSpecialization: {
+      auto STP = cast<VarTemplateSpecializationDecl>(ND)
+                     ->getSpecializedTemplateOrPartial();
+      auto *VTPSD = STP.dyn_cast<VarTemplatePartialSpecializationDecl *>();
+      if (!VTPSD)
+        return insert(cast<VarTemplateDecl *>(STP), Args);
+
+      TemplateDeductionInfo Info(SourceLocation{},
+                                 VTPSD->getTemplateParameters()->getDepth());
+      [[maybe_unused]] TemplateDeductionResult Res =
+          SemaRef.DeduceTemplateArguments(VTPSD, Args, Info);
+      assert(Res == TemplateDeductionResult::Success);
+      return insert(VTPSD, Info.takeSugared()->asArray());
+    }
+    default:
+      ND->dumpColor();
+      llvm_unreachable("Unhandled Template Kind");
+    }
+  }
+
   void insert(Sema &SemaRef, const NestedNameSpecifier *NNS) {
     for (/**/; NNS; NNS = NNS->getPrefix()) {
       switch (NNS->getKind()) {
@@ -826,6 +860,82 @@ QualType Sema::resugar(const NestedNameSpecifier *NNS, QualType T) {
   return Resugarer(*this, Names).transform(T, Changed);
 }
 
+QualType Sema::resugar(const NestedNameSpecifier *NNS, NamedDecl *ND,
+                       ArrayRef<TemplateArgument> Args, QualType T) {
+  NameMap Names;
+  Names.insert(*this, ND, Args);
+  Names.insert(*this, NNS);
+
+  bool Changed = false;
+  return Resugarer(*this, Names).transform(T, Changed);
+}
+
+QualType Sema::resugar(NamedDecl *ND, ArrayRef<TemplateArgument> Args,
+                       QualType T) {
+  NameMap Names;
+  Names.insert(*this, ND, Args);
+
+  bool Changed = false;
+  return Resugarer(*this, Names).transform(T, Changed);
+}
+
+static const NestedNameSpecifier *decomposeBaseType(const Type *&Base) {
+  if (const auto *ElTy = Base->getAs<ElaboratedType>()) {
+    Base = ElTy->getNamedType().getTypePtr();
+    return ElTy->getQualifier();
+  }
+  return nullptr;
+}
+
+QualType Sema::resugar(const Type *Base, QualType T) {
+  NameMap Names;
+  const NestedNameSpecifier *BaseNNS = decomposeBaseType(Base);
+  Names.insert(*this, Base);
+  Names.insert(*this, BaseNNS);
+  if (Names.empty())
+    return T;
+
+  bool Changed = false;
+  return Resugarer(*this, Names).transform(T, Changed);
+}
+QualType Sema::resugar(const Type *Base, NamedDecl *ND,
+                       ArrayRef<TemplateArgument> Args, QualType T) {
+  NameMap Names;
+  Names.insert(*this, ND, Args);
+  const NestedNameSpecifier *BaseNNS = decomposeBaseType(Base);
+  Names.insert(*this, Base);
+  Names.insert(*this, BaseNNS);
+
+  bool Changed = false;
+  return Resugarer(*this, Names).transform(T, Changed);
+}
+QualType Sema::resugar(const Type *Base, const NestedNameSpecifier *FieldNNS,
+                       QualType T) {
+  NameMap Names;
+  Names.insert(*this, FieldNNS);
+  const NestedNameSpecifier *BaseNNS = decomposeBaseType(Base);
+  Names.insert(*this, Base);
+  Names.insert(*this, BaseNNS);
+  if (Names.empty())
+    return T;
+
+  bool Changed = false;
+  return Resugarer(*this, Names).transform(T, Changed);
+}
+QualType Sema::resugar(const Type *Base, const NestedNameSpecifier *FieldNNS,
+                       NamedDecl *ND, ArrayRef<TemplateArgument> Args,
+                       QualType T) {
+  NameMap Names;
+  Names.insert(*this, ND, Args);
+  Names.insert(*this, FieldNNS);
+  const NestedNameSpecifier *BaseNNS = decomposeBaseType(Base);
+  Names.insert(*this, Base);
+  Names.insert(*this, BaseNNS);
+
+  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.
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 5b79226a8be42..83fdc73965915 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -4205,6 +4205,10 @@ static QualType GetTypeOfFunction(Sema &S, const OverloadExpr::FindResult &R,
       S.DeduceReturnType(Fn, R.Expression->getExprLoc(), /*Diagnose*/ false))
     return {};
 
+  // FIXME: get SS.
+  QualType FT =
+      Args.size() != 0 ? S.resugar(Fn, Args, Fn->getType()) : Fn->getType();
+
   if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn))
     if (Method->isImplicitObjectMemberFunction()) {
       // An instance method that's referenced in a form that doesn't
@@ -4212,12 +4216,14 @@ static QualType GetTypeOfFunction(Sema &S, const OverloadExpr::FindResult &R,
       if (!R.HasFormOfMemberPointer)
         return {};
 
-      return S.Context.getMemberPointerType(
-          Fn->getType(), /*Qualifier=*/nullptr, Method->getParent());
+      // FIXME: resugar the class type here.
+      return S.Context.getMemberPointerType(FT, /*Qualifier=*/nullptr,
+                                            Method->getParent());
     }
 
-  if (!R.IsAddressOfOperand) return Fn->getType();
-  return S.Context.getPointerType(Fn->getType());
+  if (!R.IsAddressOfOperand)
+    return FT;
+  return S.Context.getPointerType(FT);
 }
 
 /// Apply the deduction rules for overload sets.
@@ -4334,6 +4340,7 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams,
     //   treated as a non-deduced context. [...]
     if (!Match.isNull() && !S.isSameOrCompatibleFunctionType(Match, ArgType))
       return {};
+    // FIXME: resugar
     Match = ArgType;
   }
 
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 222dd932aab37..ead3784b061a0 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -2921,8 +2921,10 @@ class TreeTransform {
       }
 
       CXXScopeSpec EmptySS;
+      // FIXME: resugar.
       return getSema().BuildFieldReferenceExpr(
-          Base, isArrow, OpLoc, EmptySS, cast<FieldDecl>(Member),
+          Base, isArrow, OpLoc, NestedNameSpecifierLoc(),
+          cast<FieldDecl>(Member), Member->getType(),
           DeclAccessPair::make(FoundDecl, FoundDecl->getAccess()),
           MemberNameInfo);
     }
diff --git a/clang/test/AST/ast-dump-for-range-lifetime.cpp b/clang/test/AST/ast-dump-for-range-lifetime.cpp
index ee046be19ab63..db1a8335cd89e 100644
--- a/clang/test/AST/ast-dump-for-range-lifetime.cpp
+++ b/clang/test/AST/ast-dump-for-range-lifetime.cpp
@@ -135,7 +135,7 @@ void test4() {
   // CHECK-NEXT:  |           `-ImplicitCastExpr {{.*}} 'const A':'const P2718R0::A' <NoOp>
   // CHECK-NEXT:  |             `-CXXBindTemporaryExpr {{.*}} 'A':'P2718R0::A' (CXXTemporary {{.*}})
   // CHECK-NEXT:  |               `-CXXTemporaryObjectExpr {{.*}} 'A':'P2718R0::A' 'void ()'
-  for (auto e : default_arg_fn()) 
+  for (auto e : default_arg_fn())
     bar(e);
 }
 
@@ -293,17 +293,17 @@ void test8() {
   // CHECK:      -CXXForRangeStmt {{.*}}
   // CHECK-NEXT:  |-<<<NULL>>>
   // CHECK-NEXT:  |-DeclStmt {{.*}}
-  // CHECK-NEXT:  | `-VarDecl {{.*}} implicit used __range1 'const P2718R0::A &' cinit
-  // CHECK-NEXT:  |   `-ExprWithCleanups {{.*}} 'const P2718R0::A' lvalue
-  // CHECK-NEXT:  |     `-CallExpr {{.*}} 'const P2718R0::A' lvalue
-  // CHECK-NEXT:  |       |-ImplicitCastExpr {{.*}} 'const P2718R0::A &(*)(const P2718R0::A &)' <FunctionToPointerDecay>
-  // CHECK-NEXT:  |       | `-DeclRefExpr {{.*}} 'const P2718R0::A &(const P2718R0::A &)' lvalue Function {{.*}} 'df1' 'const P2718R0::A &(const P2718R0::A &)' (FunctionTemplate {{.*}} 'df1')
-  // CHECK-NEXT:  |       `-MaterializeTemporaryExpr {{.*}} 'const P2718R0::A' lvalue extended by Var {{.*}} '__range1' 'const P2718R0::A &'
-  // CHECK-NEXT:  |         `-ImplicitCastExpr {{.*}} 'const P2718R0::A' <NoOp>
-  // CHECK-NEXT:  |           `-CXXBindTemporaryExpr {{.*}} 'P2718R0::A' (CXXTemporary {{.*}})
-  // CHECK-NEXT:  |             `-CallExpr {{.*}} 'P2718R0::A'
-  // CHECK-NEXT:  |               `-ImplicitCastExpr {{.*}} 'P2718R0::A (*)()' <FunctionToPointerDecay>
-  // CHECK-NEXT:  |                 `-DeclRefExpr {{.*}} 'P2718R0::A ()' lvalue Function {{.*}} 'dg' 'P2718R0::A ()' (FunctionTemplate {{.*}} 'dg')
+  // CHECK-NEXT:  | `-VarDecl {{.*}} implicit used __range1 'A const &' cinit
+  // CHECK-NEXT:  |   `-ExprWithCleanups {{.*}} 'A const':'const P2718R0::A' lvalue
+  // CHECK-NEXT:  |     `-CallExpr {{.*}} 'A const':'const P2718R0::A' lvalue
+  // CHECK-NEXT:  |       |-ImplicitCastExpr {{.*}} 'A const &(*)(A const &)' <FunctionToPointerDecay>
+  // CHECK-NEXT:  |       | `-DeclRefExpr {{.*}} 'A const &(A const &)' lvalue Function {{.*}} 'df1' 'const P2718R0::A &(const P2718R0::A &)' (FunctionTemplate {{.*}} 'df1')
+  // CHECK-NEXT:  |       `-MaterializeTemporaryExpr {{.*}} 'const A':'const P2718R0::A' lvalue extended by Var {{.*}} '__range1' 'A const &'
+  // CHECK-NEXT:  |         `-ImplicitCastExpr {{.*}} 'const A':'const P2718R0::A' <NoOp>
+  // CHECK-NEXT:  |           `-CXXBindTemporaryExpr {{.*}} 'A':'P2718R0::A' (CXXTemporary {{.*}})
+  // CHECK-NEXT:  |             `-CallExpr {{.*}} 'A':'P2718R0::A'
+  // CHECK-NEXT:  |               `-ImplicitCastExpr {{.*}} 'A (*)()' <FunctionToPointerDecay>
+  // CHECK-NEXT:  |                 `-DeclRefExpr {{.*}} 'A ()' lvalue Function {{.*}} 'dg' 'P2718R0::A ()' (FunctionTemplate {{.*}} 'dg')
   for (auto e : df1(dg<A>()))
     sum += e;
 }
@@ -319,8 +319,8 @@ void test9() {
   // CHECK-NEXT:  | `-VarDecl {{.*}} implicit used __range1 'int (&)[3]' cinit
   // CHECK-NEXT:  |   `-ExprWithCleanups {{.*}} 'int[3]' lvalue
   // CHECK-NEXT:  |     `-CallExpr {{.*}} 'int[3]' lvalue
-  // CHECK-NEXT:  |       |-ImplicitCastExpr {{.*}} 'int (&(*)(const P2718R0::A *))[3]' <FunctionToPointerDecay>
-  // CHECK-NEXT:  |       | `-DeclRefExpr {{.*}} 'int (&(const P2718R0::A *))[3]' lvalue Function {{.*}} 'df2' 'int (&(const P2718R0::A *))[3]' (FunctionTemplate {{.*}} 'df2')
+  // CHECK-NEXT:  |       |-ImplicitCastExpr {{.*}} 'int (&(*)(const A *))[3]' <FunctionToPointerDecay>
+  // CHECK-NEXT:  |       | `-DeclRefExpr {{.*}} 'int (&(const A *))[3]' lvalue Function {{.*}} 'df2' 'int (&(const P2718R0::A *))[3]' (FunctionTemplate {{.*}} 'df2')
   // CHECK-NEXT:  |       `-CallExpr {{.*}} 'const A *'
   // CHECK-NEXT:  |         |-ImplicitCastExpr {{.*}} 'const A *(*)(const A &)' <FunctionToPointerDecay>
   // CHECK-NEXT:  |         | `-DeclRefExpr {{.*}} 'const A *(const A &)' lvalue Function {{.*}} 'dg2' 'const A *(const A &)'
@@ -345,9 +345,9 @@ void test10() {
   // CHECK-NEXT:  |   `-ExprWithCleanups {{.*}} 'int[3]' lvalue
   // CHECK-NEXT:  |     `-BinaryOperator {{.*}} 'int[3]' lvalue ','
   // CHECK-NEXT:  |       |-CXXStaticCastExpr {{.*}} 'void' static_cast<void> <ToVoid>
-  // CHECK-NEXT:  |       | `-CallExpr {{.*}} 'const P2718R0::LockGuard' lvalue
-  // CHECK-NEXT:  |       |   |-ImplicitCastExpr {{.*}} 'const P2718R0::LockGuard &(*)(const P2718R0::LockGuard &)' <FunctionToPointerDecay>
-  // CHECK-NEXT:  |       |   | `-DeclRefExpr {{.*}} 'const P2718R0::LockGuard &(const P2718R0::LockGuard &)' lvalue Function {{.*}} 'df1' 'const P2718R0::LockGuard &(const P2718R0::LockGuard &)' (FunctionTemplate {{.*}} 'df1')
+  // CHECK-NEXT:  |       | `-CallExpr {{.*}} 'const LockGuard':'const P2718R0::LockGuard' lvalue
+  // CHECK-NEXT:  |       |   |-ImplicitCastExpr {{.*}} 'const LockGuard &(*)(const LockGuard &)' <FunctionToPointerDecay>
+  // CHECK-NEXT:  |       |   | `-DeclRefExpr {{.*}} 'const LockGuard &(const LockGuard &)' lvalue Function {{.*}} 'df1' 'const P2718R0::LockGuard &(const P2718R0::LockGuard &)' (FunctionTemplate {{.*}} 'df1')
   // CHECK-NEXT:  |       |   `-MaterializeTemporaryExpr {{.*}} 'const LockGuard':'const P2718R0::LockGuard' lvalue extended by Var {{.*}} '__range1' 'int (&)[3]'
   // CHECK-NEXT:  |       |     `-ImplicitCastExpr {{.*}} 'const LockGuard':'const P2718R0::LockGuard' <NoOp>
   // CHECK-NEXT:  |       |       `-CXXBindTemporaryExpr {{.*}} 'LockGuard':'P2718R0::LockGuard' (CXXTemporary {{.*}})
@@ -363,9 +363,9 @@ void test10() {
   // CHECK-NEXT:  |   `-ExprWithCleanups {{.*}} 'int[3]' lvalue
   // CHECK-NEXT:  |     `-BinaryOperator {{.*}} 'int[3]' lvalue ','
   // CHECK-NEXT:  |       |-CStyleCastExpr {{.*}} 'void' <ToVoid>
-  // CHECK-NEXT:  |       | `-CallExpr {{.*}} 'const P2718R0::LockGuard' lvalue
-  // CHECK-NEXT:  |       |   |-ImplicitCastExpr {{.*}} 'const P2718R0::LockGuard &(*)(const P2718R0::LockGuard &)' <FunctionToPointerDecay>
-  // CHECK-NEXT:  |       |   | `-DeclRefExpr {{.*}} 'const P2718R0::LockGuard &(const P2718R0::LockGuard &)' lvalue Function {{.*}} 'df1' 'const P2718R0::LockGuard &(const P2718R0::LockGuard &)' (FunctionTemplate {{.*}} 'df1')
+  // CHECK-NEXT:  |       | `-CallExpr {{.*}} 'const LockGuard':'const P2718R0::LockGuard' lvalue
+  // CHECK-NEXT:  |       |   |-ImplicitCastExpr {{.*}} 'const LockGuard &(*)(const LockGuard &)' <FunctionToPointerDecay>
+  // CHECK-NEXT:  |       |   | `-DeclRefExpr {{.*}} 'const LockGuard &(const LockGuard &)' lvalue Function {{.*}} 'df1' 'const P2718R0::LockGuard &(const P2718R0::LockGuard &)' (FunctionTemplate {{.*}} 'df1')
   // CHECK-NEXT:  |       |   `-MaterializeTemporaryExpr {{.*}} 'const LockGuard':'const P2718R0::LockGuard' lvalue extended by Var {{.*}} '__range1' 'int (&)[3]'
   // CHECK-NEXT:  |       |     `-ImplicitCastExpr {{.*}} 'const LockGuard':'const P2718R0::LockGuard' <NoOp>
   // CHECK-NEXT:  |       |       `-CXXBindTemporaryExpr {{.*}} 'LockGuard':'P2718R0::LockGuard' (CXXTemporary {{.*}})
@@ -380,17 +380,17 @@ void test10() {
   // CHECK-NEXT:  | `-VarDecl {{.*}} implicit used __range1 'int (&)[3]' cinit
   // CHECK-NEXT:  |   `-ExprWithCleanups {{.*}} 'int[3]' lvalue
   // CHECK-NEXT:  |     `-BinaryOperator {{.*}} 'int[3]' lvalue ','
-  // CHECK-NEXT:  |       |-BinaryOperator {{.*}} 'const P2718R0::LockGuard' lvalue ','
-  // CHECK-NEXT:  |       | |-CallExpr {{.*}} 'const P2718R0::LockGuard' lvalue
-  // CHECK-NEXT:  |       | | |-ImplicitCastExpr {{.*}} 'const P2718R0::LockGuard &(*)(const P2718R0::LockGuard &)' <FunctionToPointerDecay>
-  // CHECK-NEXT:  |       | | | `-DeclRefExpr {{.*}} 'const P2718R0::LockGuard &(const P2718R0::LockGuard &)' lvalue Function {{.*}} 'df1' 'const P2718R0::LockGuard &(const P2718R0::LockGuard &)' (FunctionTemplate {{.*}} 'df1')
+  // CHECK-NEXT:  |       |-BinaryOperator {{.*}} 'const LockGuard':'const P2718R0::LockGuard' lvalue ','
+  // CHECK-NEXT:  |       | |-CallExpr {{.*}} 'const LockGuard':'const P2718R0::LockGuard' lvalue
+  // CHECK-NEXT:  |       | | |-ImplicitCastExpr {{.*}} 'const LockGuard &(*)(const LockGuard &)' <FunctionToPointerDecay>
+  // CHECK-NEXT:  |       | | | `-DeclRefExpr {{.*}} 'const LockGuard &(const LockGuard &)' lvalue Function {{.*}} 'df1' 'const P2718R0::LockGuard &(const P2718R0::LockGuard &)' (FunctionTemplate {{.*}} 'df1')
   // CHECK-NEXT:  |       | | `-MaterializeTemporaryExpr {{.*}} 'const LockGuard':'const P2718R0::LockGuard' lvalue extended by Var {{.*}} '__range1' 'int (&)[3]'
   // CHECK-NEXT:  |       | |   `-ImplicitCastExpr {{.*}} 'const LockGuard':'const P2718R0::LockGuard' <NoOp>
   // CHECK-NEXT:  |       | |     `-CXXBindTemporaryExpr {{.*}} 'LockGuard':'P2718R0::LockGuard' (CXXTemporary {{.*}})
   // CHECK-NEXT:  |       | |       `-CXXTemporaryObjectExpr {{.*}} 'LockGuard':'P2718R0::LockGuard' 'void ()'
-  // CHECK-NEXT:  |       | `-CallExpr {{.*}} 'const P2718R0::LockGuard' lvalue
-  // CHECK-NEXT:  |       |   |-ImplicitCastExpr {{.*}} 'const P2718R0::LockGuard &(*)(const P2718R0::LockGuard &)' <FunctionToPointerDecay>
-  // CHECK-NEXT:  |       |   | `-DeclRefExpr {{.*}} 'const P2718R0::LockGuard &(const P2718R0::LockGuard &)' lvalue Function {{.*}} 'df1' 'const P2718R0::LockGuard &(const P2718R0::LockGuard &)' (FunctionTemplate {{.*}} 'df1')
+  // CHECK-NEXT:  |       | `-CallExpr {{.*}} 'const LockGuard':'const P2718R0::LockGuard' lvalue
+  // CHECK-NEXT:  |       |   |-ImplicitCastExpr {{.*}} 'const LockGuard &(*)(const LockGuard &)' <FunctionToPointerDecay>
+  // CHECK-NEXT:  |       |   | `-DeclRefExpr {{.*}} 'const LockGuard &(const LockGuard &)' lvalue Function {{.*}} 'df1' 'const P2718R0::LockGuard &(const P2718R0::LockGuard &)' (FunctionTemplate {{.*}} 'df1')
   // CHECK-NEXT:  |       |   `-MaterializeTemporaryExpr {{.*}} 'const LockGuard':'const P2718R0::LockGuard' lvalue extended by Var {{.*}} '__range1' 'int (&)[3]'
   // CHECK-NEXT:  |       |     `-ImplicitCastExpr {{.*}} 'const LockGuard':'const P2718R0::LockGuard' <NoOp>
   // CHECK-NEXT:  |       |       `-CXXBindTemporaryExpr {{.*}} 'LockGuard':'P2718R0::LockGuard' (CXXTemporary {{.*}})
@@ -403,7 +403,7 @@ void test10() {
 // Test default argument && dependent context
 template <typename T> int (&default_arg_fn2(const T & = T()))[3];
 void test11() {
-  for (auto e : default_arg_fn2<A>()) 
+  for (auto e : default_arg_fn2<A>())
     bar(e);
 }
 
@@ -441,11 +441,11 @@ void test13() {
   // CHECK-NEXT:  |                                   `-MemberExpr {{.*}} '<bound member function type>' .g {{.*}}
   // CHECK-NEXT:  |                                     `-CXXMemberCallExpr {{.*}} 'A':'P2718R0::A' lvalue
   // CHECK-NEXT:  |                                       `-MemberExpr {{.*}} '<bound member function type>' .r {{.*}}
-  // CHECK-NEXT:  |                                         `-MaterializeTemporaryExpr {{.*}} 'P2718R0::A' xvalue extended by Var {{.*}} '__range1' 'A &&'
-  // CHECK-NEXT:  |                                           `-CXXBindTemporaryExpr {{.*}} 'P2718R0::A' (CXXTemporary {{.*}})
-  // CHECK-NEXT:  |                                             `-CallExpr {{.*}} 'P2718R0::A'
-  // CHECK-NEXT:  |                                               `-ImplicitCastExpr {{.*}} 'P2718R0::A (*)()' <FunctionToPointerDecay>
-  // CHECK-NEXT:  |                                                 `-DeclRefExpr {{.*}} 'P2718R0::A ()' lvalue Function {{.*}} 'dg' 'P2718R0::A ()' (FunctionTemplate {{.*}} 'dg')
+  // CHECK-NEXT:  |                                         `-MaterializeTemporaryExpr {{.*}} 'A':'P2718R0::A' xvalue extended by Var {{.*}} '__range1' 'A &&'
+  // CHECK-NEXT:  |                                           `-CXXBindTemporaryExpr {{.*}} 'A':'P2718R0::A' (CXXTemporary {{.*}})
+  // CHECK-NEXT:  |                                             `-CallExpr {{.*}} 'A':'P2718R0::A'
+  // CHECK-NEXT:  |                                               `-ImplicitCastExpr {{.*}} 'A (*)()' <FunctionToPointerDecay>
+  // CHECK-NEXT:  |                                                 `-DeclRefExpr {{.*}} 'A ()' lvalue Function {{.*}} 'dg' 'P2718R0::A ()' (FunctionTemplate {{.*}} 'dg')
   for (auto e : dg<A>().r().g().r().g().r().g())
     bar(e);
 }
diff --git a/clang/test/Analysis/cast-value-notes.cpp b/clang/test/Analysis/cast-value-notes.cpp
index acd33e704d13a..af6871b448276 100644
--- a/clang/test/Analysis/cast-value-notes.cpp
+++ b/clang/test/Analysis/cast-value-notes.cpp
@@ -73,7 +73,7 @@ void clang_analyzer_printState();
 #if defined(X86)
 void evalReferences(const Shape &S) {
   const auto &C = dyn_cast<Circle>(S);
-  // expected-note at -1 {{Assuming 'S' is not a 'const class clang::Circle &'}}
+  // expected-note at -1 {{Assuming 'S' is not a 'const Circle &'}}
   // expected-note at -2 {{Dereference of null pointer}}
   // expected-warning at -3 {{Dereference of null pointer}}
   clang_analyzer_printState();
@@ -86,26 +86,26 @@ void evalReferences_addrspace(const Shape &S) {
   const auto &C = dyn_cast<DEVICE Circle>(S);
   clang_analyzer_printState();
   // X86-CHECK-SUPPRESSED: "dynamic_types": [
-  // X86-CHECK-SUPPRESSED-NEXT: { "region": "SymRegion{reg_$0<const Shape & S>}", "dyn_type": "const __attribute__((address_space(3))) class clang::Circle &", "sub_classable": true }
+  // X86-CHECK-SUPPRESSED-NEXT: { "region": "SymRegion{reg_$0<const Shape & S>}", "dyn_type": "DEVICE Circle const &", "sub_classable": true }
   (void)C;
 }
 #endif
 #if defined(NOT_SUPPRESSED)
 void evalReferences_addrspace(const Shape &S) {
   const auto &C = dyn_cast<DEVICE Circle>(S);
-  // expected-note at -1 {{Assuming 'S' is not a 'const __attribute__((address_space(3))) class clang::Circle &'}}
+  // expected-note at -1 {{Assuming 'S' is not a 'DEVICE Circle const &'}}
   // expected-note at -2 {{Dereference of null pointer}}
   // expected-warning at -3 {{Dereference of null pointer}}
   clang_analyzer_printState();
   // X86-CHECK: "dynamic_types": [
-  // X86-CHECK-NEXT: { "region": "SymRegion{reg_$0<const Shape & S>}", "dyn_type": "const __attribute__((address_space(3))) class clang::Circle &", "sub_classable": true }
+  // X86-CHECK-NEXT: { "region": "SymRegion{reg_$0<const Shape & S>}", "dyn_type": "DEVICE Circle const &", "sub_classable": true }
   (void)C;
 }
 #endif
 #elif defined(MIPS)
 void evalReferences(const Shape &S) {
   const auto &C = dyn_cast<Circle>(S);
-  // expected-note at -1 {{Assuming 'S' is not a 'const class clang::Circle &'}}
+  // expected-note at -1 {{Assuming 'S' is not a 'const Circle &'}}
   // expected-note at -2 {{Dereference of null pointer}}
   // expected-warning at -3 {{Dereference of null pointer}}
 }
@@ -122,25 +122,25 @@ void evalNonNullParamNonNullReturnReference(const Shape &S) {
   // expected-note at -1 {{'C' initialized here}}
 
   if (!dyn_cast_or_null<Circle>(C)) {
-    // expected-note at -1 {{Assuming 'C' is a 'const class clang::Circle *'}}
+    // expected-note at -1 {{Assuming 'C' is a 'const Circle *'}}
     // expected-note at -2 {{Taking false branch}}
     return;
   }
 
   if (dyn_cast_or_null<Triangle>(C)) {
-    // expected-note at -1 {{Assuming 'C' is not a 'const class clang::Triangle *'}}
+    // expected-note at -1 {{Assuming 'C' is not a 'const Triangle *'}}
     // expected-note at -2 {{Taking false branch}}
     return;
   }
 
   if (dyn_cast_or_null<Rectangle>(C)) {
-    // expected-note at -1 {{Assuming 'C' is not a 'const class clang::Rectangle *'}}
+    // expected-note at -1 {{Assuming 'C' is not a 'const Rectangle *'}}
     // expected-note at -2 {{Taking false branch}}
     return;
   }
 
   if (dyn_cast_or_null<Hexagon>(C)) {
-    // expected-note at -1 {{Assuming 'C' is not a 'const class clang::Hexagon *'}}
+    // expected-note at -1 {{Assuming 'C' is not a 'const Hexagon *'}}
     // expected-note at -2 {{Taking false branch}}
     return;
   }
@@ -176,29 +176,29 @@ void evalNonNullParamNonNullReturnReference(const Shape &S) {
 
 void evalNonNullParamNonNullReturn(const Shape *S) {
   const auto *C = cast<Circle>(S);
-  // expected-note at -1 {{'S' is a 'const class clang::Circle *'}}
+  // expected-note at -1 {{'S' is a 'const Circle *'}}
   // expected-note at -2 {{'C' initialized here}}
 
   if (!dyn_cast_or_null<Circle>(C)) {
-    // expected-note at -1 {{Assuming 'C' is a 'const class clang::Circle *'}}
+    // expected-note at -1 {{Assuming 'C' is a 'const Circle *'}}
     // expected-note at -2 {{Taking false branch}}
     return;
   }
 
   if (dyn_cast_or_null<Triangle>(C)) {
-    // expected-note at -1 {{Assuming 'C' is not a 'const class clang::Triangle *'}}
+    // expected-note at -1 {{Assuming 'C' is not a 'const Triangle *'}}
     // expected-note at -2 {{Taking false branch}}
     return;
   }
 
   if (dyn_cast_or_null<Rectangle>(C)) {
-    // expected-note at -1 {{Assuming 'C' is not a 'const class clang::Rectangle *'}}
+    // expected-note at -1 {{Assuming 'C' is not a 'const Rectangle *'}}
     // expected-note at -2 {{Taking false branch}}
     return;
   }
 
   if (dyn_cast_or_null<Hexagon>(C)) {
-    // expected-note at -1 {{Assuming 'C' is not a 'const class clang::Hexagon *'}}
+    // expected-note at -1 {{Assuming 'C' is not a 'const Hexagon *'}}
     // expected-note at -2 {{Taking false branch}}
     return;
   }
@@ -234,10 +234,10 @@ void evalNonNullParamNonNullReturn(const Shape *S) {
 
 void evalNonNullParamNullReturn(const Shape *S) {
   const auto *C = dyn_cast_or_null<Circle>(S);
-  // expected-note at -1 {{Assuming 'S' is not a 'const class clang::Circle *'}}
+  // expected-note at -1 {{Assuming 'S' is not a 'const Circle *'}}
 
   if (const auto *T = dyn_cast_or_null<Triangle>(S)) {
-    // expected-note at -1 {{Assuming 'S' is a 'const class clang::Triangle *'}}
+    // expected-note at -1 {{Assuming 'S' is a 'const Triangle *'}}
     // expected-note at -2 {{'T' initialized here}}
     // expected-note at -3 {{'T' is non-null}}
     // expected-note at -4 {{Taking true branch}}
@@ -261,7 +261,7 @@ void evalNullParamNullReturn(const Shape *S) {
 
 void evalZeroParamNonNullReturnPointer(const Shape *S) {
   const auto *C = S->castAs<Circle>();
-  // expected-note at -1 {{'S' is a 'const class clang::Circle *'}}
+  // expected-note at -1 {{'S' is a 'const Circle *'}}
   // expected-note at -2 {{'C' initialized here}}
 
   (void)(1 / !C);
@@ -282,12 +282,12 @@ void evalZeroParamNonNullReturn(const Shape &S) {
 
 void evalZeroParamNullReturn(const Shape *S) {
   const auto &C = S->getAs<Circle>();
-  // expected-note at -1 {{Assuming 'S' is not a 'const class clang::Circle *'}}
+  // expected-note at -1 {{Assuming 'S' is not a 'const Circle *'}}
   // expected-note at -2 {{Storing null pointer value}}
   // expected-note at -3 {{'C' initialized here}}
 
   if (!dyn_cast_or_null<Triangle>(S)) {
-    // expected-note at -1 {{Assuming 'S' is a 'const class clang::Triangle *'}}
+    // expected-note at -1 {{Assuming 'S' is a 'const Triangle *'}}
     // expected-note at -2 {{Taking false branch}}
     return;
   }
diff --git a/clang/test/Analysis/cast-value-state-dump.cpp b/clang/test/Analysis/cast-value-state-dump.cpp
index 07fd7abd848ab..ee2854759fcc2 100644
--- a/clang/test/Analysis/cast-value-state-dump.cpp
+++ b/clang/test/Analysis/cast-value-state-dump.cpp
@@ -18,12 +18,12 @@ using namespace clang;
 
 void evalNonNullParamNonNullReturn(const Shape *S) {
   const auto *C = dyn_cast_or_null<Circle>(S);
-  // expected-note at -1 {{Assuming 'S' is a 'const class clang::Circle *'}}
+  // expected-note at -1 {{Assuming 'S' is a 'const Circle *'}}
   // expected-note at -2 {{'C' initialized here}}
 
   // FIXME: We assumed that 'S' is a 'Circle' therefore it is not a 'Square'.
   if (dyn_cast_or_null<Square>(S)) {
-    // expected-note at -1 {{Assuming 'S' is not a 'const class clang::Square *'}}
+    // expected-note at -1 {{Assuming 'S' is not a 'const Square *'}}
     // expected-note at -2 {{Taking false branch}}
     return;
   }
@@ -31,7 +31,7 @@ void evalNonNullParamNonNullReturn(const Shape *S) {
   clang_analyzer_printState();
 
   // CHECK:      "dynamic_types": [
-  // CHECK-NEXT:   { "region": "SymRegion{reg_$0<const Shape * S>}", "dyn_type": "const class clang::Circle", "sub_classable": true }
+  // CHECK-NEXT:   { "region": "SymRegion{reg_$0<const Shape * S>}", "dyn_type": "const Circle", "sub_classable": true }
   // CHECK-NEXT: ],
   // CHECK-NEXT: "dynamic_casts": [
   // CHECK:        { "region": "SymRegion{reg_$0<const Shape * S>}", "casts": [
diff --git a/clang/test/Analysis/lifetime-extended-regions.cpp b/clang/test/Analysis/lifetime-extended-regions.cpp
index 4458ad294af7c..59f43a59add16 100644
--- a/clang/test/Analysis/lifetime-extended-regions.cpp
+++ b/clang/test/Analysis/lifetime-extended-regions.cpp
@@ -54,7 +54,7 @@ void member_access() {
   int&& x = Composite{}.x;  // extends `Composite`
   clang_analyzer_dump(x); // expected-warning-re {{&lifetime_extended_object{Composite, x, S{{[0-9]+}}}.x }}
   int&& y = create<Composite>().y; // extends `Composite`
-  clang_analyzer_dump(y); // expected-warning-re {{&lifetime_extended_object{struct Composite, y, S{{[0-9]+}}}.y }}
+  clang_analyzer_dump(y); // expected-warning-re {{&lifetime_extended_object{Composite, y, S{{[0-9]+}}}.y }}
   int&& d = Array<int>{}.front(); // dangles `Array<int>`
   clang_analyzer_dump(d); // expected-warning-re {{&Element{temp_object{Array<int>, S{{[0-9]+}}}.array,0 S64b,int} }}
 }
@@ -120,7 +120,7 @@ void aggregateWithReferences() {
   clang_analyzer_dump(viaReference);    // expected-warning-re {{&lifetime_extended_object{RefAggregate, viaReference, S{{[0-9]+}}} }}
   clang_analyzer_dump(viaReference.rx); // expected-warning-re {{&lifetime_extended_object{int, viaReference, S{{[0-9]+}}} }}
   clang_analyzer_dump(viaReference.ry); // expected-warning-re {{&lifetime_extended_object{Composite, viaReference, S{{[0-9]+}}} }}
-  
+
   // FIXME: clang currently support extending lifetime of object bound to reference members of aggregates,
   // that are created from default member initializer. But CFG and ExprEngine need to be updated to address this change.
   // The following expect warning: {{&lifetime_extended_object{Composite, defaultInitExtended, S{{[0-9]+}}} }}
@@ -140,8 +140,8 @@ void lambda() {
   // See also CWG2737 (https://cplusplus.github.io/CWG/issues/2737.html)
   auto const refExtendingCapture = [&refCapture = create<Composite const>()] {
      clang_analyzer_dump(refCapture);
-     // cpp14-warning-re at -1 {{&temp_object{const struct Composite, S{{[0-9]+}}} }}
-     // cpp17-warning-re at -2 {{&lifetime_extended_object{const struct Composite, refExtendingCapture, S{{[0-9]+}}} }}
+     // cpp14-warning-re at -1 {{&temp_object{const Composite, S{{[0-9]+}}} }}
+     // cpp17-warning-re at -2 {{&lifetime_extended_object{const Composite, refExtendingCapture, S{{[0-9]+}}} }}
   };
   refExtendingCapture();
 }
diff --git a/clang/test/CXX/class.derived/class.abstract/p3.cpp b/clang/test/CXX/class.derived/class.abstract/p3.cpp
index cf973d2567294..4616ad5c7e6ed 100644
--- a/clang/test/CXX/class.derived/class.abstract/p3.cpp
+++ b/clang/test/CXX/class.derived/class.abstract/p3.cpp
@@ -75,7 +75,7 @@ void h() {
 template<typename T> void t(T);
 void i(A &a, B &b, C &c, D &d) {
   t(a); // expected-error {{allocating an object of abstract class type 'A'}}
-  t(b); // expected-error {{allocating an object of abstract class type 'SecretlyAbstract<int>'}}
+  t(b); // expected-error {{allocating an object of abstract class type 'B' (aka 'SecretlyAbstract<int>')}}
   t(c); // expected-error {{allocating an object of abstract class type}}
   t(d); // ok, decays to pointer
 }
diff --git a/clang/test/CXX/drs/cwg23xx.cpp b/clang/test/CXX/drs/cwg23xx.cpp
index d144cf9e4e868..2262a11055148 100644
--- a/clang/test/CXX/drs/cwg23xx.cpp
+++ b/clang/test/CXX/drs/cwg23xx.cpp
@@ -63,7 +63,7 @@ template<typename T> void foo(T&, ...);
 struct Q; // #cwg2304-Q
 void fn1(Q &data_vectors) {
   foo(data_vectors, 0);
-  // expected-error at -1 {{argument type 'cwg2304::Q' is incomplete}}
+  // expected-error at -1 {{argument type 'Q' is incomplete}}
   //   expected-note@#cwg2304-Q {{forward declaration of 'cwg2304::Q'}}
 }
 } // namespace cwg2304
@@ -91,7 +91,7 @@ struct Y {};
 struct Z : W,
   X, check_derived_from<Z, X>, // #cwg2310-X
   check_derived_from<Z, Y>, Y  // #cwg2310-Y
-{  
+{
   // FIXME: It was properly rejected before, but we're crashing since Clang 11 in C++11 and C++14 modes.
   //        See https://github.com/llvm/llvm-project/issues/59920
 #if __cplusplus >= 201703L
diff --git a/clang/test/CXX/drs/cwg26xx.cpp b/clang/test/CXX/drs/cwg26xx.cpp
index 3eb70583b6026..c56bf29b8770f 100644
--- a/clang/test/CXX/drs/cwg26xx.cpp
+++ b/clang/test/CXX/drs/cwg26xx.cpp
@@ -90,7 +90,7 @@ D<T, N> d();
 std::int32_t d1{ d<std::int64_t, 31>().i };
 std::int32_t d2{ d<std::int64_t, 32>().i };
 std::int32_t d3{ d<std::int64_t, 33>().i };
-// since-cxx11-error at -1 {{non-constant-expression cannot be narrowed from type 'long long' to 'std::int32_t' (aka 'int') in initializer list}}
+// since-cxx11-error at -1 {{non-constant-expression cannot be narrowed from type 'std::int64_t' (aka 'long long') to 'std::int32_t' (aka 'int') in initializer list}}
 //   since-cxx11-note at -2 {{insert an explicit cast to silence this issue}}
 
 std::int16_t d6{ d<int, 16>().i };
diff --git a/clang/test/CXX/drs/cwg4xx.cpp b/clang/test/CXX/drs/cwg4xx.cpp
index e8e2600870233..c9596d8b4e9d8 100644
--- a/clang/test/CXX/drs/cwg4xx.cpp
+++ b/clang/test/CXX/drs/cwg4xx.cpp
@@ -565,16 +565,16 @@ namespace cwg428 { // cwg428: 2.7
     // expected-error at -1 {{cannot throw object of incomplete type 'struct X'}}
     //   expected-note@#cwg428-X {{forward declaration of 'cwg428::X'}}
     throw make<X&>();
-    // expected-error at -1 {{cannot throw object of incomplete type 'cwg428::X'}}
+    // expected-error at -1 {{cannot throw object of incomplete type 'X'}}
     //   expected-note@#cwg428-X {{forward declaration of 'cwg428::X'}}
     throw make<X*>();
-    // expected-error at -1 {{cannot throw pointer to object of incomplete type 'cwg428::X'}}
+    // expected-error at -1 {{cannot throw pointer to object of incomplete type 'X'}}
     //   expected-note@#cwg428-X {{forward declaration of 'cwg428::X'}}
     throw make<const volatile X&>();
-    // expected-error at -1 {{cannot throw object of incomplete type 'cwg428::X'}}
+    // expected-error at -1 {{cannot throw object of incomplete type 'X'}}
     //   expected-note@#cwg428-X {{forward declaration of 'cwg428::X'}}
     throw make<const volatile X*>();
-    // expected-error at -1 {{cannot throw pointer to object of incomplete type 'const volatile cwg428::X'}}
+    // expected-error at -1 {{cannot throw pointer to object of incomplete type 'const volatile X'}}
     //   expected-note@#cwg428-X {{forward declaration of 'cwg428::X'}}
   }
 } // namespace cwg428
diff --git a/clang/test/CXX/drs/cwg6xx.cpp b/clang/test/CXX/drs/cwg6xx.cpp
index e2eb009508b52..004c02bed7f86 100644
--- a/clang/test/CXX/drs/cwg6xx.cpp
+++ b/clang/test/CXX/drs/cwg6xx.cpp
@@ -750,7 +750,7 @@ namespace cwg656 { // cwg656: 2.8
   void f() {
     accept<const A&>(x);
     accept<const A&>(y);
-    // expected-error at -1 {{cannot cast 'const Y' to its private base class 'const cwg656::A'}}
+    // expected-error at -1 {{cannot cast 'const Y' to its private base class 'const A'}}
     //   expected-note@#cwg656-Y {{declared private here}}
     accept<const A&>(vy); // #cwg656-vy
     // expected-error at -1 {{call to deleted function 'accept'}}
diff --git a/clang/test/Misc/diag-template-diffing-cxx11.cpp b/clang/test/Misc/diag-template-diffing-cxx11.cpp
index c62bffe2b458d..9f80604bf3f04 100644
--- a/clang/test/Misc/diag-template-diffing-cxx11.cpp
+++ b/clang/test/Misc/diag-template-diffing-cxx11.cpp
@@ -1169,7 +1169,7 @@ Wrapper<S<&global2, nullptr>> W12 =
 // CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper<S<&global, [...]>>' to 'Wrapper<S<&global2, [...]>>'
 
 Wrapper<S<&global, &global>> W13 = MakeWrapper<S<&global, ptr>>();
-// CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper<S<[...], nullptr>>' to 'Wrapper<S<[...], &global>>'
+// CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper<S<[...], ptr aka nullptr>>' to 'Wrapper<S<[...], &global>>'
 Wrapper<S<&global, ptr>> W14 = MakeWrapper<S<&global, &global>>();
 // CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper<S<[...], &global>>' to 'Wrapper<S<[...], ptr aka nullptr>>'
 }
@@ -1381,8 +1381,8 @@ namespace DefaultNonTypeArgWithDependentType {
 template <typename SizeType = int, SizeType = 0> struct A {};
 template <typename R = A<>> R bar();
 A<> &foo() { return bar(); }
-// CHECK-ELIDE-NOTREE: error: non-const lvalue reference to type 'A<...>' cannot bind to a temporary of type 'A<...>'
-// CHECK-NOELIDE-NOTREE: error: non-const lvalue reference to type 'A<int, 0>' cannot bind to a temporary of type 'A<int, 0>'
+// CHECK-ELIDE-NOTREE: error: non-const lvalue reference to type 'A<>' cannot bind to a temporary of type 'A<>'
+// CHECK-NOELIDE-NOTREE: error: non-const lvalue reference to type 'A<>' cannot bind to a temporary of type 'A<>'
 }
 
 namespace PR24587 {
diff --git a/clang/test/Sema/Resugar/resugar-expr.cpp b/clang/test/Sema/Resugar/resugar-expr.cpp
new file mode 100644
index 0000000000000..336c480b359cc
--- /dev/null
+++ b/clang/test/Sema/Resugar/resugar-expr.cpp
@@ -0,0 +1,227 @@
+// RUN: %clang_cc1 -std=c++2b -fsyntax-only -verify %s
+
+enum class Z;
+
+struct bar {};
+
+using Int = int;
+using Float = float;
+using Bar = bar;
+
+namespace t1 {
+template <class A1> struct A {
+  static constexpr A1 a = {};
+};
+
+Z x1 = A<Int>::a;
+// expected-error at -1 {{with an lvalue of type 'const Int' (aka 'const int')}}
+} // namespace t1
+
+namespace t2 {
+template <class A1, class A2> struct A {
+  static constexpr A1 A2::*a = {};
+};
+
+Z x1 = A<Int, Bar>::a;
+// expected-error at -1 {{with an lvalue of type 'Int Bar::*const'}}
+} // namespace t2
+
+namespace t3 {
+template <class A1> struct A {
+  template <class B1> struct B {
+    static constexpr A1 B1::*a = {};
+  };
+};
+
+Z x1 = A<Float>::B<Bar>::a;
+// expected-error at -1 {{with an lvalue of type 'Float Bar::*const'}}
+} // namespace t3
+
+namespace t4 {
+template <class A1> A1 (*a) ();
+
+// FIXME: resugar this
+Z x1 = decltype(a<Int>){}();
+// expected-error at -1 {{with an rvalue of type 'int'}}
+} // namespace t4
+
+namespace t5 {
+template <class A1> struct A {
+  A1(*a)
+  ();
+};
+
+// FIXME: resugar this
+Z x1 = decltype(A<Int>().a){}();
+// expected-error at -1 {{with an rvalue of type 'int'}}
+} // namespace t5
+
+namespace t6 {
+template <class A1, class A2> struct A { A2 A1::*f(); };
+
+using M = int;
+using N = int;
+
+struct B {};
+using X = B;
+using Y = B;
+
+auto a = &A<X, M>::f;
+Z x1 = a;
+// expected-error at -1 {{with an lvalue of type 'M X::*(A<X, M>::*)()'}}
+
+A<Y, N> b;
+Z x2 = (b.*a)();
+// expected-error at -1 {{with an rvalue of type 'M X::*'}}
+
+Z x3 = decltype((b.*a)()){};
+// expected-error at -1 {{with an rvalue of type 'decltype((b .* a)())' (aka 'M X::*')}}
+} // namespace t6
+
+namespace t7 {
+template <class A1> struct A { A1 a; };
+auto [a] = A<Int>{};
+
+Z x1 = a;
+// expected-error at -1 {{with an lvalue of type 'Int' (aka 'int')}}
+} // namespace t7
+
+namespace t8 {
+template <class A1> struct A {
+  template <class B1> static constexpr B1 (*b)(A1) = nullptr;
+};
+
+Z x1 = A<Float>::b<Int>;
+// expected-error at -1 {{with an lvalue of type 'Int (*const)(Float)' (aka 'int (*const)(float)')}}
+} // namespace t8
+
+namespace t9 {
+template <class A1> struct A {
+  template <class B1> static constexpr auto b = (B1(*)(A1)){};
+};
+
+Z x1 = A<Float>::b<Int>;
+// expected-error at -1 {{with an lvalue of type 'Int (*const)(Float)' (aka 'int (*const)(float)'}}
+} // namespace t9
+
+namespace t10 {
+template <class A1> struct A {
+  template <class B1> static constexpr A1 (*m)(B1) = nullptr;
+};
+
+Z x1 = A<Int>().template m<Float>;
+// expected-error at -1 {{with an lvalue of type 'Int (*const)(Float)' (aka 'int (*const)(float)'}}
+} // namespace t10
+
+namespace t11 {
+template <class A1> A1 a;
+template <class A2> A2 a<A2 *>;
+
+Z x1 = a<Int>;
+// expected-error at -1 {{with an lvalue of type 'Int' (aka 'int')}}
+
+Z x2 = a<Float *>;
+// expected-error at -1 {{with an lvalue of type 'Float' (aka 'float')}}
+} // namespace t11
+
+namespace t12 {
+template<class A1> A1 *a;
+template<int A3, class A4> decltype(a<A4[A3 - 1]>) a<A4[A3]>;
+
+// FIXME: resugar this
+Z x1 = *a<Int[1]>;
+// expected-error at -1 {{with an lvalue of type 'int[0]'}}
+} // namespace t12
+
+namespace t13 {
+template <class A1> struct A { A1 foo(); };
+
+Z x1 = A<Int>().foo();
+// expected-error at -1 {{with an rvalue of type 'Int' (aka 'int')}}
+} // namespace t13
+
+namespace t14 {
+template <class A1> struct A {
+  auto foo() { return A1(); };
+};
+
+Z x1 = A<Int>().foo();
+// expected-error at -1 {{with an rvalue of type 'Int' (aka 'int')}}
+} // namespace t14
+
+namespace t15 {
+template <class A1> struct A {
+  template <class B1> auto foo1() -> A1 (*)(B1);
+  template <class B1> auto foo2(B1) -> A1 (*)(B1);
+};
+
+Z x1 = A<Int>().foo1<Float>();
+// expected-error at -1 {{with an rvalue of type 'Int (*)(Float)' (aka 'int (*)(float)'}}
+
+Z x2 = A<Int>().foo2(Float());
+// expected-error at -1 {{with an rvalue of type 'Int (*)(Float)' (aka 'int (*)(float)'}}
+} // namespace t15
+
+namespace t16 {
+template <class A1> struct A {
+  static auto foo() -> A1;
+};
+
+Z x1 = A<Int>().foo();
+// expected-error at -1 {{with an rvalue of type 'Int' (aka 'int')}}
+} // namespace t16
+
+namespace t17 {
+template <class A1> static auto foo() -> A1;
+
+Z x1 = foo<Int>();
+// expected-error at -1 {{with an rvalue of type 'Int' (aka 'int')}}
+} // namespace t17
+
+namespace t18 {
+template <class A1> static auto foo(A1) -> A1*;
+
+Z x1 = foo(Int());
+// expected-error at -1 {{with an rvalue of type 'Int *' (aka 'int *')}}
+} // namespace t18
+
+namespace t19 {
+template <class A1> struct A {
+  template <class B1> static auto foo() -> A1 (*)(B1);
+};
+
+Z x1 = A<Int>().template foo<Float>();
+// expected-error at -1 {{with an rvalue of type 'Int (*)(Float)' (aka 'int (*)(float)'}}
+
+Z x2 = A<Int>::template foo<Float>();
+// expected-error at -1 {{with an rvalue of type 'Int (*)(Float)' (aka 'int (*)(float)'}}
+} // namespace t19
+
+namespace t20 {
+template <class A1> struct A {
+  A1 m;
+};
+
+Z x1 = A<Int>().m;
+// expected-error at -1 {{with an rvalue of type 'Int' (aka 'int')}}
+} // namespace t20
+
+namespace t21 {
+template <class A1> struct A {
+  static A1 m;
+};
+
+Z x1 = A<Int>().m;
+// expected-error at -1 {{with an lvalue of type 'Int' (aka 'int')}}
+} // namespace t21
+
+namespace t22 {
+template <class A1> struct A {
+  struct {
+    A1 m;
+  };
+};
+
+Z x1 = A<Int>().m;
+// expected-error at -1 {{with an rvalue of type 'Int' (aka 'int')}}
+} // namespace t22
diff --git a/clang/test/SemaTemplate/attributes.cpp b/clang/test/SemaTemplate/attributes.cpp
index dea19d09745ca..10127f17a4532 100644
--- a/clang/test/SemaTemplate/attributes.cpp
+++ b/clang/test/SemaTemplate/attributes.cpp
@@ -632,7 +632,8 @@ namespace preferred_name {
   };
   template<typename T> T desugar(T);
   auto it = desugar(MemberTemplate<int>::Iter<const int>());
-  int n = it; // expected-error {{no viable conversion from 'preferred_name::MemberTemplate<int>::const_iterator' to 'int'}}
+  // FIXME: We need to implement a __builtin_canonicalize_type for this ;-)
+  int n = it; // expected-error {{no viable conversion from 'MemberTemplate<int>::Iter<const int>' to 'int'}}
 
   template<int A, int B, typename ...T> struct Foo;
   template<typename ...T> using Bar = Foo<1, 2, T...>;
diff --git a/clang/unittests/Tooling/StencilTest.cpp b/clang/unittests/Tooling/StencilTest.cpp
index 445912a53e8b6..1ef15b5ce09bd 100644
--- a/clang/unittests/Tooling/StencilTest.cpp
+++ b/clang/unittests/Tooling/StencilTest.cpp
@@ -556,8 +556,9 @@ TEST_F(StencilTest, DescribeUnqualifiedType) {
 }
 
 TEST_F(StencilTest, DescribeAnonNamespaceType) {
+  // FIXME: We need to implement a __builtin_canonicalize_type for this ;-)
   std::string Snippet = "auto c = desugar<AnonC>(); c;";
-  std::string Expected = "(anonymous namespace)::AnonC";
+  std::string Expected = "AnonC";
   auto StmtMatch =
       matchStmt(Snippet, declRefExpr(hasType(qualType().bind("type"))));
   ASSERT_TRUE(StmtMatch);



More information about the llvm-branch-commits mailing list