Skip to content

Commit a719de8

Browse files
committed
[Clang][Sema] Use the correct lookup context when building overloaded 'operator->' in the current instantiation
1 parent 1a0cf24 commit a719de8

File tree

5 files changed

+35
-35
lines changed

5 files changed

+35
-35
lines changed

clang/include/clang/Sema/Sema.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10639,8 +10639,7 @@ class Sema final : public SemaBase {
1063910639
/// BuildOverloadedArrowExpr - Build a call to an overloaded @c operator->
1064010640
/// (if one exists), where @c Base is an expression of class type and
1064110641
/// @c Member is the name of the member we're trying to find.
10642-
ExprResult BuildOverloadedArrowExpr(Scope *S, Expr *Base,
10643-
SourceLocation OpLoc,
10642+
ExprResult BuildOverloadedArrowExpr(Expr *Base, SourceLocation OpLoc,
1064410643
bool *NoArrowOperatorFound = nullptr);
1064510644

1064610645
ExprResult BuildCXXMemberCallExpr(Expr *Exp, NamedDecl *FoundDecl,

clang/lib/Sema/SemaExprCXX.cpp

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7955,18 +7955,6 @@ ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base,
79557955

79567956
QualType BaseType = Base->getType();
79577957
MayBePseudoDestructor = false;
7958-
if (BaseType->isDependentType()) {
7959-
// If we have a pointer to a dependent type and are using the -> operator,
7960-
// the object type is the type that the pointer points to. We might still
7961-
// have enough information about that type to do something useful.
7962-
if (OpKind == tok::arrow)
7963-
if (const PointerType *Ptr = BaseType->getAs<PointerType>())
7964-
BaseType = Ptr->getPointeeType();
7965-
7966-
ObjectType = ParsedType::make(BaseType);
7967-
MayBePseudoDestructor = true;
7968-
return Base;
7969-
}
79707958

79717959
// C++ [over.match.oper]p8:
79727960
// [...] When operator->returns, the operator-> is applied to the value
@@ -7981,7 +7969,7 @@ ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base,
79817969
SmallVector<FunctionDecl*, 8> OperatorArrows;
79827970
CTypes.insert(Context.getCanonicalType(BaseType));
79837971

7984-
while (BaseType->isRecordType()) {
7972+
while (BaseType->getAsRecordDecl()) {
79857973
if (OperatorArrows.size() >= getLangOpts().ArrowDepth) {
79867974
Diag(OpLoc, diag::err_operator_arrow_depth_exceeded)
79877975
<< StartingType << getLangOpts().ArrowDepth << Base->getSourceRange();
@@ -7992,7 +7980,7 @@ ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base,
79927980
}
79937981

79947982
Result = BuildOverloadedArrowExpr(
7995-
S, Base, OpLoc,
7983+
Base, OpLoc,
79967984
// When in a template specialization and on the first loop iteration,
79977985
// potentially give the default diagnostic (with the fixit in a
79987986
// separate note) instead of having the error reported back to here
@@ -8018,7 +8006,14 @@ ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base,
80188006
}
80198007
}
80208008
return ExprError();
8009+
} else if (Result.isUnset()) {
8010+
// BuildOverloadedArrowExpr returns an empty expression to indicate
8011+
// that we need to build a dependent overloaded arrow expression.
8012+
assert(BaseType->isDependentType());
8013+
BaseType = Context.DependentTy;
8014+
break;
80218015
}
8016+
80228017
Base = Result.get();
80238018
if (CXXOperatorCallExpr *OpCall = dyn_cast<CXXOperatorCallExpr>(Base))
80248019
OperatorArrows.push_back(OpCall->getDirectCallee());
@@ -8056,7 +8051,7 @@ ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base,
80568051
// it's legal for the type to be incomplete if this is a pseudo-destructor
80578052
// call. We'll do more incomplete-type checks later in the lookup process,
80588053
// so just skip this check for ObjC types.
8059-
if (!BaseType->isRecordType()) {
8054+
if (!BaseType->getAsRecordDecl()) {
80608055
ObjectType = ParsedType::make(BaseType);
80618056
MayBePseudoDestructor = true;
80628057
return Base;

clang/lib/Sema/SemaOverload.cpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15876,10 +15876,9 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
1587615876
return CheckForImmediateInvocation(MaybeBindToTemporary(TheCall), Method);
1587715877
}
1587815878

15879-
ExprResult
15880-
Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
15881-
bool *NoArrowOperatorFound) {
15882-
assert(Base->getType()->isRecordType() &&
15879+
ExprResult Sema::BuildOverloadedArrowExpr(Expr *Base, SourceLocation OpLoc,
15880+
bool *NoArrowOperatorFound) {
15881+
assert(Base->getType()->getAsRecordDecl() &&
1588315882
"left-hand side must have class type");
1588415883

1588515884
if (checkPlaceholderForOverload(*this, Base))
@@ -15902,7 +15901,12 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
1590215901
return ExprError();
1590315902

1590415903
LookupResult R(*this, OpName, OpLoc, LookupOrdinaryName);
15905-
LookupQualifiedName(R, Base->getType()->castAs<RecordType>()->getDecl());
15904+
LookupParsedName(R, /*S=*/nullptr, /*SS=*/nullptr, Base->getType());
15905+
15906+
if (R.wasNotFoundInCurrentInstantiation() ||
15907+
(Base->isTypeDependent() && !R.empty()))
15908+
return ExprEmpty();
15909+
1590615910
R.suppressAccessDiagnostics();
1590715911

1590815912
for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end();

clang/lib/Sema/TreeTransform.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16565,10 +16565,10 @@ ExprResult TreeTransform<Derived>::RebuildCXXOperatorCallExpr(
1656516565
} else if (Op == OO_Arrow) {
1656616566
// It is possible that the type refers to a RecoveryExpr created earlier
1656716567
// in the tree transformation.
16568-
if (First->getType()->isDependentType())
16568+
if (First->containsErrors())
1656916569
return ExprError();
1657016570
// -> is never a builtin operation.
16571-
return SemaRef.BuildOverloadedArrowExpr(nullptr, First, OpLoc);
16571+
return SemaRef.BuildOverloadedArrowExpr(First, OpLoc);
1657216572
} else if (Second == nullptr || isPostIncDec) {
1657316573
if (!First->getType()->isOverloadableType() ||
1657416574
(Op == OO_Amp && getSema().isQualifiedMemberAccess(First))) {

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

Lines changed: 13 additions & 11 deletions
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) {

0 commit comments

Comments
 (0)