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.

Reply via email to