Skip to content

Commit c90dac2

Browse files
committed
[clang] Print 32 candidates on the first failure, with -fshow-overloads=best.
Previously, -fshow-overloads=best always showed 4 candidates. The problem is, when this isn't enough, you're kind of up a creek; the only option available is to recompile with different flags. This can be quite expensive! With this change, we try to strike a compromise. The *first* error with more than 4 candidates will show up to 32 candidates. All further errors continue to show only 4 candidates. The hope is that this way, users will have *some chance* of making forward progress, without facing unbounded amounts of error spam. Differential Revision: https://reviews.llvm.org/D95754
1 parent 9678b07 commit c90dac2

File tree

5 files changed

+64
-18
lines changed

5 files changed

+64
-18
lines changed

clang/include/clang/Basic/Diagnostic.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,13 @@ class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> {
273273
// Which overload candidates to show.
274274
OverloadsShown ShowOverloads = Ovl_All;
275275

276+
// With Ovl_Best, the number of overload candidates to show when we encounter
277+
// an error.
278+
//
279+
// The value here is the number of candidates to show in the first nontrivial
280+
// error. Future errors may show a different number of candidates.
281+
unsigned NumOverloadsToShow = 32;
282+
276283
// Cap of # errors emitted, 0 -> no limit.
277284
unsigned ErrorLimit = 0;
278285

@@ -707,6 +714,36 @@ class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> {
707714
}
708715
OverloadsShown getShowOverloads() const { return ShowOverloads; }
709716

717+
/// When a call or operator fails, print out up to this many candidate
718+
/// overloads as suggestions.
719+
///
720+
/// With Ovl_Best, we set a high limit for the first nontrivial overload set
721+
/// we print, and a lower limit for later sets. This way the user has a
722+
/// chance of diagnosing at least one callsite in their program without
723+
/// having to recompile with -fshow-overloads=all.
724+
unsigned getNumOverloadCandidatesToShow() const {
725+
switch (getShowOverloads()) {
726+
case Ovl_All:
727+
// INT_MAX rather than UINT_MAX so that we don't have to think about the
728+
// effect of implicit conversions on this value. In practice we'll never
729+
// hit 2^31 candidates anyway.
730+
return std::numeric_limits<int>::max();
731+
case Ovl_Best:
732+
return NumOverloadsToShow;
733+
}
734+
}
735+
736+
/// Call this after showing N overload candidates. This influences the value
737+
/// returned by later calls to getNumOverloadCandidatesToShow().
738+
void overloadCandidatesShown(unsigned N) {
739+
// Current heuristic: Start out with a large value for NumOverloadsToShow,
740+
// and then once we print one nontrivially-large overload set, decrease it
741+
// for future calls.
742+
if (N > 4) {
743+
NumOverloadsToShow = 4;
744+
}
745+
}
746+
710747
/// Pretend that the last diagnostic issued was ignored, so any
711748
/// subsequent notes will be suppressed, or restore a prior ignoring
712749
/// state after ignoring some diagnostics and their notes, possibly in

clang/lib/Sema/Sema.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2312,9 +2312,7 @@ static void noteOverloads(Sema &S, const UnresolvedSetImpl &Overloads,
23122312
int SuppressedOverloads = 0;
23132313
for (UnresolvedSetImpl::iterator It = Overloads.begin(),
23142314
DeclsEnd = Overloads.end(); It != DeclsEnd; ++It) {
2315-
// FIXME: Magic number for max shown overloads stolen from
2316-
// OverloadCandidateSet::NoteCandidates.
2317-
if (ShownOverloads >= 4 && S.Diags.getShowOverloads() == Ovl_Best) {
2315+
if (ShownOverloads >= S.Diags.getNumOverloadCandidatesToShow()) {
23182316
++SuppressedOverloads;
23192317
continue;
23202318
}
@@ -2330,6 +2328,8 @@ static void noteOverloads(Sema &S, const UnresolvedSetImpl &Overloads,
23302328
++ShownOverloads;
23312329
}
23322330

2331+
S.Diags.overloadCandidatesShown(ShownOverloads);
2332+
23332333
if (SuppressedOverloads)
23342334
S.Diag(FinalNoteLoc, diag::note_ovl_too_many_candidates)
23352335
<< SuppressedOverloads;

clang/lib/Sema/SemaOverload.cpp

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10355,18 +10355,15 @@ void ImplicitConversionSequence::DiagnoseAmbiguousConversion(
1035510355
const PartialDiagnostic &PDiag) const {
1035610356
S.Diag(CaretLoc, PDiag)
1035710357
<< Ambiguous.getFromType() << Ambiguous.getToType();
10358-
// FIXME: The note limiting machinery is borrowed from
10359-
// OverloadCandidateSet::NoteCandidates; there's an opportunity for
10360-
// refactoring here.
10361-
const OverloadsShown ShowOverloads = S.Diags.getShowOverloads();
1036210358
unsigned CandsShown = 0;
1036310359
AmbiguousConversionSequence::const_iterator I, E;
1036410360
for (I = Ambiguous.begin(), E = Ambiguous.end(); I != E; ++I) {
10365-
if (CandsShown >= 4 && ShowOverloads == Ovl_Best)
10361+
if (CandsShown >= S.Diags.getNumOverloadCandidatesToShow())
1036610362
break;
1036710363
++CandsShown;
1036810364
S.NoteOverloadCandidate(I->first, I->second);
1036910365
}
10366+
S.Diags.overloadCandidatesShown(CandsShown);
1037010367
if (I != E)
1037110368
S.Diag(SourceLocation(), diag::note_ovl_too_many_candidates) << int(E - I);
1037210369
}
@@ -11644,7 +11641,7 @@ bool OverloadCandidateSet::shouldDeferDiags(Sema &S, ArrayRef<Expr *> Args,
1164411641
(Cand.Function->template hasAttr<CUDAHostAttr>() &&
1164511642
Cand.Function->template hasAttr<CUDADeviceAttr>());
1164611643
});
11647-
DeferHint = WrongSidedCands.size();
11644+
DeferHint = !WrongSidedCands.empty();
1164811645
}
1164911646
return DeferHint;
1165011647
}
@@ -11677,10 +11674,8 @@ void OverloadCandidateSet::NoteCandidates(Sema &S, ArrayRef<Expr *> Args,
1167711674
for (; I != E; ++I) {
1167811675
OverloadCandidate *Cand = *I;
1167911676

11680-
// Set an arbitrary limit on the number of candidate functions we'll spam
11681-
// the user with. FIXME: This limit should depend on details of the
11682-
// candidate list.
11683-
if (CandsShown >= 4 && ShowOverloads == Ovl_Best) {
11677+
if (CandsShown >= S.Diags.getNumOverloadCandidatesToShow() &&
11678+
ShowOverloads == Ovl_Best) {
1168411679
break;
1168511680
}
1168611681
++CandsShown;
@@ -11709,6 +11704,10 @@ void OverloadCandidateSet::NoteCandidates(Sema &S, ArrayRef<Expr *> Args,
1170911704
}
1171011705
}
1171111706

11707+
// Inform S.Diags that we've shown an overload set with N elements. This may
11708+
// inform the future value of S.Diags.getNumOverloadCandidatesToShow().
11709+
S.Diags.overloadCandidatesShown(CandsShown);
11710+
1171211711
if (I != E)
1171311712
S.Diag(OpLoc, diag::note_ovl_too_many_candidates,
1171411713
shouldDeferDiags(S, Args, OpLoc))

clang/test/SemaCXX/ambiguous-conversion-show-overload.cpp

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,20 @@ struct S {
1010
S(signed int*);
1111
};
1212
void f(const S& s);
13-
void g() {
14-
f(0);
15-
}
13+
14+
// First call to f emits all candidates. Second call emits just the first 4.
15+
void g() { f(0); }
16+
// CHECK: {{conversion from 'int' to 'const S' is ambiguous}}
17+
// CHECK-NEXT: {{candidate constructor}}
18+
// CHECK-NEXT: {{candidate constructor}}
19+
// CHECK-NEXT: {{candidate constructor}}
20+
// CHECK-NEXT: {{candidate constructor}}
21+
// CHECK-NEXT: {{candidate constructor}}
22+
// CHECK-NEXT: {{candidate constructor}}
23+
// CHECK-NEXT: {{candidate constructor}}
24+
// CHECK-NEXT: {{candidate constructor}}
25+
26+
void h() { f(0); }
1627
// CHECK: {{conversion from 'int' to 'const S' is ambiguous}}
1728
// CHECK-NEXT: {{candidate constructor}}
1829
// CHECK-NEXT: {{candidate constructor}}

clang/test/SemaCXX/overloaded-builtin-operators.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,7 @@ struct A {
195195

196196
void test_dr425(A a) {
197197
(void)(1.0f * a); // expected-error{{ambiguous}} \
198-
// expected-note 4{{candidate}} \
199-
// expected-note {{remaining 8 candidates omitted; pass -fshow-overloads=all to show them}}
198+
// expected-note 12{{candidate}}
200199
}
201200

202201
// pr5432

0 commit comments

Comments
 (0)