From a013806c0199e260c37bc6b16b600e61e4caa1c9 Mon Sep 17 00:00:00 2001 From: Krystian Stasiowski Date: Mon, 13 May 2024 10:22:04 -0400 Subject: [PATCH 1/2] [Clang][Sema] Fix bug where operator-> typo corrects in the current instantiation --- clang/lib/Sema/SemaExprMember.cpp | 10 +++++----- .../CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp | 7 +++++++ 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp index 9fa69da4f9685..ac81d4fd57654 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,7 +1320,11 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, else if (const ObjCObjectPointerType *Ptr = BaseType->getAs()) BaseType = Ptr->getPointeeType(); - else if (!BaseType->isDependentType()) { + 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; @@ -1337,8 +1339,6 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, << 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(); 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..fafd54bde7622 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 @@ -551,4 +551,11 @@ namespace N4 { template void D::instantiated(D); // expected-note {{in instantiation of}} + template + struct Typo { + void not_instantiated(Typo a) { + a->Not_instantiated; + a->typo; + } + }; } // namespace N4 From f13826746be9893a48485275ef819b5cd454a53d Mon Sep 17 00:00:00 2001 From: Krystian Stasiowski Date: Mon, 13 May 2024 11:57:47 -0400 Subject: [PATCH 2/2] [FOLD] fix operator-> with nested-name-specifier --- clang/lib/Sema/SemaExprMember.cpp | 41 ++++++++++--------- .../temp.res/temp.dep/temp.dep.type/p4.cpp | 20 +++++++++ 2 files changed, 41 insertions(+), 20 deletions(-) diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp index ac81d4fd57654..244488a0b562b 100644 --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -1324,26 +1324,24 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, 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(); + 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 fafd54bde7622..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,6 +557,11 @@ 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'}} } }; @@ -553,9 +569,13 @@ namespace N4 { template struct Typo { + T *operator->(); + void not_instantiated(Typo a) { a->Not_instantiated; a->typo; + a->T::Not_instantiated; + a->T::typo; } }; } // namespace N4