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

Matheus Izvekov via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Fri Mar 21 11:28:54 PDT 2025


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

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.

>From 53a3db55936c22bd73b6d3c10bf31001efafeefd 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 c966d70b66f25..8e4f1fb645ff5 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 26db3567c86d2..cf12e1ba4ac94 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -8707,7 +8707,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
@@ -8756,7 +8757,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);
 
@@ -14008,6 +14009,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 d7604484792dc..39c74b93c4289 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -8459,6 +8459,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);
 
@@ -8480,7 +8481,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 25dea4e230797..2d2b297466f38 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -1850,7 +1850,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 14a20138dfda7..bf5e38452c305 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -19513,7 +19513,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())
@@ -19530,7 +19531,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);
   }
 
@@ -19875,17 +19876,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 2e83ed58474db..d21fdc6d3c5f5 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 47fe68e77b2af..0844b9b2f2206 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -935,6 +935,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 e30c8faceaccf..9820194ee068f 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -9627,7 +9627,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 88223fb0bf449..82883b479c97f 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) {
@@ -3297,9 +3302,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 5d57ea8758ad5..a56738ce470ba 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