Skip to content
Open
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ Improvements to Clang's diagnostics
which are supposed to only exist once per program, but may get duplicated when
built into a shared library.
- Fixed a bug where Clang's Analysis did not correctly model the destructor behavior of ``union`` members (#GH119415).
- Clang now provides a diagnostic note for ``function-like macros`` that are missing the required parentheses.

Improvements to Clang's time-trace
----------------------------------
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -5961,6 +5961,8 @@ def err_fold_expression_limit_exceeded: Error<
"instantiating fold expression with %0 arguments exceeded expression nesting "
"limit of %1">, DefaultFatal, NoSFINAE;

def note_function_like_macro_requires_parens
: Note<"'%0' defined here as a function-like macro">;
def err_unexpected_typedef : Error<
"unexpected type name %0: expected expression">;
def err_unexpected_namespace : Error<
Expand Down Expand Up @@ -10855,6 +10857,8 @@ def err_undeclared_use_suggest : Error<
"use of undeclared %0; did you mean %1?">;
def err_undeclared_var_use_suggest : Error<
"use of undeclared identifier %0; did you mean %1?">;
def err_undeclared_var_use_suggest_func_like_macro
: Error<"use of undeclared identifier %0; did you mean %0(...)?">;
def err_no_template : Error<"no template named %0">;
def err_no_template_suggest : Error<"no template named %0; did you mean %1?">;
def err_no_member_template : Error<"no template named %0 in %1">;
Expand Down
29 changes: 28 additions & 1 deletion clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2347,6 +2347,27 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
return E;
}

// Check whether a similar function-like macro exists and suggest it
static bool isFunctionLikeMacro(const DeclarationName &Name, Sema &SemaRef,
const SourceLocation &TypoLoc) {

if (IdentifierInfo *II = Name.getAsIdentifierInfo()) {
if (II->hasMacroDefinition()) {
MacroInfo *MI = SemaRef.PP.getMacroInfo(II);
if (MI && MI->isFunctionLike()) {
SemaRef.Diag(TypoLoc,
diag::err_undeclared_var_use_suggest_func_like_macro)
<< II->getName();
SemaRef.Diag(MI->getDefinitionLoc(),
diag::note_function_like_macro_requires_parens)
<< II->getName();
return true;
}
}
}
return false;
}

void
Sema::DecomposeUnqualifiedId(const UnqualifiedId &Id,
TemplateArgumentListInfo &Buffer,
Expand Down Expand Up @@ -2382,8 +2403,11 @@ static void emitEmptyLookupTypoDiagnostic(
if (Ctx)
SemaRef.Diag(TypoLoc, diag::err_no_member) << Typo << Ctx
<< SS.getRange();
else
else {
if (isFunctionLikeMacro(Typo, SemaRef, TypoLoc))
return;
SemaRef.Diag(TypoLoc, DiagnosticID) << Typo;
}
return;
}

Expand Down Expand Up @@ -2624,6 +2648,9 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
}
R.clear();

if (isFunctionLikeMacro(Name, SemaRef, R.getNameLoc()))
return true;

// Emit a special diagnostic for failed member lookups.
// FIXME: computing the declaration context might fail here (?)
if (!SS.isEmpty()) {
Expand Down
8 changes: 5 additions & 3 deletions clang/test/Preprocessor/macro_with_initializer_list.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,8 @@ void test_NE() {
// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{110:9-110:9}:"("
// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{110:32-110:32}:")"

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

// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{145:11-145:11}:"("
// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{145:23-145:23}:")"
// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{146:11-146:11}:"("
// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{146:23-146:23}:")"

#define M(name,a,b,c,d,e,f,g,h,i,j,k,l) \
Foo name = a + b + c + d + e + f + g + h + i + j + k + l;
// expected-note@-2 2{{defined here}}
// expected-note@-3 {{'M' defined here as a function-like macro}}
void test2() {
M(F1, Foo(), Foo(), Foo(), Foo(), Foo(), Foo(),
Foo(), Foo(), Foo(), Foo(), Foo(), Foo());
Expand Down
22 changes: 22 additions & 0 deletions clang/test/Sema/typo-correction.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,25 @@ void PR40286_3(int the_value) {
void PR40286_4(int the_value) { // expected-note {{'the_value' declared here}}
PR40286_h(the_value, the_value, the_walue); // expected-error {{use of undeclared identifier 'the_walue'; did you mean 'the_value'?}}
}

#define FOO1() 10
// expected-note@-1 4 {{'FOO1' defined here as a function-like macro}}

int x = FOO1; // expected-error {{use of undeclared identifier FOO1; did you mean FOO1(...)?}}

void test3() {
int iter = FOO1;
// expected-error@-1 {{use of undeclared identifier FOO1; did you mean FOO1(...)?}}
}

void bar(int);

void test4() {
int FOO; // expected-note {{'FOO' declared here}}
int x = FOO1; // expected-error {{use of undeclared identifier 'FOO1'; did you mean 'FOO'?}}
}

void test5() {
FOO1 + 1; // expected-error {{use of undeclared identifier FOO1; did you mean FOO1(...)?}}
bar(FOO1); // expected-error {{use of undeclared identifier FOO1; did you mean FOO1(...)?}}
}