Consider this C code:
void foo(char *);
void bar(void) {
foo("");
}
When I compile that with -pedantic -Wall -Wextra
with GCC or Clang, or with -Weverything
with Clang, it compiles without giving me any relevant warnings. If I add -Wwrite-strings
, then GCC gives me this:
<source>:4:9: warning: passing argument 1 of 'foo' discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
4 | foo("");
| ^~
<source>:1:10: note: expected 'char *' but argument is of type 'const char *'
1 | void foo(char *);
| ^~~~~~
And clang gives me this:
<source>:4:9: warning: passing 'const char [1]' to parameter of type 'char *' discards qualifiers [-Wincompatible-pointer-types-discards-qualifiers]
foo("");
^~
<source>:1:16: note: passing argument to parameter here
void foo(char *);
^
Lots of things seem wrong here to me:
-Wdiscarded-qualifiers
, but if I pass that instead of -Wwrite-strings
, I don't get that warning.-Weverything
meant "literally every single warning the compiler knows about", but this seems to contradict that.What's going on here? Why does this particular warning seem so buggy?
In C, string literals existed before const
did. So C string literals were not const-qualified (although the results of attempting to write to them are not defined by the C standard). If string literals were made const-qualified, much old software would break due to type errors. The C committee has decided this change is not worthwhile.
The switch -Wwrite-strings
is not really a warning switch, in spite of -W
. It changes the language being compiled to a non-standard C in which string literals are const-qualified. (There is a bug report that it is a mistake for GCC to categorize this as a warning switch.) This explains why GCC shows a -Wdiscarded-qualifier
when a string literal is assigned to a char *
, and it also explains why -Wdiscarded-qualifier
alone does not trigger these warnings—because without -Wwrite-strings
, the string literal is not const-qualified, so no qualifier is being discarded by the assignment.
Presumably Clang’s -Weverything
does not include -Wwrite-strings
because, as noted above, it is not truly a warning option and because it changes the language to non-standard C.