[llvm-branch-commits] [clang] WIP: [clang] Store in exprs the conveed arguments for function calls. (PR #132444)

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


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

>From 6ee15e5569c66997be0c7e4c3627e7ec11ed0fd5 Mon Sep 17 00:00:00 2001
From: Matheus Izvekov <mizvekov at gmail.com>
Date: Sat, 17 Sep 2022 23:34:04 +0200
Subject: [PATCH] WIP: [clang] Store in exprs the conveed arguments for
 function calls.

WIP - Not ready for review

This keeps around in expressions the sugared converted arguments.
This is a pre-requisite for adding some additional users of the
resugaring transform.

Differential Revision: https://reviews.llvm.org/D134115
---
 clang/include/clang/AST/ASTImporter.h      |   7 +
 clang/include/clang/AST/DeclTemplate.h     |   2 +-
 clang/include/clang/AST/Expr.h             |  38 ++-
 clang/include/clang/Sema/Initialization.h  |   8 +-
 clang/include/clang/Sema/Overload.h        |   3 +
 clang/include/clang/Sema/Sema.h            |  45 ++--
 clang/include/clang/Sema/SemaCUDA.h        |   4 +-
 clang/lib/AST/ASTImporter.cpp              |  18 +-
 clang/lib/AST/DeclTemplate.cpp             |   2 +-
 clang/lib/AST/Expr.cpp                     |  49 ++--
 clang/lib/Analysis/BodyFarm.cpp            |   4 +-
 clang/lib/CodeGen/CGExpr.cpp               |   3 +-
 clang/lib/Sema/SemaCUDA.cpp                |  17 +-
 clang/lib/Sema/SemaCast.cpp                |  30 +--
 clang/lib/Sema/SemaChecking.cpp            |   2 +-
 clang/lib/Sema/SemaDeclAttr.cpp            |  12 +-
 clang/lib/Sema/SemaExpr.cpp                |  68 +++---
 clang/lib/Sema/SemaExprCXX.cpp             |  31 ++-
 clang/lib/Sema/SemaExprMember.cpp          |  19 +-
 clang/lib/Sema/SemaInit.cpp                |  45 ++--
 clang/lib/Sema/SemaOverload.cpp            | 270 ++++++++++++---------
 clang/lib/Sema/SemaTemplate.cpp            |  53 ++--
 clang/lib/Sema/SemaTemplateDeduction.cpp   |  24 +-
 clang/lib/Sema/SemaTemplateInstantiate.cpp |   1 +
 clang/lib/Sema/TreeTransform.h             | 142 ++++++++---
 clang/lib/Serialization/ASTReader.cpp      |   9 +
 clang/lib/Serialization/ASTReaderStmt.cpp  |   3 +
 clang/lib/Serialization/ASTWriterDecl.cpp  |   1 +
 clang/lib/Serialization/ASTWriterStmt.cpp  |  11 +-
 29 files changed, 578 insertions(+), 343 deletions(-)

diff --git a/clang/include/clang/AST/ASTImporter.h b/clang/include/clang/AST/ASTImporter.h
index c40b92666a2ff..343db3438b6ca 100644
--- a/clang/include/clang/AST/ASTImporter.h
+++ b/clang/include/clang/AST/ASTImporter.h
@@ -489,6 +489,13 @@ class TypeSourceInfo;
     /// error.
     llvm::Expected<APValue> Import(const APValue &FromValue);
 
+    /// Import the given C++ TemplateArgumentList from the "from"
+    /// context into the "to" context.
+    ///
+    /// \returns The equivalent initializer in the "to" context, or the import
+    /// error.
+    llvm::Expected<TemplateArgumentList *> Import(const TemplateArgumentList *);
+
     /// Import the definition of the given declaration, including all of
     /// the declarations it contains.
     [[nodiscard]] llvm::Error ImportDefinition(Decl *From);
diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h
index 7ba21aa2c1a4c..d2778ae0988d9 100644
--- a/clang/include/clang/AST/DeclTemplate.h
+++ b/clang/include/clang/AST/DeclTemplate.h
@@ -265,7 +265,7 @@ class TemplateArgumentList final
 
   /// Create a new template argument list that copies the given set of
   /// template arguments.
-  static TemplateArgumentList *CreateCopy(ASTContext &Context,
+  static TemplateArgumentList *CreateCopy(const ASTContext &Context,
                                           ArrayRef<TemplateArgument> Args);
 
   /// Retrieve the template argument at a given index.
diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index 08e34fdf2aa2f..2ba787ac6df55 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -1274,6 +1274,8 @@ class DeclRefExpr final
   /// The declaration that we are referencing.
   ValueDecl *D;
 
+  const TemplateArgumentList *ConvertedArgs;
+
   /// Provides source/type location info for the declaration name
   /// embedded in D.
   DeclarationNameLoc DNLoc;
@@ -1298,7 +1300,8 @@ class DeclRefExpr final
               SourceLocation TemplateKWLoc, ValueDecl *D,
               bool RefersToEnclosingVariableOrCapture,
               const DeclarationNameInfo &NameInfo, NamedDecl *FoundD,
-              const TemplateArgumentListInfo *TemplateArgs, QualType T,
+              const TemplateArgumentListInfo *TemplateArgs,
+              const TemplateArgumentList *ConvertedArgs, QualType T,
               ExprValueKind VK, NonOdrUseReason NOUR);
 
   /// Construct an empty declaration reference expression.
@@ -1317,6 +1320,7 @@ class DeclRefExpr final
          bool RefersToEnclosingVariableOrCapture, SourceLocation NameLoc,
          QualType T, ExprValueKind VK, NamedDecl *FoundD = nullptr,
          const TemplateArgumentListInfo *TemplateArgs = nullptr,
+         const TemplateArgumentList *ConvertedArgs = nullptr,
          NonOdrUseReason NOUR = NOUR_None);
 
   static DeclRefExpr *
@@ -1326,6 +1330,7 @@ class DeclRefExpr final
          const DeclarationNameInfo &NameInfo, QualType T, ExprValueKind VK,
          NamedDecl *FoundD = nullptr,
          const TemplateArgumentListInfo *TemplateArgs = nullptr,
+         const TemplateArgumentList *ConvertedArgs = nullptr,
          NonOdrUseReason NOUR = NOUR_None);
 
   /// Construct an empty declaration reference expression.
@@ -1433,6 +1438,8 @@ class DeclRefExpr final
     return getTrailingObjects<TemplateArgumentLoc>();
   }
 
+  const TemplateArgumentList *getConvertedArgs() const { return ConvertedArgs; }
+
   /// Retrieve the number of template arguments provided as part of this
   /// template-id.
   unsigned getNumTemplateArgs() const {
@@ -3248,6 +3255,8 @@ class MemberExpr final
   /// In X.F, this is the decl referenced by F.
   ValueDecl *MemberDecl;
 
+  const TemplateArgumentList *Deduced;
+
   /// MemberDNLoc - Provides source/type location info for the
   /// declaration name embedded in MemberDecl.
   DeclarationNameLoc MemberDNLoc;
@@ -3277,21 +3286,21 @@ class MemberExpr final
              NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc,
              ValueDecl *MemberDecl, DeclAccessPair FoundDecl,
              const DeclarationNameInfo &NameInfo,
-             const TemplateArgumentListInfo *TemplateArgs, QualType T,
-             ExprValueKind VK, ExprObjectKind OK, NonOdrUseReason NOUR);
+             const TemplateArgumentListInfo *TemplateArgs,
+             const TemplateArgumentList *Deduced, QualType T, ExprValueKind VK,
+             ExprObjectKind OK, NonOdrUseReason NOUR);
   MemberExpr(EmptyShell Empty)
       : Expr(MemberExprClass, Empty), Base(), MemberDecl() {}
 
 public:
-  static MemberExpr *Create(const ASTContext &C, Expr *Base, bool IsArrow,
-                            SourceLocation OperatorLoc,
-                            NestedNameSpecifierLoc QualifierLoc,
-                            SourceLocation TemplateKWLoc, ValueDecl *MemberDecl,
-                            DeclAccessPair FoundDecl,
-                            DeclarationNameInfo MemberNameInfo,
-                            const TemplateArgumentListInfo *TemplateArgs,
-                            QualType T, ExprValueKind VK, ExprObjectKind OK,
-                            NonOdrUseReason NOUR);
+  static MemberExpr *
+  Create(const ASTContext &C, Expr *Base, bool IsArrow,
+         SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc,
+         SourceLocation TemplateKWLoc, ValueDecl *MemberDecl,
+         DeclAccessPair FoundDecl, DeclarationNameInfo MemberNameInfo,
+         const TemplateArgumentListInfo *TemplateArgs,
+         const TemplateArgumentList *Deduced, QualType T, ExprValueKind VK,
+         ExprObjectKind OK, NonOdrUseReason NOUR);
 
   /// Create an implicit MemberExpr, with no location, qualifier, template
   /// arguments, and so on. Suitable only for non-static member access.
@@ -3302,7 +3311,8 @@ class MemberExpr final
     return Create(C, Base, IsArrow, SourceLocation(), NestedNameSpecifierLoc(),
                   SourceLocation(), MemberDecl,
                   DeclAccessPair::make(MemberDecl, MemberDecl->getAccess()),
-                  DeclarationNameInfo(), nullptr, T, VK, OK, NOUR_None);
+                  DeclarationNameInfo(), nullptr, /*Deduced=*/{}, T, VK, OK,
+                  NOUR_None);
   }
 
   static MemberExpr *CreateEmpty(const ASTContext &Context, bool HasQualifier,
@@ -3328,6 +3338,8 @@ class MemberExpr final
     return *getTrailingObjects<DeclAccessPair>();
   }
 
+  const TemplateArgumentList *getDeduced() const { return Deduced; }
+
   /// Determines whether this member expression actually had
   /// a C++ nested-name-specifier prior to the name of the member, e.g.,
   /// x->Base::foo.
diff --git a/clang/include/clang/Sema/Initialization.h b/clang/include/clang/Sema/Initialization.h
index 0455e1fa5016b..77e3100a69ace 100644
--- a/clang/include/clang/Sema/Initialization.h
+++ b/clang/include/clang/Sema/Initialization.h
@@ -957,6 +957,7 @@ class InitializationSequence {
       bool HadMultipleCandidates;
       FunctionDecl *Function;
       DeclAccessPair FoundDecl;
+      const TemplateArgumentList *ConvertedArgs;
     };
 
     union {
@@ -1262,9 +1263,10 @@ class InitializationSequence {
   ///
   /// \param Function the function to which the overloaded function reference
   /// resolves.
-  void AddAddressOverloadResolutionStep(FunctionDecl *Function,
-                                        DeclAccessPair Found,
-                                        bool HadMultipleCandidates);
+  void
+  AddAddressOverloadResolutionStep(FunctionDecl *Function, DeclAccessPair Found,
+                                   const TemplateArgumentList *ConvertedArgs,
+                                   bool HadMultipleCandidates);
 
   /// Add a new step in the initialization that performs a derived-to-
   /// base cast.
diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h
index 6e08762dcc6d7..4ec7163ac1f07 100644
--- a/clang/include/clang/Sema/Overload.h
+++ b/clang/include/clang/Sema/Overload.h
@@ -961,6 +961,9 @@ class Sema;
       StandardConversionSequence FinalConversion;
     };
 
+    /// Deduced Arguments for Function Templates.
+    const TemplateArgumentList *Deduced;
+
     /// Get RewriteKind value in OverloadCandidateRewriteKind type (This
     /// function is to workaround the spurious GCC bitfield enum warning)
     OverloadCandidateRewriteKind getRewriteKind() const {
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 069fe077cc74c..8b7d651594f55 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -6856,7 +6856,8 @@ class Sema final : public SemaBase {
                    const CXXScopeSpec *SS = nullptr,
                    NamedDecl *FoundD = nullptr,
                    SourceLocation TemplateKWLoc = SourceLocation(),
-                   const TemplateArgumentListInfo *TemplateArgs = nullptr);
+                   const TemplateArgumentListInfo *TemplateArgs = nullptr,
+                   const TemplateArgumentList *ConvertArgs = nullptr);
 
   /// BuildDeclRefExpr - Build an expression that references a
   /// declaration that does not require a closure capture.
@@ -6865,7 +6866,8 @@ class Sema final : public SemaBase {
                    const DeclarationNameInfo &NameInfo,
                    NestedNameSpecifierLoc NNS, NamedDecl *FoundD = nullptr,
                    SourceLocation TemplateKWLoc = SourceLocation(),
-                   const TemplateArgumentListInfo *TemplateArgs = nullptr);
+                   const TemplateArgumentListInfo *TemplateArgs = nullptr,
+                   const TemplateArgumentList *ConvertArgs = nullptr);
 
   bool UseArgumentDependentLookup(const CXXScopeSpec &SS, const LookupResult &R,
                                   bool HasTrailingLParen);
@@ -6887,6 +6889,7 @@ class Sema final : public SemaBase {
       const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, NamedDecl *D,
       NamedDecl *FoundD = nullptr,
       const TemplateArgumentListInfo *TemplateArgs = nullptr,
+      const TemplateArgumentList *ConvertedArgs = nullptr,
       bool AcceptInvalidDecl = false);
 
   // ExpandFunctionLocalPredefinedMacros - Returns a new vector of Tokens,
@@ -8700,14 +8703,13 @@ class Sema final : public SemaBase {
                                    SourceLocation TemplateKWLoc,
                                    UnqualifiedId &Member, Decl *ObjCImpDecl);
 
-  MemberExpr *
-  BuildMemberExpr(Expr *Base, bool IsArrow, SourceLocation OpLoc,
-                  NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc,
-                  ValueDecl *Member, DeclAccessPair FoundDecl,
-                  bool HadMultipleCandidates,
-                  const DeclarationNameInfo &MemberNameInfo, QualType Ty,
-                  ExprValueKind VK, ExprObjectKind OK,
-                  const TemplateArgumentListInfo *TemplateArgs = nullptr);
+  MemberExpr *BuildMemberExpr(
+      Expr *Base, bool IsArrow, SourceLocation OpLoc,
+      NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc,
+      ValueDecl *Member, DeclAccessPair FoundDecl, bool HadMultipleCandidates,
+      const DeclarationNameInfo &MemberNameInfo, QualType Ty, ExprValueKind VK,
+      ExprObjectKind OK, const TemplateArgumentListInfo *TemplateArgs = nullptr,
+      const TemplateArgumentList *Deduced = nullptr);
 
   // Check whether the declarations we found through a nested-name
   // specifier in a member expression are actually members of the base
@@ -10299,6 +10301,7 @@ class Sema final : public SemaBase {
       ADLCallKind IsADLCandidate = ADLCallKind::NotADL,
       ConversionSequenceList EarlyConversions = {},
       OverloadCandidateParamOrder PO = {},
+      const TemplateArgumentList *Deduced = nullptr,
       bool AggregateCandidateDeduction = false, bool StrictPackMatch = false);
 
   /// Add all of the function declarations in the given function set to
@@ -10335,6 +10338,7 @@ class Sema final : public SemaBase {
                           bool PartialOverloading = false,
                           ConversionSequenceList EarlyConversions = {},
                           OverloadCandidateParamOrder PO = {},
+                          const TemplateArgumentList *Deduced = nullptr,
                           bool StrictPackMatch = false);
 
   /// Add a C++ member function template as a candidate to the candidate
@@ -10543,6 +10547,7 @@ class Sema final : public SemaBase {
   FunctionDecl *
   ResolveAddressOfOverloadedFunction(Expr *AddressOfExpr, QualType TargetType,
                                      bool Complain, DeclAccessPair &Found,
+                                     const TemplateArgumentList *&ConvertedArgs,
                                      bool *pHadMultipleCandidates = nullptr);
 
   /// Given an expression that refers to an overloaded function, try to
@@ -10576,7 +10581,9 @@ class Sema final : public SemaBase {
   /// If no template-ids are found, no diagnostics are emitted and NULL is
   /// returned.
   FunctionDecl *ResolveSingleFunctionTemplateSpecialization(
-      OverloadExpr *ovl, bool Complain = false, DeclAccessPair *Found = nullptr,
+      OverloadExpr *ovl, TemplateArgumentListInfo &ExplicitTemplateArgs,
+      const TemplateArgumentList *&ConvertedArgs, bool Complain = false,
+      DeclAccessPair *Found = nullptr,
       TemplateSpecCandidateSet *FailedTSC = nullptr,
       bool ForTypeDeduction = false);
 
@@ -10761,11 +10768,14 @@ class Sema final : public SemaBase {
   /// perhaps a '&' around it). We have resolved the overloaded function
   /// to the function declaration Fn, so patch up the expression E to
   /// refer (possibly indirectly) to Fn. Returns the new expr.
-  ExprResult FixOverloadedFunctionReference(Expr *E, DeclAccessPair FoundDecl,
-                                            FunctionDecl *Fn);
-  ExprResult FixOverloadedFunctionReference(ExprResult,
-                                            DeclAccessPair FoundDecl,
-                                            FunctionDecl *Fn);
+  ExprResult
+  FixOverloadedFunctionReference(Expr *E, DeclAccessPair FoundDecl,
+                                 FunctionDecl *Fn,
+                                 const TemplateArgumentList *Deduced);
+  ExprResult
+  FixOverloadedFunctionReference(ExprResult, DeclAccessPair FoundDecl,
+                                 FunctionDecl *Fn,
+                                 const TemplateArgumentList *Deduced);
 
   /// - Returns a selector which best matches given argument list or
   /// nullptr if none could be found
@@ -11545,7 +11555,8 @@ class Sema final : public SemaBase {
   DeclResult CheckVarTemplateId(VarTemplateDecl *Template,
                                 SourceLocation TemplateLoc,
                                 SourceLocation TemplateNameLoc,
-                                const TemplateArgumentListInfo &TemplateArgs);
+                                const TemplateArgumentListInfo &TemplateArgs,
+                                const TemplateArgumentList *&ConvertedArgs);
 
   /// Form a reference to the specialization of the given variable template
   /// corresponding to the specified argument list, or a null-but-valid result
diff --git a/clang/include/clang/Sema/SemaCUDA.h b/clang/include/clang/Sema/SemaCUDA.h
index 71f05e88fb539..645857ba8b4a3 100644
--- a/clang/include/clang/Sema/SemaCUDA.h
+++ b/clang/include/clang/Sema/SemaCUDA.h
@@ -229,8 +229,8 @@ class SemaCUDA : public SemaBase {
   /// calling priority.
   void EraseUnwantedMatches(
       const FunctionDecl *Caller,
-      llvm::SmallVectorImpl<std::pair<DeclAccessPair, FunctionDecl *>>
-          &Matches);
+      llvm::SmallVectorImpl<std::tuple<DeclAccessPair, FunctionDecl *,
+                                       const TemplateArgumentList *>> &Matches);
 
   /// Given a implicit special member, infer its CUDA target from the
   /// calls it needs to make to underlying base/field special members.
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index cb3974837569e..2d163873c740d 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -7493,6 +7493,7 @@ ExpectedStmt ASTNodeImporter::VisitDeclRefExpr(DeclRefExpr *E) {
   auto ToQualifierLoc = importChecked(Err, E->getQualifierLoc());
   auto ToTemplateKeywordLoc = importChecked(Err, E->getTemplateKeywordLoc());
   auto ToDecl = importChecked(Err, E->getDecl());
+  auto ToConvertedArgs = importChecked(Err, E->getConvertedArgs());
   auto ToLocation = importChecked(Err, E->getLocation());
   auto ToType = importChecked(Err, E->getType());
   if (Err)
@@ -7519,7 +7520,8 @@ ExpectedStmt ASTNodeImporter::VisitDeclRefExpr(DeclRefExpr *E) {
   auto *ToE = DeclRefExpr::Create(
       Importer.getToContext(), ToQualifierLoc, ToTemplateKeywordLoc, ToDecl,
       E->refersToEnclosingVariableOrCapture(), ToLocation, ToType,
-      E->getValueKind(), ToFoundD, ToResInfo, E->isNonOdrUse());
+      E->getValueKind(), ToFoundD, ToResInfo, ToConvertedArgs,
+      E->isNonOdrUse());
   if (E->hadMultipleCandidates())
     ToE->setHadMultipleCandidates(true);
   ToE->setIsImmediateEscalating(E->isImmediateEscalating());
@@ -8444,6 +8446,7 @@ ExpectedStmt ASTNodeImporter::VisitMemberExpr(MemberExpr *E) {
   auto ToQualifierLoc = importChecked(Err, E->getQualifierLoc());
   auto ToTemplateKeywordLoc = importChecked(Err, E->getTemplateKeywordLoc());
   auto ToMemberDecl = importChecked(Err, E->getMemberDecl());
+  auto ToDeduced = importChecked(Err, E->getDeduced());
   auto ToType = importChecked(Err, E->getType());
   auto ToDecl = importChecked(Err, E->getFoundDecl().getDecl());
   auto ToName = importChecked(Err, E->getMemberNameInfo().getName());
@@ -8468,7 +8471,7 @@ ExpectedStmt ASTNodeImporter::VisitMemberExpr(MemberExpr *E) {
   return MemberExpr::Create(Importer.getToContext(), ToBase, E->isArrow(),
                             ToOperatorLoc, ToQualifierLoc, ToTemplateKeywordLoc,
                             ToMemberDecl, ToFoundDecl, ToMemberNameInfo,
-                            ResInfo, ToType, E->getValueKind(),
+                            ResInfo, ToDeduced, ToType, E->getValueKind(),
                             E->getObjectKind(), E->isNonOdrUse());
 }
 
@@ -10174,6 +10177,17 @@ llvm::Expected<APValue> ASTImporter::Import(const APValue &FromValue) {
   return Importer.ImportAPValue(FromValue);
 }
 
+llvm::Expected<TemplateArgumentList *>
+ASTImporter::Import(const TemplateArgumentList *ArgList) {
+  ASTNodeImporter Importer(*this);
+  if (!ArgList)
+    return nullptr;
+  SmallVector<TemplateArgument, 4> ToArgs(ArgList->size());
+  if (auto Res = Importer.ImportTemplateArguments(ArgList->asArray(), ToArgs))
+    return std::move(Res);
+  return TemplateArgumentList::CreateCopy(ToContext, ToArgs);
+}
+
 Error ASTImporter::ImportDefinition(Decl *From) {
   ExpectedDecl ToOrErr = Import(From);
   if (!ToOrErr)
diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp
index fb76239ae434c..57ec0a579c0b7 100644
--- a/clang/lib/AST/DeclTemplate.cpp
+++ b/clang/lib/AST/DeclTemplate.cpp
@@ -950,7 +950,7 @@ TemplateArgumentList::TemplateArgumentList(ArrayRef<TemplateArgument> Args)
 }
 
 TemplateArgumentList *
-TemplateArgumentList::CreateCopy(ASTContext &Context,
+TemplateArgumentList::CreateCopy(const ASTContext &Context,
                                  ArrayRef<TemplateArgument> Args) {
   void *Mem = Context.Allocate(totalSizeToAlloc<TemplateArgument>(Args.size()));
   return new (Mem) TemplateArgumentList(Args);
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 389fa70a61b4b..7d3918c80ff1b 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -431,7 +431,8 @@ DeclRefExpr::DeclRefExpr(const ASTContext &Ctx, ValueDecl *D,
                          ExprValueKind VK, SourceLocation L,
                          const DeclarationNameLoc &LocInfo,
                          NonOdrUseReason NOUR)
-    : Expr(DeclRefExprClass, T, VK, OK_Ordinary), D(D), DNLoc(LocInfo) {
+    : Expr(DeclRefExprClass, T, VK, OK_Ordinary), D(D), ConvertedArgs(nullptr),
+      DNLoc(LocInfo) {
   DeclRefExprBits.HasQualifier = false;
   DeclRefExprBits.HasTemplateKWAndArgsInfo = false;
   DeclRefExprBits.HasFoundDecl = false;
@@ -451,9 +452,12 @@ DeclRefExpr::DeclRefExpr(const ASTContext &Ctx,
                          bool RefersToEnclosingVariableOrCapture,
                          const DeclarationNameInfo &NameInfo, NamedDecl *FoundD,
                          const TemplateArgumentListInfo *TemplateArgs,
-                         QualType T, ExprValueKind VK, NonOdrUseReason NOUR)
+                         const TemplateArgumentList *ConvertedArgs, QualType T,
+                         ExprValueKind VK, NonOdrUseReason NOUR)
     : Expr(DeclRefExprClass, T, VK, OK_Ordinary), D(D),
-      DNLoc(NameInfo.getInfo()) {
+      ConvertedArgs(ConvertedArgs), DNLoc(NameInfo.getInfo()) {
+  assert(!TemplateArgs || ConvertedArgs);
+  assert(!ConvertedArgs || ConvertedArgs->size() != 0);
   DeclRefExprBits.Loc = NameInfo.getLoc();
   DeclRefExprBits.HasQualifier = QualifierLoc ? 1 : 0;
   if (QualifierLoc)
@@ -491,22 +495,21 @@ DeclRefExpr *DeclRefExpr::Create(const ASTContext &Context,
                                  SourceLocation NameLoc, QualType T,
                                  ExprValueKind VK, NamedDecl *FoundD,
                                  const TemplateArgumentListInfo *TemplateArgs,
+                                 const TemplateArgumentList *ConvertedArgs,
                                  NonOdrUseReason NOUR) {
   return Create(Context, QualifierLoc, TemplateKWLoc, D,
                 RefersToEnclosingVariableOrCapture,
-                DeclarationNameInfo(D->getDeclName(), NameLoc),
-                T, VK, FoundD, TemplateArgs, NOUR);
+                DeclarationNameInfo(D->getDeclName(), NameLoc), T, VK, FoundD,
+                TemplateArgs, ConvertedArgs, NOUR);
 }
 
-DeclRefExpr *DeclRefExpr::Create(const ASTContext &Context,
-                                 NestedNameSpecifierLoc QualifierLoc,
-                                 SourceLocation TemplateKWLoc, ValueDecl *D,
-                                 bool RefersToEnclosingVariableOrCapture,
-                                 const DeclarationNameInfo &NameInfo,
-                                 QualType T, ExprValueKind VK,
-                                 NamedDecl *FoundD,
-                                 const TemplateArgumentListInfo *TemplateArgs,
-                                 NonOdrUseReason NOUR) {
+DeclRefExpr *DeclRefExpr::Create(
+    const ASTContext &Context, NestedNameSpecifierLoc QualifierLoc,
+    SourceLocation TemplateKWLoc, ValueDecl *D,
+    bool RefersToEnclosingVariableOrCapture,
+    const DeclarationNameInfo &NameInfo, QualType T, ExprValueKind VK,
+    NamedDecl *FoundD, const TemplateArgumentListInfo *TemplateArgs,
+    const TemplateArgumentList *ConvertedArgs, NonOdrUseReason NOUR) {
   // Filter out cases where the found Decl is the same as the value refenenced.
   if (D == FoundD)
     FoundD = nullptr;
@@ -520,9 +523,10 @@ DeclRefExpr *DeclRefExpr::Create(const ASTContext &Context,
           TemplateArgs ? TemplateArgs->size() : 0);
 
   void *Mem = Context.Allocate(Size, alignof(DeclRefExpr));
-  return new (Mem) DeclRefExpr(Context, QualifierLoc, TemplateKWLoc, D,
-                               RefersToEnclosingVariableOrCapture, NameInfo,
-                               FoundD, TemplateArgs, T, VK, NOUR);
+  return new (Mem)
+      DeclRefExpr(Context, QualifierLoc, TemplateKWLoc, D,
+                  RefersToEnclosingVariableOrCapture, NameInfo, FoundD,
+                  TemplateArgs, ConvertedArgs, T, VK, NOUR);
 }
 
 DeclRefExpr *DeclRefExpr::CreateEmpty(const ASTContext &Context,
@@ -1734,11 +1738,13 @@ MemberExpr::MemberExpr(Expr *Base, bool IsArrow, SourceLocation OperatorLoc,
                        SourceLocation TemplateKWLoc, ValueDecl *MemberDecl,
                        DeclAccessPair FoundDecl,
                        const DeclarationNameInfo &NameInfo,
-                       const TemplateArgumentListInfo *TemplateArgs, QualType T,
+                       const TemplateArgumentListInfo *TemplateArgs,
+                       const TemplateArgumentList *Deduced, QualType T,
                        ExprValueKind VK, ExprObjectKind OK,
                        NonOdrUseReason NOUR)
     : Expr(MemberExprClass, T, VK, OK), Base(Base), MemberDecl(MemberDecl),
-      MemberDNLoc(NameInfo.getInfo()), MemberLoc(NameInfo.getLoc()) {
+      Deduced(Deduced), MemberDNLoc(NameInfo.getInfo()),
+      MemberLoc(NameInfo.getLoc()) {
   assert(!NameInfo.getName() ||
          MemberDecl->getDeclName() == NameInfo.getName());
   MemberExprBits.IsArrow = IsArrow;
@@ -1774,7 +1780,8 @@ MemberExpr *MemberExpr::Create(
     NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc,
     ValueDecl *MemberDecl, DeclAccessPair FoundDecl,
     DeclarationNameInfo NameInfo, const TemplateArgumentListInfo *TemplateArgs,
-    QualType T, ExprValueKind VK, ExprObjectKind OK, NonOdrUseReason NOUR) {
+    const TemplateArgumentList *Deduced, QualType T, ExprValueKind VK,
+    ExprObjectKind OK, NonOdrUseReason NOUR) {
   bool HasQualifier = QualifierLoc.hasQualifier();
   bool HasFoundDecl = FoundDecl.getDecl() != MemberDecl ||
                       FoundDecl.getAccess() != MemberDecl->getAccess();
@@ -1788,7 +1795,7 @@ MemberExpr *MemberExpr::Create(
   void *Mem = C.Allocate(Size, alignof(MemberExpr));
   return new (Mem) MemberExpr(Base, IsArrow, OperatorLoc, QualifierLoc,
                               TemplateKWLoc, MemberDecl, FoundDecl, NameInfo,
-                              TemplateArgs, T, VK, OK, NOUR);
+                              TemplateArgs, Deduced, T, VK, OK, NOUR);
 }
 
 MemberExpr *MemberExpr::CreateEmpty(const ASTContext &Context,
diff --git a/clang/lib/Analysis/BodyFarm.cpp b/clang/lib/Analysis/BodyFarm.cpp
index c5f35b35ad357..058d8fa1328e3 100644
--- a/clang/lib/Analysis/BodyFarm.cpp
+++ b/clang/lib/Analysis/BodyFarm.cpp
@@ -231,8 +231,8 @@ MemberExpr *ASTMaker::makeMemberExpression(Expr *base, ValueDecl *MemberDecl,
       C, base, IsArrow, SourceLocation(), NestedNameSpecifierLoc(),
       SourceLocation(), MemberDecl, FoundDecl,
       DeclarationNameInfo(MemberDecl->getDeclName(), SourceLocation()),
-      /* TemplateArgumentListInfo=*/ nullptr, MemberDecl->getType(), ValueKind,
-      OK_Ordinary, NOUR_None);
+      /* TemplateArgumentListInfo=*/nullptr, /*Deduced=*/nullptr,
+      MemberDecl->getType(), ValueKind, OK_Ordinary, NOUR_None);
 }
 
 ValueDecl *ASTMaker::findMemberField(const RecordDecl *RD, StringRef Name) {
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 73020389b5e45..01d2b3af362ab 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -1867,7 +1867,8 @@ static DeclRefExpr *tryToConvertMemberExprToDeclRefExpr(CodeGenFunction &CGF,
     return DeclRefExpr::Create(
         CGF.getContext(), NestedNameSpecifierLoc(), SourceLocation(), VD,
         /*RefersToEnclosingVariableOrCapture=*/false, ME->getExprLoc(),
-        ME->getType(), ME->getValueKind(), nullptr, nullptr, ME->isNonOdrUse());
+        ME->getType(), ME->getValueKind(), nullptr, nullptr, nullptr,
+        ME->isNonOdrUse());
   }
   return nullptr;
 }
diff --git a/clang/lib/Sema/SemaCUDA.cpp b/clang/lib/Sema/SemaCUDA.cpp
index 0e5fc5e1a40b4..9217a8d4810b0 100644
--- a/clang/lib/Sema/SemaCUDA.cpp
+++ b/clang/lib/Sema/SemaCUDA.cpp
@@ -317,25 +317,28 @@ bool SemaCUDA::isImplicitHostDeviceFunction(const FunctionDecl *D) {
 
 void SemaCUDA::EraseUnwantedMatches(
     const FunctionDecl *Caller,
-    SmallVectorImpl<std::pair<DeclAccessPair, FunctionDecl *>> &Matches) {
+    SmallVectorImpl<std::tuple<DeclAccessPair, FunctionDecl *,
+                               const TemplateArgumentList *>> &Matches) {
   if (Matches.size() <= 1)
     return;
 
-  using Pair = std::pair<DeclAccessPair, FunctionDecl*>;
+  using Tuple =
+      std::tuple<DeclAccessPair, FunctionDecl *, const TemplateArgumentList *>;
 
   // Gets the CUDA function preference for a call from Caller to Match.
-  auto GetCFP = [&](const Pair &Match) {
-    return IdentifyPreference(Caller, Match.second);
+  auto GetCFP = [&](const Tuple &Match) {
+    return IdentifyPreference(Caller, std::get<1>(Match));
   };
 
   // Find the best call preference among the functions in Matches.
   CUDAFunctionPreference BestCFP = GetCFP(*std::max_element(
-      Matches.begin(), Matches.end(),
-      [&](const Pair &M1, const Pair &M2) { return GetCFP(M1) < GetCFP(M2); }));
+      Matches.begin(), Matches.end(), [&](const Tuple &M1, const Tuple &M2) {
+        return GetCFP(M1) < GetCFP(M2);
+      }));
 
   // Erase all functions with lower priority.
   llvm::erase_if(Matches,
-                 [&](const Pair &Match) { return GetCFP(Match) < BestCFP; });
+                 [&](const Tuple &Match) { return GetCFP(Match) < BestCFP; });
 }
 
 /// When an implicitly-declared special member has to invoke more than one
diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp
index 2824dfce1572c..0c961c2f89388 100644
--- a/clang/lib/Sema/SemaCast.cpp
+++ b/clang/lib/Sema/SemaCast.cpp
@@ -1784,9 +1784,9 @@ TryStaticMemberPointerUpcast(Sema &Self, ExprResult &SrcExpr, QualType SrcType,
   bool WasOverloadedFunction = false;
   DeclAccessPair FoundOverload;
   if (SrcExpr.get()->getType() == Self.Context.OverloadTy) {
-    if (FunctionDecl *Fn
-          = Self.ResolveAddressOfOverloadedFunction(SrcExpr.get(), DestType, false,
-                                                    FoundOverload)) {
+    const TemplateArgumentList *ConvertedArgs;
+    if (FunctionDecl *Fn = Self.ResolveAddressOfOverloadedFunction(
+            SrcExpr.get(), DestType, false, FoundOverload, ConvertedArgs)) {
       CXXMethodDecl *M = cast<CXXMethodDecl>(Fn);
       SrcType = Self.Context.getMemberPointerType(
           Fn->getType(), /*Qualifier=*/nullptr, M->getParent());
@@ -1816,16 +1816,16 @@ TryStaticMemberPointerUpcast(Sema &Self, ExprResult &SrcExpr, QualType SrcType,
   if (WasOverloadedFunction) {
     // Resolve the address of the overloaded function again, this time
     // allowing complaints if something goes wrong.
-    FunctionDecl *Fn = Self.ResolveAddressOfOverloadedFunction(SrcExpr.get(),
-                                                               DestType,
-                                                               true,
-                                                               FoundOverload);
+    const TemplateArgumentList *ConvertedArgs;
+    FunctionDecl *Fn = Self.ResolveAddressOfOverloadedFunction(
+        SrcExpr.get(), DestType, true, FoundOverload, ConvertedArgs);
     if (!Fn) {
       msg = 0;
       return TC_Failed;
     }
 
-    SrcExpr = Self.FixOverloadedFunctionReference(SrcExpr, FoundOverload, Fn);
+    SrcExpr = Self.FixOverloadedFunctionReference(SrcExpr, FoundOverload, Fn,
+                                                  ConvertedArgs);
     if (!SrcExpr.isUsable()) {
       msg = 0;
       return TC_Failed;
@@ -2815,10 +2815,10 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle,
   if (tcr != TC_Success && msg != 0) {
     if (SrcExpr.get()->getType() == Self.Context.OverloadTy) {
       DeclAccessPair Found;
-      FunctionDecl *Fn = Self.ResolveAddressOfOverloadedFunction(SrcExpr.get(),
-                                DestType,
-                                /*Complain*/ true,
-                                Found);
+      const TemplateArgumentList *ConvertedArgs;
+      FunctionDecl *Fn = Self.ResolveAddressOfOverloadedFunction(
+          SrcExpr.get(), DestType,
+          /*Complain*/ true, Found, ConvertedArgs);
       if (Fn) {
         // If DestType is a function type (not to be confused with the function
         // pointer type), it will be possible to resolve the function address,
@@ -2974,10 +2974,12 @@ void CastOperation::CheckCStyleCast() {
 
   // Overloads are allowed with C extensions, so we need to support them.
   if (SrcExpr.get()->getType() == Self.Context.OverloadTy) {
+    const TemplateArgumentList *ConvertedArgs;
     DeclAccessPair DAP;
     if (FunctionDecl *FD = Self.ResolveAddressOfOverloadedFunction(
-            SrcExpr.get(), DestType, /*Complain=*/true, DAP))
-      SrcExpr = Self.FixOverloadedFunctionReference(SrcExpr.get(), DAP, FD);
+            SrcExpr.get(), DestType, /*Complain=*/true, DAP, ConvertedArgs))
+      SrcExpr = Self.FixOverloadedFunctionReference(SrcExpr.get(), DAP, FD,
+                                                    ConvertedArgs);
     else
       return;
     assert(SrcExpr.isUsable());
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 5a4fa97366809..db61af1495793 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -4629,7 +4629,7 @@ ExprResult Sema::BuiltinAtomicOverloaded(ExprResult TheCallResult) {
   DeclRefExpr *NewDRE = DeclRefExpr::Create(
       Context, DRE->getQualifierLoc(), SourceLocation(), NewBuiltinDecl,
       /*enclosing*/ false, DRE->getLocation(), Context.BuiltinFnTy,
-      DRE->getValueKind(), nullptr, nullptr, DRE->isNonOdrUse());
+      DRE->getValueKind(), nullptr, nullptr, nullptr, DRE->isNonOdrUse());
 
   // Set the callee in the CallExpr.
   // FIXME: This loses syntactic information.
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 0b844b44930b9..88d5c66953b40 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -1816,7 +1816,8 @@ static void handleRestrictAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
       return;
     }
   } else if (auto *ULE = dyn_cast<UnresolvedLookupExpr>(DeallocE)) {
-    DeallocFD = S.ResolveSingleFunctionTemplateSpecialization(ULE, true);
+    DeclAccessPair DAP;
+    DeallocFD = S.resolveAddressOfSingleOverloadCandidate(ULE, DAP);
     DeallocNI = ULE->getNameInfo();
     if (!DeallocFD) {
       S.Diag(DeallocLoc, diag::err_attribute_malloc_arg_not_function)
@@ -3610,9 +3611,14 @@ static void handleCleanupAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
       return;
     }
   } else if (auto *ULE = dyn_cast<UnresolvedLookupExpr>(E)) {
-    if (ULE->hasExplicitTemplateArgs())
+    if (ULE->hasExplicitTemplateArgs()) {
       S.Diag(Loc, diag::warn_cleanup_ext);
-    FD = S.ResolveSingleFunctionTemplateSpecialization(ULE, true);
+      TemplateArgumentListInfo ExplicitTemplateArgs;
+      const TemplateArgumentList *ConvertedArgs;
+      ULE->copyTemplateArgumentsInto(ExplicitTemplateArgs);
+      FD = S.ResolveSingleFunctionTemplateSpecialization(
+          ULE, ExplicitTemplateArgs, ConvertedArgs, /*Complain=*/true);
+    }
     NI = ULE->getNameInfo();
     if (!FD) {
       S.Diag(Loc, diag::err_attribute_cleanup_arg_not_function) << 2
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index d70e42d86ef10..dc0215f44137f 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -2232,11 +2232,12 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
                        const DeclarationNameInfo &NameInfo,
                        const CXXScopeSpec *SS, NamedDecl *FoundD,
                        SourceLocation TemplateKWLoc,
-                       const TemplateArgumentListInfo *TemplateArgs) {
+                       const TemplateArgumentListInfo *TemplateArgs,
+                       const TemplateArgumentList *ConvertedArgs) {
   NestedNameSpecifierLoc NNS =
       SS ? SS->getWithLocInContext(Context) : NestedNameSpecifierLoc();
   return BuildDeclRefExpr(D, Ty, VK, NameInfo, NNS, FoundD, TemplateKWLoc,
-                          TemplateArgs);
+                          TemplateArgs, ConvertedArgs);
 }
 
 // CUDA/HIP: Check whether a captured reference variable is referencing a
@@ -2301,13 +2302,16 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
                        const DeclarationNameInfo &NameInfo,
                        NestedNameSpecifierLoc NNS, NamedDecl *FoundD,
                        SourceLocation TemplateKWLoc,
-                       const TemplateArgumentListInfo *TemplateArgs) {
+                       const TemplateArgumentListInfo *TemplateArgs,
+                       const TemplateArgumentList *ConvertedArgs) {
   bool RefersToCapturedVariable = isa<VarDecl, BindingDecl>(D) &&
                                   NeedToCaptureVariable(D, NameInfo.getLoc());
 
-  DeclRefExpr *E = DeclRefExpr::Create(
-      Context, NNS, TemplateKWLoc, D, RefersToCapturedVariable, NameInfo, Ty,
-      VK, FoundD, TemplateArgs, getNonOdrUseReasonInCurrentContext(D));
+  assert(!TemplateArgs || ConvertedArgs);
+  DeclRefExpr *E = DeclRefExpr::Create(Context, NNS, TemplateKWLoc, D,
+                                       RefersToCapturedVariable, NameInfo, Ty,
+                                       VK, FoundD, TemplateArgs, ConvertedArgs,
+                                       getNonOdrUseReasonInCurrentContext(D));
   MarkDeclRefReferenced(E);
 
   // C++ [except.spec]p17:
@@ -3221,7 +3225,7 @@ ExprResult Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
       !R.getAsSingle<FunctionTemplateDecl>() &&
       !ShouldLookupResultBeMultiVersionOverload(R))
     return BuildDeclarationNameExpr(SS, R.getLookupNameInfo(), R.getFoundDecl(),
-                                    R.getRepresentativeDecl(), nullptr,
+                                    R.getRepresentativeDecl(), nullptr, nullptr,
                                     AcceptInvalidDecl);
 
   // We only need to check the declaration if there's exactly one
@@ -3252,10 +3256,11 @@ static void diagnoseUncapturableValueReferenceOrBinding(Sema &S,
 ExprResult Sema::BuildDeclarationNameExpr(
     const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, NamedDecl *D,
     NamedDecl *FoundD, const TemplateArgumentListInfo *TemplateArgs,
-    bool AcceptInvalidDecl) {
+    const TemplateArgumentList *ConvertedArgs, bool AcceptInvalidDecl) {
   assert(D && "Cannot refer to a NULL declaration");
   assert(!isa<FunctionTemplateDecl>(D) &&
          "Cannot refer unambiguously to a function template");
+  assert(!TemplateArgs || ConvertedArgs);
 
   SourceLocation Loc = NameInfo.getLoc();
   if (CheckDeclInExpr(*this, Loc, D, AcceptInvalidDecl)) {
@@ -3485,9 +3490,9 @@ ExprResult Sema::BuildDeclarationNameExpr(
     break;
   }
 
-  auto *E =
-      BuildDeclRefExpr(VD, type, valueKind, NameInfo, &SS, FoundD,
-                       /*FIXME: TemplateKWLoc*/ SourceLocation(), TemplateArgs);
+  auto *E = BuildDeclRefExpr(VD, type, valueKind, NameInfo, &SS, FoundD,
+                             /*FIXME: TemplateKWLoc*/ SourceLocation(),
+                             TemplateArgs, ConvertedArgs);
   // Clang AST consumers assume a DeclRefExpr refers to a valid decl. We
   // wrap a DeclRefExpr referring to an invalid decl with a dependent-type
   // RecoveryExpr to avoid follow-up semantic analysis (thus prevent bogus
@@ -6657,7 +6662,7 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
         Fn = DeclRefExpr::Create(
             Context, FDecl->getQualifierLoc(), SourceLocation(), FDecl, false,
             SourceLocation(), FDecl->getType(), Fn->getValueKind(), FDecl,
-            nullptr, DRE->isNonOdrUse());
+            nullptr, nullptr, DRE->isNonOdrUse());
       }
     }
   } else if (auto *ME = dyn_cast<MemberExpr>(NakedFn))
@@ -9758,9 +9763,10 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS,
     // As a set of extensions to C, we support overloading on functions. These
     // functions need to be resolved here.
     DeclAccessPair DAP;
+    const TemplateArgumentList *ConvertedArgs;
     if (FunctionDecl *FD = ResolveAddressOfOverloadedFunction(
-            RHS.get(), LHSType, /*Complain=*/false, DAP))
-      RHS = FixOverloadedFunctionReference(RHS.get(), DAP, FD);
+            RHS.get(), LHSType, /*Complain=*/false, DAP, ConvertedArgs))
+      RHS = FixOverloadedFunctionReference(RHS.get(), DAP, FD, ConvertedArgs);
     else
       return Incompatible;
   }
@@ -14246,14 +14252,19 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) {
       }
 
       OverloadExpr *Ovl = cast<OverloadExpr>(E);
-      if (isa<UnresolvedMemberExpr>(Ovl))
-        if (!ResolveSingleFunctionTemplateSpecialization(Ovl)) {
-          Diag(OpLoc, diag::err_invalid_form_pointer_member_function)
-            << OrigOp.get()->getSourceRange();
-          return QualType();
-        }
-
-      return Context.OverloadTy;
+      if (!isa<UnresolvedMemberExpr>(Ovl))
+        return Context.OverloadTy;
+      if (Ovl->hasExplicitTemplateArgs()) {
+        TemplateArgumentListInfo ExplicitTemplateArgs;
+        Ovl->copyTemplateArgumentsInto(ExplicitTemplateArgs);
+        const TemplateArgumentList *ConvertedArgs;
+        if (ResolveSingleFunctionTemplateSpecialization(
+                Ovl, ExplicitTemplateArgs, ConvertedArgs))
+          return Context.OverloadTy;
+      }
+      Diag(OpLoc, diag::err_invalid_form_pointer_member_function)
+          << OrigOp.get()->getSourceRange();
+      return QualType();
     }
 
     if (PTy->getKind() == BuiltinType::UnknownAny)
@@ -19473,7 +19484,8 @@ static ExprResult rebuildPotentialResultsAsNonOdrUsed(Sema &S, Expr *E,
         S.Context, DRE->getQualifierLoc(), DRE->getTemplateKeywordLoc(),
         DRE->getDecl(), DRE->refersToEnclosingVariableOrCapture(),
         DRE->getNameInfo(), DRE->getType(), DRE->getValueKind(),
-        DRE->getFoundDecl(), CopiedTemplateArgs(DRE), NOUR);
+        DRE->getFoundDecl(), CopiedTemplateArgs(DRE), DRE->getConvertedArgs(),
+        NOUR);
   }
 
   case Expr::FunctionParmPackExprClass: {
@@ -19519,8 +19531,8 @@ static ExprResult rebuildPotentialResultsAsNonOdrUsed(Sema &S, Expr *E,
           S.Context, Base.get(), ME->isArrow(), ME->getOperatorLoc(),
           ME->getQualifierLoc(), ME->getTemplateKeywordLoc(),
           ME->getMemberDecl(), ME->getFoundDecl(), ME->getMemberNameInfo(),
-          CopiedTemplateArgs(ME), ME->getType(), ME->getValueKind(),
-          ME->getObjectKind(), ME->isNonOdrUse());
+          CopiedTemplateArgs(ME), ME->getDeduced(), ME->getType(),
+          ME->getValueKind(), ME->getObjectKind(), ME->isNonOdrUse());
     }
 
     if (ME->getMemberDecl()->isCXXInstanceMember())
@@ -19537,7 +19549,8 @@ static ExprResult rebuildPotentialResultsAsNonOdrUsed(Sema &S, Expr *E,
         S.Context, ME->getBase(), ME->isArrow(), ME->getOperatorLoc(),
         ME->getQualifierLoc(), ME->getTemplateKeywordLoc(), ME->getMemberDecl(),
         ME->getFoundDecl(), ME->getMemberNameInfo(), CopiedTemplateArgs(ME),
-        ME->getType(), ME->getValueKind(), ME->getObjectKind(), NOUR);
+        ME->getDeduced(), ME->getType(), ME->getValueKind(),
+        ME->getObjectKind(), NOUR);
   }
 
   case Expr::BinaryOperatorClass: {
@@ -21191,7 +21204,8 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) {
             FD, FD->getType(), VK_LValue, DRE->getNameInfo(),
             DRE->hasQualifier() ? &SS : nullptr, DRE->getFoundDecl(),
             DRE->getTemplateKeywordLoc(),
-            DRE->hasExplicitTemplateArgs() ? &TemplateArgs : nullptr);
+            DRE->hasExplicitTemplateArgs() ? &TemplateArgs : nullptr,
+            DRE->getConvertedArgs());
       }
     }
 
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index e43f5e3f75bfe..0a4917c221fe5 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -2847,7 +2847,10 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
 
   FoundDelete.suppressDiagnostics();
 
-  SmallVector<std::pair<DeclAccessPair,FunctionDecl*>, 2> Matches;
+  SmallVector<
+      std::tuple<DeclAccessPair, FunctionDecl *, const TemplateArgumentList *>,
+      2>
+      Matches;
 
   // Whether we're looking for a placement operator delete is dictated
   // by whether we selected a placement operator new, not by whether
@@ -2897,6 +2900,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
                              DEnd = FoundDelete.end();
          D != DEnd; ++D) {
       FunctionDecl *Fn = nullptr;
+      const TemplateArgumentList *ConvertedArgs = nullptr;
       if (FunctionTemplateDecl *FnTmpl =
               dyn_cast<FunctionTemplateDecl>((*D)->getUnderlyingDecl())) {
         // Perform template argument deduction to try to match the
@@ -2905,14 +2909,15 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
         if (DeduceTemplateArguments(FnTmpl, nullptr, ExpectedFunctionType, Fn,
                                     Info) != TemplateDeductionResult::Success)
           continue;
+        ConvertedArgs = Info.takeSugared();
       } else
         Fn = cast<FunctionDecl>((*D)->getUnderlyingDecl());
 
       if (Context.hasSameType(adjustCCAndNoReturn(Fn->getType(),
                                                   ExpectedFunctionType,
-                                                  /*AdjustExcpetionSpec*/true),
+                                                  /*AdjustExcpetionSpec=*/true),
                               ExpectedFunctionType))
-        Matches.push_back(std::make_pair(D.getPair(), Fn));
+        Matches.push_back({D.getPair(), Fn, ConvertedArgs});
     }
 
     if (getLangOpts().CUDA)
@@ -2932,12 +2937,12 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
         /*WantAlign*/ hasNewExtendedAlignment(*this, AllocElemType),
         &BestDeallocFns);
     if (Selected)
-      Matches.push_back(std::make_pair(Selected.Found, Selected.FD));
+      Matches.push_back({Selected.Found, Selected.FD, nullptr});
     else {
       // If we failed to select an operator, all remaining functions are viable
       // but ambiguous.
       for (auto Fn : BestDeallocFns)
-        Matches.push_back(std::make_pair(Fn.Found, Fn.FD));
+        Matches.push_back({Fn.Found, Fn.FD, nullptr});
     }
   }
 
@@ -2946,7 +2951,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
   //   function, that function will be called; otherwise, no
   //   deallocation function will be called.
   if (Matches.size() == 1) {
-    OperatorDelete = Matches[0].second;
+    OperatorDelete = std::get<1>(Matches[0]);
 
     // C++1z [expr.new]p23:
     //   If the lookup finds a usual deallocation function (3.7.4.2)
@@ -2985,7 +2990,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
     }
 
     CheckAllocationAccess(StartLoc, Range, FoundDelete.getNamingClass(),
-                          Matches[0].first);
+                          std::get<0>(Matches[0]));
   } else if (!Matches.empty()) {
     // We found multiple suitable operators. Per [expr.new]p20, that means we
     // call no 'operator delete' function, but we should at least warn the user.
@@ -2994,8 +2999,8 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
       << DeleteName << AllocElemType;
 
     for (auto &Match : Matches)
-      Diag(Match.second->getLocation(),
-           diag::note_member_declared_here) << DeleteName;
+      Diag(std::get<1>(Match)->getLocation(), diag::note_member_declared_here)
+          << DeleteName;
   }
 
   return false;
@@ -4353,15 +4358,17 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
   // Resolve overloaded function references.
   if (Context.hasSameType(FromType, Context.OverloadTy)) {
     DeclAccessPair Found;
-    FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(From, ToType,
-                                                          true, Found);
+    const TemplateArgumentList *ConvertedArgs;
+    FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(From, ToType, true,
+                                                          Found, ConvertedArgs);
     if (!Fn)
       return ExprError();
 
     if (DiagnoseUseOfDecl(Fn, From->getBeginLoc()))
       return ExprError();
 
-    ExprResult Res = FixOverloadedFunctionReference(From, Found, Fn);
+    ExprResult Res =
+        FixOverloadedFunctionReference(From, Found, Fn, ConvertedArgs);
     if (Res.isInvalid())
       return ExprError();
 
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index b0872122ed740..f6da4ec339adf 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -935,13 +935,14 @@ MemberExpr *Sema::BuildMemberExpr(
     SourceLocation TemplateKWLoc, ValueDecl *Member, DeclAccessPair FoundDecl,
     bool HadMultipleCandidates, const DeclarationNameInfo &MemberNameInfo,
     QualType Ty, ExprValueKind VK, ExprObjectKind OK,
-    const TemplateArgumentListInfo *TemplateArgs) {
+    const TemplateArgumentListInfo *TemplateArgs,
+    const TemplateArgumentList *Deduced) {
   assert((!IsArrow || Base->isPRValue()) &&
          "-> base must be a pointer prvalue");
-  MemberExpr *E =
-      MemberExpr::Create(Context, Base, IsArrow, OpLoc, NNS, TemplateKWLoc,
-                         Member, FoundDecl, MemberNameInfo, TemplateArgs, Ty,
-                         VK, OK, getNonOdrUseReasonInCurrentContext(Member));
+  MemberExpr *E = MemberExpr::Create(
+      Context, Base, IsArrow, OpLoc, NNS, TemplateKWLoc, Member, FoundDecl,
+      MemberNameInfo, TemplateArgs, Deduced, Ty, VK, OK,
+      getNonOdrUseReasonInCurrentContext(Member));
   E->setHadMultipleCandidates(HadMultipleCandidates);
   MarkMemberReferenced(E);
 
@@ -1232,8 +1233,10 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
       return ExprError();
     }
 
-    DeclResult VDecl = CheckVarTemplateId(VarTempl, TemplateKWLoc,
-                                          MemberNameInfo.getLoc(), *TemplateArgs);
+    const TemplateArgumentList *ConvertedArgs;
+    DeclResult VDecl =
+        CheckVarTemplateId(VarTempl, TemplateKWLoc, MemberNameInfo.getLoc(),
+                           *TemplateArgs, ConvertedArgs);
     if (VDecl.isInvalid())
       return ExprError();
 
@@ -1251,7 +1254,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
                            SS.getWithLocInContext(Context), TemplateKWLoc, Var,
                            FoundDecl, /*HadMultipleCandidates=*/false,
                            MemberNameInfo, Var->getType().getNonReferenceType(),
-                           VK_LValue, OK_Ordinary, TemplateArgs);
+                           VK_LValue, OK_Ordinary, TemplateArgs, ConvertedArgs);
   }
 
   // We found something that we didn't expect. Complain.
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 87a4244f2fb76..370e7ca1d918c 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -3895,17 +3895,16 @@ bool InitializationSequence::isConstructorInitialization() const {
   return !Steps.empty() && Steps.back().Kind == SK_ConstructorInitialization;
 }
 
-void
-InitializationSequence
-::AddAddressOverloadResolutionStep(FunctionDecl *Function,
-                                   DeclAccessPair Found,
-                                   bool HadMultipleCandidates) {
+void InitializationSequence ::AddAddressOverloadResolutionStep(
+    FunctionDecl *Function, DeclAccessPair Found,
+    const TemplateArgumentList *ConvertedArgs, bool HadMultipleCandidates) {
   Step S;
   S.Kind = SK_ResolveAddressOfOverloadedFunction;
   S.Type = Function->getType();
   S.Function.HadMultipleCandidates = HadMultipleCandidates;
   S.Function.Function = Function;
   S.Function.FoundDecl = Found;
+  S.Function.ConvertedArgs = ConvertedArgs;
   Steps.push_back(S);
 }
 
@@ -4697,13 +4696,12 @@ ResolveOverloadedFunctionForReferenceBinding(Sema &S,
   if (S.Context.getCanonicalType(UnqualifiedSourceType) ==
         S.Context.OverloadTy) {
     DeclAccessPair Found;
+    const TemplateArgumentList *ConvertedArgs;
     bool HadMultipleCandidates = false;
-    if (FunctionDecl *Fn
-        = S.ResolveAddressOfOverloadedFunction(Initializer,
-                                               UnqualifiedTargetType,
-                                               false, Found,
-                                               &HadMultipleCandidates)) {
-      Sequence.AddAddressOverloadResolutionStep(Fn, Found,
+    if (FunctionDecl *Fn = S.ResolveAddressOfOverloadedFunction(
+            Initializer, UnqualifiedTargetType, false, Found, ConvertedArgs,
+            &HadMultipleCandidates)) {
+      Sequence.AddAddressOverloadResolutionStep(Fn, Found, ConvertedArgs,
                                                 HadMultipleCandidates);
       SourceType = Fn->getType();
       UnqualifiedSourceType = SourceType.getUnqualifiedType();
@@ -6879,12 +6877,14 @@ void InitializationSequence::InitializeFrom(Sema &S,
 
     AddPassByIndirectCopyRestoreStep(DestType, ShouldCopy);
   } else if (ICS.isBad()) {
+    const TemplateArgumentList *ConvertedArgs;
     if (isLibstdcxxPointerReturnFalseHack(S, Entity, Initializer))
       AddZeroInitializationStep(Entity.getType());
     else if (DeclAccessPair Found;
              Initializer->getType() == Context.OverloadTy &&
              !S.ResolveAddressOfOverloadedFunction(Initializer, DestType,
-                                                   /*Complain=*/false, Found))
+                                                   /*Complain=*/false, Found,
+                                                   ConvertedArgs))
       SetFailed(InitializationSequence::FK_AddressOfOverloadFailed);
     else if (Initializer->getType()->isFunctionType() &&
              isExprAnUnaddressableFunction(S, Initializer))
@@ -7914,9 +7914,9 @@ ExprResult InitializationSequence::Perform(Sema &S,
       S.CheckAddressOfMemberAccess(CurInit.get(), Step->Function.FoundDecl);
       if (S.DiagnoseUseOfDecl(Step->Function.FoundDecl, Kind.getLocation()))
         return ExprError();
-      CurInit = S.FixOverloadedFunctionReference(CurInit,
-                                                 Step->Function.FoundDecl,
-                                                 Step->Function.Function);
+      CurInit = S.FixOverloadedFunctionReference(
+          CurInit, Step->Function.FoundDecl, Step->Function.Function,
+          Step->Function.ConvertedArgs);
       // We might get back another placeholder expression if we resolved to a
       // builtin.
       if (!CurInit.isInvalid())
@@ -8795,11 +8795,13 @@ bool InitializationSequence::Diagnose(Sema &S,
 
     if (OnlyArg->getType() == S.Context.OverloadTy) {
       DeclAccessPair Found;
+      const TemplateArgumentList *ConvertedArgs;
       if (FunctionDecl *FD = S.ResolveAddressOfOverloadedFunction(
               OnlyArg, DestType.getNonReferenceType(), /*Complain=*/false,
-              Found)) {
-        if (Expr *Resolved =
-                S.FixOverloadedFunctionReference(OnlyArg, Found, FD).get())
+              Found, ConvertedArgs)) {
+        if (Expr *Resolved = S.FixOverloadedFunctionReference(OnlyArg, Found,
+                                                              FD, ConvertedArgs)
+                                 .get())
           OnlyArg = Resolved;
       }
     }
@@ -8877,10 +8879,9 @@ bool InitializationSequence::Diagnose(Sema &S,
 
   case FK_AddressOfOverloadFailed: {
     DeclAccessPair Found;
-    S.ResolveAddressOfOverloadedFunction(OnlyArg,
-                                         DestType.getNonReferenceType(),
-                                         true,
-                                         Found);
+    const TemplateArgumentList *ConvertedArgs;
+    S.ResolveAddressOfOverloadedFunction(
+        OnlyArg, DestType.getNonReferenceType(), true, Found, ConvertedArgs);
     break;
   }
 
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 0564557738170..0e6191f406866 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -2213,9 +2213,9 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
 
   if (FromType == S.Context.OverloadTy) {
     DeclAccessPair AccessPair;
-    if (FunctionDecl *Fn
-          = S.ResolveAddressOfOverloadedFunction(From, ToType, false,
-                                                 AccessPair)) {
+    const TemplateArgumentList *ConvertedArgs;
+    if (FunctionDecl *Fn = S.ResolveAddressOfOverloadedFunction(
+            From, ToType, false, AccessPair, ConvertedArgs)) {
       // We were able to resolve the address of the overloaded function,
       // so we can convert to the type of that function.
       FromType = Fn->getType();
@@ -5218,8 +5218,9 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
   // type of the resulting function.
   if (S.Context.getCanonicalType(T2) == S.Context.OverloadTy) {
     DeclAccessPair Found;
-    if (FunctionDecl *Fn = S.ResolveAddressOfOverloadedFunction(Init, DeclType,
-                                                                false, Found))
+    const TemplateArgumentList *ConvertedArgs;
+    if (FunctionDecl *Fn = S.ResolveAddressOfOverloadedFunction(
+            Init, DeclType, false, Found, ConvertedArgs))
       T2 = Fn->getType();
   }
 
@@ -5708,8 +5709,9 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType,
       // type of the resulting function.
       if (S.Context.getCanonicalType(T2) == S.Context.OverloadTy) {
         DeclAccessPair Found;
+        const TemplateArgumentList *ConvertedArgs;
         if (FunctionDecl *Fn = S.ResolveAddressOfOverloadedFunction(
-                                   Init, ToType, false, Found))
+                Init, ToType, false, Found, ConvertedArgs))
           T2 = Fn->getType();
       }
 
@@ -6976,8 +6978,8 @@ void Sema::AddOverloadCandidate(
     OverloadCandidateSet &CandidateSet, bool SuppressUserConversions,
     bool PartialOverloading, bool AllowExplicit, bool AllowExplicitConversions,
     ADLCallKind IsADLCandidate, ConversionSequenceList EarlyConversions,
-    OverloadCandidateParamOrder PO, bool AggregateCandidateDeduction,
-    bool StrictPackMatch) {
+    OverloadCandidateParamOrder PO, const TemplateArgumentList *Deduced,
+    bool AggregateCandidateDeduction, bool StrictPackMatch) {
   const FunctionProtoType *Proto
     = dyn_cast<FunctionProtoType>(Function->getType()->getAs<FunctionType>());
   assert(Proto && "Functions without a prototype cannot be overloaded");
@@ -6996,7 +6998,7 @@ void Sema::AddOverloadCandidate(
       AddMethodCandidate(Method, FoundDecl, Method->getParent(), QualType(),
                          Expr::Classification::makeSimpleLValue(), Args,
                          CandidateSet, SuppressUserConversions,
-                         PartialOverloading, EarlyConversions, PO,
+                         PartialOverloading, EarlyConversions, PO, Deduced,
                          StrictPackMatch);
       return;
     }
@@ -7041,6 +7043,7 @@ void Sema::AddOverloadCandidate(
   Candidate.IsADLCandidate = llvm::to_underlying(IsADLCandidate);
   Candidate.ExplicitCallArguments = Args.size();
   Candidate.StrictPackMatch = StrictPackMatch;
+  Candidate.Deduced = Deduced;
 
   // Explicit functions are not actually candidates at all if we're not
   // allowing them in this context, but keep them around so we can point
@@ -7612,7 +7615,8 @@ void Sema::AddMethodCandidate(
     Expr::Classification ObjectClassification, ArrayRef<Expr *> Args,
     OverloadCandidateSet &CandidateSet, bool SuppressUserConversions,
     bool PartialOverloading, ConversionSequenceList EarlyConversions,
-    OverloadCandidateParamOrder PO, bool StrictPackMatch) {
+    OverloadCandidateParamOrder PO, const TemplateArgumentList *Deduced,
+    bool StrictPackMatch) {
   const FunctionProtoType *Proto
     = dyn_cast<FunctionProtoType>(Method->getType()->getAs<FunctionType>());
   assert(Proto && "Methods without a prototype cannot be overloaded");
@@ -7644,6 +7648,7 @@ void Sema::AddMethodCandidate(
       CandidateSet.getKind() == OverloadCandidateSet::CSK_AddressOfOverloadSet;
   Candidate.ExplicitCallArguments = Args.size();
   Candidate.StrictPackMatch = StrictPackMatch;
+  Candidate.Deduced = Deduced;
 
   bool IgnoreExplicitObject =
       (Method->isExplicitObjectMemberFunction() &&
@@ -7853,7 +7858,8 @@ void Sema::AddMethodTemplateCandidate(
   AddMethodCandidate(cast<CXXMethodDecl>(Specialization), FoundDecl,
                      ActingContext, ObjectType, ObjectClassification, Args,
                      CandidateSet, SuppressUserConversions, PartialOverloading,
-                     Conversions, PO, Info.hasStrictPackMatch());
+                     Conversions, PO, Info.takeSugared(),
+                     Info.hasStrictPackMatch());
 }
 
 /// Determine whether a given function template has a simple explicit specifier
@@ -7940,7 +7946,7 @@ void Sema::AddTemplateOverloadCandidate(
       Specialization, FoundDecl, Args, CandidateSet, SuppressUserConversions,
       PartialOverloading, AllowExplicit,
       /*AllowExplicitConversions=*/false, IsADLCandidate, Conversions, PO,
-      Info.AggregateDeductionCandidateHasMismatchedArity,
+      Info.takeSugared(), Info.AggregateDeductionCandidateHasMismatchedArity,
       Info.hasStrictPackMatch());
 }
 
@@ -13014,7 +13020,10 @@ class AddressOfFunctionResolver {
   OverloadExpr::FindResult OvlExprInfo;
   OverloadExpr *OvlExpr;
   TemplateArgumentListInfo OvlExplicitTemplateArgs;
-  SmallVector<std::pair<DeclAccessPair, FunctionDecl*>, 4> Matches;
+  SmallVector<
+      std::tuple<DeclAccessPair, FunctionDecl *, const TemplateArgumentList *>,
+      4>
+      Matches;
   TemplateSpecCandidateSet FailedCandidates;
 
 public:
@@ -13032,15 +13041,22 @@ class AddressOfFunctionResolver {
         FailedCandidates(OvlExpr->getNameLoc(), /*ForTakingAddress=*/true) {
     ExtractUnqualifiedFunctionTypeFromTargetType();
 
+    if (OvlExpr->hasExplicitTemplateArgs())
+      OvlExpr->copyTemplateArgumentsInto(OvlExplicitTemplateArgs);
+
+    const TemplateArgumentList *ConvertedArgs;
     if (TargetFunctionType->isFunctionType()) {
       if (UnresolvedMemberExpr *UME = dyn_cast<UnresolvedMemberExpr>(OvlExpr))
         if (!UME->isImplicitAccess() &&
-            !S.ResolveSingleFunctionTemplateSpecialization(UME))
+            (!OvlExpr->hasExplicitTemplateArgs() ||
+             !S.ResolveSingleFunctionTemplateSpecialization(
+                 UME, OvlExplicitTemplateArgs, ConvertedArgs)))
           StaticMemberFunctionFromBoundPointer = true;
     } else if (OvlExpr->hasExplicitTemplateArgs()) {
       DeclAccessPair dap;
       if (FunctionDecl *Fn = S.ResolveSingleFunctionTemplateSpecialization(
-              OvlExpr, false, &dap)) {
+              OvlExpr, OvlExplicitTemplateArgs, ConvertedArgs,
+              /*Complain=*/false, &dap)) {
         if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn))
           if (!Method->isStatic()) {
             // If the target type is a non-function type and the function found
@@ -13054,14 +13070,11 @@ class AddressOfFunctionResolver {
               return;
           }
 
-        Matches.push_back(std::make_pair(dap, Fn));
+        Matches.push_back({dap, Fn, ConvertedArgs});
       }
       return;
     }
 
-    if (OvlExpr->hasExplicitTemplateArgs())
-      OvlExpr->copyTemplateArgumentsInto(OvlExplicitTemplateArgs);
-
     if (FindAllFunctionsThatMatchTargetTypeExactly()) {
       // C++ [over.over]p4:
       //   If more than one function is selected, [...]
@@ -13104,15 +13117,17 @@ class AddressOfFunctionResolver {
     // Same algorithm as overload resolution -- one pass to pick the "best",
     // another pass to be sure that nothing is better than the best.
     auto Best = Matches.begin();
-    for (auto I = Matches.begin()+1, E = Matches.end(); I != E; ++I)
-      if (isBetterCandidate(I->second, Best->second))
+    for (auto I = Matches.begin() + 1, E = Matches.end(); I != E; ++I)
+      if (isBetterCandidate(std::get<1>(*I), std::get<1>(*Best)))
         Best = I;
 
-    const FunctionDecl *BestFn = Best->second;
-    auto IsBestOrInferiorToBest = [this, BestFn](
-        const std::pair<DeclAccessPair, FunctionDecl *> &Pair) {
-      return BestFn == Pair.second || isBetterCandidate(BestFn, Pair.second);
-    };
+    const FunctionDecl *BestFn = std::get<1>(*Best);
+    auto IsBestOrInferiorToBest =
+        [this, BestFn](const std::tuple<DeclAccessPair, FunctionDecl *,
+                                        const TemplateArgumentList *> &Tuple) {
+          return BestFn == std::get<1>(Tuple) ||
+                 isBetterCandidate(BestFn, std::get<1>(Tuple));
+        };
 
     // Note: We explicitly leave Matches unmodified if there isn't a clear best
     // option, so we can potentially give the user a better error
@@ -13180,7 +13195,7 @@ class AddressOfFunctionResolver {
     if (!S.checkAddressOfFunctionIsAvailable(Specialization))
       return false;
 
-    Matches.push_back(std::make_pair(CurAccessFunPair, Specialization));
+    Matches.push_back({CurAccessFunPair, Specialization, Info.takeSugared()});
     return true;
   }
 
@@ -13227,8 +13242,9 @@ class AddressOfFunctionResolver {
       // If we're in C, we need to support types that aren't exactly identical.
       if (!S.getLangOpts().CPlusPlus ||
           candidateHasExactlyCorrectType(FunDecl)) {
-        Matches.push_back(std::make_pair(
-            CurAccessFunPair, cast<FunctionDecl>(FunDecl->getCanonicalDecl())));
+        Matches.push_back({CurAccessFunPair,
+                           cast<FunctionDecl>(FunDecl->getCanonicalDecl()),
+                           nullptr});
         FoundNonTemplateFunction = true;
         return true;
       }
@@ -13285,7 +13301,8 @@ class AddressOfFunctionResolver {
 
     UnresolvedSet<4> MatchesCopy; // TODO: avoid!
     for (unsigned I = 0, E = Matches.size(); I != E; ++I)
-      MatchesCopy.addDecl(Matches[I].second, Matches[I].first.getAccess());
+      MatchesCopy.addDecl(std::get<1>(Matches[I]),
+                          std::get<0>(Matches[I]).getAccess());
 
     // TODO: It looks like FailedCandidates does not serve much purpose
     // here, since the no_viable diagnostic has index 0.
@@ -13293,15 +13310,16 @@ class AddressOfFunctionResolver {
         MatchesCopy.begin(), MatchesCopy.end(), FailedCandidates,
         SourceExpr->getBeginLoc(), S.PDiag(),
         S.PDiag(diag::err_addr_ovl_ambiguous)
-            << Matches[0].second->getDeclName(),
+            << std::get<1>(Matches[0])->getDeclName(),
         S.PDiag(diag::note_ovl_candidate)
             << (unsigned)oc_function << (unsigned)ocs_described_template,
         Complain, TargetFunctionType);
 
     if (Result != MatchesCopy.end()) {
       // Make it the first and only element
-      Matches[0].first = Matches[Result - MatchesCopy.begin()].first;
-      Matches[0].second = cast<FunctionDecl>(*Result);
+      const auto &Old = Matches[Result - MatchesCopy.begin()];
+      Matches[0] = {std::get<0>(Old), cast<FunctionDecl>(*Result),
+                    std::get<2>(Old)};
       Matches.resize(1);
     } else
       HasComplained |= Complain;
@@ -13311,7 +13329,7 @@ class AddressOfFunctionResolver {
     //   [...] any function template specializations in the set are
     //   eliminated if the set also contains a non-template function, [...]
     for (unsigned I = 0, N = Matches.size(); I != N; ) {
-      if (Matches[I].second->getPrimaryTemplate() == nullptr)
+      if (std::get<1>(Matches[I])->getPrimaryTemplate() == nullptr)
         ++I;
       else {
         Matches[I] = Matches[--N];
@@ -13325,21 +13343,26 @@ class AddressOfFunctionResolver {
     //   [...] Any given non-template function F0 is eliminated if the set
     //   contains a second non-template function that is more
     //   partial-ordering-constrained than F0. [...]
-    assert(Matches[0].second->getPrimaryTemplate() == nullptr &&
+    auto &[_1, FD, _2] = Matches[0];
+    assert(FD->getPrimaryTemplate() == nullptr &&
            "Call EliminateAllTemplateMatches() first");
-    SmallVector<std::pair<DeclAccessPair, FunctionDecl *>, 4> Results;
+    SmallVector<std::tuple<DeclAccessPair, FunctionDecl *,
+                           const TemplateArgumentList *>,
+                4>
+        Results;
     Results.push_back(Matches[0]);
     for (unsigned I = 1, N = Matches.size(); I < N; ++I) {
-      assert(Matches[I].second->getPrimaryTemplate() == nullptr);
-      FunctionDecl *F = getMorePartialOrderingConstrained(
-          S, Matches[I].second, Results[0].second,
-          /*IsFn1Reversed=*/false,
-          /*IsFn2Reversed=*/false);
+      auto &[_1, FD, _2] = Matches[I];
+      assert(FD->getPrimaryTemplate() == nullptr);
+      FunctionDecl *F =
+          getMorePartialOrderingConstrained(S, FD, std::get<1>(Results[0]),
+                                            /*IsFn1Reversed=*/false,
+                                            /*IsFn2Reversed=*/false);
       if (!F) {
         Results.push_back(Matches[I]);
         continue;
       }
-      if (F == Matches[I].second) {
+      if (F == FD) {
         Results.clear();
         Results.push_back(Matches[I]);
       }
@@ -13419,22 +13442,26 @@ class AddressOfFunctionResolver {
 
   FunctionDecl* getMatchingFunctionDecl() const {
     if (Matches.size() != 1) return nullptr;
-    return Matches[0].second;
+    return std::get<1>(Matches[0]);
   }
 
   const DeclAccessPair* getMatchingFunctionAccessPair() const {
     if (Matches.size() != 1) return nullptr;
-    return &Matches[0].first;
+    return &std::get<0>(Matches[0]);
+  }
+
+  const TemplateArgumentList *getMatchingFunctionConvertedArgs() const {
+    if (Matches.size() != 1)
+      return nullptr;
+    return std::get<2>(Matches[0]);
   }
 };
 }
 
-FunctionDecl *
-Sema::ResolveAddressOfOverloadedFunction(Expr *AddressOfExpr,
-                                         QualType TargetType,
-                                         bool Complain,
-                                         DeclAccessPair &FoundResult,
-                                         bool *pHadMultipleCandidates) {
+FunctionDecl *Sema::ResolveAddressOfOverloadedFunction(
+    Expr *AddressOfExpr, QualType TargetType, bool Complain,
+    DeclAccessPair &FoundResult, const TemplateArgumentList *&ConvertedArgs,
+    bool *pHadMultipleCandidates) {
   assert(AddressOfExpr->getType() == Context.OverloadTy);
 
   AddressOfFunctionResolver Resolver(*this, AddressOfExpr, TargetType,
@@ -13456,6 +13483,7 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *AddressOfExpr,
     if (auto *FPT = Fn->getType()->getAs<FunctionProtoType>())
       ResolveExceptionSpec(AddressOfExpr->getExprLoc(), FPT);
     FoundResult = *Resolver.getMatchingFunctionAccessPair();
+    ConvertedArgs = Resolver.getMatchingFunctionConvertedArgs();
     if (Complain) {
       if (Resolver.IsStaticMemberFunctionFromBoundPointer())
         Resolver.ComplainIsStaticMemberFunctionFromBoundPointer();
@@ -13578,7 +13606,8 @@ bool Sema::resolveAndFixAddressOfSingleOverloadCandidate(
   // for both.
   DiagnoseUseOfDecl(Found, E->getExprLoc());
   CheckAddressOfMemberAccess(E, DAP);
-  ExprResult Res = FixOverloadedFunctionReference(E, DAP, Found);
+  ExprResult Res =
+      FixOverloadedFunctionReference(E, DAP, Found, /*ConvertedArgs=*/{});
   if (Res.isInvalid())
     return false;
   Expr *Fixed = Res.get();
@@ -13590,8 +13619,10 @@ bool Sema::resolveAndFixAddressOfSingleOverloadCandidate(
 }
 
 FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(
-    OverloadExpr *ovl, bool Complain, DeclAccessPair *FoundResult,
-    TemplateSpecCandidateSet *FailedTSC, bool ForTypeDeduction) {
+    OverloadExpr *ovl, TemplateArgumentListInfo &ExplicitTemplateArgs,
+    const TemplateArgumentList *&ConvertedArgs, bool Complain,
+    DeclAccessPair *FoundResult, TemplateSpecCandidateSet *FailedTSC,
+    bool ForTypeDeduction) {
   // C++ [over.over]p1:
   //   [...] [Note: any redundant set of parentheses surrounding the
   //   overloaded function name is ignored (5.1). ]
@@ -13599,12 +13630,8 @@ FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(
   //   [...] The overloaded function name can be preceded by the &
   //   operator.
 
-  // If we didn't actually find any template-ids, we're done.
-  if (!ovl->hasExplicitTemplateArgs())
-    return nullptr;
-
-  TemplateArgumentListInfo ExplicitTemplateArgs;
-  ovl->copyTemplateArgumentsInto(ExplicitTemplateArgs);
+  // Specializations must have template args.
+  assert(ovl->hasExplicitTemplateArgs());
 
   // Look through all of the overloaded functions, searching for one
   // whose type matches exactly.
@@ -13662,6 +13689,7 @@ FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(
 
     Matched = Specialization;
     if (FoundResult) *FoundResult = I.getPair();
+    ConvertedArgs = Info.takeSugared();
   }
 
   if (Matched &&
@@ -13678,50 +13706,55 @@ bool Sema::ResolveAndFixSingleFunctionTemplateSpecialization(
   assert(SrcExpr.get()->getType() == Context.OverloadTy);
 
   OverloadExpr::FindResult ovl = OverloadExpr::find(SrcExpr.get());
-
-  DeclAccessPair found;
   ExprResult SingleFunctionExpression;
-  if (FunctionDecl *fn = ResolveSingleFunctionTemplateSpecialization(
-                           ovl.Expression, /*complain*/ false, &found)) {
-    if (DiagnoseUseOfDecl(fn, SrcExpr.get()->getBeginLoc())) {
-      SrcExpr = ExprError();
-      return true;
-    }
+  if (ovl.Expression->hasExplicitTemplateArgs()) {
+    TemplateArgumentListInfo ExplicitTemplateArgs;
+    ovl.Expression->copyTemplateArgumentsInto(ExplicitTemplateArgs);
+
+    const TemplateArgumentList *ConvertedArgs;
+    DeclAccessPair found;
+    if (FunctionDecl *fn = ResolveSingleFunctionTemplateSpecialization(
+            ovl.Expression, ExplicitTemplateArgs, ConvertedArgs,
+            /*Complain=*/false, &found)) {
+      if (DiagnoseUseOfDecl(fn, SrcExpr.get()->getBeginLoc())) {
+        SrcExpr = ExprError();
+        return true;
+      }
 
-    // It is only correct to resolve to an instance method if we're
-    // resolving a form that's permitted to be a pointer to member.
-    // Otherwise we'll end up making a bound member expression, which
-    // is illegal in all the contexts we resolve like this.
-    if (!ovl.HasFormOfMemberPointer &&
-        isa<CXXMethodDecl>(fn) &&
-        cast<CXXMethodDecl>(fn)->isInstance()) {
-      if (!complain) return false;
-
-      Diag(ovl.Expression->getExprLoc(),
-           diag::err_bound_member_function)
-        << 0 << ovl.Expression->getSourceRange();
-
-      // TODO: I believe we only end up here if there's a mix of
-      // static and non-static candidates (otherwise the expression
-      // would have 'bound member' type, not 'overload' type).
-      // Ideally we would note which candidate was chosen and why
-      // the static candidates were rejected.
-      SrcExpr = ExprError();
-      return true;
-    }
+      // It is only correct to resolve to an instance method if we're
+      // resolving a form that's permitted to be a pointer to member.
+      // Otherwise we'll end up making a bound member expression, which
+      // is illegal in all the contexts we resolve like this.
+      if (!ovl.HasFormOfMemberPointer && isa<CXXMethodDecl>(fn) &&
+          cast<CXXMethodDecl>(fn)->isInstance()) {
+        if (!complain)
+          return false;
 
-    // Fix the expression to refer to 'fn'.
-    SingleFunctionExpression =
-        FixOverloadedFunctionReference(SrcExpr.get(), found, fn);
+        Diag(ovl.Expression->getExprLoc(), diag::err_bound_member_function)
+            << 0 << ovl.Expression->getSourceRange();
 
-    // If desired, do function-to-pointer decay.
-    if (doFunctionPointerConversion) {
-      SingleFunctionExpression =
-        DefaultFunctionArrayLvalueConversion(SingleFunctionExpression.get());
-      if (SingleFunctionExpression.isInvalid()) {
+        // TODO: I believe we only end up here if there's a mix of
+        // static and non-static candidates (otherwise the expression
+        // would have 'bound member' type, not 'overload' type).
+        // Ideally we would note which candidate was chosen and why
+        // the static candidates were rejected.
         SrcExpr = ExprError();
         return true;
       }
+
+      // Fix the expression to refer to 'fn'.
+      SingleFunctionExpression = FixOverloadedFunctionReference(
+          SrcExpr.get(), found, fn, ConvertedArgs);
+
+      // If desired, do function-to-pointer decay.
+      if (doFunctionPointerConversion) {
+        SingleFunctionExpression = DefaultFunctionArrayLvalueConversion(
+            SingleFunctionExpression.get());
+        if (SingleFunctionExpression.isInvalid()) {
+          SrcExpr = ExprError();
+          return true;
+        }
+      }
     }
   }
 
@@ -14226,8 +14259,8 @@ static ExprResult FinishOverloadedCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
     SemaRef.CheckUnresolvedLookupAccess(ULE, (*Best)->FoundDecl);
     if (SemaRef.DiagnoseUseOfDecl(FDecl, ULE->getNameLoc()))
       return ExprError();
-    ExprResult Res =
-        SemaRef.FixOverloadedFunctionReference(Fn, (*Best)->FoundDecl, FDecl);
+    ExprResult Res = SemaRef.FixOverloadedFunctionReference(
+        Fn, (*Best)->FoundDecl, FDecl, (*Best)->Deduced);
     if (Res.isInvalid())
       return ExprError();
     return SemaRef.BuildResolvedCallExpr(
@@ -14301,8 +14334,8 @@ static ExprResult FinishOverloadedCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
 
     // We emitted an error for the unavailable/deleted function call but keep
     // the call in the AST.
-    ExprResult Res =
-        SemaRef.FixOverloadedFunctionReference(Fn, (*Best)->FoundDecl, FDecl);
+    ExprResult Res = SemaRef.FixOverloadedFunctionReference(
+        Fn, (*Best)->FoundDecl, FDecl, (*Best)->Deduced);
     if (Res.isInvalid())
       return ExprError();
     return SemaRef.BuildResolvedCallExpr(
@@ -15742,8 +15775,8 @@ ExprResult Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
     if (!Succeeded)
       return BuildRecoveryExpr(chooseRecoveryType(CandidateSet, &Best));
 
-    ExprResult Res =
-        FixOverloadedFunctionReference(MemExprE, FoundDecl, Method);
+    ExprResult Res = FixOverloadedFunctionReference(MemExprE, FoundDecl, Method,
+                                                    Best->Deduced);
     if (Res.isInvalid())
       return ExprError();
     MemExprE = Res.get();
@@ -16393,11 +16426,13 @@ Sema::BuildForRangeBeginEndCall(SourceLocation Loc,
   return FRS_Success;
 }
 
-ExprResult Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
-                                                FunctionDecl *Fn) {
+ExprResult
+Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
+                                     FunctionDecl *Fn,
+                                     const TemplateArgumentList *Deduced) {
   if (ParenExpr *PE = dyn_cast<ParenExpr>(E)) {
     ExprResult SubExpr =
-        FixOverloadedFunctionReference(PE->getSubExpr(), Found, Fn);
+        FixOverloadedFunctionReference(PE->getSubExpr(), Found, Fn, Deduced);
     if (SubExpr.isInvalid())
       return ExprError();
     if (SubExpr.get() == PE->getSubExpr())
@@ -16409,7 +16444,7 @@ ExprResult Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
 
   if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
     ExprResult SubExpr =
-        FixOverloadedFunctionReference(ICE->getSubExpr(), Found, Fn);
+        FixOverloadedFunctionReference(ICE->getSubExpr(), Found, Fn, Deduced);
     if (SubExpr.isInvalid())
       return ExprError();
     assert(Context.hasSameType(ICE->getSubExpr()->getType(),
@@ -16426,8 +16461,8 @@ ExprResult Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
 
   if (auto *GSE = dyn_cast<GenericSelectionExpr>(E)) {
     if (!GSE->isResultDependent()) {
-      ExprResult SubExpr =
-          FixOverloadedFunctionReference(GSE->getResultExpr(), Found, Fn);
+      ExprResult SubExpr = FixOverloadedFunctionReference(GSE->getResultExpr(),
+                                                          Found, Fn, Deduced);
       if (SubExpr.isInvalid())
         return ExprError();
       if (SubExpr.get() == GSE->getResultExpr())
@@ -16468,8 +16503,8 @@ ExprResult Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
         // Fix the subexpression, which really has to be an
         // UnresolvedLookupExpr holding an overloaded member function
         // or template.
-        ExprResult SubExpr =
-            FixOverloadedFunctionReference(UnOp->getSubExpr(), Found, Fn);
+        ExprResult SubExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(),
+                                                            Found, Fn, Deduced);
         if (SubExpr.isInvalid())
           return ExprError();
         if (SubExpr.get() == UnOp->getSubExpr())
@@ -16503,7 +16538,7 @@ ExprResult Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
       }
     }
     ExprResult SubExpr =
-        FixOverloadedFunctionReference(UnOp->getSubExpr(), Found, Fn);
+        FixOverloadedFunctionReference(UnOp->getSubExpr(), Found, Fn, Deduced);
     if (SubExpr.isInvalid())
       return ExprError();
     if (SubExpr.get() == UnOp->getSubExpr())
@@ -16537,7 +16572,7 @@ ExprResult Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
 
     DeclRefExpr *DRE = BuildDeclRefExpr(
         Fn, Type, ValueKind, ULE->getNameInfo(), ULE->getQualifierLoc(),
-        Found.getDecl(), ULE->getTemplateKeywordLoc(), TemplateArgs);
+        Found.getDecl(), ULE->getTemplateKeywordLoc(), TemplateArgs, Deduced);
     DRE->setHadMultipleCandidates(ULE->getNumDecls() > 1);
     return DRE;
   }
@@ -16559,7 +16594,7 @@ ExprResult Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
         DeclRefExpr *DRE = BuildDeclRefExpr(
             Fn, Fn->getType(), VK_LValue, MemExpr->getNameInfo(),
             MemExpr->getQualifierLoc(), Found.getDecl(),
-            MemExpr->getTemplateKeywordLoc(), TemplateArgs);
+            MemExpr->getTemplateKeywordLoc(), TemplateArgs, Deduced);
         DRE->setHadMultipleCandidates(MemExpr->getNumDecls() > 1);
         return DRE;
       } else {
@@ -16592,10 +16627,11 @@ ExprResult Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
   llvm_unreachable("Invalid reference to overloaded function");
 }
 
-ExprResult Sema::FixOverloadedFunctionReference(ExprResult E,
-                                                DeclAccessPair Found,
-                                                FunctionDecl *Fn) {
-  return FixOverloadedFunctionReference(E.get(), Found, Fn);
+ExprResult
+Sema::FixOverloadedFunctionReference(ExprResult E, DeclAccessPair Found,
+                                     FunctionDecl *Fn,
+                                     const TemplateArgumentList *Deduced) {
+  return FixOverloadedFunctionReference(E.get(), Found, Fn, Deduced);
 }
 
 bool clang::shouldEnforceArgLimit(bool PartialOverloading,
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 0b78f3d9e02bb..479fcc1f147a2 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -5103,14 +5103,15 @@ namespace {
 /// a given template-id.
 struct PartialSpecMatchResult {
   VarTemplatePartialSpecializationDecl *Partial;
-  TemplateArgumentList *Args;
+  TemplateArgumentList *CanonicalArgs, *SugaredArgs;
 };
 } // end anonymous namespace
 
 DeclResult
 Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
                          SourceLocation TemplateNameLoc,
-                         const TemplateArgumentListInfo &TemplateArgs) {
+                         const TemplateArgumentListInfo &TemplateArgs,
+                         const TemplateArgumentList *&ConvertedArgs) {
   assert(Template && "A variable template id without template?");
 
   // Check that the template argument list is well-formed for this template.
@@ -5128,12 +5129,17 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
           TemplateArgs, CTAI.CanonicalConverted))
     return DeclResult();
 
+  ConvertedArgs =
+      TemplateArgumentList::CreateCopy(Context, CTAI.SugaredConverted);
+
   // Find the variable template specialization declaration that
   // corresponds to these arguments.
   void *InsertPos = nullptr;
   if (VarTemplateSpecializationDecl *Spec =
           Template->findSpecialization(CTAI.CanonicalConverted, InsertPos)) {
     checkSpecializationReachability(TemplateNameLoc, Spec);
+    ConvertedArgs =
+        TemplateArgumentList::CreateCopy(Context, CTAI.SugaredConverted);
     // If we already have a variable template specialization, return it.
     return Spec;
   }
@@ -5187,7 +5193,8 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
     } else {
       Matched.push_back(PartialSpecMatchResult());
       Matched.back().Partial = Partial;
-      Matched.back().Args = Info.takeSugared();
+      Matched.back().SugaredArgs = Info.takeSugared();
+      Matched.back().CanonicalArgs = Info.takeCanonical();
     }
   }
 
@@ -5230,11 +5237,13 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
 
     // Instantiate using the best variable template partial specialization.
     InstantiationPattern = Best->Partial;
-    PartialSpecArgs = Best->Args;
+    PartialSpecArgs = Best->SugaredArgs;
   } else {
     //   -- If no match is found, the instantiation is generated
     //      from the primary template.
     // InstantiationPattern = Template->getTemplatedDecl();
+    ConvertedArgs =
+        TemplateArgumentList::CreateCopy(Context, CTAI.SugaredConverted);
   }
 
   // 2. Create the canonical declaration.
@@ -5255,9 +5264,10 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
 
     // Print the matching partial specializations.
     for (MatchResult P : Matched)
+      // FIXME: Use SugaredArgs here.
       Diag(P.Partial->getLocation(), diag::note_partial_spec_match)
           << getTemplateArgumentBindingsText(P.Partial->getTemplateParameters(),
-                                             *P.Args);
+                                             *P.CanonicalArgs);
     return true;
   }
 
@@ -5275,9 +5285,9 @@ ExprResult Sema::CheckVarTemplateId(
     const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo,
     VarTemplateDecl *Template, NamedDecl *FoundD, SourceLocation TemplateLoc,
     const TemplateArgumentListInfo *TemplateArgs) {
-
+  const TemplateArgumentList *ConvertedArgs;
   DeclResult Decl = CheckVarTemplateId(Template, TemplateLoc, NameInfo.getLoc(),
-                                       *TemplateArgs);
+                                       *TemplateArgs, ConvertedArgs);
   if (Decl.isInvalid())
     return ExprError();
 
@@ -5290,7 +5300,8 @@ ExprResult Sema::CheckVarTemplateId(
                                        NameInfo.getLoc());
 
   // Build an ordinary singleton decl ref.
-  return BuildDeclarationNameExpr(SS, NameInfo, Var, FoundD, TemplateArgs);
+  return BuildDeclarationNameExpr(SS, NameInfo, Var, FoundD, TemplateArgs,
+                                  ConvertedArgs);
 }
 
 void Sema::diagnoseMissingTemplateArguments(TemplateName Name,
@@ -8004,13 +8015,14 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
          ->isFunctionType())) {
 
     if (Arg->getType() == Context.OverloadTy) {
-      if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Arg, ParamType,
-                                                                true,
-                                                                FoundResult)) {
+      const TemplateArgumentList *ConvertedArgs;
+      if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(
+              Arg, ParamType, true, FoundResult, ConvertedArgs)) {
         if (DiagnoseUseOfDecl(Fn, Arg->getBeginLoc()))
           return ExprError();
 
-        ExprResult Res = FixOverloadedFunctionReference(Arg, FoundResult, Fn);
+        ExprResult Res =
+            FixOverloadedFunctionReference(Arg, FoundResult, Fn, ConvertedArgs);
         if (Res.isInvalid())
           return ExprError();
         Arg = Res.get();
@@ -8058,13 +8070,14 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
            "Only object references allowed here");
 
     if (Arg->getType() == Context.OverloadTy) {
-      if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Arg,
-                                                 ParamRefType->getPointeeType(),
-                                                                true,
-                                                                FoundResult)) {
+      const TemplateArgumentList *ConvertedArgs;
+      if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(
+              Arg, ParamRefType->getPointeeType(), true, FoundResult,
+              ConvertedArgs)) {
         if (DiagnoseUseOfDecl(Fn, Arg->getBeginLoc()))
           return ExprError();
-        ExprResult Res = FixOverloadedFunctionReference(Arg, FoundResult, Fn);
+        ExprResult Res =
+            FixOverloadedFunctionReference(Arg, FoundResult, Fn, ConvertedArgs);
         if (Res.isInvalid())
           return ExprError();
         Arg = Res.get();
@@ -11018,8 +11031,10 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
       TemplateArgumentListInfo TemplateArgs =
           makeTemplateArgumentListInfo(*this, *D.getName().TemplateId);
 
-      DeclResult Res = CheckVarTemplateId(PrevTemplate, TemplateLoc,
-                                          D.getIdentifierLoc(), TemplateArgs);
+      const TemplateArgumentList *ConvertedArgs;
+      DeclResult Res =
+          CheckVarTemplateId(PrevTemplate, TemplateLoc, D.getIdentifierLoc(),
+                             TemplateArgs, ConvertedArgs);
       if (Res.isInvalid())
         return true;
 
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 658969b25638f..5b79226a8be42 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -4198,7 +4198,8 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
 /// Gets the type of a function for template-argument-deducton
 /// purposes when it's considered as part of an overload set.
 static QualType GetTypeOfFunction(Sema &S, const OverloadExpr::FindResult &R,
-                                  FunctionDecl *Fn) {
+                                  FunctionDecl *Fn,
+                                  ArrayRef<TemplateArgument> Args) {
   // We may need to deduce the return type of the function now.
   if (S.getLangOpts().CPlusPlus14 && Fn->getReturnType()->isUndeducedType() &&
       S.DeduceReturnType(Fn, R.Expression->getExprLoc(), /*Diagnose*/ false))
@@ -4240,6 +4241,11 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams,
   if (R.IsAddressOfOperand)
     TDF |= TDF_IgnoreQualifiers;
 
+  // Gather the explicit template arguments, if any.
+  TemplateArgumentListInfo ExplicitTemplateArgs;
+  if (Ovl->hasExplicitTemplateArgs())
+    Ovl->copyTemplateArgumentsInto(ExplicitTemplateArgs);
+
   // C++0x [temp.deduct.call]p6:
   //   When P is a function type, pointer to function type, or pointer
   //   to member function type:
@@ -4249,31 +4255,29 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams,
       !ParamType->isMemberFunctionPointerType()) {
     if (Ovl->hasExplicitTemplateArgs()) {
       // But we can still look for an explicit specialization.
+      const TemplateArgumentList *ConvertedArgs;
       if (FunctionDecl *ExplicitSpec =
               S.ResolveSingleFunctionTemplateSpecialization(
-                  Ovl, /*Complain=*/false,
+                  Ovl, ExplicitTemplateArgs, ConvertedArgs, /*Complain=*/false,
                   /*Found=*/nullptr, FailedTSC,
                   /*ForTypeDeduction=*/true))
-        return GetTypeOfFunction(S, R, ExplicitSpec);
+        return GetTypeOfFunction(S, R, ExplicitSpec, ConvertedArgs->asArray());
     }
 
     DeclAccessPair DAP;
     if (FunctionDecl *Viable =
             S.resolveAddressOfSingleOverloadCandidate(Arg, DAP))
-      return GetTypeOfFunction(S, R, Viable);
+      return GetTypeOfFunction(S, R, Viable, /*Args=*/{});
 
     return {};
   }
 
-  // Gather the explicit template arguments, if any.
-  TemplateArgumentListInfo ExplicitTemplateArgs;
-  if (Ovl->hasExplicitTemplateArgs())
-    Ovl->copyTemplateArgumentsInto(ExplicitTemplateArgs);
   QualType Match;
   for (UnresolvedSetIterator I = Ovl->decls_begin(),
          E = Ovl->decls_end(); I != E; ++I) {
     NamedDecl *D = (*I)->getUnderlyingDecl();
 
+    const TemplateArgumentList *ConvertedArgs = nullptr;
     if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D)) {
       //   - If the argument is an overload set containing one or more
       //     function templates, the parameter is treated as a
@@ -4290,10 +4294,12 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams,
         continue;
 
       D = Specialization;
+      ConvertedArgs = Info.takeSugared();
     }
 
     FunctionDecl *Fn = cast<FunctionDecl>(D);
-    QualType ArgType = GetTypeOfFunction(S, R, Fn);
+    QualType ArgType = GetTypeOfFunction(
+        S, R, Fn, ConvertedArgs ? ConvertedArgs->asArray() : std::nullopt);
     if (ArgType.isNull()) continue;
 
     // Function-to-pointer conversion.
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 68c801098f20a..5748ab849c43f 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1635,6 +1635,7 @@ namespace {
       }
       return Type;
     }
+    using inherited::TransformTemplateArgument;
     // Override the default version to handle a rewrite-template-arg-pack case
     // for building a deduction guide.
     bool TransformTemplateArgument(const TemplateArgumentLoc &Input,
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 67677669b08d8..222dd932aab37 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -597,6 +597,9 @@ class TreeTransform {
                         NamedDecl *FirstQualifierInScope = nullptr,
                         bool AllowInjectedClassName = false);
 
+  std::optional<TemplateArgument>
+  TransformTemplateArgument(const TemplateArgument &Arg);
+
   /// Transform the given template argument.
   ///
   /// By default, this operation transforms the type, expression, or
@@ -2707,11 +2710,12 @@ class TreeTransform {
                                 ValueDecl *VD,
                                 const DeclarationNameInfo &NameInfo,
                                 NamedDecl *Found,
-                                TemplateArgumentListInfo *TemplateArgs) {
+                                TemplateArgumentListInfo *TemplateArgs,
+                                const TemplateArgumentList *ConvertedArgs) {
     CXXScopeSpec SS;
     SS.Adopt(QualifierLoc);
     return getSema().BuildDeclarationNameExpr(SS, NameInfo, VD, Found,
-                                              TemplateArgs);
+                                              TemplateArgs, ConvertedArgs);
   }
 
   /// Build a new expression in parentheses.
@@ -4827,6 +4831,80 @@ TreeTransform<Derived>::TransformTemplateName(CXXScopeSpec &SS,
   llvm_unreachable("overloaded function decl survived to here");
 }
 
+template <typename Derived>
+std::optional<TemplateArgument>
+TreeTransform<Derived>::TransformTemplateArgument(const TemplateArgument &Arg) {
+  switch (auto Kind = Arg.getKind()) {
+  case TemplateArgument::Null:
+    llvm_unreachable("Unexpected TemplateArgument Null");
+  case TemplateArgument::Expression:
+    llvm_unreachable("Unexpected TemplateArgument Expr");
+
+  case TemplateArgument::Pack: {
+    SmallVector<TemplateArgument, 4> Args(Arg.getPackAsArray());
+    for (auto &I : Args) {
+      const auto Arg = getDerived().TransformTemplateArgument(I);
+      if (!Arg)
+        return std::nullopt;
+      I = *Arg;
+    }
+    return TemplateArgument(
+        TemplateArgumentList::CreateCopy(getSema().Context, Args)->asArray());
+  }
+
+  case TemplateArgument::Integral:
+  case TemplateArgument::NullPtr:
+  case TemplateArgument::Declaration:
+  case TemplateArgument::StructuralValue: {
+    QualType T = Arg.getNonTypeTemplateArgumentType();
+    QualType NewT = getDerived().TransformType(T);
+    if (NewT.isNull())
+      return std::nullopt;
+
+    ValueDecl *D = Arg.getKind() == TemplateArgument::Declaration
+                       ? Arg.getAsDecl()
+                       : nullptr;
+    ValueDecl *NewD = D ? cast_or_null<ValueDecl>(getDerived().TransformDecl(
+                              getDerived().getBaseLocation(), D))
+                        : nullptr;
+    if (D && !NewD)
+      return std::nullopt;
+    if (NewT == T && D == NewD)
+      return Arg;
+    if (Kind == TemplateArgument::Integral)
+      return TemplateArgument(getSema().Context, Arg.getAsIntegral(), NewT);
+    if (Kind == TemplateArgument::NullPtr)
+      return TemplateArgument(NewT, /*IsNullPtr=*/true);
+    if (Kind == TemplateArgument::StructuralValue)
+      return TemplateArgument(getSema().Context, NewT,
+                              Arg.getAsStructuralValue());
+    assert(Kind == TemplateArgument::Declaration);
+    return TemplateArgument(NewD, NewT);
+  }
+  case TemplateArgument::Type:
+    if (QualType T = getDerived().TransformType(Arg.getAsType()); !T.isNull())
+      return TemplateArgument(T);
+    return std::nullopt;
+  case TemplateArgument::Template: {
+    CXXScopeSpec SS;
+    if (TemplateName Template = getDerived().TransformTemplateName(
+            SS, Arg.getAsTemplate(), SourceLocation());
+        !Template.isNull())
+      return TemplateArgument(Template);
+    return std::nullopt;
+  }
+  case TemplateArgument::TemplateExpansion: {
+    CXXScopeSpec SS;
+    if (TemplateName Template = getDerived().TransformTemplateName(
+            SS, Arg.getAsTemplateOrTemplatePattern(), SourceLocation());
+        !Template.isNull())
+      return TemplateArgument(Template, Arg.getNumTemplateExpansions());
+    return std::nullopt;
+  }
+  }
+  llvm_unreachable("Unexpected Template Kind");
+}
+
 template<typename Derived>
 void TreeTransform<Derived>::InventTemplateArgumentLoc(
                                          const TemplateArgument &Arg,
@@ -4848,45 +4926,15 @@ bool TreeTransform<Derived>::TransformTemplateArgument(
   case TemplateArgument::Integral:
   case TemplateArgument::NullPtr:
   case TemplateArgument::Declaration:
-  case TemplateArgument::StructuralValue: {
+  case TemplateArgument::StructuralValue:
     // Transform a resolved template argument straight to a resolved template
     // argument. We get here when substituting into an already-substituted
     // template type argument during concept satisfaction checking.
-    QualType T = Arg.getNonTypeTemplateArgumentType();
-    QualType NewT = getDerived().TransformType(T);
-    if (NewT.isNull())
-      return true;
-
-    ValueDecl *D = Arg.getKind() == TemplateArgument::Declaration
-                       ? Arg.getAsDecl()
-                       : nullptr;
-    ValueDecl *NewD = D ? cast_or_null<ValueDecl>(getDerived().TransformDecl(
-                              getDerived().getBaseLocation(), D))
-                        : nullptr;
-    if (D && !NewD)
-      return true;
-
-    if (NewT == T && D == NewD)
-      Output = Input;
-    else if (Arg.getKind() == TemplateArgument::Integral)
-      Output = TemplateArgumentLoc(
-          TemplateArgument(getSema().Context, Arg.getAsIntegral(), NewT),
-          TemplateArgumentLocInfo());
-    else if (Arg.getKind() == TemplateArgument::NullPtr)
-      Output = TemplateArgumentLoc(TemplateArgument(NewT, /*IsNullPtr=*/true),
-                                   TemplateArgumentLocInfo());
-    else if (Arg.getKind() == TemplateArgument::Declaration)
-      Output = TemplateArgumentLoc(TemplateArgument(NewD, NewT),
-                                   TemplateArgumentLocInfo());
-    else if (Arg.getKind() == TemplateArgument::StructuralValue)
-      Output = TemplateArgumentLoc(
-          TemplateArgument(getSema().Context, NewT, Arg.getAsStructuralValue()),
-          TemplateArgumentLocInfo());
-    else
-      llvm_unreachable("unexpected template argument kind");
-
-    return false;
-  }
+    if (const auto Out = getDerived().TransformTemplateArgument(Arg)) {
+      Output = TemplateArgumentLoc(*Out, TemplateArgumentLocInfo());
+      return false;
+    }
+    return true;
 
   case TemplateArgument::Type: {
     TypeSourceInfo *DI = Input.getTypeSourceInfo();
@@ -7368,6 +7416,7 @@ QualType TreeTransform<Derived>::TransformTemplateSpecializationType(
             ArgIterator(*this, ConvertedArgs.begin()),
             ArgIterator(*this, ConvertedArgs.end()), NewTemplateArgs))
       return QualType();
+    assert(NewTemplateArgs.size() != 0);
   } else {
     using ArgIterator =
         TemplateArgumentLocContainerIterator<TemplateSpecializationTypeLoc>;
@@ -12881,9 +12930,22 @@ TreeTransform<Derived>::TransformDeclRefExpr(DeclRefExpr *E) {
                                                 TransArgs))
       return ExprError();
   }
+  const TemplateArgumentList *NewConvertedArgs = nullptr;
+  if (const TemplateArgumentList *OldConvertedArgs = E->getConvertedArgs()) {
+    assert(OldConvertedArgs->size() != 0);
+    SmallVector<TemplateArgument, 4> NewArgs(OldConvertedArgs->asArray());
+    for (auto I : NewArgs) {
+      const auto Arg = getDerived().TransformTemplateArgument(I);
+      if (!Arg)
+        return ExprError();
+      I = *Arg;
+    }
+    NewConvertedArgs =
+        TemplateArgumentList::CreateCopy(getSema().Context, NewArgs);
+  }
 
-  return getDerived().RebuildDeclRefExpr(QualifierLoc, ND, NameInfo,
-                                         Found, TemplateArgs);
+  return getDerived().RebuildDeclRefExpr(QualifierLoc, ND, NameInfo, Found,
+                                         TemplateArgs, NewConvertedArgs);
 }
 
 template<typename Derived>
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index 969b1f7416ddb..06adaee8eaadb 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -9798,6 +9798,15 @@ void ASTRecordReader::readTemplateArgumentList(
     TemplArgs.push_back(readTemplateArgument(Canonicalize));
 }
 
+const TemplateArgumentList *
+ASTRecordReader::readTemplateArgumentList(bool Canonicalize) {
+  SmallVector<TemplateArgument, 8> Args;
+  readTemplateArgumentList(Args, Canonicalize);
+  if (Args.size() == 0)
+    return nullptr;
+  return TemplateArgumentList::CreateCopy(getContext(), Args);
+}
+
 /// Read a UnresolvedSet structure.
 void ASTRecordReader::readUnresolvedSet(LazyASTUnresolvedSet &Set) {
   unsigned NumDecls = readInt();
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index d26152f3780ed..a4f1856401b71 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -623,6 +623,7 @@ void ASTStmtReader::VisitDeclRefExpr(DeclRefExpr *E) {
   E->DeclRefExprBits.HasTemplateKWAndArgsInfo =
       CurrentUnpackingBits->getNextBit();
   E->DeclRefExprBits.CapturedByCopyInLambdaWithExplicitObjectParameter = false;
+
   unsigned NumTemplateArgs = 0;
   if (E->hasTemplateKWAndArgsInfo())
     NumTemplateArgs = Record.readInt();
@@ -640,6 +641,7 @@ void ASTStmtReader::VisitDeclRefExpr(DeclRefExpr *E) {
         E->getTrailingObjects<TemplateArgumentLoc>(), NumTemplateArgs);
 
   E->D = readDeclAs<ValueDecl>();
+  E->ConvertedArgs = Record.readTemplateArgumentList();
   E->setLocation(readSourceLocation());
   E->DNLoc = Record.readDeclarationNameLoc(E->getDecl()->getDeclName());
 }
@@ -1072,6 +1074,7 @@ void ASTStmtReader::VisitMemberExpr(MemberExpr *E) {
   E->MemberExprBits.NonOdrUseReason =
       CurrentUnpackingBits->getNextBits(/*Width=*/2);
   E->MemberExprBits.OperatorLoc = Record.readSourceLocation();
+  E->Deduced = Record.readTemplateArgumentList();
 
   if (HasQualifier)
     new (E->getTrailingObjects<NestedNameSpecifierLoc>())
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index 3a7a23481ea98..13abedaab85ed 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -2786,6 +2786,7 @@ void ASTWriter::WriteDeclAbbrevs() {
   // GetDeclFound, HasQualifier and ExplicitTemplateArgs should be 0.
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 5));
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclRef
+  Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ConvertedArgs
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
   DeclRefExprAbbrev = Stream.EmitAbbrev(std::move(Abv));
 
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
index 23bb5ff22efaf..85a89b2a1308b 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -706,7 +706,8 @@ void ASTStmtWriter::VisitDeclRefExpr(DeclRefExpr *E) {
 
   if ((!E->hasTemplateKWAndArgsInfo()) && (!E->hasQualifier()) &&
       (E->getDecl() == E->getFoundDecl()) &&
-      nk == DeclarationName::Identifier && E->getObjectKind() == OK_Ordinary) {
+      nk == DeclarationName::Identifier && E->getObjectKind() == OK_Ordinary &&
+      !E->getConvertedArgs()) {
     AbbrevToUse = Writer.getDeclRefExprAbbrev();
   }
 
@@ -721,6 +722,10 @@ void ASTStmtWriter::VisitDeclRefExpr(DeclRefExpr *E) {
                              E->getTrailingObjects<TemplateArgumentLoc>());
 
   Record.AddDeclRef(E->getDecl());
+  if (E->ConvertedArgs)
+    Record.AddTemplateArgumentList(E->ConvertedArgs);
+  else
+    Record.push_back(0);
   Record.AddSourceLocation(E->getLocation());
   Record.AddDeclarationNameLoc(E->DNLoc, E->getDecl()->getDeclName());
   Code = serialization::EXPR_DECL_REF;
@@ -1011,6 +1016,10 @@ void ASTStmtWriter::VisitMemberExpr(MemberExpr *E) {
   CurrentPackingBits.addBit(E->hadMultipleCandidates());
   CurrentPackingBits.addBits(E->isNonOdrUse(), /*Width=*/2);
   Record.AddSourceLocation(E->getOperatorLoc());
+  if (E->Deduced)
+    Record.AddTemplateArgumentList(E->Deduced);
+  else
+    Record.push_back(0);
 
   if (HasQualifier)
     Record.AddNestedNameSpecifierLoc(E->getQualifierLoc());



More information about the llvm-branch-commits mailing list