https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92167
Bug ID: 92167
Summary: Poor source location choice for diagnostic in macro
expansion
Product: gcc
Version: 9.2.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c
Assignee: unassigned at gcc dot gnu.org
Reporter: achurch+gcc at achurch dot org
Target Milestone: ---
Given a macro which expands to a function call and passes a macro argument as
an argument in that call, if the macro argument is parenthesized, a diagnostic
triggered by an improper argument in an invocation will be associated with the
macro definition rather than the invocation. For example:
-----------------------------
$ cat test.c
extern int a(void *);
#define b(x) a((x))
int c(int x) {return b(x);}
$ gcc-9.2.0 -c test.c
test.c: In function 'c':
test.c:2:16: warning: passing argument 1 of 'a' makes pointer from integer
without a cast [-Wint-conversion]
2 | #define b(x) a((x))
| ^~~
| |
| int
test.c:3:22: note: in expansion of macro 'b'
3 | int c(int x) {return b(x);}
| ^
test.c:1:14: note: expected 'void *' but argument is of type 'int'
1 | extern int a(void *);
| ^~~~~~
-----------------------------
The invocation is also shown as a note, but one must read through the list of
notes in order to find it rather than simply checking the line given with the
diagnostic itself. It would arguably be more useful to associate the
diagnostic with the macro invocation on line 3 and include the macro expansion
as a note, as Clang does:
-----------------------------
$ clang-9 -c test.c
test.c:3:22: warning: incompatible integer to pointer conversion passing 'int'
to parameter of type 'void *' [-Wint-conversion]
int c(int x) {return b(x);}
^~~~
test.c:2:16: note: expanded from macro 'b'
#define b(x) a((x))
^~~
test.c:1:20: note: passing argument to parameter here
extern int a(void *);
^
1 warning generated.
-----------------------------
If the macro parameter is used as is (not parenthesized), GCC does identify the
macro invocation as the diagnostic location:
-----------------------------
$ cat test2.c
extern int a(void *);
#define b(x) a(x)
int c(int x) {return b(x);}
$ gcc-9.2.0 -c test2.c
test.c: In function 'c':
test.c:3:24: warning: passing argument 1 of 'a' makes pointer from integer
without a cast [-Wint-conversion]
3 | int c(int x) {return b(x);}
| ^
| |
| int
test.c:2:16: note: in definition of macro 'b'
2 | #define b(x) a(x)
| ^
test.c:1:14: note: expected 'void *' but argument is of type 'int'
1 | extern int a(void *);
| ^~~~~~
-----------------------------
But this is not particularly helpful because most macro arguments must be
parenthesized to be used safely.