Skip to content

Commit 596a9c1

Browse files
authored
[Clang][Sema] Fix bug where operator-> typo corrects in the current instantiation (llvm#91972)
llvm#90152 introduced a bug that occurs when typo-correction attempts to fix a reference to a non-existent member of the current instantiation (even though `operator->` may return a different type than the object type). This patch fixes it by simply considering the object expression to be of type `ASTContext::DependentTy` when the arrow operator is used with a dependent non-pointer non-function operand (after any implicit conversions).
1 parent 89a080c commit 596a9c1

File tree

2 files changed

+52
-24
lines changed

2 files changed

+52
-24
lines changed

clang/lib/Sema/SemaExprMember.cpp

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -995,8 +995,6 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
995995
// arrow operator was used with a dependent non-pointer object expression,
996996
// build a CXXDependentScopeMemberExpr.
997997
if (R.wasNotFoundInCurrentInstantiation() ||
998-
(IsArrow && !BaseExprType->isPointerType() &&
999-
BaseExprType->isDependentType()) ||
1000998
(R.getLookupName().getCXXOverloadedOperator() == OO_Equal &&
1001999
(SS.isSet() ? SS.getScopeRep()->isDependent()
10021000
: BaseExprType->isDependentType())))
@@ -1322,28 +1320,28 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
13221320
else if (const ObjCObjectPointerType *Ptr =
13231321
BaseType->getAs<ObjCObjectPointerType>())
13241322
BaseType = Ptr->getPointeeType();
1325-
else if (!BaseType->isDependentType()) {
1326-
if (BaseType->isRecordType()) {
1327-
// Recover from arrow accesses to records, e.g.:
1328-
// struct MyRecord foo;
1329-
// foo->bar
1330-
// This is actually well-formed in C++ if MyRecord has an
1331-
// overloaded operator->, but that should have been dealt with
1332-
// by now--or a diagnostic message already issued if a problem
1333-
// was encountered while looking for the overloaded operator->.
1334-
if (!S.getLangOpts().CPlusPlus) {
1335-
S.Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
1336-
<< BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange()
1337-
<< FixItHint::CreateReplacement(OpLoc, ".");
1338-
}
1339-
IsArrow = false;
1340-
} else if (BaseType->isFunctionType()) {
1341-
goto fail;
1342-
} else {
1343-
S.Diag(MemberLoc, diag::err_typecheck_member_reference_arrow)
1344-
<< BaseType << BaseExpr.get()->getSourceRange();
1345-
return ExprError();
1323+
else if (BaseType->isFunctionType())
1324+
goto fail;
1325+
else if (BaseType->isDependentType())
1326+
BaseType = S.Context.DependentTy;
1327+
else if (BaseType->isRecordType()) {
1328+
// Recover from arrow accesses to records, e.g.:
1329+
// struct MyRecord foo;
1330+
// foo->bar
1331+
// This is actually well-formed in C++ if MyRecord has an
1332+
// overloaded operator->, but that should have been dealt with
1333+
// by now--or a diagnostic message already issued if a problem
1334+
// was encountered while looking for the overloaded operator->.
1335+
if (!S.getLangOpts().CPlusPlus) {
1336+
S.Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
1337+
<< BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange()
1338+
<< FixItHint::CreateReplacement(OpLoc, ".");
13461339
}
1340+
IsArrow = false;
1341+
} else {
1342+
S.Diag(MemberLoc, diag::err_typecheck_member_reference_arrow)
1343+
<< BaseType << BaseExpr.get()->getSourceRange();
1344+
return ExprError();
13471345
}
13481346
}
13491347

@@ -1363,7 +1361,7 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
13631361
}
13641362

13651363
// Handle field access to simple records.
1366-
if (BaseType->getAsRecordDecl() || BaseType->isDependentType()) {
1364+
if (BaseType->getAsRecordDecl()) {
13671365
TypoExpr *TE = nullptr;
13681366
if (LookupMemberExprInRecord(S, R, BaseExpr.get(), BaseType, OpLoc, IsArrow,
13691367
SS, HasTemplateArgs, TemplateKWLoc, TE))
@@ -1374,6 +1372,9 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
13741372
// failed, the lookup result will have been cleared--that combined with the
13751373
// valid-but-null ExprResult will trigger the appropriate diagnostics.
13761374
return ExprResult(TE);
1375+
} else if (BaseType->isDependentType()) {
1376+
R.setNotFoundInCurrentInstantiation();
1377+
return ExprEmpty();
13771378
}
13781379

13791380
// Handle ivar access to Objective-C objects.

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

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -539,16 +539,43 @@ namespace N4 {
539539
a->y;
540540
a->f();
541541
a->g();
542+
543+
a->T::x;
544+
a->T::y;
545+
a->T::f();
546+
a->T::g();
547+
548+
// FIXME: 'U' should be a dependent name, and its lookup context should be 'a.operator->()'!
549+
a->U::x; // expected-error {{use of undeclared identifier 'U'}}
550+
a->U::y; // expected-error {{use of undeclared identifier 'U'}}
551+
a->U::f(); // expected-error {{use of undeclared identifier 'U'}}
552+
a->U::g(); // expected-error {{use of undeclared identifier 'U'}}
542553
}
543554

544555
void instantiated(D a) {
545556
a->x;
546557
a->y; // expected-error {{no member named 'y' in 'N4::B'}}
547558
a->f();
548559
a->g(); // expected-error {{no member named 'g' in 'N4::B'}}
560+
561+
a->T::x;
562+
a->T::y; // expected-error {{no member named 'y' in 'N4::B'}}
563+
a->T::f();
564+
a->T::g(); // expected-error {{no member named 'g' in 'N4::B'}}
549565
}
550566
};
551567

552568
template void D<B>::instantiated(D); // expected-note {{in instantiation of}}
553569

570+
template<typename T>
571+
struct Typo {
572+
T *operator->();
573+
574+
void not_instantiated(Typo a) {
575+
a->Not_instantiated;
576+
a->typo;
577+
a->T::Not_instantiated;
578+
a->T::typo;
579+
}
580+
};
554581
} // namespace N4

0 commit comments

Comments
 (0)