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

Matheus Izvekov via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Wed Apr 2 18:53:36 PDT 2025


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

>From 022799a62f0c3018168db688ee234c9bda208d12 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 d4bc49b056252..339bed8c43ff7 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 474c23bb9495a..c8f3f880faa12 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 57bb5796c64a9..a5bbfbe3a765b 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 e9e154912619b..c5d44bd1a93cd 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -1864,7 +1864,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 e04a8f452f4c1..6510f7718d985 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -16642,13 +16642,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;
@@ -16658,7 +16659,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 b65612e0b5737..d6ffc9efb639f 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 f7410564b3661..e987c94875d9f 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -9617,7 +9617,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 81c3788686933..f18385c47223f 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 7a129ddb49579..575b14625e2e1 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