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.