summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatheus Izvekov <mizvekov@gmail.com>2025-03-16 13:44:04 -0300
committerMatheus Izvekov <mizvekov@gmail.com>2025-04-03 14:58:05 -0300
commitad1ef07c4034404dadd7d8798c55af053f1dcd05 (patch)
tree53556f251648bcaf361a761a3a763be93c3ac192
parent0a363317b9ac02a6a6e2f70e805223bdb135fed3 (diff)
[clang] resugar decltype of MemberExprusers/mizvekov/clang/resugar-decltype-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.
-rw-r--r--clang/include/clang/AST/Expr.h33
-rw-r--r--clang/include/clang/AST/Stmt.h4
-rw-r--r--clang/include/clang/Sema/Sema.h6
-rw-r--r--clang/lib/AST/ASTImporter.cpp3
-rw-r--r--clang/lib/AST/Expr.cpp50
-rw-r--r--clang/lib/Analysis/BodyFarm.cpp2
-rw-r--r--clang/lib/CodeGen/CGExpr.cpp2
-rw-r--r--clang/lib/Sema/SemaExpr.cpp19
-rw-r--r--clang/lib/Sema/SemaExprMember.cpp25
-rw-r--r--clang/lib/Sema/SemaOverload.cpp9
-rw-r--r--clang/lib/Sema/SemaTemplate.cpp11
-rw-r--r--clang/lib/Sema/SemaType.cpp2
-rw-r--r--clang/lib/Serialization/ASTReaderStmt.cpp9
-rw-r--r--clang/lib/Serialization/ASTWriterStmt.cpp4
-rw-r--r--clang/test/Sema/Resugar/resugar-expr.cpp3
15 files changed, 129 insertions, 53 deletions
diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index e92f6696027f..53afd206073a 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 @@ public:
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 @@ public:
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 @@ public:
/// 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 805d301b95f8..a64f8de07423 100644
--- a/clang/include/clang/AST/Stmt.h
+++ b/clang/include/clang/AST/Stmt.h
@@ -616,6 +616,10 @@ protected:
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 c476c80f5237..101062ce778c 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -8709,7 +8709,8 @@ public:
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 @@ public:
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 @@ public:
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 876e6cd26ff7..a5fb4f286d1c 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 80f22a4eab99..82e54839547b 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 058d8fa1328e..9fdfe2946d7c 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 6b9b6199e575..f9be8fbc1444 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 18e5c77b55c4..62c852eb5b22 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 72ae475548e2..427241f36b2b 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 934e0d05b494..f5b582ec42cb 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 ec4d3a30bbb0..8c0f1b3a2d87 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 c94d706a829c..fafe1cc093a0 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 57f47bd75a74..ec7ea584c03e 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 82ed11d0f060..561db3925281 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 4b6b82f1b9ea..db250640a46e 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@-1 {{with an rvalue of type 'int'}}
+// expected-error@-1 {{with an rvalue of type 'Int' (aka 'int')}}
} // namespace t5
namespace t6 {