[clang] 596a9c1 - [Clang][Sema] Fix bug where operator-> typo corrects in the current instantiation (#91972)
via cfe-commits
cfe-commits at lists.llvm.org
Mon May 13 09:24:49 PDT 2024
Author: Krystian Stasiowski
Date: 2024-05-13T12:24:46-04:00
New Revision: 596a9c1f9b3179b3c77cbde1e96619292ce2a10a
URL: https://github.com/llvm/llvm-project/commit/596a9c1f9b3179b3c77cbde1e96619292ce2a10a
DIFF: https://github.com/llvm/llvm-project/commit/596a9c1f9b3179b3c77cbde1e96619292ce2a10a.diff
LOG: [Clang][Sema] Fix bug where operator-> typo corrects in the current instantiation (#91972)
#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).
Added:
Modified:
clang/lib/Sema/SemaExprMember.cpp
clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp
Removed:
################################################################################
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index 9fa69da4f9685..244488a0b562b 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -995,8 +995,6 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
// arrow operator was used with a dependent non-pointer object expression,
// build a CXXDependentScopeMemberExpr.
if (R.wasNotFoundInCurrentInstantiation() ||
- (IsArrow && !BaseExprType->isPointerType() &&
- BaseExprType->isDependentType()) ||
(R.getLookupName().getCXXOverloadedOperator() == OO_Equal &&
(SS.isSet() ? SS.getScopeRep()->isDependent()
: BaseExprType->isDependentType())))
@@ -1322,28 +1320,28 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
else if (const ObjCObjectPointerType *Ptr =
BaseType->getAs<ObjCObjectPointerType>())
BaseType = Ptr->getPointeeType();
- else if (!BaseType->isDependentType()) {
- if (BaseType->isRecordType()) {
- // Recover from arrow accesses to records, e.g.:
- // struct MyRecord foo;
- // foo->bar
- // This is actually well-formed in C++ if MyRecord has an
- // overloaded operator->, but that should have been dealt with
- // by now--or a diagnostic message already issued if a problem
- // was encountered while looking for the overloaded operator->.
- if (!S.getLangOpts().CPlusPlus) {
- S.Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
- << BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange()
- << FixItHint::CreateReplacement(OpLoc, ".");
- }
- IsArrow = false;
- } else if (BaseType->isFunctionType()) {
- goto fail;
- } else {
- S.Diag(MemberLoc, diag::err_typecheck_member_reference_arrow)
- << BaseType << BaseExpr.get()->getSourceRange();
- return ExprError();
+ else if (BaseType->isFunctionType())
+ goto fail;
+ else if (BaseType->isDependentType())
+ BaseType = S.Context.DependentTy;
+ else if (BaseType->isRecordType()) {
+ // Recover from arrow accesses to records, e.g.:
+ // struct MyRecord foo;
+ // foo->bar
+ // This is actually well-formed in C++ if MyRecord has an
+ // overloaded operator->, but that should have been dealt with
+ // by now--or a diagnostic message already issued if a problem
+ // was encountered while looking for the overloaded operator->.
+ if (!S.getLangOpts().CPlusPlus) {
+ S.Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
+ << BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange()
+ << FixItHint::CreateReplacement(OpLoc, ".");
}
+ IsArrow = false;
+ } else {
+ S.Diag(MemberLoc, diag::err_typecheck_member_reference_arrow)
+ << BaseType << BaseExpr.get()->getSourceRange();
+ return ExprError();
}
}
@@ -1363,7 +1361,7 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
}
// Handle field access to simple records.
- if (BaseType->getAsRecordDecl() || BaseType->isDependentType()) {
+ if (BaseType->getAsRecordDecl()) {
TypoExpr *TE = nullptr;
if (LookupMemberExprInRecord(S, R, BaseExpr.get(), BaseType, OpLoc, IsArrow,
SS, HasTemplateArgs, TemplateKWLoc, TE))
@@ -1374,6 +1372,9 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
// failed, the lookup result will have been cleared--that combined with the
// valid-but-null ExprResult will trigger the appropriate diagnostics.
return ExprResult(TE);
+ } else if (BaseType->isDependentType()) {
+ R.setNotFoundInCurrentInstantiation();
+ return ExprEmpty();
}
// Handle ivar access to Objective-C objects.
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 1adbc33a701c1..3ca7c6c7eb8ee 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
@@ -539,6 +539,17 @@ namespace N4 {
a->y;
a->f();
a->g();
+
+ a->T::x;
+ a->T::y;
+ 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'}}
}
void instantiated(D a) {
@@ -546,9 +557,25 @@ namespace N4 {
a->y; // expected-error {{no member named 'y' in 'N4::B'}}
a->f();
a->g(); // expected-error {{no member named 'g' in 'N4::B'}}
+
+ a->T::x;
+ a->T::y; // expected-error {{no member named 'y' in 'N4::B'}}
+ a->T::f();
+ a->T::g(); // expected-error {{no member named 'g' in 'N4::B'}}
}
};
template void D<B>::instantiated(D); // expected-note {{in instantiation of}}
+ template<typename T>
+ struct Typo {
+ T *operator->();
+
+ void not_instantiated(Typo a) {
+ a->Not_instantiated;
+ a->typo;
+ a->T::Not_instantiated;
+ a->T::typo;
+ }
+ };
} // namespace N4
More information about the cfe-commits
mailing list