Date: Tue, 14 Apr 2015 16:46:43 +1000 (EST) From: Bruce Evans <brde@optusnet.com.au> To: Eitan Adler <eadler@freebsd.org> Cc: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: Re: svn commit: r281517 - head/usr.bin/ipcs Message-ID: <20150414153545.U838@besplex.bde.org> In-Reply-To: <201504140452.t3E4qrae040029@svn.freebsd.org> References: <201504140452.t3E4qrae040029@svn.freebsd.org>
next in thread | previous in thread | raw e-mail | index | archive | help
On Tue, 14 Apr 2015, Eitan Adler wrote: > Log: > ipcs: fix builds that use gcc > gcc gets annoyed by duplicate declarations You mean "Fix builds that use a working compiler. Working compilers report redundant declarations when requested to do so by the -Wredundant-decls flag which I recently enabled by raising WARNS to 6." clang apparently silently ignores the request. gcc48 still has the following bugs in -Wredundant-decls: - it redundantly says that redundant declarations are redeclarations. Only a very magic type or variable could redundant if it is only declared once by the program (including in headers included by the program). Perhaps some predefined type or variable is magic enough. But then the warning should be different. E.g., main() and exit() are known to the compiler except in freestanding environments. gcc already has special handling for main(), to allow it to be declared as either "int main(void);" or "int main(int argc, char **argv);", as required to allow the program to use either of these. Declaring one of these in either <stdlib.h> or a compiler predeclaration would break use of the other one unless the first declaration is magic. I think gcc skips the warning for its builtin predeclaration but wouldn't skip if for a declaration in a header. I think standards don't allow main() to be declared in any standard header since they don't require compilers to have magic to support this. exit() is simpler since it has only 1 correct declaration in hosted environments. It should have a predeclaration in the compiler and another one in <stdlib.h>. The one in <stdlib.h> is redundant, but the compiler must not warn about it. The compiler should warn about it for any declaration of it outside of standard headers. The correct practice is to include <stdlib.h> to get the declaration. That gives at least a doubly-redundant declaration if the application declares it again, and no magic is needed to get the warning. If the application doesn't include <stdlib.h>, then the warning should change to one about improper practice when certain warnings are enabled. I think gcc only warns about inconsistent uses and the C standard only requires this. So you should be able to non-redundantly declare exit() iff you are careful to not include <stdlib.h> and use the same declaration as <stdlib.h>. - it incorrectly says that non-redundant non-redeclarations are redundant redeclarations. C allows building up types by supplying additional information in each step. E.g.: void myfunc(); void myfunc(int); gcc48 still warns that the second declaration is a redundant redeclaration when it is actually a non-redundant non-redeclaration. The first declaration is redundant in some cases (especially when there is nothing between the declarations. Nested incomplete function declarations allow arbitrarily long chains of non-redundant non-redeclarations to build up a single top-level declaration: typedef void ifv(); /* incomplete type for func returning void */ typedef void cfv(int); /* complete type for func returning void */ void myfunc(); void myfunc(ifv *, ifv *); /* parameters incomplete */ void myfunc(cfv *, ifv *); /* complete only first parameter */ void myfunc(ifv *, cfv *); /* complete only first parameter */ /* * All non-redundant so far. The type of myfunc is now complete in * Standard C although not in GNC C, so any further declarations of * all or parts of it are redundant. */ C also allows building up declarations by adding linkage info. This is even more confusing. GNUC also allows building up declarations by adding attribute info one or several but not all attributes at a time. This is less confusing, at least for the 1-at-a-time case. E.g.: void panic(const char *, ...); #ifdef __MUMBLE >= 99 void panic(const char * restrict, ...); /* add C99 feature */ #endif void panic(const char *, ...) __dead2; /* add old GNU feature */ void panic(const char *, ...) __printflike(1, 2); /* newer GNU feature */ void panic(const char *, ...) __nonnull(1); /* even newer GNU feature */ Building up types is very confusing so you should rarely do it, but the above is almost reasonable. Adding the restrict qualifier only for C99 and later is obfuscated in a different way using ifdefs for __restrict. The bugs in "gcc -Wredundant-decls" accidentally detect the style bug of using the building-up-types feature. This should be detected under a different warning. panic(9) is still missing both 'restrict' and __nonnull(1), though it needs __nonull() even more than printf([39]) because a null panicstr is magic (used for recursion detection). Bruce
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20150414153545.U838>