[llvm-branch-commits] [clang] [clang] resugar decltype of MemberExpr (PR #132448)

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


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

>From ad1ef07c4034404dadd7d8798c55af053f1dcd05 Mon Sep 17 00:00:00 2001
From: Matheus Izvekov <mizvekov at gmail.com>
Date: Sun, 16 Mar 2025 13:44:04 -0300
Subject: [PATCH] [clang] resugar decltype of MemberExpr

This keeps around the resugared DeclType for MemberExpr,
which is otherwise partially lost as the expression type
removes top level references.

This helps 'decltype' resugaring work without any loss
of information.
---
 clang/include/clang/AST/Expr.h            | 33 ++++++++++++---
 clang/include/clang/AST/Stmt.h            |  4 ++
 clang/include/clang/Sema/Sema.h           |  6 ++-
 clang/lib/AST/ASTImporter.cpp             |  3 +-
 clang/lib/AST/Expr.cpp                    | 50 ++++++++++++++++++-----
 clang/lib/Analysis/BodyFarm.cpp           |  2 +-
 clang/lib/CodeGen/CGExpr.cpp              |  2 +-
 clang/lib/Sema/SemaExpr.cpp               | 19 +++------
 clang/lib/Sema/SemaExprMember.cpp         | 25 +++++++-----
 clang/lib/Sema/SemaOverload.cpp           |  9 ++--
 clang/lib/Sema/SemaTemplate.cpp           | 11 +++++
 clang/lib/Sema/SemaType.cpp               |  2 +-
 clang/lib/Serialization/ASTReaderStmt.cpp |  9 +++-
 clang/lib/Serialization/ASTWriterStmt.cpp |  4 ++
 clang/test/Sema/Resugar/resugar-expr.cpp  |  3 +-
 15 files changed, 129 insertions(+), 53 deletions(-)

diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index e92f6696027f9..53afd206073ab 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -3263,7 +3263,7 @@ class MemberExpr final
     : public Expr,
       private llvm::TrailingObjects<MemberExpr, NestedNameSpecifierLoc,
                                     DeclAccessPair, ASTTemplateKWAndArgsInfo,
-                                    TemplateArgumentLoc> {
+                                    TemplateArgumentLoc, QualType> {
   friend class ASTReader;
   friend class ASTStmtReader;
   friend class ASTStmtWriter;
@@ -3304,13 +3304,23 @@ class MemberExpr final
     return MemberExprBits.HasTemplateKWAndArgsInfo;
   }
 
+  size_t numTrailingObjects(OverloadToken<TemplateArgumentLoc>) const {
+    return getNumTemplateArgs();
+  }
+
+  size_t numTrailingObjects(OverloadToken<QualType>) const {
+    return HasResugaredDeclType();
+  }
+
+  static bool needsDeclTypeStorage(ValueDecl *VD, QualType DeclType);
+
   MemberExpr(Expr *Base, bool IsArrow, SourceLocation OperatorLoc,
              NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc,
              ValueDecl *MemberDecl, DeclAccessPair FoundDecl,
              const DeclarationNameInfo &NameInfo,
              const TemplateArgumentListInfo *TemplateArgs,
              const TemplateArgumentList *Deduced, QualType T, ExprValueKind VK,
-             ExprObjectKind OK, NonOdrUseReason NOUR);
+             QualType DeclType, ExprObjectKind OK, NonOdrUseReason NOUR);
   MemberExpr(EmptyShell Empty)
       : Expr(MemberExprClass, Empty), Base(), MemberDecl() {}
 
@@ -3322,7 +3332,7 @@ class MemberExpr final
          DeclAccessPair FoundDecl, DeclarationNameInfo MemberNameInfo,
          const TemplateArgumentListInfo *TemplateArgs,
          const TemplateArgumentList *Deduced, QualType T, ExprValueKind VK,
-         ExprObjectKind OK, NonOdrUseReason NOUR);
+         QualType DeclType, ExprObjectKind OK, NonOdrUseReason NOUR);
 
   /// Create an implicit MemberExpr, with no location, qualifier, template
   /// arguments, and so on. Suitable only for non-static member access.
@@ -3333,14 +3343,15 @@ class MemberExpr final
     return Create(C, Base, IsArrow, SourceLocation(), NestedNameSpecifierLoc(),
                   SourceLocation(), MemberDecl,
                   DeclAccessPair::make(MemberDecl, MemberDecl->getAccess()),
-                  DeclarationNameInfo(), nullptr, /*Deduced=*/{}, T, VK, OK,
-                  NOUR_None);
+                  DeclarationNameInfo(), nullptr, /*Deduced=*/{}, T, VK,
+                  QualType(), OK, NOUR_None);
   }
 
   static MemberExpr *CreateEmpty(const ASTContext &Context, bool HasQualifier,
                                  bool HasFoundDecl,
                                  bool HasTemplateKWAndArgsInfo,
-                                 unsigned NumTemplateArgs);
+                                 unsigned NumTemplateArgs,
+                                 bool HasResugaredDeclType);
 
   void setBase(Expr *E) { Base = E; }
   Expr *getBase() const { return cast<Expr>(Base); }
@@ -3351,6 +3362,16 @@ class MemberExpr final
   /// static data members), a CXXMethodDecl, or an EnumConstantDecl.
   ValueDecl *getMemberDecl() const { return MemberDecl; }
   void setMemberDecl(ValueDecl *D);
+  void recomputeDependency();
+
+  bool HasResugaredDeclType() const {
+    return MemberExprBits.HasResugaredDeclType;
+  }
+  QualType getDeclType() const {
+    return HasResugaredDeclType() ? *getTrailingObjects<QualType>()
+                                  : MemberDecl->getType();
+  }
+  void setDeclType(QualType T);
 
   /// Retrieves the declaration found by lookup.
   DeclAccessPair getFoundDecl() const {
diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h
index 805d301b95f8e..a64f8de074237 100644
--- a/clang/include/clang/AST/Stmt.h
+++ b/clang/include/clang/AST/Stmt.h
@@ -616,6 +616,10 @@ class alignas(void *) Stmt {
     LLVM_PREFERRED_TYPE(NonOdrUseReason)
     unsigned NonOdrUseReason : 2;
 
+    /// Consider a different type for the MemberDecl this MemberExpr refers to.
+    LLVM_PREFERRED_TYPE(bool)
+    unsigned HasResugaredDeclType : 1;
+
     /// This is the location of the -> or . in the expression.
     SourceLocation OperatorLoc;
   };
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index c476c80f5237d..101062ce778c7 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -8709,7 +8709,8 @@ class Sema final : public SemaBase {
       NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc,
       ValueDecl *Member, DeclAccessPair FoundDecl, bool HadMultipleCandidates,
       const DeclarationNameInfo &MemberNameInfo, QualType Ty, ExprValueKind VK,
-      ExprObjectKind OK, const TemplateArgumentListInfo *TemplateArgs = nullptr,
+      ExprObjectKind OK, QualType DeclType = QualType(),
+      const TemplateArgumentListInfo *TemplateArgs = nullptr,
       const TemplateArgumentList *Deduced = nullptr);
 
   // Check whether the declarations we found through a nested-name
@@ -8758,7 +8759,7 @@ class Sema final : public SemaBase {
   ExprResult BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow,
                                      SourceLocation OpLoc,
                                      const NestedNameSpecifierLoc &NNS,
-                                     FieldDecl *Field, QualType FieldType,
+                                     FieldDecl *Field, QualType FieldDeclType,
                                      DeclAccessPair FoundDecl,
                                      const DeclarationNameInfo &MemberNameInfo);
 
@@ -14013,6 +14014,7 @@ class Sema final : public SemaBase {
   QualType resugar(const Type *Base, NamedDecl *ND,
                    ArrayRef<TemplateArgument> Args, QualType T);
   QualType resugar(DeclRefExpr *DRE, ValueDecl *VD);
+  QualType resugar(MemberExpr *ME, ValueDecl *VD);
 
   /// Performs template instantiation for all implicit template
   /// instantiations we have seen until this point.
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 876e6cd26ff7b..a5fb4f286d1cf 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -8452,6 +8452,7 @@ ExpectedStmt ASTNodeImporter::VisitMemberExpr(MemberExpr *E) {
   auto ToDecl = importChecked(Err, E->getFoundDecl().getDecl());
   auto ToName = importChecked(Err, E->getMemberNameInfo().getName());
   auto ToLoc = importChecked(Err, E->getMemberNameInfo().getLoc());
+  auto ToDeclType = importChecked(Err, E->getDeclType());
   if (Err)
     return std::move(Err);
 
@@ -8473,7 +8474,7 @@ ExpectedStmt ASTNodeImporter::VisitMemberExpr(MemberExpr *E) {
                             ToOperatorLoc, ToQualifierLoc, ToTemplateKeywordLoc,
                             ToMemberDecl, ToFoundDecl, ToMemberNameInfo,
                             ResInfo, ToDeduced, ToType, E->getValueKind(),
-                            E->getObjectKind(), E->isNonOdrUse());
+                            ToDeclType, E->getObjectKind(), E->isNonOdrUse());
 }
 
 ExpectedStmt
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 80f22a4eab99c..82e54839547b7 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -1761,6 +1761,11 @@ UnaryExprOrTypeTraitExpr::UnaryExprOrTypeTraitExpr(
   setDependence(computeDependence(this));
 }
 
+bool MemberExpr::needsDeclTypeStorage(ValueDecl *VD, QualType DeclType) {
+  return !DeclType.isNull() &&
+         (DeclType != VD->getType() || VD->getType()->isUndeducedType());
+}
+
 MemberExpr::MemberExpr(Expr *Base, bool IsArrow, SourceLocation OperatorLoc,
                        NestedNameSpecifierLoc QualifierLoc,
                        SourceLocation TemplateKWLoc, ValueDecl *MemberDecl,
@@ -1768,7 +1773,7 @@ MemberExpr::MemberExpr(Expr *Base, bool IsArrow, SourceLocation OperatorLoc,
                        const DeclarationNameInfo &NameInfo,
                        const TemplateArgumentListInfo *TemplateArgs,
                        const TemplateArgumentList *Deduced, QualType T,
-                       ExprValueKind VK, ExprObjectKind OK,
+                       ExprValueKind VK, QualType DeclType, ExprObjectKind OK,
                        NonOdrUseReason NOUR)
     : Expr(MemberExprClass, T, VK, OK), Base(Base), MemberDecl(MemberDecl),
       Deduced(Deduced), MemberDNLoc(NameInfo.getInfo()),
@@ -1784,6 +1789,8 @@ MemberExpr::MemberExpr(Expr *Base, bool IsArrow, SourceLocation OperatorLoc,
       TemplateArgs || TemplateKWLoc.isValid();
   MemberExprBits.HadMultipleCandidates = false;
   MemberExprBits.NonOdrUseReason = NOUR;
+  MemberExprBits.HasResugaredDeclType =
+      needsDeclTypeStorage(MemberDecl, DeclType);
   MemberExprBits.OperatorLoc = OperatorLoc;
 
   if (hasQualifier())
@@ -1800,6 +1807,12 @@ MemberExpr::MemberExpr(Expr *Base, bool IsArrow, SourceLocation OperatorLoc,
     getTrailingObjects<ASTTemplateKWAndArgsInfo>()->initializeFrom(
         TemplateKWLoc);
   }
+  if (HasResugaredDeclType()) {
+    assert(DeclType.getCanonicalType() ==
+           MemberDecl->getType().getCanonicalType());
+    *getTrailingObjects<QualType>() =
+        DeclType.isNull() ? MemberDecl->getType() : DeclType;
+  }
   setDependence(computeDependence(this));
 }
 
@@ -1809,45 +1822,60 @@ MemberExpr *MemberExpr::Create(
     ValueDecl *MemberDecl, DeclAccessPair FoundDecl,
     DeclarationNameInfo NameInfo, const TemplateArgumentListInfo *TemplateArgs,
     const TemplateArgumentList *Deduced, QualType T, ExprValueKind VK,
-    ExprObjectKind OK, NonOdrUseReason NOUR) {
+    QualType DeclType, ExprObjectKind OK, NonOdrUseReason NOUR) {
   bool HasQualifier = QualifierLoc.hasQualifier();
   bool HasFoundDecl = FoundDecl.getDecl() != MemberDecl ||
                       FoundDecl.getAccess() != MemberDecl->getAccess();
   bool HasTemplateKWAndArgsInfo = TemplateArgs || TemplateKWLoc.isValid();
   std::size_t Size =
       totalSizeToAlloc<NestedNameSpecifierLoc, DeclAccessPair,
-                       ASTTemplateKWAndArgsInfo, TemplateArgumentLoc>(
+                       ASTTemplateKWAndArgsInfo, TemplateArgumentLoc, QualType>(
           HasQualifier, HasFoundDecl, HasTemplateKWAndArgsInfo,
-          TemplateArgs ? TemplateArgs->size() : 0);
+          TemplateArgs ? TemplateArgs->size() : 0,
+          needsDeclTypeStorage(MemberDecl, DeclType) ? 1 : 0);
 
   void *Mem = C.Allocate(Size, alignof(MemberExpr));
   return new (Mem) MemberExpr(Base, IsArrow, OperatorLoc, QualifierLoc,
                               TemplateKWLoc, MemberDecl, FoundDecl, NameInfo,
-                              TemplateArgs, Deduced, T, VK, OK, NOUR);
+                              TemplateArgs, Deduced, T, VK, DeclType, OK, NOUR);
 }
 
 MemberExpr *MemberExpr::CreateEmpty(const ASTContext &Context,
                                     bool HasQualifier, bool HasFoundDecl,
                                     bool HasTemplateKWAndArgsInfo,
-                                    unsigned NumTemplateArgs) {
+                                    unsigned NumTemplateArgs,
+                                    bool HasResugaredDeclType) {
   assert((!NumTemplateArgs || HasTemplateKWAndArgsInfo) &&
          "template args but no template arg info?");
   std::size_t Size =
       totalSizeToAlloc<NestedNameSpecifierLoc, DeclAccessPair,
-                       ASTTemplateKWAndArgsInfo, TemplateArgumentLoc>(
-          HasQualifier, HasFoundDecl, HasTemplateKWAndArgsInfo,
-          NumTemplateArgs);
+                       ASTTemplateKWAndArgsInfo, TemplateArgumentLoc, QualType>(
+          HasQualifier, HasFoundDecl, HasTemplateKWAndArgsInfo, NumTemplateArgs,
+          HasResugaredDeclType);
   void *Mem = Context.Allocate(Size, alignof(MemberExpr));
   return new (Mem) MemberExpr(EmptyShell());
 }
 
 void MemberExpr::setMemberDecl(ValueDecl *NewD) {
+  assert(MemberDecl != NewD);
+  assert(declaresSameEntity(MemberDecl, NewD));
+  assert(!HasResugaredDeclType() ||
+         MemberDecl->getASTContext().hasSameType(
+             NewD->getType(), *getTrailingObjects<QualType>()));
   MemberDecl = NewD;
-  if (getType()->isUndeducedType())
-    setType(NewD->getType());
+  recomputeDependency();
+}
+
+void MemberExpr::recomputeDependency() {
   setDependence(computeDependence(this));
 }
 
+void MemberExpr::setDeclType(QualType T) {
+  assert(!T.isNull());
+  if (HasResugaredDeclType())
+    *getTrailingObjects<QualType>() = T;
+}
+
 SourceLocation MemberExpr::getBeginLoc() const {
   if (isImplicitAccess()) {
     if (hasQualifier())
diff --git a/clang/lib/Analysis/BodyFarm.cpp b/clang/lib/Analysis/BodyFarm.cpp
index 058d8fa1328e3..9fdfe2946d7c1 100644
--- a/clang/lib/Analysis/BodyFarm.cpp
+++ b/clang/lib/Analysis/BodyFarm.cpp
@@ -232,7 +232,7 @@ MemberExpr *ASTMaker::makeMemberExpression(Expr *base, ValueDecl *MemberDecl,
       SourceLocation(), MemberDecl, FoundDecl,
       DeclarationNameInfo(MemberDecl->getDeclName(), SourceLocation()),
       /* TemplateArgumentListInfo=*/nullptr, /*Deduced=*/nullptr,
-      MemberDecl->getType(), ValueKind, OK_Ordinary, NOUR_None);
+      MemberDecl->getType(), ValueKind, QualType(), 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 6b9b6199e575b..f9be8fbc1444b 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -1867,7 +1867,7 @@ static DeclRefExpr *tryToConvertMemberExprToDeclRefExpr(CodeGenFunction &CGF,
     return DeclRefExpr::Create(
         CGF.getContext(), NestedNameSpecifierLoc(), SourceLocation(), VD,
         /*RefersToEnclosingVariableOrCapture=*/false, ME->getExprLoc(),
-        ME->getType(), ME->getValueKind(), QualType(), nullptr, nullptr,
+        ME->getType(), ME->getValueKind(), ME->getDeclType(), nullptr, nullptr,
         nullptr, ME->isNonOdrUse());
   }
   return nullptr;
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 18e5c77b55c49..62c852eb5b22e 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -19537,7 +19537,8 @@ static ExprResult rebuildPotentialResultsAsNonOdrUsed(Sema &S, Expr *E,
           ME->getQualifierLoc(), ME->getTemplateKeywordLoc(),
           ME->getMemberDecl(), ME->getFoundDecl(), ME->getMemberNameInfo(),
           CopiedTemplateArgs(ME), ME->getDeduced(), ME->getType(),
-          ME->getValueKind(), ME->getObjectKind(), ME->isNonOdrUse());
+          ME->getValueKind(), ME->getDeclType(), ME->getObjectKind(),
+          ME->isNonOdrUse());
     }
 
     if (ME->getMemberDecl()->isCXXInstanceMember())
@@ -19554,7 +19555,7 @@ 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->getDeduced(), ME->getType(), ME->getValueKind(),
+        ME->getDeduced(), ME->getType(), ME->getValueKind(), ME->getDeclType(),
         ME->getObjectKind(), NOUR);
   }
 
@@ -19905,17 +19906,9 @@ static void DoMarkVarDeclReferenced(
             DRE->setType(SemaRef.resugar(DRE, DRE->getDecl()));
           DRE->recomputeDependency();
         } else if (auto *ME = dyn_cast_or_null<MemberExpr>(E)) {
-          ME->setMemberDecl(ME->getMemberDecl());
-          CXXScopeSpec SS;
-          SS.Adopt(ME->getQualifierLoc());
-          assert(ME->template_arguments().size() == 0 ||
-                 ME->getDeduced() != nullptr);
-          QualType T =
-              ME->getDeduced()
-                  ? SemaRef.resugar(SS.getScopeRep(), ME->getMemberDecl(),
-                                    ME->getDeduced()->asArray(), ME->getType())
-                  : SemaRef.resugar(SS.getScopeRep(), ME->getType());
-          ME->setType(T);
+          if (ME->getType()->isUndeducedType())
+            ME->setType(SemaRef.resugar(ME, ME->getMemberDecl()));
+          ME->recomputeDependency();
         }
       } else if (FirstInstantiation) {
         SemaRef.PendingInstantiations
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index 72ae475548e23..427241f36b2b7 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -943,14 +943,14 @@ MemberExpr *Sema::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,
+    QualType Ty, ExprValueKind VK, ExprObjectKind OK, QualType DeclType,
     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, Deduced, Ty, VK, OK,
+      MemberNameInfo, TemplateArgs, Deduced, Ty, VK, DeclType, OK,
       getNonOdrUseReasonInCurrentContext(Member));
   E->setHadMultipleCandidates(HadMultipleCandidates);
   MarkMemberReferenced(E);
@@ -1204,13 +1204,15 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
     return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, NNS, TemplateKWLoc, Var,
                            FoundDecl, /*HadMultipleCandidates=*/false,
                            MemberNameInfo, VarType.getNonReferenceType(),
-                           VK_LValue, OK_Ordinary);
+                           VK_LValue, OK_Ordinary, VarType);
   }
 
   if (CXXMethodDecl *MemberFn = dyn_cast<CXXMethodDecl>(MemberDecl)) {
     assert(!TemplateArgs);
     NestedNameSpecifierLoc NNS = SS.getWithLocInContext(Context);
 
+    QualType DeclType =
+        resugar(BaseType.getTypePtr(), SS.getScopeRep(), MemberFn->getType());
     ExprValueKind valueKind;
     QualType type;
     if (MemberFn->isInstance()) {
@@ -1224,13 +1226,13 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
       if (ConvertBaseExprToDiscardedValue())
         return ExprError();
       valueKind = VK_LValue;
-      type =
-          resugar(BaseType.getTypePtr(), SS.getScopeRep(), MemberFn->getType());
+      type = DeclType;
     }
 
     return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, NNS, TemplateKWLoc,
                            MemberFn, FoundDecl, /*HadMultipleCandidates=*/false,
-                           MemberNameInfo, type, valueKind, OK_Ordinary);
+                           MemberNameInfo, type, valueKind, OK_Ordinary,
+                           DeclType);
   }
   assert(!isa<FunctionDecl>(MemberDecl) && "member function not C++ method?");
 
@@ -1244,7 +1246,8 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
         resugar(BaseType.getTypePtr(), SS.getScopeRep(), Enum->getType());
     return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, NNS, TemplateKWLoc, Enum,
                            FoundDecl, /*HadMultipleCandidates=*/false,
-                           MemberNameInfo, EnumType, VK_PRValue, OK_Ordinary);
+                           MemberNameInfo, EnumType, VK_PRValue, OK_Ordinary,
+                           EnumType);
   }
 
   if (VarTemplateDecl *VarTempl = dyn_cast<VarTemplateDecl>(MemberDecl)) {
@@ -1279,7 +1282,8 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
     return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, NNS, TemplateKWLoc, Var,
                            FoundDecl, /*HadMultipleCandidates=*/false,
                            MemberNameInfo, VarType.getNonReferenceType(),
-                           VK_LValue, OK_Ordinary, TemplateArgs, ConvertedArgs);
+                           VK_LValue, OK_Ordinary, VarType, TemplateArgs,
+                           ConvertedArgs);
   }
 
   // We found something that we didn't expect. Complain.
@@ -1893,12 +1897,13 @@ void Sema::CheckMemberAccessOfNoDeref(const MemberExpr *E) {
 
 ExprResult Sema::BuildFieldReferenceExpr(
     Expr *BaseExpr, bool IsArrow, SourceLocation OpLoc,
-    const NestedNameSpecifierLoc &NNS, FieldDecl *Field, QualType FieldType,
+    const NestedNameSpecifierLoc &NNS, FieldDecl *Field, QualType FieldDeclType,
     DeclAccessPair FoundDecl, const DeclarationNameInfo &MemberNameInfo) {
   // x.a is an l-value if 'a' has a reference type. Otherwise:
   // x.a is an l-value/x-value/pr-value if the base is (and note
   //   that *x is always an l-value), except that if the base isn't
   //   an ordinary object then we must have an rvalue.
+  QualType FieldType = FieldDeclType;
   ExprValueKind VK = VK_LValue;
   ExprObjectKind OK = OK_Ordinary;
   if (!IsArrow) {
@@ -1975,7 +1980,7 @@ ExprResult Sema::BuildFieldReferenceExpr(
   return BuildMemberExpr(Base.get(), IsArrow, OpLoc, NNS,
                          /*TemplateKWLoc=*/SourceLocation(), Field, FoundDecl,
                          /*HadMultipleCandidates=*/false, MemberNameInfo,
-                         FieldType, VK, OK);
+                         FieldType, VK, OK, FieldDeclType);
 }
 
 ExprResult
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 934e0d05b4948..f5b582ec42cb6 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -16645,13 +16645,14 @@ Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
     } else
       Base = MemExpr->getBase();
 
+    QualType DeclType = Deduced ? resugar(BasePointeeType, Fn,
+                                          Deduced->asArray(), Fn->getType())
+                                : resugar(BasePointeeType, Fn->getType());
     ExprValueKind valueKind;
     QualType Type;
     if (cast<CXXMethodDecl>(Fn)->isStatic()) {
       valueKind = VK_LValue;
-      Type = Deduced ? resugar(BasePointeeType, Fn, Deduced->asArray(),
-                               Fn->getType())
-                     : resugar(BasePointeeType, Fn->getType());
+      Type = DeclType;
     } else {
       valueKind = VK_PRValue;
       Type = Context.BoundMemberTy;
@@ -16661,7 +16662,7 @@ Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
         Base, MemExpr->isArrow(), MemExpr->getOperatorLoc(),
         MemExpr->getQualifierLoc(), MemExpr->getTemplateKeywordLoc(), Fn, Found,
         /*HadMultipleCandidates=*/true, MemExpr->getMemberNameInfo(), Type,
-        valueKind, OK_Ordinary, TemplateArgs, Deduced);
+        valueKind, OK_Ordinary, DeclType, TemplateArgs, Deduced);
   }
 
   llvm_unreachable("Invalid reference to overloaded function");
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index ec4d3a30bbb01..8c0f1b3a2d871 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -948,6 +948,17 @@ QualType Sema::resugar(DeclRefExpr *DRE, ValueDecl *VD) {
   DRE->setDeclType(NewT);
   return NewT;
 }
+QualType Sema::resugar(MemberExpr *ME, ValueDecl *VD) {
+  assert(ME->template_arguments().size() == 0 || ME->getDeduced() != nullptr);
+  const NestedNameSpecifier *NNS =
+      ME->getQualifierLoc().getNestedNameSpecifier();
+  QualType T = VD->getType();
+  QualType NewT = ME->getDeduced()
+                      ? SemaRef.resugar(NNS, VD, ME->getDeduced()->asArray(), T)
+                      : SemaRef.resugar(NNS, T);
+  ME->setDeclType(NewT);
+  return NewT;
+}
 
 /// \brief Determine whether the declaration found is acceptable as the name
 /// of a template and, if so, return that template declaration. Otherwise,
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index c94d706a829c4..fafe1cc093a06 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -9622,7 +9622,7 @@ QualType Sema::getDecltypeForExpr(Expr *E) {
   if (const auto *ME = dyn_cast<MemberExpr>(IDExpr)) {
     if (const auto *VD = ME->getMemberDecl())
       if (isa<FieldDecl>(VD) || isa<VarDecl>(VD))
-        return VD->getType();
+        return ME->getDeclType();
   } else if (const auto *IR = dyn_cast<ObjCIvarRefExpr>(IDExpr)) {
     return IR->getDecl()->getType();
   } else if (const auto *PR = dyn_cast<ObjCPropertyRefExpr>(IDExpr)) {
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index 57f47bd75a745..ec7ea584c03ef 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -1064,6 +1064,7 @@ void ASTStmtReader::VisitMemberExpr(MemberExpr *E) {
   bool HasQualifier = CurrentUnpackingBits->getNextBit();
   bool HasFoundDecl = CurrentUnpackingBits->getNextBit();
   bool HasTemplateInfo = CurrentUnpackingBits->getNextBit();
+  bool HasResugaredDeclType = CurrentUnpackingBits->getNextBit();
   unsigned NumTemplateArgs = Record.readInt();
 
   E->Base = Record.readSubExpr();
@@ -1074,6 +1075,7 @@ void ASTStmtReader::VisitMemberExpr(MemberExpr *E) {
   E->MemberExprBits.HasQualifier = HasQualifier;
   E->MemberExprBits.HasFoundDecl = HasFoundDecl;
   E->MemberExprBits.HasTemplateKWAndArgsInfo = HasTemplateInfo;
+  E->MemberExprBits.HasResugaredDeclType = HasResugaredDeclType;
   E->MemberExprBits.HadMultipleCandidates = CurrentUnpackingBits->getNextBit();
   E->MemberExprBits.NonOdrUseReason =
       CurrentUnpackingBits->getNextBits(/*Width=*/2);
@@ -1094,6 +1096,9 @@ void ASTStmtReader::VisitMemberExpr(MemberExpr *E) {
     ReadTemplateKWAndArgsInfo(
         *E->getTrailingObjects<ASTTemplateKWAndArgsInfo>(),
         E->getTrailingObjects<TemplateArgumentLoc>(), NumTemplateArgs);
+
+  if (HasResugaredDeclType)
+    *E->getTrailingObjects<QualType>() = Record.readQualType();
 }
 
 void ASTStmtReader::VisitObjCIsaExpr(ObjCIsaExpr *E) {
@@ -3295,9 +3300,11 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
       bool HasQualifier = ExprMemberBits.getNextBit();
       bool HasFoundDecl = ExprMemberBits.getNextBit();
       bool HasTemplateInfo = ExprMemberBits.getNextBit();
+      bool HasResugaredDeclType = ExprMemberBits.getNextBit();
       unsigned NumTemplateArgs = Record[ASTStmtReader::NumExprFields + 1];
       S = MemberExpr::CreateEmpty(Context, HasQualifier, HasFoundDecl,
-                                  HasTemplateInfo, NumTemplateArgs);
+                                  HasTemplateInfo, NumTemplateArgs,
+                                  HasResugaredDeclType);
       break;
     }
 
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
index 82ed11d0f0607..561db39252816 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -1009,6 +1009,7 @@ void ASTStmtWriter::VisitMemberExpr(MemberExpr *E) {
   CurrentPackingBits.addBit(HasQualifier);
   CurrentPackingBits.addBit(HasFoundDecl);
   CurrentPackingBits.addBit(HasTemplateInfo);
+  CurrentPackingBits.addBit(E->HasResugaredDeclType());
   Record.push_back(NumTemplateArgs);
 
   Record.AddStmt(E->getBase());
@@ -1038,6 +1039,9 @@ void ASTStmtWriter::VisitMemberExpr(MemberExpr *E) {
     AddTemplateKWAndArgsInfo(*E->getTrailingObjects<ASTTemplateKWAndArgsInfo>(),
                              E->getTrailingObjects<TemplateArgumentLoc>());
 
+  if (E->HasResugaredDeclType())
+    Record.writeQualType(E->getDeclType());
+
   Code = serialization::EXPR_MEMBER;
 }
 
diff --git a/clang/test/Sema/Resugar/resugar-expr.cpp b/clang/test/Sema/Resugar/resugar-expr.cpp
index 4b6b82f1b9eaa..db250640a46e2 100644
--- a/clang/test/Sema/Resugar/resugar-expr.cpp
+++ b/clang/test/Sema/Resugar/resugar-expr.cpp
@@ -50,9 +50,8 @@ template <class A1> struct A {
   ();
 };
 
-// FIXME: resugar this
 Z x1 = decltype(A<Int>().a){}();
-// expected-error at -1 {{with an rvalue of type 'int'}}
+// expected-error at -1 {{with an rvalue of type 'Int' (aka 'int')}}
 } // namespace t5
 
 namespace t6 {



More information about the llvm-branch-commits mailing list