[clang] [clang][Sema] Add diagnostic note for reference of function-like macros requiring without parentheses (PR #123495)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Feb 12 03:53:50 PST 2025
https://github.com/StarOne01 updated https://github.com/llvm/llvm-project/pull/123495
>From ea6c9ca9cffbf4327fc7bab85e37e2a3c2c0f0cd Mon Sep 17 00:00:00 2001
From: Prashanth <TheStarOne01 at proton.me>
Date: Sun, 19 Jan 2025 07:28:24 +0530
Subject: [PATCH 01/11] [clang][Sema] Add diagnostic note for function-like
macros requiring parentheses
---
clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 ++
clang/lib/Sema/SemaExpr.cpp | 15 ++++++++++++++-
2 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index bcae9e9f30093..d9c8fcc66acf2 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -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' exists, but as a function-like macro; perhaps, did you forget the parentheses?">;
def err_unexpected_typedef : Error<
"unexpected type name %0: expected expression">;
def err_unexpected_namespace : Error<
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 3cd4010740d19..dff03ac31ef2a 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -2522,6 +2522,19 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
DC = DC->getLookupParent();
}
+ // Check whether a similar function-like macro exists and suggest it
+ if (IdentifierInfo *II = Name.getAsIdentifierInfo()) {
+ if (II->hasMacroDefinition()) {
+ MacroInfo *MI = PP.getMacroInfo(II);
+ if (MI && MI->isFunctionLike()) {
+ Diag( R.getNameLoc() ,diag::err_undeclared_var_use) << II->getName();
+ Diag(MI->getDefinitionLoc(), diag::note_function_like_macro_requires_parens)
+ << II->getName();
+ return true;
+ }
+ }
+ }
+
// We didn't find anything, so try to correct for a typo.
TypoCorrection Corrected;
if (S && Out) {
@@ -2632,7 +2645,7 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
<< SS.getRange();
return true;
}
-
+
// Give up, we can't recover.
Diag(R.getNameLoc(), diagnostic) << Name;
return true;
>From c274178a0ce3a510eaaa9390b277b860bcc5a2a9 Mon Sep 17 00:00:00 2001
From: Prashanth <TheStarOne01 at proton.me>
Date: Sun, 19 Jan 2025 08:30:39 +0530
Subject: [PATCH 02/11] [clang][Tests] Modify tests for function-like macros
according to the new behavior and Format the changes
---
clang/include/clang/Basic/DiagnosticSemaKinds.td | 5 +++--
clang/lib/Sema/SemaExpr.cpp | 7 ++++---
clang/test/Preprocessor/macro_with_initializer_list.cpp | 6 ++++--
3 files changed, 11 insertions(+), 7 deletions(-)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index d9c8fcc66acf2..697b92d325240 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5961,8 +5961,9 @@ 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' exists, but as a function-like macro; perhaps, did you forget the parentheses?">;
+def note_function_like_macro_requires_parens
+ : Note<"'%0' exists, but as a function-like macro; perhaps, did you forget "
+ "the parentheses?">;
def err_unexpected_typedef : Error<
"unexpected type name %0: expected expression">;
def err_unexpected_namespace : Error<
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index dff03ac31ef2a..da894dd3a6d6a 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -2527,8 +2527,9 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
if (II->hasMacroDefinition()) {
MacroInfo *MI = PP.getMacroInfo(II);
if (MI && MI->isFunctionLike()) {
- Diag( R.getNameLoc() ,diag::err_undeclared_var_use) << II->getName();
- Diag(MI->getDefinitionLoc(), diag::note_function_like_macro_requires_parens)
+ Diag(R.getNameLoc(), diag::err_undeclared_var_use) << II->getName();
+ Diag(MI->getDefinitionLoc(),
+ diag::note_function_like_macro_requires_parens)
<< II->getName();
return true;
}
@@ -2645,7 +2646,7 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
<< SS.getRange();
return true;
}
-
+
// Give up, we can't recover.
Diag(R.getNameLoc(), diagnostic) << Name;
return true;
diff --git a/clang/test/Preprocessor/macro_with_initializer_list.cpp b/clang/test/Preprocessor/macro_with_initializer_list.cpp
index 40f53164b263d..cc7dae0b5a3e0 100644
--- a/clang/test/Preprocessor/macro_with_initializer_list.cpp
+++ b/clang/test/Preprocessor/macro_with_initializer_list.cpp
@@ -134,6 +134,7 @@ void test_NE() {
// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{110:32-110:32}:")"
#define INIT(var, init) Foo var = init; // expected-note 3{{defined here}}
+// expected-note at -1 2{{'INIT' exists, but as a function-like macro; perhaps, did you forget the parentheses?}}
// 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.
@@ -159,12 +160,13 @@ void test() {
// expected-note at -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 at -2 2{{defined here}}
+// expected-note at -3 {{'M' exists, but as a function-like macro; perhaps, did you forget the parentheses?}}
void test2() {
M(F1, Foo(), Foo(), Foo(), Foo(), Foo(), Foo(),
Foo(), Foo(), Foo(), Foo(), Foo(), Foo());
>From 33e001ee6e852f630fd1b69bea424c6e7166078b Mon Sep 17 00:00:00 2001
From: Prashanth <TheStarOne01 at proton.me>
Date: Mon, 20 Jan 2025 13:34:48 +0530
Subject: [PATCH 03/11] Change the note for reference of function-like macros
requiring without parentheses
Co-authored-by: Sirraide <aeternalmail at gmail.com>
---
clang/include/clang/Basic/DiagnosticSemaKinds.td | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 697b92d325240..6d3a065077d4b 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5962,8 +5962,7 @@ def err_fold_expression_limit_exceeded: Error<
"limit of %1">, DefaultFatal, NoSFINAE;
def note_function_like_macro_requires_parens
- : Note<"'%0' exists, but as a function-like macro; perhaps, did you forget "
- "the parentheses?">;
+ : Note<"'%0' is defined here as a function-like macro; did you mean to write '%0(...)'">;
def err_unexpected_typedef : Error<
"unexpected type name %0: expected expression">;
def err_unexpected_namespace : Error<
>From 5aa4654ffe3f7499faf6f8abc7dbdf3468a8dcb9 Mon Sep 17 00:00:00 2001
From: Prashanth <TheStarOne01 at proton.me>
Date: Tue, 21 Jan 2025 16:20:10 +0530
Subject: [PATCH 04/11] [clang][Tests] Update diagnostic tests for
function-like macros to clarify usage and improve error messages
---
.../Preprocessor/macro_with_initializer_list.cpp | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/clang/test/Preprocessor/macro_with_initializer_list.cpp b/clang/test/Preprocessor/macro_with_initializer_list.cpp
index cc7dae0b5a3e0..f7f645cce1180 100644
--- a/clang/test/Preprocessor/macro_with_initializer_list.cpp
+++ b/clang/test/Preprocessor/macro_with_initializer_list.cpp
@@ -133,8 +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}}
-// expected-note at -1 2{{'INIT' exists, but as a function-like macro; perhaps, did you forget the parentheses?}}
+#define INIT(var, init) Foo var = init; // expected-note 3{{macro 'INIT' defined here}}
+// expected-note at -1 2{{'INIT' is defined here as a function-like macro; did you mean to write 'INIT(...)'}}
// 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.
@@ -166,7 +166,7 @@ void test() {
#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 at -2 2{{defined here}}
-// expected-note at -3 {{'M' exists, but as a function-like macro; perhaps, did you forget the parentheses?}}
+// expected-note at -3 {{'M' is defined here as a function-like macro; did you mean to write 'M(...)'}}
void test2() {
M(F1, Foo(), Foo(), Foo(), Foo(), Foo(), Foo(),
Foo(), Foo(), Foo(), Foo(), Foo(), Foo());
@@ -182,3 +182,11 @@ void test2() {
// expected-error at -3 {{use of undeclared identifier}}
// expected-note at -4 {{cannot use initializer list at the beginning of a macro argument}}
}
+
+#define LIM() 10
+// expected-note at -1 {{'LIM' is defined here as a function-like macro; did you mean to write 'LIM(...)'}}
+
+void test3() {
+ int iter = LIM;
+ // expected-error at -1 {{use of undeclared identifier LIM}}
+}
\ No newline at end of file
>From bd0848786ffb70e6f06b2b93b1b2fae46478484c Mon Sep 17 00:00:00 2001
From: Prashanth <TheStarOne01 at proton.me>
Date: Tue, 21 Jan 2025 16:22:39 +0530
Subject: [PATCH 05/11] Change the note for reference of function-like macros
requiring without parentheses
Co-authored-by: Mariya Podchishchaeva <mariya.podchishchaeva at intel.com>
---
clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 6d3a065077d4b..34ed18e518773 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5962,7 +5962,7 @@ def err_fold_expression_limit_exceeded: Error<
"limit of %1">, DefaultFatal, NoSFINAE;
def note_function_like_macro_requires_parens
- : Note<"'%0' is defined here as a function-like macro; did you mean to write '%0(...)'">;
+ : Note<"'%0' is defined here as a function-like macro; did you mean '%0(...)'">;
def err_unexpected_typedef : Error<
"unexpected type name %0: expected expression">;
def err_unexpected_namespace : Error<
>From 6ef338ab4c2dd123397327fb3de7f1057643fa49 Mon Sep 17 00:00:00 2001
From: Prashanth <TheStarOne01 at proton.me>
Date: Tue, 21 Jan 2025 17:03:21 +0530
Subject: [PATCH 06/11] [clang][Tests] Update diagnostic tests for
function-like macros for the updated note
---
clang/test/Preprocessor/macro_with_initializer_list.cpp | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/clang/test/Preprocessor/macro_with_initializer_list.cpp b/clang/test/Preprocessor/macro_with_initializer_list.cpp
index f7f645cce1180..cf1d137eadcbe 100644
--- a/clang/test/Preprocessor/macro_with_initializer_list.cpp
+++ b/clang/test/Preprocessor/macro_with_initializer_list.cpp
@@ -134,7 +134,7 @@ void test_NE() {
// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{110:32-110:32}:")"
#define INIT(var, init) Foo var = init; // expected-note 3{{macro 'INIT' defined here}}
-// expected-note at -1 2{{'INIT' is defined here as a function-like macro; did you mean to write 'INIT(...)'}}
+// expected-note at -1 2{{'INIT' is defined here as a function-like macro; did you mean 'INIT(...)'}}
// 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.
@@ -166,7 +166,7 @@ void test() {
#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 at -2 2{{defined here}}
-// expected-note at -3 {{'M' is defined here as a function-like macro; did you mean to write 'M(...)'}}
+// expected-note at -3 {{'M' is defined here as a function-like macro; did you mean 'M(...)'}}
void test2() {
M(F1, Foo(), Foo(), Foo(), Foo(), Foo(), Foo(),
Foo(), Foo(), Foo(), Foo(), Foo(), Foo());
@@ -184,7 +184,7 @@ void test2() {
}
#define LIM() 10
-// expected-note at -1 {{'LIM' is defined here as a function-like macro; did you mean to write 'LIM(...)'}}
+// expected-note at -1 {{'LIM' is defined here as a function-like macro; did you mean 'LIM(...)'}}
void test3() {
int iter = LIM;
>From 094887dbe3a521ad4733cd37cbfb5313bbb0dc4e Mon Sep 17 00:00:00 2001
From: Prashanth <TheStarOne01 at proton.me>
Date: Sun, 9 Feb 2025 14:20:36 +0530
Subject: [PATCH 07/11] [clang][Sema] Improve diagnostics for undeclared
function-like macros
---
.../clang/Basic/DiagnosticSemaKinds.td | 4 +-
clang/lib/Sema/SemaExpr.cpp | 43 ++++++++++++-------
.../macro_with_initializer_list.cpp | 14 +-----
clang/test/Sema/typo-correction.c | 22 ++++++++++
4 files changed, 55 insertions(+), 28 deletions(-)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 34ed18e518773..33a3bfe4ff646 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5962,7 +5962,7 @@ def err_fold_expression_limit_exceeded: Error<
"limit of %1">, DefaultFatal, NoSFINAE;
def note_function_like_macro_requires_parens
- : Note<"'%0' is defined here as a function-like macro; did you mean '%0(...)'">;
+ : 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<
@@ -10857,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">;
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index da894dd3a6d6a..27c2cf65762e3 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -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,
@@ -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;
}
@@ -2522,20 +2546,6 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
DC = DC->getLookupParent();
}
- // Check whether a similar function-like macro exists and suggest it
- if (IdentifierInfo *II = Name.getAsIdentifierInfo()) {
- if (II->hasMacroDefinition()) {
- MacroInfo *MI = PP.getMacroInfo(II);
- if (MI && MI->isFunctionLike()) {
- Diag(R.getNameLoc(), diag::err_undeclared_var_use) << II->getName();
- Diag(MI->getDefinitionLoc(),
- diag::note_function_like_macro_requires_parens)
- << II->getName();
- return true;
- }
- }
- }
-
// We didn't find anything, so try to correct for a typo.
TypoCorrection Corrected;
if (S && Out) {
@@ -2638,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()) {
diff --git a/clang/test/Preprocessor/macro_with_initializer_list.cpp b/clang/test/Preprocessor/macro_with_initializer_list.cpp
index cf1d137eadcbe..5f66971622ce7 100644
--- a/clang/test/Preprocessor/macro_with_initializer_list.cpp
+++ b/clang/test/Preprocessor/macro_with_initializer_list.cpp
@@ -134,7 +134,6 @@ void test_NE() {
// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{110:32-110:32}:")"
#define INIT(var, init) Foo var = init; // expected-note 3{{macro 'INIT' defined here}}
-// expected-note at -1 2{{'INIT' is defined here as a function-like macro; did you mean 'INIT(...)'}}
// 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.
@@ -160,13 +159,12 @@ void test() {
// expected-note at -3 {{cannot use initializer list at the beginning of a macro argument}}
}
-// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{146:11-146:11}:"("
-// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{146:23-146:23}:")"
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{145:11-145:11}:"("
+// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{145:23-145: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 at -2 2{{defined here}}
-// expected-note at -3 {{'M' is defined here as a function-like macro; did you mean 'M(...)'}}
void test2() {
M(F1, Foo(), Foo(), Foo(), Foo(), Foo(), Foo(),
Foo(), Foo(), Foo(), Foo(), Foo(), Foo());
@@ -181,12 +179,4 @@ void test2() {
// expected-error at -2 {{too many arguments provided}}
// expected-error at -3 {{use of undeclared identifier}}
// expected-note at -4 {{cannot use initializer list at the beginning of a macro argument}}
-}
-
-#define LIM() 10
-// expected-note at -1 {{'LIM' is defined here as a function-like macro; did you mean 'LIM(...)'}}
-
-void test3() {
- int iter = LIM;
- // expected-error at -1 {{use of undeclared identifier LIM}}
}
\ No newline at end of file
diff --git a/clang/test/Sema/typo-correction.c b/clang/test/Sema/typo-correction.c
index 4157207a9ac42..3efd35538dd58 100644
--- a/clang/test/Sema/typo-correction.c
+++ b/clang/test/Sema/typo-correction.c
@@ -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 at -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 at -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(...)?}}
+}
>From eac145ae3c3de06573cc7cbef40fe5436606e089 Mon Sep 17 00:00:00 2001
From: Prashanth <TheStarOne01 at proton.me>
Date: Sun, 9 Feb 2025 14:50:49 +0530
Subject: [PATCH 08/11] [clang][Tests] Enhance diagnostic notes for
function-like macros in initializer list tests
---
clang/test/Preprocessor/macro_with_initializer_list.cpp | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/clang/test/Preprocessor/macro_with_initializer_list.cpp b/clang/test/Preprocessor/macro_with_initializer_list.cpp
index 5f66971622ce7..dab60e60b14a1 100644
--- a/clang/test/Preprocessor/macro_with_initializer_list.cpp
+++ b/clang/test/Preprocessor/macro_with_initializer_list.cpp
@@ -134,6 +134,7 @@ void test_NE() {
// CHECK: fix-it:"{{.*}}macro_with_initializer_list.cpp":{110:32-110:32}:")"
#define INIT(var, init) Foo var = init; // expected-note 3{{macro 'INIT' defined here}}
+// expected-note at -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.
@@ -159,12 +160,13 @@ void test() {
// expected-note at -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 at -2 2{{defined here}}
+// expected-note at -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());
@@ -179,4 +181,4 @@ void test2() {
// expected-error at -2 {{too many arguments provided}}
// expected-error at -3 {{use of undeclared identifier}}
// expected-note at -4 {{cannot use initializer list at the beginning of a macro argument}}
-}
\ No newline at end of file
+}
>From e7404fb8509f7b2e80782cea27986ee610b69b20 Mon Sep 17 00:00:00 2001
From: Prashanth <TheStarOne01 at proton.me>
Date: Sun, 9 Feb 2025 20:28:12 +0530
Subject: [PATCH 09/11] [clang][Docs] Add release note for diagnosing missing
parentheses in function-like macros
---
clang/docs/ReleaseNotes.rst | 1 +
1 file changed, 1 insertion(+)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 50d3bbbc97e91..a469e5a97a4ac 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -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
----------------------------------
>From e4d2186162e5383d787450c07d81f08d527a429d Mon Sep 17 00:00:00 2001
From: Prashanth <TheStarOne01 at proton.me>
Date: Wed, 12 Feb 2025 09:52:23 +0530
Subject: [PATCH 10/11] [clang][Sema] Improve diagnostics for function-like
macros and update related notes
---
clang/docs/ReleaseNotes.rst | 5 +++--
.../include/clang/Basic/DiagnosticSemaKinds.td | 4 ++--
clang/lib/Sema/SemaExpr.cpp | 18 +++++++++---------
3 files changed, 14 insertions(+), 13 deletions(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index a469e5a97a4ac..c37c3d586de7b 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -128,8 +128,9 @@ 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.
-
+- Clang now provides a diagnostic note for function-like macros that are
+ missing the required parentheses (#GH123038).
+
Improvements to Clang's time-trace
----------------------------------
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 33a3bfe4ff646..e74020f8c8a0e 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10857,8 +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_undeclared_var_use_suggest_func_like_macro : Error<
+ "%0 is defined as an object-like macro; 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">;
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 27c2cf65762e3..26150bcb34967 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -2347,9 +2347,10 @@ 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) {
+// Diagnose when a macro cannot be expanded because it's a function-like macro
+// being used as an object-like macro. Returns true if a diagnostic is emitted.
+static bool diagnoseFunctionLikeMacro(Sema &SemaRef, DeclarationName Name,
+ SourceLocation TypoLoc) {
if (IdentifierInfo *II = Name.getAsIdentifierInfo()) {
if (II->hasMacroDefinition()) {
@@ -2357,7 +2358,7 @@ static bool isFunctionLikeMacro(const DeclarationName &Name, Sema &SemaRef,
if (MI && MI->isFunctionLike()) {
SemaRef.Diag(TypoLoc,
diag::err_undeclared_var_use_suggest_func_like_macro)
- << II->getName();
+ << II;
SemaRef.Diag(MI->getDefinitionLoc(),
diag::note_function_like_macro_requires_parens)
<< II->getName();
@@ -2403,11 +2404,10 @@ static void emitEmptyLookupTypoDiagnostic(
if (Ctx)
SemaRef.Diag(TypoLoc, diag::err_no_member) << Typo << Ctx
<< SS.getRange();
- else {
- if (isFunctionLikeMacro(Typo, SemaRef, TypoLoc))
- return;
+ else if (diagnoseFunctionLikeMacro(SemaRef, Typo, TypoLoc))
+ return;
+ else
SemaRef.Diag(TypoLoc, DiagnosticID) << Typo;
- }
return;
}
@@ -2648,7 +2648,7 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
}
R.clear();
- if (isFunctionLikeMacro(Name, SemaRef, R.getNameLoc()))
+ if (diagnoseFunctionLikeMacro(SemaRef, Name, R.getNameLoc()))
return true;
// Emit a special diagnostic for failed member lookups.
>From cc50469f3fbbe3d9cb877386abad68b59a84c816 Mon Sep 17 00:00:00 2001
From: Prashanth <TheStarOne01 at proton.me>
Date: Wed, 12 Feb 2025 16:17:08 +0530
Subject: [PATCH 11/11] [clang][Sema] Update diagnostic tests for object-like
macros in initializer list tests
---
clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 +-
clang/lib/Sema/SemaExpr.cpp | 2 +-
clang/test/Preprocessor/macro_with_initializer_list.cpp | 6 +++---
clang/test/Sema/typo-correction.c | 8 ++++----
4 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index e74020f8c8a0e..bafc2308f522f 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10858,7 +10858,7 @@ def err_undeclared_use_suggest : Error<
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<
- "%0 is defined as an object-like macro; did you mean '%0(...)'?">;
+ "'%0' is defined as an object-like macro; 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">;
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 26150bcb34967..c3b5c705178a1 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -2358,7 +2358,7 @@ static bool diagnoseFunctionLikeMacro(Sema &SemaRef, DeclarationName Name,
if (MI && MI->isFunctionLike()) {
SemaRef.Diag(TypoLoc,
diag::err_undeclared_var_use_suggest_func_like_macro)
- << II;
+ << II ->getName();
SemaRef.Diag(MI->getDefinitionLoc(),
diag::note_function_like_macro_requires_parens)
<< II->getName();
diff --git a/clang/test/Preprocessor/macro_with_initializer_list.cpp b/clang/test/Preprocessor/macro_with_initializer_list.cpp
index dab60e60b14a1..d9e653106d4a1 100644
--- a/clang/test/Preprocessor/macro_with_initializer_list.cpp
+++ b/clang/test/Preprocessor/macro_with_initializer_list.cpp
@@ -150,13 +150,13 @@ void test() {
// Can't be fixed by parentheses.
INIT(e, {1, 2, 3});
// expected-error at -1 {{too many arguments provided}}
- // expected-error at -2 {{use of undeclared identifier}}
+ // expected-error at -2 {{'INIT' is defined as an object-like macro; did you mean 'INIT(...)'?}}
// expected-note at -3 {{cannot use initializer list at the beginning of a macro argument}}
// Can't be fixed by parentheses.
INIT(e, {1, 2, 3} + {1, 2, 3});
// expected-error at -1 {{too many arguments provided}}
- // expected-error at -2 {{use of undeclared identifier}}
+ // expected-error at -2 {{'INIT' is defined as an object-like macro; did you mean 'INIT(...)'?}}
// expected-note at -3 {{cannot use initializer list at the beginning of a macro argument}}
}
@@ -179,6 +179,6 @@ void test2() {
M(F3, {1,2,3}, {1,2,3}, {1,2,3}, {1,2,3}, {1,2,3}, {1,2,3},
{1,2,3}, {1,2,3}, {1,2,3}, {1,2,3}, {1,2,3}, {1,2,3});
// expected-error at -2 {{too many arguments provided}}
- // expected-error at -3 {{use of undeclared identifier}}
+ // expected-error at -3 {{'M' is defined as an object-like macro; did you mean 'M(...)'?}}
// expected-note at -4 {{cannot use initializer list at the beginning of a macro argument}}
}
diff --git a/clang/test/Sema/typo-correction.c b/clang/test/Sema/typo-correction.c
index 3efd35538dd58..e16ad78583223 100644
--- a/clang/test/Sema/typo-correction.c
+++ b/clang/test/Sema/typo-correction.c
@@ -118,11 +118,11 @@ void PR40286_4(int the_value) { // expected-note {{'the_value' declared here}}
#define FOO1() 10
// expected-note at -1 4 {{'FOO1' defined here as a function-like macro}}
-int x = FOO1; // expected-error {{use of undeclared identifier FOO1; did you mean FOO1(...)?}}
+int x = FOO1; // expected-error {{'FOO1' is defined as an object-like macro; did you mean 'FOO1(...)'?}}
void test3() {
int iter = FOO1;
- // expected-error at -1 {{use of undeclared identifier FOO1; did you mean FOO1(...)?}}
+ // expected-error at -1 {{'FOO1' is defined as an object-like macro; did you mean 'FOO1(...)'?}}
}
void bar(int);
@@ -133,6 +133,6 @@ void test4() {
}
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(...)?}}
+ FOO1 + 1; // expected-error {{'FOO1' is defined as an object-like macro; did you mean 'FOO1(...)'?}}
+ bar(FOO1); // expected-error {{'FOO1' is defined as an object-like macro; did you mean 'FOO1'(...)'?}}
}
More information about the cfe-commits
mailing list