From b8fda8106405eed0c234802fff8eecde53f2562e Mon Sep 17 00:00:00 2001 From: Krystian Stasiowski Date: Thu, 25 Apr 2024 20:20:46 -0400 Subject: [PATCH] [FOLD] Fix arrow operator for expressions with non-pointer type that is the current instantiation --- clang/lib/Sema/SemaExprMember.cpp | 67 ++++++++--------- .../temp.res/temp.dep/temp.dep.type/p4.cpp | 71 ++++++++++++++++++- 2 files changed, 104 insertions(+), 34 deletions(-) diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp index 52b3d23b4f3b6..5facb14a18b7c 100644 --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -991,7 +991,12 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, bool SuppressQualifierCheck, ActOnMemberAccessExtraArgs *ExtraArgs) { assert(!SS.isInvalid() && "nested-name-specifier cannot be invalid"); - if (R.wasNotFoundInCurrentInstantiation()) + // If the member wasn't found in the current instantiation, or if the + // arrow operator was used with a dependent non-pointer object expression, + // build a CXXDependentScopeMemberExpr. + if (R.wasNotFoundInCurrentInstantiation() || + (IsArrow && !BaseExprType->isPointerType() && + BaseExprType->isDependentType())) return ActOnDependentMemberExpr(BaseExpr, BaseExprType, IsArrow, OpLoc, SS, TemplateKWLoc, FirstQualifierInScope, R.getLookupNameInfo(), TemplateArgs); @@ -1036,41 +1041,39 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, << isa(FD); if (R.empty()) { - // Rederive where we looked up. - DeclContext *DC = - (SS.isSet() ? computeDeclContext(SS) : computeDeclContext(BaseType)); - if (ExtraArgs) { - ExprResult RetryExpr; - if (!IsArrow && BaseExpr && !BaseExpr->isTypeDependent()) { - SFINAETrap Trap(*this, true); - ParsedType ObjectType; - bool MayBePseudoDestructor = false; - RetryExpr = ActOnStartCXXMemberReference(getCurScope(), BaseExpr, - OpLoc, tok::arrow, ObjectType, - MayBePseudoDestructor); - if (RetryExpr.isUsable() && !Trap.hasErrorOccurred()) { - CXXScopeSpec TempSS(SS); - RetryExpr = ActOnMemberAccessExpr( - ExtraArgs->S, RetryExpr.get(), OpLoc, tok::arrow, TempSS, - TemplateKWLoc, ExtraArgs->Id, ExtraArgs->ObjCImpDecl); - } - if (Trap.hasErrorOccurred()) - RetryExpr = ExprError(); - } - if (RetryExpr.isUsable()) { - Diag(OpLoc, diag::err_no_member_overloaded_arrow) - << MemberName << DC << FixItHint::CreateReplacement(OpLoc, "->"); - return RetryExpr; + ExprResult RetryExpr = ExprError(); + if (ExtraArgs && !IsArrow && BaseExpr && !BaseExpr->isTypeDependent()) { + SFINAETrap Trap(*this, true); + ParsedType ObjectType; + bool MayBePseudoDestructor = false; + RetryExpr = ActOnStartCXXMemberReference(getCurScope(), BaseExpr, OpLoc, + tok::arrow, ObjectType, + MayBePseudoDestructor); + if (RetryExpr.isUsable() && !Trap.hasErrorOccurred()) { + CXXScopeSpec TempSS(SS); + RetryExpr = ActOnMemberAccessExpr( + ExtraArgs->S, RetryExpr.get(), OpLoc, tok::arrow, TempSS, + TemplateKWLoc, ExtraArgs->Id, ExtraArgs->ObjCImpDecl); } + if (Trap.hasErrorOccurred()) + RetryExpr = ExprError(); } + // Rederive where we looked up. + DeclContext *DC = + (SS.isSet() ? computeDeclContext(SS) : computeDeclContext(BaseType)); assert(DC); - Diag(R.getNameLoc(), diag::err_no_member) - << MemberName << DC - << (SS.isSet() - ? SS.getRange() - : (BaseExpr ? BaseExpr->getSourceRange() : SourceRange())); - return ExprError(); + + if (RetryExpr.isUsable()) + Diag(OpLoc, diag::err_no_member_overloaded_arrow) + << MemberName << DC << FixItHint::CreateReplacement(OpLoc, "->"); + else + Diag(R.getNameLoc(), diag::err_no_member) + << MemberName << DC + << (SS.isSet() + ? SS.getRange() + : (BaseExpr ? BaseExpr->getSourceRange() : SourceRange())); + return RetryExpr; } // Diagnose lookups that find only declarations from a non-base 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 b1d2859be863a..0f24d716a7b74 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 @@ -439,7 +439,7 @@ namespace N2 { a->B::C::x; } }; -} +} // namespace N2 namespace N3 { struct A { }; @@ -453,4 +453,71 @@ namespace N3 { this->A::operator=(*this); } }; -} +} // namespace N3 + +namespace N4 { + template + struct A { + void not_instantiated(A a, A b, T c) { + a->x; + b->x; + c->x; + } + + void instantiated(A a, A b, T c) { + a->x; // expected-error {{member reference type 'A' is not a pointer; did you mean to use '.'?}} + // expected-error@-1 {{no member named 'x' in 'N4::A'}} + b->x; // expected-error {{member reference type 'A' is not a pointer; did you mean to use '.'?}} + // expected-error@-1 {{no member named 'x' in 'N4::A'}} + c->x; // expected-error {{member reference type 'int' is not a pointer}} + } + }; + + template void A::instantiated(A, A, int); // expected-note {{in instantiation of}} + + struct B { + int x; + + void f(); + }; + + template + struct C { + B *operator->(); + + void not_instantiated(C a, C b, T c) { + a->x; + b->x; + c->x; + } + + void instantiated(C a, C b, T c) { + a->x; + b->x; + c->x; // expected-error {{member reference type 'int' is not a pointer}} + } + }; + + template void C::instantiated(C, C, int); // expected-note {{in instantiation of}} + + template + struct D { + T *operator->(); + + void not_instantiated(D a) { + a->x; + a->y; + a->f(); + a->g(); + } + + void instantiated(D a) { + a->x; + a->y; // expected-error {{no member named 'y' in 'N4::B'}} + a->f(); + a->g(); // expected-error {{no member named 'g' in 'N4::B'}} + } + }; + + template void D::instantiated(D); // expected-note {{in instantiation of}} +} // namespace N4