Bug 16358

Summary: -Wno-system-headers hides warning caused by user header vs system header conflict [i.e. add -Wmacro-redefined]
Product: gcc Reporter: Avi Kivity <avi>
Component: preprocessorAssignee: Not yet assigned to anyone <unassigned>
Status: NEW ---    
Severity: minor CC: egallager, gcc-bugs, msebor, niva
Priority: P2 Keywords: diagnostic
Version: 3.2.2   
Target Milestone: ---   
See Also: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79214
Host: i386-redhat-linux Target: i386-redhat-linux
Build: i386-redhat-linux Known to work:
Known to fail: Last reconfirmed: 2006-01-28 00:49:38
Bug Depends on:    
Bug Blocks: 87403    
Attachments: Testcase. Linux specific, but can be readily adapted to other systems.

Description Avi Kivity 2004-07-04 08:05:14 UTC
Consider the code

  #define BLOCK_SIZE 4096
  #include <linux/fs.h>

The header re#defines BLOCK_SIZE. Now, -Wno-system-headers suppresses the
warning as it comes in a system header, and the result is that BLOCK_SIZE is
silently redefined to 1024.

This can probably be fixed by considering all sources of a multi-source warning
(like symbol redefinition) when checking whether to suppress the warning or not.
Comment 1 Avi Kivity 2004-07-04 08:08:59 UTC
Created attachment 6684 [details]
Testcase. Linux specific, but can be readily adapted to other systems.
Comment 2 Avi Kivity 2004-07-04 08:11:24 UTC
An obvious workaround is to perform all system #includes before everything else.
But there are valid reasons to #include system headers later, and a problem may
still remain with #include guard symbols.
Comment 3 Andrew Pinski 2004-07-04 14:44:02 UTC
And why do you think we should warn here because the redefine is in a system header file?  Also you 
should not be including the kernel headers in user land programs.
Comment 4 Avi Kivity 2004-07-04 14:57:01 UTC
(In reply to comment #3)
> And why do you think we should warn here because the redefine is in a system
header file? 

The user gets an unexpected value for their define. I wanted BLOCK_SIZE to be
4096, and I wanted the value of BLKBSZGET. I didn't know that linux/fs.h defines
BLOCK_SIZE, and I assumed that if it did I'd get a warning.

As it was, my code was silently broken.


 Also you 
> should not be including the kernel headers in user land programs.

I needed an ioctl definition. But this is true for non-kernel headers as well:

  // define some options:

  #define O_SCP     1  // use /usr/bin/scp
  #define O_WGET    2  // use /usr/bin/wget
  #define O_RSYNC   3  // use /usr/bin/rsync

  // ...

  #include <fcntl.h>  // oops: silently redefines O_RSYNC

The user may not be aware that O_RSYNC exists.

Comment 5 Andrew Pinski 2004-07-04 15:04:04 UTC
Since O_RSYNC is reserved by the UNIX standard that part is invalid.  Yes there is such a thing, see 
<http://www.opengroup.org/onlinepubs/007908799/xsh/open.html> for the standard definition.

If you do not know what the marcos you are being in by using the headers why are you bring in the 
headers.  Also it is always custumary to include system headers first and then do the defines/includes 
of the user headers and you will never run into this.

Again this is invalid as the redefinition is the system header and the system header depends on the 
macros being defined right.
Comment 6 Avi Kivity 2004-07-04 16:07:53 UTC
(In reply to comment #5)
> Since O_RSYNC is reserved by the UNIX standard that part is invalid.  Yes
there is such a thing, see 
> <http://www.opengroup.org/onlinepubs/007908799/xsh/open.html> for the standard
definition.

If it is reserved, my code shouldn't compile if I define it.

if I do

  #include <fcntl.h>
  #define O_RSYNC blah

I get a warning. If I switch the order of the lines, I don't. The code compiles
after silently overriding my #define.



> 
> If you do not know what the marcos you are being in by using the headers why
are you bring in the 
> headers. 

Say I wanted O_SYNC, and knew about that. Or I included some other file that
included it. In a complex program a very large amount of headers can be expected
to be used. It's unreasonable to expect the user to know about all defines in a
header (did you know about O_RSYNC? I didn't).

 Also it is always custumary to include system headers first and then do the
defines/includes 
> of the user headers and you will never run into this.

This is a valid workaround.

> 
> Again this is invalid as the redefinition is the system header and the system
header depends on the 
> macros being defined right.

The code _is_ invalid, no doubt. I just want a warning, that's all. Shouldn't
gcc reject invalid code?
Comment 7 Giovanni Bajo 2004-07-05 16:15:30 UTC
I agree with Avi. The system header doesn't do a #undef + #define, but just a 
#define and it silently overwrites the previous macro. Even if this is 
undefined behaviour, we can do better than we do now and emit at least a 
warning.
Comment 8 Andrew Pinski 2005-10-24 00:34:57 UTC
Please file this bug with the Linux Kernel people also.
And glibc for O_RSYNC.
Comment 9 niva 2016-04-22 10:54:33 UTC
ISO C treats redefinition of a macro as an error (6.10.3 2). 

IMHO it is reasonable to add a gcc/cpp option which provides treating 
redefinition of a macro as an error.
Comment 10 Martin Sebor 2016-04-22 16:27:00 UTC
(In reply to niva from comment #9)

-Werror turns the warning GCC issues for a macro redefinition into an error.  A part of the problem is that warnings in system headers are suppressed by default, without -Wsystem-headers, so -Werror alone doesn't help.

What is also missing, though, is a mechanism/option to silence the macro redefinition warning without also suppressing all other warnings (i.e., an option other that -w).

For example, there is no way to suppress the warning in the example below without also suppressing the -Wcpp warning.  In contrast to GCC, Clang provides the -Wmacro-redefined option that makes it possible to control just the macro redefinition warning.

Providing the same feature in GCC might help resolve this problem by enabling warnings for macro redefinitions in user headers without also enabling all other warnings in them.

$ cat t.c && gcc -S t.c
#define A   1
#define A   2
#warning foo
t.c:2:0: warning: "A" redefined
 #define A   2
 
t.c:1:0: note: this is the location of the previous definition
 #define A   1
 
t.c:3:2: warning: #warning foo [-Wcpp]
 #warning foo
  ^~~~~~~
Comment 11 niva 2016-04-25 12:55:38 UTC
(in reply to Martin Sebor in comment #10)

Implementation of -Wmacro-redefined (with possibility of turning this warning to error) would solve the problem of our users.
Comment 12 Eric Gallager 2021-10-27 05:09:42 UTC
(In reply to niva from comment #11)
> (in reply to Martin Sebor in comment #10)
> 
> Implementation of -Wmacro-redefined (with possibility of turning this
> warning to error) would solve the problem of our users.

Retitling accordingly