Skip to content

Commit 195a1fc

Browse files
authored
Reapply "[Clang][Sema] Use the correct lookup context when building overloaded 'operator->' in the current instantiation (#104458)" (#109422)
Reapplies #104458, fixing a bug that occurs when a class member access expression calls an `operator->` operator function that returns a non-dependent class type.
1 parent b40739a commit 195a1fc

File tree

6 files changed

+59
-39
lines changed

6 files changed

+59
-39
lines changed

clang/include/clang/Sema/Sema.h

+2-3
Original file line numberDiff line numberDiff line change
@@ -10608,9 +10608,8 @@ class Sema final : public SemaBase {
1060810608
/// BuildOverloadedArrowExpr - Build a call to an overloaded @c operator->
1060910609
/// (if one exists), where @c Base is an expression of class type and
1061010610
/// @c Member is the name of the member we're trying to find.
10611-
ExprResult BuildOverloadedArrowExpr(Scope *S, Expr *Base,
10612-
SourceLocation OpLoc,
10613-
bool *NoArrowOperatorFound = nullptr);
10611+
ExprResult BuildOverloadedArrowExpr(Expr *Base, SourceLocation OpLoc,
10612+
bool *NoArrowOperatorFound);
1061410613

1061510614
ExprResult BuildCXXMemberCallExpr(Expr *Exp, NamedDecl *FoundDecl,
1061610615
CXXConversionDecl *Method,

clang/lib/Sema/SemaExprCXX.cpp

+4-17
Original file line numberDiff line numberDiff line change
@@ -7999,18 +7999,6 @@ ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base,
79997999

80008000
QualType BaseType = Base->getType();
80018001
MayBePseudoDestructor = false;
8002-
if (BaseType->isDependentType()) {
8003-
// If we have a pointer to a dependent type and are using the -> operator,
8004-
// the object type is the type that the pointer points to. We might still
8005-
// have enough information about that type to do something useful.
8006-
if (OpKind == tok::arrow)
8007-
if (const PointerType *Ptr = BaseType->getAs<PointerType>())
8008-
BaseType = Ptr->getPointeeType();
8009-
8010-
ObjectType = ParsedType::make(BaseType);
8011-
MayBePseudoDestructor = true;
8012-
return Base;
8013-
}
80148002

80158003
// C++ [over.match.oper]p8:
80168004
// [...] When operator->returns, the operator-> is applied to the value
@@ -8025,7 +8013,7 @@ ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base,
80258013
SmallVector<FunctionDecl*, 8> OperatorArrows;
80268014
CTypes.insert(Context.getCanonicalType(BaseType));
80278015

8028-
while (BaseType->isRecordType()) {
8016+
while (BaseType->getAsRecordDecl()) {
80298017
if (OperatorArrows.size() >= getLangOpts().ArrowDepth) {
80308018
Diag(OpLoc, diag::err_operator_arrow_depth_exceeded)
80318019
<< StartingType << getLangOpts().ArrowDepth << Base->getSourceRange();
@@ -8036,7 +8024,7 @@ ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base,
80368024
}
80378025

80388026
Result = BuildOverloadedArrowExpr(
8039-
S, Base, OpLoc,
8027+
Base, OpLoc,
80408028
// When in a template specialization and on the first loop iteration,
80418029
// potentially give the default diagnostic (with the fixit in a
80428030
// separate note) instead of having the error reported back to here
@@ -8100,7 +8088,7 @@ ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base,
81008088
// it's legal for the type to be incomplete if this is a pseudo-destructor
81018089
// call. We'll do more incomplete-type checks later in the lookup process,
81028090
// so just skip this check for ObjC types.
8103-
if (!BaseType->isRecordType()) {
8091+
if (BaseType->isDependentType() || !BaseType->isRecordType()) {
81048092
ObjectType = ParsedType::make(BaseType);
81058093
MayBePseudoDestructor = true;
81068094
return Base;
@@ -8111,8 +8099,7 @@ ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base,
81118099
// Unlike the object expression in other contexts, *this is not required to
81128100
// be of complete type for purposes of class member access (5.2.5) outside
81138101
// the member function body.
8114-
if (!BaseType->isDependentType() &&
8115-
!isThisOutsideMemberFunctionBody(BaseType) &&
8102+
if (!isThisOutsideMemberFunctionBody(BaseType) &&
81168103
RequireCompleteType(OpLoc, BaseType,
81178104
diag::err_incomplete_member_access)) {
81188105
return CreateRecoveryExpr(Base->getBeginLoc(), Base->getEndLoc(), {Base});

clang/lib/Sema/SemaExprMember.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1357,7 +1357,7 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
13571357
BaseType = Ptr->getPointeeType();
13581358
else if (BaseType->isFunctionType())
13591359
goto fail;
1360-
else if (BaseType->isDependentType())
1360+
else if (BaseExpr.get()->isTypeDependent())
13611361
BaseType = S.Context.DependentTy;
13621362
else if (BaseType->isRecordType()) {
13631363
// Recover from arrow accesses to records, e.g.:

clang/lib/Sema/SemaOverload.cpp

+15-5
Original file line numberDiff line numberDiff line change
@@ -15962,10 +15962,9 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
1596215962
return CheckForImmediateInvocation(MaybeBindToTemporary(TheCall), Method);
1596315963
}
1596415964

15965-
ExprResult
15966-
Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
15967-
bool *NoArrowOperatorFound) {
15968-
assert(Base->getType()->isRecordType() &&
15965+
ExprResult Sema::BuildOverloadedArrowExpr(Expr *Base, SourceLocation OpLoc,
15966+
bool *NoArrowOperatorFound) {
15967+
assert(Base->getType()->getAsRecordDecl() &&
1596915968
"left-hand side must have class type");
1597015969

1597115970
if (checkPlaceholderForOverload(*this, Base))
@@ -15988,9 +15987,20 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
1598815987
return ExprError();
1598915988

1599015989
LookupResult R(*this, OpName, OpLoc, LookupOrdinaryName);
15991-
LookupQualifiedName(R, Base->getType()->castAs<RecordType>()->getDecl());
15990+
LookupParsedName(R, /*S=*/nullptr, /*SS=*/nullptr, Base->getType());
1599215991
R.suppressAccessDiagnostics();
1599315992

15993+
if (Base->getType()->isDependentType() &&
15994+
(!R.empty() || R.wasNotFoundInCurrentInstantiation())) {
15995+
DeclarationNameInfo OpNameInfo(OpName, OpLoc);
15996+
ExprResult Fn = CreateUnresolvedLookupExpr(
15997+
/*NamingClass=*/nullptr, /*NNSLoc=*/NestedNameSpecifierLoc(),
15998+
OpNameInfo, R.asUnresolvedSet(), /*PerformADL=*/false);
15999+
return CXXOperatorCallExpr::Create(Context, OO_Arrow, Fn.get(), Base,
16000+
Context.DependentTy, VK_PRValue, OpLoc,
16001+
CurFPFeatureOverrides());
16002+
}
16003+
1599416004
for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end();
1599516005
Oper != OperEnd; ++Oper) {
1599616006
AddMethodCandidate(Oper.getPair(), Base->getType(), Base->Classify(Context),

clang/lib/Sema/TreeTransform.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -17282,10 +17282,11 @@ ExprResult TreeTransform<Derived>::RebuildCXXOperatorCallExpr(
1728217282
} else if (Op == OO_Arrow) {
1728317283
// It is possible that the type refers to a RecoveryExpr created earlier
1728417284
// in the tree transformation.
17285-
if (First->getType()->isDependentType())
17285+
if (First->containsErrors())
1728617286
return ExprError();
1728717287
// -> is never a builtin operation.
17288-
return SemaRef.BuildOverloadedArrowExpr(nullptr, First, OpLoc);
17288+
return getSema().BuildOverloadedArrowExpr(First, OpLoc,
17289+
/*NoArrowOperatorFound=*/nullptr);
1728917290
} else if (Second == nullptr || isPostIncDec) {
1729017291
if (!First->getType()->isOverloadableType() ||
1729117292
(Op == OO_Amp && getSema().isQualifiedMemberAccess(First))) {

clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp

+34-11
Original file line numberDiff line numberDiff line change
@@ -484,16 +484,19 @@ namespace N4 {
484484
template<typename T>
485485
struct A {
486486
void not_instantiated(A a, A<T> b, T c) {
487-
a->x;
488-
b->x;
487+
a->x; // expected-error {{member reference type 'A<T>' is not a pointer; did you mean to use '.'?}}
488+
b->x; // expected-error {{member reference type 'A<T>' is not a pointer; did you mean to use '.'?}}
489489
c->x;
490490
}
491491

492492
void instantiated(A a, A<T> b, T c) {
493-
a->x; // expected-error {{member reference type 'A<int>' is not a pointer; did you mean to use '.'?}}
494-
// expected-error@-1 {{no member named 'x' in 'N4::A<int>'}}
495-
b->x; // expected-error {{member reference type 'A<int>' is not a pointer; did you mean to use '.'?}}
496-
// expected-error@-1 {{no member named 'x' in 'N4::A<int>'}}
493+
// FIXME: We should only emit a single diagnostic suggesting to use '.'!
494+
a->x; // expected-error {{member reference type 'A<T>' is not a pointer; did you mean to use '.'?}}
495+
// expected-error@-1 {{member reference type 'A<int>' is not a pointer; did you mean to use '.'?}}
496+
// expected-error@-2 {{no member named 'x' in 'N4::A<int>'}}
497+
b->x; // expected-error {{member reference type 'A<T>' is not a pointer; did you mean to use '.'?}}
498+
// expected-error@-1 {{member reference type 'A<int>' is not a pointer; did you mean to use '.'?}}
499+
// expected-error@-2 {{no member named 'x' in 'N4::A<int>'}}
497500
c->x; // expected-error {{member reference type 'int' is not a pointer}}
498501
}
499502
};
@@ -540,11 +543,10 @@ namespace N4 {
540543
a->T::f();
541544
a->T::g();
542545

543-
// FIXME: 'U' should be a dependent name, and its lookup context should be 'a.operator->()'!
544-
a->U::x; // expected-error {{use of undeclared identifier 'U'}}
545-
a->U::y; // expected-error {{use of undeclared identifier 'U'}}
546-
a->U::f(); // expected-error {{use of undeclared identifier 'U'}}
547-
a->U::g(); // expected-error {{use of undeclared identifier 'U'}}
546+
a->U::x;
547+
a->U::y;
548+
a->U::f();
549+
a->U::g();
548550
}
549551

550552
void instantiated(D a) {
@@ -605,3 +607,24 @@ namespace N5 {
605607

606608
template void g(int); // expected-note {{in instantiation of}}
607609
} // namespace N5
610+
611+
namespace N6 {
612+
struct A {
613+
int x;
614+
};
615+
616+
struct B {
617+
A* operator->();
618+
};
619+
620+
struct C {
621+
B y;
622+
};
623+
624+
template<typename T>
625+
struct D : C {
626+
void f() {
627+
y->x;
628+
}
629+
};
630+
} // namespace N6

0 commit comments

Comments
 (0)