[clang] Reapply "[Clang][Sema] Use the correct lookup context when building overloaded 'operator->' in the current instantiation (#104458)" (PR #109422)
Krystian Stasiowski via cfe-commits
cfe-commits at lists.llvm.org
Tue Jan 21 09:59:30 PST 2025
https://github.com/sdkrystian updated https://github.com/llvm/llvm-project/pull/109422
>From 6edb1455c03c8d6453ff813dd1c797dbaefc6398 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Thu, 15 Aug 2024 11:27:34 -0400
Subject: [PATCH 1/9] Reapply "[Clang][Sema] Use the correct lookup context
when building overloaded 'operator->' in the current instantiation (#104458)"
---
clang/include/clang/Sema/Sema.h | 3 +--
clang/lib/Sema/SemaExprCXX.cpp | 25 ++++++++-----------
clang/lib/Sema/SemaOverload.cpp | 14 +++++++----
clang/lib/Sema/TreeTransform.h | 4 +--
.../temp.res/temp.dep/temp.dep.type/p4.cpp | 24 ++++++++++--------
5 files changed, 35 insertions(+), 35 deletions(-)
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index a41f16f6dc8c9b..a29b8cf0765a01 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -10608,8 +10608,7 @@ class Sema final : public SemaBase {
/// BuildOverloadedArrowExpr - Build a call to an overloaded @c operator->
/// (if one exists), where @c Base is an expression of class type and
/// @c Member is the name of the member we're trying to find.
- ExprResult BuildOverloadedArrowExpr(Scope *S, Expr *Base,
- SourceLocation OpLoc,
+ ExprResult BuildOverloadedArrowExpr(Expr *Base, SourceLocation OpLoc,
bool *NoArrowOperatorFound = nullptr);
ExprResult BuildCXXMemberCallExpr(Expr *Exp, NamedDecl *FoundDecl,
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 1e39d69e8b230f..c0aad3aa9a813b 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -7999,18 +7999,6 @@ ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base,
QualType BaseType = Base->getType();
MayBePseudoDestructor = false;
- if (BaseType->isDependentType()) {
- // If we have a pointer to a dependent type and are using the -> operator,
- // the object type is the type that the pointer points to. We might still
- // have enough information about that type to do something useful.
- if (OpKind == tok::arrow)
- if (const PointerType *Ptr = BaseType->getAs<PointerType>())
- BaseType = Ptr->getPointeeType();
-
- ObjectType = ParsedType::make(BaseType);
- MayBePseudoDestructor = true;
- return Base;
- }
// C++ [over.match.oper]p8:
// [...] When operator->returns, the operator-> is applied to the value
@@ -8025,7 +8013,7 @@ ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base,
SmallVector<FunctionDecl*, 8> OperatorArrows;
CTypes.insert(Context.getCanonicalType(BaseType));
- while (BaseType->isRecordType()) {
+ while (BaseType->getAsRecordDecl()) {
if (OperatorArrows.size() >= getLangOpts().ArrowDepth) {
Diag(OpLoc, diag::err_operator_arrow_depth_exceeded)
<< StartingType << getLangOpts().ArrowDepth << Base->getSourceRange();
@@ -8036,7 +8024,7 @@ ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base,
}
Result = BuildOverloadedArrowExpr(
- S, Base, OpLoc,
+ Base, OpLoc,
// When in a template specialization and on the first loop iteration,
// potentially give the default diagnostic (with the fixit in a
// separate note) instead of having the error reported back to here
@@ -8062,7 +8050,14 @@ ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base,
}
}
return ExprError();
+ } else if (Result.isUnset()) {
+ // BuildOverloadedArrowExpr returns an empty expression to indicate
+ // that we need to build a dependent overloaded arrow expression.
+ assert(BaseType->isDependentType());
+ BaseType = Context.DependentTy;
+ break;
}
+
Base = Result.get();
if (CXXOperatorCallExpr *OpCall = dyn_cast<CXXOperatorCallExpr>(Base))
OperatorArrows.push_back(OpCall->getDirectCallee());
@@ -8100,7 +8095,7 @@ ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base,
// it's legal for the type to be incomplete if this is a pseudo-destructor
// call. We'll do more incomplete-type checks later in the lookup process,
// so just skip this check for ObjC types.
- if (!BaseType->isRecordType()) {
+ if (!BaseType->getAsRecordDecl()) {
ObjectType = ParsedType::make(BaseType);
MayBePseudoDestructor = true;
return Base;
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 7e8811b5274efb..46dc823ed92262 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -15962,10 +15962,9 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
return CheckForImmediateInvocation(MaybeBindToTemporary(TheCall), Method);
}
-ExprResult
-Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
- bool *NoArrowOperatorFound) {
- assert(Base->getType()->isRecordType() &&
+ExprResult Sema::BuildOverloadedArrowExpr(Expr *Base, SourceLocation OpLoc,
+ bool *NoArrowOperatorFound) {
+ assert(Base->getType()->getAsRecordDecl() &&
"left-hand side must have class type");
if (checkPlaceholderForOverload(*this, Base))
@@ -15988,7 +15987,12 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
return ExprError();
LookupResult R(*this, OpName, OpLoc, LookupOrdinaryName);
- LookupQualifiedName(R, Base->getType()->castAs<RecordType>()->getDecl());
+ LookupParsedName(R, /*S=*/nullptr, /*SS=*/nullptr, Base->getType());
+
+ if (R.wasNotFoundInCurrentInstantiation() ||
+ (Base->isTypeDependent() && !R.empty()))
+ return ExprEmpty();
+
R.suppressAccessDiagnostics();
for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end();
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 7dc88a1ae23b98..d529a40eedceb6 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -17282,10 +17282,10 @@ ExprResult TreeTransform<Derived>::RebuildCXXOperatorCallExpr(
} else if (Op == OO_Arrow) {
// It is possible that the type refers to a RecoveryExpr created earlier
// in the tree transformation.
- if (First->getType()->isDependentType())
+ if (First->containsErrors())
return ExprError();
// -> is never a builtin operation.
- return SemaRef.BuildOverloadedArrowExpr(nullptr, First, OpLoc);
+ return SemaRef.BuildOverloadedArrowExpr(First, OpLoc);
} else if (Second == nullptr || isPostIncDec) {
if (!First->getType()->isOverloadableType() ||
(Op == OO_Amp && getSema().isQualifiedMemberAccess(First))) {
diff --git a/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp b/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp
index f32f49ef4539a5..89c22a0bc137d9 100644
--- a/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp
+++ b/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp
@@ -484,16 +484,19 @@ namespace N4 {
template<typename T>
struct A {
void not_instantiated(A a, A<T> b, T c) {
- a->x;
- b->x;
+ a->x; // expected-error {{member reference type 'A<T>' is not a pointer; did you mean to use '.'?}}
+ b->x; // expected-error {{member reference type 'A<T>' is not a pointer; did you mean to use '.'?}}
c->x;
}
void instantiated(A a, A<T> b, T c) {
- a->x; // expected-error {{member reference type 'A<int>' is not a pointer; did you mean to use '.'?}}
- // expected-error at -1 {{no member named 'x' in 'N4::A<int>'}}
- b->x; // expected-error {{member reference type 'A<int>' is not a pointer; did you mean to use '.'?}}
- // expected-error at -1 {{no member named 'x' in 'N4::A<int>'}}
+ // FIXME: We should only emit a single diagnostic suggesting to use '.'!
+ a->x; // expected-error {{member reference type 'A<T>' is not a pointer; did you mean to use '.'?}}
+ // expected-error at -1 {{member reference type 'A<int>' is not a pointer; did you mean to use '.'?}}
+ // expected-error at -2 {{no member named 'x' in 'N4::A<int>'}}
+ b->x; // expected-error {{member reference type 'A<T>' is not a pointer; did you mean to use '.'?}}
+ // expected-error at -1 {{member reference type 'A<int>' is not a pointer; did you mean to use '.'?}}
+ // expected-error at -2 {{no member named 'x' in 'N4::A<int>'}}
c->x; // expected-error {{member reference type 'int' is not a pointer}}
}
};
@@ -540,11 +543,10 @@ namespace N4 {
a->T::f();
a->T::g();
- // FIXME: 'U' should be a dependent name, and its lookup context should be 'a.operator->()'!
- a->U::x; // expected-error {{use of undeclared identifier 'U'}}
- a->U::y; // expected-error {{use of undeclared identifier 'U'}}
- a->U::f(); // expected-error {{use of undeclared identifier 'U'}}
- a->U::g(); // expected-error {{use of undeclared identifier 'U'}}
+ a->U::x;
+ a->U::y;
+ a->U::f();
+ a->U::g();
}
void instantiated(D a) {
>From a4ad2b900f3669db43fc509111cf279f9c5971b8 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Thu, 15 Aug 2024 13:24:27 -0400
Subject: [PATCH 2/9] [FOLD] fix destructor lookup when the object expression
is dependent
---
clang/lib/Sema/SemaExprCXX.cpp | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index c0aad3aa9a813b..605d98c419f988 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -8113,6 +8113,10 @@ ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base,
return CreateRecoveryExpr(Base->getBeginLoc(), Base->getEndLoc(), {Base});
}
+ // We can't implicitly declare the destructor for a templated class.
+ if (BaseType->isDependentType())
+ MayBePseudoDestructor = true;
+
// C++ [basic.lookup.classref]p2:
// If the id-expression in a class member access (5.2.5) is an
// unqualified-id, and the type of the object expression is of a class
>From 0380314895076a8faae98518e92fd2152ddf294e Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Tue, 3 Sep 2024 12:17:39 -0400
Subject: [PATCH 3/9] [FOLD] use IsDependent output parameter
---
clang/include/clang/Sema/Sema.h | 3 ++-
clang/lib/Sema/SemaExprCXX.cpp | 19 ++++++++++++-------
clang/lib/Sema/SemaOverload.cpp | 16 +++++++++++++---
clang/lib/Sema/TreeTransform.h | 6 +++++-
4 files changed, 32 insertions(+), 12 deletions(-)
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index a29b8cf0765a01..1601acd1b06a13 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -10609,7 +10609,8 @@ class Sema final : public SemaBase {
/// (if one exists), where @c Base is an expression of class type and
/// @c Member is the name of the member we're trying to find.
ExprResult BuildOverloadedArrowExpr(Expr *Base, SourceLocation OpLoc,
- bool *NoArrowOperatorFound = nullptr);
+ bool *NoArrowOperatorFound,
+ bool &IsDependent);
ExprResult BuildCXXMemberCallExpr(Expr *Exp, NamedDecl *FoundDecl,
CXXConversionDecl *Method,
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 605d98c419f988..b8e66aba51f39d 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -8023,6 +8023,7 @@ ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base,
return ExprError();
}
+ bool IsDependent;
Result = BuildOverloadedArrowExpr(
Base, OpLoc,
// When in a template specialization and on the first loop iteration,
@@ -8031,7 +8032,17 @@ ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base,
// and giving a diagnostic with a fixit attached to the error itself.
(FirstIteration && CurFD && CurFD->isFunctionTemplateSpecialization())
? nullptr
- : &NoArrowOperatorFound);
+ : &NoArrowOperatorFound,
+ IsDependent);
+
+ if (IsDependent) {
+ // BuildOverloadedArrowExpr sets IsDependent to indicate that we need
+ // to build a dependent overloaded arrow expression.
+ assert(BaseType->isDependentType());
+ BaseType = Context.DependentTy;
+ break;
+ }
+
if (Result.isInvalid()) {
if (NoArrowOperatorFound) {
if (FirstIteration) {
@@ -8050,12 +8061,6 @@ ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base,
}
}
return ExprError();
- } else if (Result.isUnset()) {
- // BuildOverloadedArrowExpr returns an empty expression to indicate
- // that we need to build a dependent overloaded arrow expression.
- assert(BaseType->isDependentType());
- BaseType = Context.DependentTy;
- break;
}
Base = Result.get();
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 46dc823ed92262..69f41ec4585743 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -15963,10 +15963,13 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
}
ExprResult Sema::BuildOverloadedArrowExpr(Expr *Base, SourceLocation OpLoc,
- bool *NoArrowOperatorFound) {
+ bool *NoArrowOperatorFound,
+ bool &IsDependent) {
assert(Base->getType()->getAsRecordDecl() &&
"left-hand side must have class type");
+ IsDependent = false;
+
if (checkPlaceholderForOverload(*this, Base))
return ExprError();
@@ -15989,9 +15992,16 @@ ExprResult Sema::BuildOverloadedArrowExpr(Expr *Base, SourceLocation OpLoc,
LookupResult R(*this, OpName, OpLoc, LookupOrdinaryName);
LookupParsedName(R, /*S=*/nullptr, /*SS=*/nullptr, Base->getType());
+ // If the expression is dependent and we either:
+ // - Found a member of the current instantiation named 'operator->', or
+ // - Found nothing, and the lookup context has no dependent base classes
+ //
+ // Then we should build a dependent class member access expression.
if (R.wasNotFoundInCurrentInstantiation() ||
- (Base->isTypeDependent() && !R.empty()))
- return ExprEmpty();
+ (Base->isTypeDependent() && !R.empty())) {
+ IsDependent = true;
+ return Base;
+ }
R.suppressAccessDiagnostics();
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index d529a40eedceb6..5d4aece9524e94 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -17284,8 +17284,12 @@ ExprResult TreeTransform<Derived>::RebuildCXXOperatorCallExpr(
// in the tree transformation.
if (First->containsErrors())
return ExprError();
+ bool IsDependent;
// -> is never a builtin operation.
- return SemaRef.BuildOverloadedArrowExpr(First, OpLoc);
+ ExprResult Result = SemaRef.BuildOverloadedArrowExpr(
+ First, OpLoc, /*NoArrowOperatorFound=*/nullptr, IsDependent);
+ assert(!IsDependent);
+ return Result;
} else if (Second == nullptr || isPostIncDec) {
if (!First->getType()->isOverloadableType() ||
(Op == OO_Amp && getSema().isQualifiedMemberAccess(First))) {
>From 772a6c0c77446cb0e2e19e8049df2dafd05be793 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Wed, 4 Sep 2024 09:43:22 -0400
Subject: [PATCH 4/9] [FOLD] don't use getAsRecordDecl
---
clang/lib/Sema/SemaExprCXX.cpp | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index b8e66aba51f39d..f7721fb0b41f27 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -8013,7 +8013,8 @@ ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base,
SmallVector<FunctionDecl*, 8> OperatorArrows;
CTypes.insert(Context.getCanonicalType(BaseType));
- while (BaseType->getAsRecordDecl()) {
+ while (
+ isa<InjectedClassNameType, RecordType>(BaseType.getCanonicalType())) {
if (OperatorArrows.size() >= getLangOpts().ArrowDepth) {
Diag(OpLoc, diag::err_operator_arrow_depth_exceeded)
<< StartingType << getLangOpts().ArrowDepth << Base->getSourceRange();
@@ -8100,7 +8101,7 @@ ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base,
// it's legal for the type to be incomplete if this is a pseudo-destructor
// call. We'll do more incomplete-type checks later in the lookup process,
// so just skip this check for ObjC types.
- if (!BaseType->getAsRecordDecl()) {
+ if (!isa<InjectedClassNameType, RecordType>(BaseType.getCanonicalType())) {
ObjectType = ParsedType::make(BaseType);
MayBePseudoDestructor = true;
return Base;
>From 51a3384b5a0e8c152666b8635200b05332202b4d Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Mon, 9 Sep 2024 11:35:18 -0400
Subject: [PATCH 5/9] [FOLD] fix capitalization
---
clang/lib/Sema/SemaOverload.cpp | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 69f41ec4585743..6f43e747c41c8d 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -15993,10 +15993,10 @@ ExprResult Sema::BuildOverloadedArrowExpr(Expr *Base, SourceLocation OpLoc,
LookupParsedName(R, /*S=*/nullptr, /*SS=*/nullptr, Base->getType());
// If the expression is dependent and we either:
- // - Found a member of the current instantiation named 'operator->', or
- // - Found nothing, and the lookup context has no dependent base classes
+ // - found a member of the current instantiation named 'operator->', or
+ // - found nothing, and the lookup context has no dependent base classes
//
- // Then we should build a dependent class member access expression.
+ // then we should build a dependent class member access expression.
if (R.wasNotFoundInCurrentInstantiation() ||
(Base->isTypeDependent() && !R.empty())) {
IsDependent = true;
>From e3326ab703ad159a4a69f453891206d716de540e Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Thu, 12 Sep 2024 09:42:05 -0400
Subject: [PATCH 6/9] [FOLD] fix dependent overloaded arrow
---
clang/lib/Sema/SemaExprCXX.cpp | 2 +-
clang/lib/Sema/SemaExprMember.cpp | 6 ++++--
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index f7721fb0b41f27..994202958816c4 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -8039,7 +8039,7 @@ ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base,
if (IsDependent) {
// BuildOverloadedArrowExpr sets IsDependent to indicate that we need
// to build a dependent overloaded arrow expression.
- assert(BaseType->isDependentType());
+ assert(Base->isTypeDependent());
BaseType = Context.DependentTy;
break;
}
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index d130e8b86bc56d..17bd30e4d4d5f7 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -581,7 +581,9 @@ Sema::ActOnDependentMemberExpr(Expr *BaseExpr, QualType BaseType,
}
}
- assert(BaseType->isDependentType() || NameInfo.getName().isDependentName() ||
+ assert(BaseType->isDependentType() ||
+ (BaseExpr && BaseExpr->isTypeDependent()) ||
+ NameInfo.getName().isDependentName() ||
isDependentScopeSpecifier(SS) ||
(TemplateArgs && llvm::any_of(TemplateArgs->arguments(),
[](const TemplateArgumentLoc &Arg) {
@@ -1357,7 +1359,7 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
BaseType = Ptr->getPointeeType();
else if (BaseType->isFunctionType())
goto fail;
- else if (BaseType->isDependentType())
+ else if (BaseExpr.get()->isTypeDependent())
BaseType = S.Context.DependentTy;
else if (BaseType->isRecordType()) {
// Recover from arrow accesses to records, e.g.:
>From 764a9a873a8076fc1329c06b290a37eef52f9eab Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Fri, 20 Sep 2024 09:25:23 -0400
Subject: [PATCH 7/9] [FOLD] cleanup
---
clang/lib/Sema/SemaExprCXX.cpp | 9 ++-------
1 file changed, 2 insertions(+), 7 deletions(-)
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 994202958816c4..ecbd3e410bc8f6 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -8101,7 +8101,7 @@ ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base,
// it's legal for the type to be incomplete if this is a pseudo-destructor
// call. We'll do more incomplete-type checks later in the lookup process,
// so just skip this check for ObjC types.
- if (!isa<InjectedClassNameType, RecordType>(BaseType.getCanonicalType())) {
+ if (BaseType->isDependentType() || !BaseType->isRecordType()) {
ObjectType = ParsedType::make(BaseType);
MayBePseudoDestructor = true;
return Base;
@@ -8112,17 +8112,12 @@ ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base,
// Unlike the object expression in other contexts, *this is not required to
// be of complete type for purposes of class member access (5.2.5) outside
// the member function body.
- if (!BaseType->isDependentType() &&
- !isThisOutsideMemberFunctionBody(BaseType) &&
+ if (!isThisOutsideMemberFunctionBody(BaseType) &&
RequireCompleteType(OpLoc, BaseType,
diag::err_incomplete_member_access)) {
return CreateRecoveryExpr(Base->getBeginLoc(), Base->getEndLoc(), {Base});
}
- // We can't implicitly declare the destructor for a templated class.
- if (BaseType->isDependentType())
- MayBePseudoDestructor = true;
-
// C++ [basic.lookup.classref]p2:
// If the id-expression in a class member access (5.2.5) is an
// unqualified-id, and the type of the object expression is of a class
>From 30297f7aefe0dba6a7b8718d9819ca07f5121190 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Fri, 20 Sep 2024 10:03:19 -0400
Subject: [PATCH 8/9] [FOLD] add test
---
.../temp.res/temp.dep/temp.dep.type/p4.cpp | 21 +++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp b/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp
index 89c22a0bc137d9..03eda1f13feed7 100644
--- a/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp
+++ b/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp
@@ -607,3 +607,24 @@ namespace N5 {
template void g(int); // expected-note {{in instantiation of}}
} // namespace N5
+
+namespace N6 {
+ struct A {
+ int x;
+ };
+
+ struct B {
+ A* operator->();
+ };
+
+ struct C {
+ B y;
+ };
+
+ template<typename T>
+ struct D : C {
+ void f() {
+ y->x;
+ }
+ };
+} // namespace N6
>From dead49d85b11e74c3dd6626eaa77b248b217df64 Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Tue, 21 Jan 2025 12:59:05 -0500
Subject: [PATCH 9/9] [FOLD] fix dependence check
---
clang/lib/Sema/SemaOverload.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 6f43e747c41c8d..40ab5086806f1e 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -15998,7 +15998,7 @@ ExprResult Sema::BuildOverloadedArrowExpr(Expr *Base, SourceLocation OpLoc,
//
// then we should build a dependent class member access expression.
if (R.wasNotFoundInCurrentInstantiation() ||
- (Base->isTypeDependent() && !R.empty())) {
+ (Base->getType()->isDependentType() && !R.empty())) {
IsDependent = true;
return Base;
}
More information about the cfe-commits
mailing list