Skip to content

Commit 094887d

Browse files
committed
[clang][Sema] Improve diagnostics for undeclared function-like macros
1 parent 6ef338a commit 094887d

File tree

4 files changed

+55
-28
lines changed

4 files changed

+55
-28
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5962,7 +5962,7 @@ def err_fold_expression_limit_exceeded: Error<
59625962
"limit of %1">, DefaultFatal, NoSFINAE;
59635963

59645964
def note_function_like_macro_requires_parens
5965-
: Note<"'%0' is defined here as a function-like macro; did you mean '%0(...)'">;
5965+
: Note<"'%0' defined here as a function-like macro">;
59665966
def err_unexpected_typedef : Error<
59675967
"unexpected type name %0: expected expression">;
59685968
def err_unexpected_namespace : Error<
@@ -10857,6 +10857,8 @@ def err_undeclared_use_suggest : Error<
1085710857
"use of undeclared %0; did you mean %1?">;
1085810858
def err_undeclared_var_use_suggest : Error<
1085910859
"use of undeclared identifier %0; did you mean %1?">;
10860+
def err_undeclared_var_use_suggest_func_like_macro
10861+
: Error<"use of undeclared identifier %0; did you mean %0(...)?">;
1086010862
def err_no_template : Error<"no template named %0">;
1086110863
def err_no_template_suggest : Error<"no template named %0; did you mean %1?">;
1086210864
def err_no_member_template : Error<"no template named %0 in %1">;

clang/lib/Sema/SemaExpr.cpp

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2347,6 +2347,27 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
23472347
return E;
23482348
}
23492349

2350+
// Check whether a similar function-like macro exists and suggest it
2351+
static bool isFunctionLikeMacro(const DeclarationName &Name, Sema &SemaRef,
2352+
const SourceLocation &TypoLoc) {
2353+
2354+
if (IdentifierInfo *II = Name.getAsIdentifierInfo()) {
2355+
if (II->hasMacroDefinition()) {
2356+
MacroInfo *MI = SemaRef.PP.getMacroInfo(II);
2357+
if (MI && MI->isFunctionLike()) {
2358+
SemaRef.Diag(TypoLoc,
2359+
diag::err_undeclared_var_use_suggest_func_like_macro)
2360+
<< II->getName();
2361+
SemaRef.Diag(MI->getDefinitionLoc(),
2362+
diag::note_function_like_macro_requires_parens)
2363+
<< II->getName();
2364+
return true;
2365+
}
2366+
}
2367+
}
2368+
return false;
2369+
}
2370+
23502371
void
23512372
Sema::DecomposeUnqualifiedId(const UnqualifiedId &Id,
23522373
TemplateArgumentListInfo &Buffer,
@@ -2382,8 +2403,11 @@ static void emitEmptyLookupTypoDiagnostic(
23822403
if (Ctx)
23832404
SemaRef.Diag(TypoLoc, diag::err_no_member) << Typo << Ctx
23842405
<< SS.getRange();
2385-
else
2406+
else {
2407+
if (isFunctionLikeMacro(Typo, SemaRef, TypoLoc))
2408+
return;
23862409
SemaRef.Diag(TypoLoc, DiagnosticID) << Typo;
2410+
}
23872411
return;
23882412
}
23892413

@@ -2522,20 +2546,6 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
25222546
DC = DC->getLookupParent();
25232547
}
25242548

2525-
// Check whether a similar function-like macro exists and suggest it
2526-
if (IdentifierInfo *II = Name.getAsIdentifierInfo()) {
2527-
if (II->hasMacroDefinition()) {
2528-
MacroInfo *MI = PP.getMacroInfo(II);
2529-
if (MI && MI->isFunctionLike()) {
2530-
Diag(R.getNameLoc(), diag::err_undeclared_var_use) << II->getName();
2531-
Diag(MI->getDefinitionLoc(),
2532-
diag::note_function_like_macro_requires_parens)
2533-
<< II->getName();
2534-
return true;
2535-
}
2536-
}
2537-
}
2538-
25392549
// We didn't find anything, so try to correct for a typo.
25402550
TypoCorrection Corrected;
25412551
if (S && Out) {
@@ -2638,6 +2648,9 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
26382648
}
26392649
R.clear();
26402650

2651+
if (isFunctionLikeMacro(Name, SemaRef, R.getNameLoc()))
2652+
return true;
2653+
26412654
// Emit a special diagnostic for failed member lookups.
26422655
// FIXME: computing the declaration context might fail here (?)
26432656
if (!SS.isEmpty()) {

clang/test/Preprocessor/macro_with_initializer_list.cpp

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,6 @@ void test_NE() {
134134
// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{110:32-110:32}:")"
135135

136136
#define INIT(var, init) Foo var = init; // expected-note 3{{macro 'INIT' defined here}}
137-
// expected-note@-1 2{{'INIT' is defined here as a function-like macro; did you mean 'INIT(...)'}}
138137
// Can't use an initializer list as a macro argument. The commas in the list
139138
// will be interpretted as argument separaters and adding parenthesis will
140139
// make it no longer an initializer list.
@@ -160,13 +159,12 @@ void test() {
160159
// expected-note@-3 {{cannot use initializer list at the beginning of a macro argument}}
161160
}
162161

163-
// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{146:11-146:11}:"("
164-
// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{146:23-146:23}:")"
162+
// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{145:11-145:11}:"("
163+
// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{145:23-145:23}:")"
165164

166165
#define M(name,a,b,c,d,e,f,g,h,i,j,k,l) \
167166
Foo name = a + b + c + d + e + f + g + h + i + j + k + l;
168167
// expected-note@-2 2{{defined here}}
169-
// expected-note@-3 {{'M' is defined here as a function-like macro; did you mean 'M(...)'}}
170168
void test2() {
171169
M(F1, Foo(), Foo(), Foo(), Foo(), Foo(), Foo(),
172170
Foo(), Foo(), Foo(), Foo(), Foo(), Foo());
@@ -181,12 +179,4 @@ void test2() {
181179
// expected-error@-2 {{too many arguments provided}}
182180
// expected-error@-3 {{use of undeclared identifier}}
183181
// expected-note@-4 {{cannot use initializer list at the beginning of a macro argument}}
184-
}
185-
186-
#define LIM() 10
187-
// expected-note@-1 {{'LIM' is defined here as a function-like macro; did you mean 'LIM(...)'}}
188-
189-
void test3() {
190-
int iter = LIM;
191-
// expected-error@-1 {{use of undeclared identifier LIM}}
192182
}

clang/test/Sema/typo-correction.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,3 +114,25 @@ void PR40286_3(int the_value) {
114114
void PR40286_4(int the_value) { // expected-note {{'the_value' declared here}}
115115
PR40286_h(the_value, the_value, the_walue); // expected-error {{use of undeclared identifier 'the_walue'; did you mean 'the_value'?}}
116116
}
117+
118+
#define FOO1() 10
119+
// expected-note@-1 4 {{'FOO1' defined here as a function-like macro}}
120+
121+
int x = FOO1; // expected-error {{use of undeclared identifier FOO1; did you mean FOO1(...)?}}
122+
123+
void test3() {
124+
int iter = FOO1;
125+
// expected-error@-1 {{use of undeclared identifier FOO1; did you mean FOO1(...)?}}
126+
}
127+
128+
void bar(int);
129+
130+
void test4() {
131+
int FOO; // expected-note {{'FOO' declared here}}
132+
int x = FOO1; // expected-error {{use of undeclared identifier 'FOO1'; did you mean 'FOO'?}}
133+
}
134+
135+
void test5() {
136+
FOO1 + 1; // expected-error {{use of undeclared identifier FOO1; did you mean FOO1(...)?}}
137+
bar(FOO1); // expected-error {{use of undeclared identifier FOO1; did you mean FOO1(...)?}}
138+
}

0 commit comments

Comments
 (0)