Skip to content

Commit 176981a

Browse files
committed
[clang][Diagnostics] Fix distant source ranges in bad-conversion notes
Now that clang supports printing of multiple lines of code snippet in diagnostics, source ranges in diagnostics that are located in different lines from the diagnosed source location get to be printed if the gap happened to be less than the maximum number of lines clang is allowed to print in. Many of the bad-conversion notes in overload resolution failures have their source location in the function declaration and source range in the argument of function call. This can cause an unnecessarily many lines of snippet printing. This patch fixes it by changing the source range from function callsite to the problematic parameter in function declaration. e.g. ``` void func(int aa, int bb); void test() { func(1, "two"); } ``` BEFORE this patch: ``` source:4:15: error: no matching function for call to 'func' 4 | void test() { func(1, "two"); } | ^~~~ source:1:6: note: candidate function not viable: no known conversion from 'const char[4]' to 'int' for 2nd argument 1 | void func(int aa, int bb); | ^ 2 | 3 | 4 | void test() { func(1, "two"); } | ~~~~~ 1 error generated. ``` AFTER this patch: ``` source:4:15: error: no matching function for call to 'func' 4 | void test() { func(1, "two"); } | ^~~~ source:1:6: note: candidate function not viable: no known conversion from 'const char[4]' to 'int' for 2nd argument 1 | void func(int aa, int bb); | ^ ~~~~~~ ``` Reviewed By: cjdb Differential Revision: https://reviews.llvm.org/D153359
1 parent 6e55370 commit 176981a

File tree

4 files changed

+157
-36
lines changed

4 files changed

+157
-36
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,37 @@ Improvements to Clang's diagnostics
384384
(`#57081: <https://github.com/llvm/llvm-project/issues/57081>`_)
385385
- Clang no longer emits inappropriate notes about the loss of ``__unaligned`` qualifier
386386
on overload resolution, when the actual reason for the failure is loss of other qualifiers.
387+
- Clang's notes about unconvertible types in overload resolution failure now covers
388+
the source range of parameter declaration of the candidate function declaration.
389+
390+
*Example Code*:
391+
392+
.. code-block:: c++
393+
394+
void func(int aa, int bb);
395+
void test() { func(1, "two"); }
396+
397+
*BEFORE*:
398+
399+
.. code-block:: text
400+
401+
source:2:15: error: no matching function for call to 'func'
402+
void test() { func(1, "two"); }
403+
^~~~
404+
source:1:6: note: candidate function not viable: no known conversion from 'const char[4]' to 'int' for 2nd argument
405+
void func(int aa, int bb);
406+
^
407+
408+
*AFTER*:
409+
410+
.. code-block:: text
411+
412+
source:2:15: error: no matching function for call to 'func'
413+
void test() { func(1, "two"); }
414+
^~~~
415+
source:1:6: note: candidate function not viable: no known conversion from 'const char[4]' to 'int' for 2nd argument
416+
void func(int aa, int bb);
417+
^ ~~~~~~
387418
388419
Bug Fixes in This Version
389420
-------------------------

clang/lib/Sema/SemaOverload.cpp

Lines changed: 28 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -10753,6 +10753,8 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
1075310753
Expr *FromExpr = Conv.Bad.FromExpr;
1075410754
QualType FromTy = Conv.Bad.getFromType();
1075510755
QualType ToTy = Conv.Bad.getToType();
10756+
SourceRange ToParamRange =
10757+
!isObjectArgument ? Fn->getParamDecl(I)->getSourceRange() : SourceRange();
1075610758

1075710759
if (FromTy == S.Context.OverloadTy) {
1075810760
assert(FromExpr && "overload set argument came from implicit argument?");
@@ -10763,8 +10765,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
1076310765

1076410766
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_overload)
1076510767
<< (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc
10766-
<< (FromExpr ? FromExpr->getSourceRange() : SourceRange()) << ToTy
10767-
<< Name << I + 1;
10768+
<< ToParamRange << ToTy << Name << I + 1;
1076810769
MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
1076910770
return;
1077010771
}
@@ -10793,34 +10794,30 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
1079310794
if (isObjectArgument)
1079410795
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_addrspace_this)
1079510796
<< (unsigned)FnKindPair.first << (unsigned)FnKindPair.second
10796-
<< FnDesc << (FromExpr ? FromExpr->getSourceRange() : SourceRange())
10797-
<< FromQs.getAddressSpace() << ToQs.getAddressSpace();
10797+
<< FnDesc << FromQs.getAddressSpace() << ToQs.getAddressSpace();
1079810798
else
1079910799
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_addrspace)
1080010800
<< (unsigned)FnKindPair.first << (unsigned)FnKindPair.second
10801-
<< FnDesc << (FromExpr ? FromExpr->getSourceRange() : SourceRange())
10802-
<< FromQs.getAddressSpace() << ToQs.getAddressSpace()
10803-
<< ToTy->isReferenceType() << I + 1;
10801+
<< FnDesc << ToParamRange << FromQs.getAddressSpace()
10802+
<< ToQs.getAddressSpace() << ToTy->isReferenceType() << I + 1;
1080410803
MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
1080510804
return;
1080610805
}
1080710806

1080810807
if (FromQs.getObjCLifetime() != ToQs.getObjCLifetime()) {
1080910808
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_ownership)
1081010809
<< (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc
10811-
<< (FromExpr ? FromExpr->getSourceRange() : SourceRange()) << FromTy
10812-
<< FromQs.getObjCLifetime() << ToQs.getObjCLifetime()
10813-
<< (unsigned)isObjectArgument << I + 1;
10810+
<< ToParamRange << FromTy << FromQs.getObjCLifetime()
10811+
<< ToQs.getObjCLifetime() << (unsigned)isObjectArgument << I + 1;
1081410812
MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
1081510813
return;
1081610814
}
1081710815

1081810816
if (FromQs.getObjCGCAttr() != ToQs.getObjCGCAttr()) {
1081910817
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_gc)
1082010818
<< (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc
10821-
<< (FromExpr ? FromExpr->getSourceRange() : SourceRange()) << FromTy
10822-
<< FromQs.getObjCGCAttr() << ToQs.getObjCGCAttr()
10823-
<< (unsigned)isObjectArgument << I + 1;
10819+
<< ToParamRange << FromTy << FromQs.getObjCGCAttr()
10820+
<< ToQs.getObjCGCAttr() << (unsigned)isObjectArgument << I + 1;
1082410821
MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
1082510822
return;
1082610823
}
@@ -10831,13 +10828,11 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
1083110828
if (isObjectArgument) {
1083210829
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_cvr_this)
1083310830
<< (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc
10834-
<< (FromExpr ? FromExpr->getSourceRange() : SourceRange()) << FromTy
10835-
<< (CVR - 1);
10831+
<< FromTy << (CVR - 1);
1083610832
} else {
1083710833
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_cvr)
1083810834
<< (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc
10839-
<< (FromExpr ? FromExpr->getSourceRange() : SourceRange()) << FromTy
10840-
<< (CVR - 1) << I + 1;
10835+
<< ToParamRange << FromTy << (CVR - 1) << I + 1;
1084110836
}
1084210837
MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
1084310838
return;
@@ -10849,7 +10844,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
1084910844
<< (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc
1085010845
<< (unsigned)isObjectArgument << I + 1
1085110846
<< (Conv.Bad.Kind == BadConversionSequence::rvalue_ref_to_lvalue)
10852-
<< (FromExpr ? FromExpr->getSourceRange() : SourceRange());
10847+
<< ToParamRange;
1085310848
MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
1085410849
return;
1085510850
}
@@ -10859,8 +10854,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
1085910854
if (FromExpr && isa<InitListExpr>(FromExpr)) {
1086010855
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_list_argument)
1086110856
<< (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc
10862-
<< FromExpr->getSourceRange() << FromTy << ToTy
10863-
<< (unsigned)isObjectArgument << I + 1
10857+
<< ToParamRange << FromTy << ToTy << (unsigned)isObjectArgument << I + 1
1086410858
<< (Conv.Bad.Kind == BadConversionSequence::too_few_initializers ? 1
1086510859
: Conv.Bad.Kind == BadConversionSequence::too_many_initializers
1086610860
? 2
@@ -10879,8 +10873,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
1087910873
// Emit the generic diagnostic and, optionally, add the hints to it.
1088010874
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_conv_incomplete)
1088110875
<< (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc
10882-
<< (FromExpr ? FromExpr->getSourceRange() : SourceRange()) << FromTy
10883-
<< ToTy << (unsigned)isObjectArgument << I + 1
10876+
<< ToParamRange << FromTy << ToTy << (unsigned)isObjectArgument << I + 1
1088410877
<< (unsigned)(Cand->Fix.Kind);
1088510878

1088610879
MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
@@ -10921,24 +10914,24 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
1092110914
if (BaseToDerivedConversion) {
1092210915
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_base_to_derived_conv)
1092310916
<< (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc
10924-
<< (FromExpr ? FromExpr->getSourceRange() : SourceRange())
10925-
<< (BaseToDerivedConversion - 1) << FromTy << ToTy << I + 1;
10917+
<< ToParamRange << (BaseToDerivedConversion - 1) << FromTy << ToTy
10918+
<< I + 1;
1092610919
MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
1092710920
return;
1092810921
}
1092910922

1093010923
if (isa<ObjCObjectPointerType>(CFromTy) &&
1093110924
isa<PointerType>(CToTy)) {
10932-
Qualifiers FromQs = CFromTy.getQualifiers();
10933-
Qualifiers ToQs = CToTy.getQualifiers();
10934-
if (FromQs.getObjCLifetime() != ToQs.getObjCLifetime()) {
10935-
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_arc_conv)
10936-
<< (unsigned)FnKindPair.first << (unsigned)FnKindPair.second
10937-
<< FnDesc << (FromExpr ? FromExpr->getSourceRange() : SourceRange())
10938-
<< FromTy << ToTy << (unsigned)isObjectArgument << I + 1;
10939-
MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
10940-
return;
10941-
}
10925+
Qualifiers FromQs = CFromTy.getQualifiers();
10926+
Qualifiers ToQs = CToTy.getQualifiers();
10927+
if (FromQs.getObjCLifetime() != ToQs.getObjCLifetime()) {
10928+
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_arc_conv)
10929+
<< (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc
10930+
<< ToParamRange << FromTy << ToTy << (unsigned)isObjectArgument
10931+
<< I + 1;
10932+
MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
10933+
return;
10934+
}
1094210935
}
1094310936

1094410937
if (TakingCandidateAddress &&
@@ -10948,8 +10941,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
1094810941
// Emit the generic diagnostic and, optionally, add the hints to it.
1094910942
PartialDiagnostic FDiag = S.PDiag(diag::note_ovl_candidate_bad_conv);
1095010943
FDiag << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc
10951-
<< (FromExpr ? FromExpr->getSourceRange() : SourceRange()) << FromTy
10952-
<< ToTy << (unsigned)isObjectArgument << I + 1
10944+
<< ToParamRange << FromTy << ToTy << (unsigned)isObjectArgument << I + 1
1095310945
<< (unsigned)(Cand->Fix.Kind);
1095410946

1095510947
// Check that location of Fn is not in system header.
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-print-source-range-info %s 2>&1 | FileCheck %s --strict-whitespace
2+
// CHECK: error: no matching function
3+
template <typename T> struct mcdata {
4+
typedef int result_type;
5+
};
6+
template <class T> typename mcdata<T>::result_type wrap_mean(mcdata<T> const &);
7+
// CHECK: :{[[@LINE+1]]:19-[[@LINE+1]]:53}: note: {{.*}}: no overload of 'wrap_mean'
8+
void add_property(double (*)(mcdata<double> const &));
9+
void f() { add_property(&wrap_mean); }
10+
11+
// CHECK: error: no matching function
12+
// CHECK: :{[[@LINE+1]]:10-[[@LINE+1]]:51}: note: {{.*}}: cannot pass pointer to generic address space
13+
void baz(__attribute__((opencl_private)) int *Data) {}
14+
void fizz() {
15+
int *Nop;
16+
baz(Nop);
17+
// CHECK: error: no matching function
18+
// CHECK: :[[@LINE+1]]:53: note: {{.*}}: 'this' object is in address space '__private'
19+
__attribute__((opencl_private)) static auto err = [&]() {};
20+
err();
21+
}
22+
23+
// CHECK: error: no matching function
24+
struct Bar {
25+
// CHECK: :{[[@LINE+1]]:26-[[@LINE+1]]:32}: note: {{.*}} would lose const qualifier
26+
static void foo(int num, int *X) {}
27+
// CHECK: :{[[@LINE+1]]:17-[[@LINE+1]]:25}: note: {{.*}} no known conversion
28+
static void foo(int *err, int *x) {}
29+
};
30+
void bar(const int *Y) {
31+
Bar::foo(5, Y);
32+
}
33+
34+
struct InComp;
35+
36+
struct A {};
37+
struct B : public A{};
38+
// CHECK: error: no matching function
39+
// CHECK: :{[[@LINE+5]]:36-[[@LINE+5]]:50}: note: {{.*}}: cannot convert initializer
40+
// CHECK: error: no matching function
41+
// CHECK: :{[[@LINE+3]]:36-[[@LINE+3]]:50}: note: {{.*}}: cannot convert argument
42+
// CHECK: error: no matching function
43+
// CHECK: :{[[@LINE+1]]:11-[[@LINE+1]]:18}: note: {{.*}}: no known conversion
44+
void hoge(char aa, const char *bb, const A& third);
45+
46+
// CHECK: error: no matching function
47+
// CHECK: :{[[@LINE+1]]:14-[[@LINE+1]]:16}: note: {{.*}}: cannot convert from base class
48+
void derived(B*);
49+
50+
void func(const A &arg) {
51+
hoge(1, "pass", {{{arg}}});
52+
InComp *a;
53+
hoge(1, "pass", a);
54+
hoge("first", 5, 6);
55+
A *b;
56+
derived(b);
57+
}
58+
59+
struct Q {
60+
// CHECK: error: invalid operands
61+
// CHECK: :[[@LINE+1]]:6: note: {{.*}}: 'this' argument has type 'const Q'
62+
Q &operator+(void*);
63+
};
64+
65+
void fuga(const Q q) { q + 3; }
66+
67+
template <short T> class Type1 {};
68+
// CHECK: error: no matching function
69+
// CHECK: :{[[@LINE+1]]:43-[[@LINE+1]]:54}: note: {{.*}}: expects an lvalue
70+
template <short T> void Function1(int zz, Type1<T> &x, int ww) {}
71+
72+
void Function() { Function1(33, Type1<-42>(), 66); }
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// RUN: not %clang_cc1 -fobjc-runtime-has-weak -fobjc-arc -fsyntax-only -fdiagnostics-print-source-range-info %s 2>&1 | FileCheck %s --strict-whitespace -check-prefixes=CHECK,ARC
2+
// RUN: not %clang_cc1 -fobjc-runtime-has-weak -fobjc-gc -fsyntax-only -fdiagnostics-print-source-range-info %s 2>&1 | FileCheck %s --strict-whitespace -check-prefixes=CHECK,GC
3+
4+
// CHECK: error: no matching function
5+
// CHECK: :{[[@LINE+1]]:15-[[@LINE+1]]:28}: note: {{.*}}: 1st argument
6+
void powerful(__strong id &);
7+
void lifetime_gcattr_mismatch() {
8+
static __weak id weak_id;
9+
powerful(weak_id);
10+
}
11+
12+
// CHECK: error: no matching function
13+
// ARC: :{[[@LINE+2]]:11-[[@LINE+2]]:21}: note: {{.*}}: cannot implicitly convert
14+
// GC: :{[[@LINE+1]]:11-[[@LINE+1]]:21}: note: {{.*}}: no known conversion
15+
void func(char *uiui);
16+
17+
__attribute__((objc_root_class))
18+
@interface Interface
19+
- (void)something;
20+
@end
21+
22+
@implementation Interface
23+
- (void)something{
24+
func(self);
25+
}
26+
@end

0 commit comments

Comments
 (0)