Skip to content

Commit cc1b666

Browse files
committed
[Clang] Fix member lookup so that we don't ignore ambiguous lookups in some cases
There are some cases during member lookup we are aggressively suppressing diagnostics when we should just be suppressing access control diagnostic. In this PR I add the ability to simply suppress access diagnostics while not suppressing ambiguous lookup diagnostics. Fixes: llvm#22413 llvm#29942 llvm#35574 llvm#27224 Differential Revision: https://reviews.llvm.org/D155387
1 parent 63f8922 commit cc1b666

File tree

7 files changed

+113
-38
lines changed

7 files changed

+113
-38
lines changed

Diff for: clang/docs/ReleaseNotes.rst

+6
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,12 @@ Bug Fixes to C++ Support
121121
a Unicode character whose name contains a ``-``.
122122
(`Fixes #64161 <https://github.com/llvm/llvm-project/issues/64161>_`)
123123

124+
- Fix cases where we ignore ambiguous name lookup when looking up memebers.
125+
(`#22413 <https://github.com/llvm/llvm-project/issues/22413>_`),
126+
(`#29942 <https://github.com/llvm/llvm-project/issues/29942>_`),
127+
(`#35574 <https://github.com/llvm/llvm-project/issues/35574>_`) and
128+
(`#27224 <https://github.com/llvm/llvm-project/issues/27224>_`).
129+
124130
Bug Fixes to AST Handling
125131
^^^^^^^^^^^^^^^^^^^^^^^^^
126132

Diff for: clang/include/clang/Sema/Lookup.h

+38-18
Original file line numberDiff line numberDiff line change
@@ -148,20 +148,22 @@ class LookupResult {
148148
: SemaPtr(&SemaRef), NameInfo(NameInfo), LookupKind(LookupKind),
149149
Redecl(Redecl != Sema::NotForRedeclaration),
150150
ExternalRedecl(Redecl == Sema::ForExternalRedeclaration),
151-
Diagnose(Redecl == Sema::NotForRedeclaration) {
151+
DiagnoseAccess(Redecl == Sema::NotForRedeclaration),
152+
DiagnoseAmbiguous(Redecl == Sema::NotForRedeclaration) {
152153
configure();
153154
}
154155

155156
// TODO: consider whether this constructor should be restricted to take
156157
// as input a const IdentifierInfo* (instead of Name),
157158
// forcing other cases towards the constructor taking a DNInfo.
158-
LookupResult(Sema &SemaRef, DeclarationName Name,
159-
SourceLocation NameLoc, Sema::LookupNameKind LookupKind,
159+
LookupResult(Sema &SemaRef, DeclarationName Name, SourceLocation NameLoc,
160+
Sema::LookupNameKind LookupKind,
160161
Sema::RedeclarationKind Redecl = Sema::NotForRedeclaration)
161162
: SemaPtr(&SemaRef), NameInfo(Name, NameLoc), LookupKind(LookupKind),
162163
Redecl(Redecl != Sema::NotForRedeclaration),
163164
ExternalRedecl(Redecl == Sema::ForExternalRedeclaration),
164-
Diagnose(Redecl == Sema::NotForRedeclaration) {
165+
DiagnoseAccess(Redecl == Sema::NotForRedeclaration),
166+
DiagnoseAmbiguous(Redecl == Sema::NotForRedeclaration) {
165167
configure();
166168
}
167169

@@ -192,12 +194,14 @@ class LookupResult {
192194
Redecl(std::move(Other.Redecl)),
193195
ExternalRedecl(std::move(Other.ExternalRedecl)),
194196
HideTags(std::move(Other.HideTags)),
195-
Diagnose(std::move(Other.Diagnose)),
197+
DiagnoseAccess(std::move(Other.DiagnoseAccess)),
198+
DiagnoseAmbiguous(std::move(Other.DiagnoseAmbiguous)),
196199
AllowHidden(std::move(Other.AllowHidden)),
197200
Shadowed(std::move(Other.Shadowed)),
198201
TemplateNameLookup(std::move(Other.TemplateNameLookup)) {
199202
Other.Paths = nullptr;
200-
Other.Diagnose = false;
203+
Other.DiagnoseAccess = false;
204+
Other.DiagnoseAmbiguous = false;
201205
}
202206

203207
LookupResult &operator=(LookupResult &&Other) {
@@ -215,17 +219,22 @@ class LookupResult {
215219
Redecl = std::move(Other.Redecl);
216220
ExternalRedecl = std::move(Other.ExternalRedecl);
217221
HideTags = std::move(Other.HideTags);
218-
Diagnose = std::move(Other.Diagnose);
222+
DiagnoseAccess = std::move(Other.DiagnoseAccess);
223+
DiagnoseAmbiguous = std::move(Other.DiagnoseAmbiguous);
219224
AllowHidden = std::move(Other.AllowHidden);
220225
Shadowed = std::move(Other.Shadowed);
221226
TemplateNameLookup = std::move(Other.TemplateNameLookup);
222227
Other.Paths = nullptr;
223-
Other.Diagnose = false;
228+
Other.DiagnoseAccess = false;
229+
Other.DiagnoseAmbiguous = false;
224230
return *this;
225231
}
226232

227233
~LookupResult() {
228-
if (Diagnose) diagnose();
234+
if (DiagnoseAccess)
235+
diagnoseAccess();
236+
if (DiagnoseAmbiguous)
237+
diagnoseAmbiguous();
229238
if (Paths) deletePaths(Paths);
230239
}
231240

@@ -607,13 +616,20 @@ class LookupResult {
607616
/// Suppress the diagnostics that would normally fire because of this
608617
/// lookup. This happens during (e.g.) redeclaration lookups.
609618
void suppressDiagnostics() {
610-
Diagnose = false;
619+
DiagnoseAccess = false;
620+
DiagnoseAmbiguous = false;
611621
}
612622

613-
/// Determines whether this lookup is suppressing diagnostics.
614-
bool isSuppressingDiagnostics() const {
615-
return !Diagnose;
616-
}
623+
/// Suppress the diagnostics that would normally fire because of this
624+
/// lookup due to access control violations.
625+
void suppressAccessDiagnostics() { DiagnoseAccess = false; }
626+
627+
/// Determines whether this lookup is suppressing access control diagnostics.
628+
bool isSuppressingAccessDiagnostics() const { return !DiagnoseAccess; }
629+
630+
/// Determines whether this lookup is suppressing ambiguous lookup
631+
/// diagnostics.
632+
bool isSuppressingAmbiguousDiagnostics() const { return !DiagnoseAmbiguous; }
617633

618634
/// Sets a 'context' source range.
619635
void setContextRange(SourceRange SR) {
@@ -726,11 +742,14 @@ class LookupResult {
726742
}
727743

728744
private:
729-
void diagnose() {
745+
void diagnoseAccess() {
746+
if (isClassLookup() && getSema().getLangOpts().AccessControl)
747+
getSema().CheckLookupAccess(*this);
748+
}
749+
750+
void diagnoseAmbiguous() {
730751
if (isAmbiguous())
731752
getSema().DiagnoseAmbiguousLookup(*this);
732-
else if (isClassLookup() && getSema().getLangOpts().AccessControl)
733-
getSema().CheckLookupAccess(*this);
734753
}
735754

736755
void setAmbiguous(AmbiguityKind AK) {
@@ -776,7 +795,8 @@ class LookupResult {
776795
/// are present
777796
bool HideTags = true;
778797

779-
bool Diagnose = false;
798+
bool DiagnoseAccess = false;
799+
bool DiagnoseAmbiguous = false;
780800

781801
/// True if we should allow hidden declarations to be 'visible'.
782802
bool AllowHidden = false;

Diff for: clang/lib/Sema/SemaOverload.cpp

+18-16
Original file line numberDiff line numberDiff line change
@@ -950,7 +950,7 @@ static bool shouldAddReversedEqEq(Sema &S, SourceLocation OpLoc,
950950
LookupResult Members(S, NotEqOp, OpLoc,
951951
Sema::LookupNameKind::LookupMemberName);
952952
S.LookupQualifiedName(Members, RHSRec->getDecl());
953-
Members.suppressDiagnostics();
953+
Members.suppressAccessDiagnostics();
954954
for (NamedDecl *Op : Members)
955955
if (FunctionsCorrespond(S.Context, EqFD, Op->getAsFunction()))
956956
return false;
@@ -961,7 +961,7 @@ static bool shouldAddReversedEqEq(Sema &S, SourceLocation OpLoc,
961961
Sema::LookupNameKind::LookupOperatorName);
962962
S.LookupName(NonMembers,
963963
S.getScopeForContext(EqFD->getEnclosingNamespaceContext()));
964-
NonMembers.suppressDiagnostics();
964+
NonMembers.suppressAccessDiagnostics();
965965
for (NamedDecl *Op : NonMembers) {
966966
auto *FD = Op->getAsFunction();
967967
if(auto* UD = dyn_cast<UsingShadowDecl>(Op))
@@ -7987,7 +7987,7 @@ void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op,
79877987

79887988
LookupResult Operators(*this, OpName, OpLoc, LookupOrdinaryName);
79897989
LookupQualifiedName(Operators, T1Rec->getDecl());
7990-
Operators.suppressDiagnostics();
7990+
Operators.suppressAccessDiagnostics();
79917991

79927992
for (LookupResult::iterator Oper = Operators.begin(),
79937993
OperEnd = Operators.end();
@@ -14983,7 +14983,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
1498314983
const auto *Record = Object.get()->getType()->castAs<RecordType>();
1498414984
LookupResult R(*this, OpName, LParenLoc, LookupOrdinaryName);
1498514985
LookupQualifiedName(R, Record->getDecl());
14986-
R.suppressDiagnostics();
14986+
R.suppressAccessDiagnostics();
1498714987

1498814988
for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end();
1498914989
Oper != OperEnd; ++Oper) {
@@ -15080,12 +15080,13 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
1508015080
break;
1508115081
}
1508215082
case OR_Ambiguous:
15083-
CandidateSet.NoteCandidates(
15084-
PartialDiagnosticAt(Object.get()->getBeginLoc(),
15085-
PDiag(diag::err_ovl_ambiguous_object_call)
15086-
<< Object.get()->getType()
15087-
<< Object.get()->getSourceRange()),
15088-
*this, OCD_AmbiguousCandidates, Args);
15083+
if (!R.isAmbiguous())
15084+
CandidateSet.NoteCandidates(
15085+
PartialDiagnosticAt(Object.get()->getBeginLoc(),
15086+
PDiag(diag::err_ovl_ambiguous_object_call)
15087+
<< Object.get()->getType()
15088+
<< Object.get()->getSourceRange()),
15089+
*this, OCD_AmbiguousCandidates, Args);
1508915090
break;
1509015091

1509115092
case OR_Deleted:
@@ -15248,7 +15249,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
1524815249

1524915250
LookupResult R(*this, OpName, OpLoc, LookupOrdinaryName);
1525015251
LookupQualifiedName(R, Base->getType()->castAs<RecordType>()->getDecl());
15251-
R.suppressDiagnostics();
15252+
R.suppressAccessDiagnostics();
1525215253

1525315254
for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end();
1525415255
Oper != OperEnd; ++Oper) {
@@ -15289,11 +15290,12 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
1528915290
return ExprError();
1529015291
}
1529115292
case OR_Ambiguous:
15292-
CandidateSet.NoteCandidates(
15293-
PartialDiagnosticAt(OpLoc, PDiag(diag::err_ovl_ambiguous_oper_unary)
15294-
<< "->" << Base->getType()
15295-
<< Base->getSourceRange()),
15296-
*this, OCD_AmbiguousCandidates, Base);
15293+
if (!R.isAmbiguous())
15294+
CandidateSet.NoteCandidates(
15295+
PartialDiagnosticAt(OpLoc, PDiag(diag::err_ovl_ambiguous_oper_unary)
15296+
<< "->" << Base->getType()
15297+
<< Base->getSourceRange()),
15298+
*this, OCD_AmbiguousCandidates, Base);
1529715299
return ExprError();
1529815300

1529915301
case OR_Deleted:

Diff for: clang/lib/Sema/SemaTemplate.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -593,7 +593,7 @@ bool Sema::LookupTemplateName(LookupResult &Found,
593593
// postfix-expression and does not name a class template, the name
594594
// found in the class of the object expression is used, otherwise
595595
FoundOuter.clear();
596-
} else if (!Found.isSuppressingDiagnostics()) {
596+
} else if (!Found.isSuppressingAmbiguousDiagnostics()) {
597597
// - if the name found is a class template, it must refer to the same
598598
// entity as the one found in the class of the object expression,
599599
// otherwise the program is ill-formed.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// RUN: %clang_cc1 -fsyntax-only -verify %s
2+
3+
struct A {
4+
void operator()(int); // expected-note {{member found by ambiguous name lookup}}
5+
void f(int); // expected-note {{member found by ambiguous name lookup}}
6+
};
7+
struct B {
8+
void operator()(); // expected-note {{member found by ambiguous name lookup}}
9+
void f() {} // expected-note {{member found by ambiguous name lookup}}
10+
};
11+
12+
struct C : A, B {};
13+
14+
int f() {
15+
C c;
16+
c(); // expected-error {{member 'operator()' found in multiple base classes of different types}}
17+
c.f(10); //expected-error {{member 'f' found in multiple base classes of different types}}
18+
return 0;
19+
}
+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// RUN: %clang_cc1 -fsyntax-only -verify %s
2+
3+
struct B1 {
4+
void f();
5+
static void f(int);
6+
int i; // expected-note 2{{member found by ambiguous name lookup}}
7+
};
8+
struct B2 {
9+
void f(double);
10+
};
11+
struct I1: B1 { };
12+
struct I2: B1 { };
13+
14+
struct D: I1, I2, B2 {
15+
using B1::f;
16+
using B2::f;
17+
void g() {
18+
f(); // expected-error {{ambiguous conversion from derived class 'D' to base class 'B1'}}
19+
f(0); // ok
20+
f(0.0); // ok
21+
// FIXME next line should be well-formed
22+
int B1::* mpB1 = &D::i; // expected-error {{non-static member 'i' found in multiple base-class subobjects of type 'B1'}}
23+
int D::* mpD = &D::i; // expected-error {{non-static member 'i' found in multiple base-class subobjects of type 'B1'}}
24+
}
25+
};

Diff for: clang/test/SemaCXX/arrow-operator.cpp

+6-3
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ struct T {
44
};
55

66
struct A {
7-
T* operator->(); // expected-note{{candidate function}}
7+
T* operator->();
8+
// expected-note@-1 {{member found by ambiguous name lookup}}
89
};
910

1011
struct B {
11-
T* operator->(); // expected-note{{candidate function}}
12+
T* operator->();
13+
// expected-note@-1 {{member found by ambiguous name lookup}}
1214
};
1315

1416
struct C : A, B {
@@ -19,7 +21,8 @@ struct D : A { };
1921
struct E; // expected-note {{forward declaration of 'E'}}
2022

2123
void f(C &c, D& d, E& e) {
22-
c->f(); // expected-error{{use of overloaded operator '->' is ambiguous}}
24+
c->f();
25+
// expected-error@-1 {{member 'operator->' found in multiple base classes of different types}}
2326
d->f();
2427
e->f(); // expected-error{{incomplete definition of type}}
2528
}

0 commit comments

Comments
 (0)