https://gcc.gnu.org/bugzilla/show_bug.cgi?id=118636
Bug ID: 118636 Summary: `-Werror` and `-w` do not affect linker warnings, but the docs say they should [docs bug?] Product: gcc Version: unknown Status: UNCONFIRMED Severity: normal Priority: P3 Component: driver Assignee: unassigned at gcc dot gnu.org Reporter: evaned at gmail dot com Target Milestone: --- [Detailed information, including the input file, are at the end of the report.] This could be considered either a behavior bug or a documentation bug. There wasn't a Docs component to select and the bug writing guidelines don't provide info on filing documentation bugs, so please excuse if this isn't quite the format you want for that. I discovered during an online discussion that `-Werror` does not affect linker warnings: /tmp$ gcc -Werror linker-warning.c -o linker-warning /usr/bin/ld: warning: /tmp/cciBYjrB.o: requires executable stack (because the .note.GNU-stack section is executable) /tmp$ echo $? 0 /tmp$ ./linker-warning /tmp$ Should it? According to the documentation, yes. There's a corresponding problem where `-w` does not suppress linker warnings, even though the documentation says it should. I'll argue that the docs do in fact say that `-Werror` should fail a compilation when the linker warns, discuss if this is a behavior that should be changed, propose doc changes, and then provide the detailed info about my environment. THE DOCS SAY IT SHOULD WORK =========================== Here's what the docs say the flags should do: -w Inhibit all warning messages. -Werror Make all warnings into errors. Emphasis on the word "all", and lack of any mention that linker warnings are not included. Maybe the section they are in has that qualification? Let's see: 3.9 Options to Request or Suppress Warnings Warnings are diagnostic messages that report constructions that are not inherently erroneous but that are risky or suggest there may have been an error. The following language-independent options do not enable specific warnings but control the kinds of diagnostics produced by GCC. I would say not really. "Produced by GCC" is moving in that direction, but at best it's ambiguous. You could read it as appling to just the compiler proper, but this has two problems. First, I feel that this interpretation is one of those things where a prerequisite to understanding something is to already understand it. Second, and worse, is that the very first sentence of the "description" of GCC in the manpage is "When you invoke GCC, it normally does preprocessing, compilation, assembly and linking." But if "GCC" is supposed to refer to the compiler proper, clearly the description of what GCC *is* is incorrect. Further, even if the section intro had such a clarification, I think the documentation would still be quite poor on this point, and not reflective of how people most use reference docs like manpages, which is to search for the specific thing of interest. Ironically enough, I *was* going to say the following: The closest thing to an unambiguous statement that `-Werror` refers to just compiler warnings is if you note that it is part of the output of `--help=warnings`, the behavior of which is described as "Display all of the options controlling warning messages produced by the compiler," with emphasis on "by the compiler." ... but THAT IS WRONG! `-Werror` is actually NOT included in that output! (Another bug?) I feel quite confident in claiming that the documentation says that `-Werror` should affect linker warnings. DOC OR BEHAVIOR BUG? ==================== This bug could be viewed in a couple of ways. The first is a behavior bug, where the GCC driver should pass `--fatal-warnings` to the linker. I think there are some obvious attractions to this change, and it should be considered. That said, I don't know how universal that flag is. I checked ld.bfd, ld.gold, lld, and mold and all support that flag, so maybe it's universal enough (or any remaining problems can be papered over in the linker script), but I don't say that with confidence. Potentially a bigger problem is that while `-Werror` would be improved, it introduces a gulf with some other warning flags. I mentioned how `-w` doesn't suppress linker warnings, but I don't see an analogue to `-w` for the linker that the driver could pass; just a bunch of individual no-warning flags that vary by linker and linker version. And of course the GCC driver allows controlling compiler warnings with `-Wnonnull` or whatever, and I have layperson concerns about if GCC could similarly control linker warnings; and assuming those concerns are well-founded, that's another rough edge. So I'm kind of expecting you to not change the behavior, and that's why I'm kind of framing this so much around the documentation bug aspect. DOCUMENTATION FIXES =================== Doc fixes seem like they'd be easy. Something like this seems like it'd be my ideal: -w Inhibit all compiler warning messages. -Werror Make all compiler warnings into errors. For linker warnings, also pass -Wl,--fatal-warnings, which works with most linkers. I considered "non-linker" instead of "compiler". And of course massage the "for linker warnings" sentence as you wish. The "For linker warnings" sentence serves two purposes. First, it emphasizes that "compiler" is not just a redundant word but is in contrast to linker warnings. Even if you don't want to suggest `--fatal-warnings` here to remain more decoupled, I think this is valuable to keep around; e.g. "Make all compiler warnings into errors. Linker warnings are not affected" or something similar. Second, it of course provides a very helpful nudge into what users who want the extra checking should do. Some of the surrounding text could be improved as well, however I think the documentation for `-w` and `-Werror` is the most important and surrounding improvements should not be viewed as a substitute. some suggestions for other improvements: -Werror= Make the specified compiler warning into an error. ... -Wfatal-errors .... You can request many specific compiler warnings with options beginning with -W, for example -Wimplicit to request warnings on implicit declarations. ... and then I would suggest a new paragraph before `-Wpedantic`, in that section about warnings in general: The GCC driver provides flags for controlling warnings in the preprocessor and compiler only. Warnings from the assembler and linker can be controlled by passing command line options to the assembler with -Wa and the linker with -Wl; for example, -Wl,--fatal-warnings will cause the linker to exit with an error if it would otherwise produce a warning. See the documentation for your assembler and linker for the relevant flags. I decided to be inclusive with the assembler in that description, but I'm not sure how important that is. DETAILED INFORMATION ==================== The copy/paste sessions were gathered from the `gcc:latest` Docker image, sha256:c8a47caa..., running on an Ubuntu 20.04 amd64 host. That said, I discovered this on older versions and I suspect that this problem has been around for approximately forever and is universal, because of its nature as mostly a docs bug. The input file is adapted from https://www.redhat.com/en/blog/linkers-warnings-about-executable-stacks-and-segments, though I originally discovered it when having a discussion of some things related to `gets`. (I just wanted an example that wasn't using an obviously terrible feature.) /tmp$ cat linker-warning.c int foo(int (*p)(int)) { return p(7); } int bar (int arg) { int baz (int arg2) { return arg2 * arg; } return foo (& baz) + arg; } int main() { return bar(1); } And then all the GCC information: /tmp$ gcc -v -save-temps -Werror linker-warning.c Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/usr/local/libexec/gcc/x86_64-linux-gnu/14.2.0/lto-wrapper Target: x86_64-linux-gnu Configured with: /usr/src/gcc/configure --build=x86_64-linux-gnu --disable-multilib --enable-languages=c,c++,fortran,go Thread model: posix Supported LTO compression algorithms: zlib zstd gcc version 14.2.0 (GCC) COLLECT_GCC_OPTIONS='-v' '-save-temps' '-Werror' '-mtune=generic' '-march=x86-64' '-dumpdir' 'a-' /usr/local/libexec/gcc/x86_64-linux-gnu/14.2.0/cc1 -E -quiet -v -imultiarch x86_64-linux-gnu linker-warning.c -mtune=generic -march=x86-64 -Werror -fpch-preprocess -o a-linker-warning.i ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu" ignoring nonexistent directory "/usr/local/lib/gcc/x86_64-linux-gnu/14.2.0/include-fixed/x86_64-linux-gnu" ignoring nonexistent directory "/usr/local/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../x86_64-linux-gnu/include" #include "..." search starts here: #include <...> search starts here: /usr/local/lib/gcc/x86_64-linux-gnu/14.2.0/include /usr/local/include /usr/local/lib/gcc/x86_64-linux-gnu/14.2.0/include-fixed /usr/include/x86_64-linux-gnu /usr/include End of search list. COLLECT_GCC_OPTIONS='-v' '-save-temps' '-Werror' '-mtune=generic' '-march=x86-64' '-dumpdir' 'a-' /usr/local/libexec/gcc/x86_64-linux-gnu/14.2.0/cc1 -fpreprocessed a-linker-warning.i -quiet -dumpdir a- -dumpbase linker-warning.c -dumpbase-ext .c -mtune=generic -march=x86-64 -Werror -version -o a-linker-warning.s GNU C17 (GCC) version 14.2.0 (x86_64-linux-gnu) compiled by GNU C version 14.2.0, GMP version 6.2.1, MPFR version 4.1.0, MPC version 1.2.1, isl version isl-0.24-GMP GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 Compiler executable checksum: b4330599559c5c656cd247a77c8981b6 COLLECT_GCC_OPTIONS='-v' '-save-temps' '-Werror' '-mtune=generic' '-march=x86-64' '-dumpdir' 'a-' as -v --64 -o a-linker-warning.o a-linker-warning.s GNU assembler version 2.40 (x86_64-linux-gnu) using BFD version (GNU Binutils for Debian) 2.40 COMPILER_PATH=/usr/local/libexec/gcc/x86_64-linux-gnu/14.2.0/:/usr/local/libexec/gcc/x86_64-linux-gnu/14.2.0/:/usr/local/libexec/gcc/x86_64-linux-gnu/:/usr/local/lib/gcc/x86_64-linux-gnu/14.2.0/:/usr/local/lib/gcc/x86_64-linux-gnu/ LIBRARY_PATH=/usr/local/lib/gcc/x86_64-linux-gnu/14.2.0/:/usr/local/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../lib64/:/lib/x86_64-linux-gnu/:/lib/../lib64/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib64/:/usr/local/lib/gcc/x86_64-linux-gnu/14.2.0/../../../:/lib/:/usr/lib/ COLLECT_GCC_OPTIONS='-v' '-save-temps' '-Werror' '-mtune=generic' '-march=x86-64' '-dumpdir' 'a.' /usr/local/libexec/gcc/x86_64-linux-gnu/14.2.0/collect2 -plugin /usr/local/libexec/gcc/x86_64-linux-gnu/14.2.0/liblto_plugin.so -plugin-opt=/usr/local/libexec/gcc/x86_64-linux-gnu/14.2.0/lto-wrapper -plugin-opt=-fresolution=a.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s --eh-frame-hdr -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 /lib/x86_64-linux-gnu/crt1.o /lib/x86_64-linux-gnu/crti.o /usr/local/lib/gcc/x86_64-linux-gnu/14.2.0/crtbegin.o -L/usr/local/lib/gcc/x86_64-linux-gnu/14.2.0 -L/usr/local/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../lib64 -L/lib/x86_64-linux-gnu -L/lib/../lib64 -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib64 -L/usr/local/lib/gcc/x86_64-linux-gnu/14.2.0/../../.. a-linker-warning.o -lgcc --push-state --as-needed -lgcc_s --pop-state -lc -lgcc --push-state --as-needed -lgcc_s --pop-state /usr/local/lib/gcc/x86_64-linux-gnu/14.2.0/crtend.o /lib/x86_64-linux-gnu/crtn.o /usr/bin/ld: warning: a-linker-warning.o: requires executable stack (because the .note.GNU-stack section is executable) COLLECT_GCC_OPTIONS='-v' '-save-temps' '-Werror' '-mtune=generic' '-march=x86-64' '-dumpdir' 'a.' For the documentation excerpts, I copied/pasted from https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html as the docker container doesn't have `man` installed, but it substantially agrees across the other versions of GCC I have installed.