Date: Sun, 16 Feb 2014 15:09:51 +1100 (EST) From: Bruce Evans <brde@optusnet.com.au> To: David Chisnall <theraven@FreeBSD.org> Cc: svn-src-head@FreeBSD.org, svn-src-all@FreeBSD.org, src-committers@FreeBSD.org, Dimitry Andric <dim@FreeBSD.org>, Bruce Evans <brde@optusnet.com.au> Subject: Re: svn commit: r261916 - head/sys/dev/xen/console Message-ID: <20140216134006.R788@besplex.bde.org> In-Reply-To: <8C22DE47-60F2-47C0-938D-590324818872@FreeBSD.org> References: <201402151237.s1FCbRnh000507@svn.freebsd.org> <20140216035823.I2978@besplex.bde.org> <8C22DE47-60F2-47C0-938D-590324818872@FreeBSD.org>
next in thread | previous in thread | raw e-mail | index | archive | help
On Sat, 15 Feb 2014, David Chisnall wrote: > On 15 Feb 2014, at 17:02, Bruce Evans <brde@optusnet.com.au> wrote: > >> Why? There are hundreds if not thousands of static inline functions in >> headers, and most of these functions are not always used, so there would >> be [hundreds if not thousands] * [number of #includes] compiler warnings >> if compilers warned about things like this. They could handle include >> files specially, but shouldn't. > > They do, and absolutely should, handle include files separately. If you have a static inline function in a header that is not used in a specific compilation unit, then that is a little bit of extra work for the compiler as it has to parse it without it being used, but it is not a problem. It is a safe assumption that it is used by at least one compilation unit and so is not dead code (and even if it isn't yet, it is part of an API, and so removing it would be an error). No, there is no difference between an include file and a main source file, except for STDC headers in hosted implementations. Main source files may by included. Compilers shouldn't police the dubious style of this. > In contrast, a static inline function in the main source file for a compilation unit is definitely a bug. It is obviously dead code. It is likely that it either should have been removed when all callers were deleted, or should not have been static but accidentally was. It is _not_ obviously a bug. The main source file may have been carefully designed to be #included, with only the necessary #ifdef uglyness for this. Something like: main.c: /* * Broken compilers might barf if this is file used in the usual way by * including it, but I refuse to work around the brokenness by ifdefing * standards-conforming code. */ static inline int foo(int _x) { ... } /* Squillions more non-ifdefed static inline functions. */ /* Public functions need ifdefs of course. */ #ifdef WANT_MAIN int main(void) { ... } #endif /* * In C99, 'inline' is only a hint, so non-online functions strictly don't * need ifdefs any more that inline ones. However, some compilers will * keep plain static functions, and we need this feature. Ifdefing these * functions is not as essential as for public functions, but we do it to * avoid duplication of the functions. * * It is unclear how to write the ifdefs for this. The above main() is * only used in a special testing context, so we can use the condition * used to configure this context (the tests of it probably started in * a makefile). Whether this file is used being used as an include file * is probably determined by the same configuration info, but we don't * want to depend on that, and we want to show the full awfulness of the * potential ifdef ugliness, so we use a separate macro for each function. * The number of functions that need this should of course be minimized. * * XXX need more magic to keep static functions in a portable way as * renamed public functions. */ #ifdef WANT_BAR static int bar(int x) /* The ifdef messes allow naming x without an underscore. */ { ... } #endif For extra complications, use even worse style where the main source file is never used directly, but is included deeply nested and turns back into the main source file (with public functions) in 1 compilation unit. The ifdefs in the above example already support this, since they don't have any magic depending on the nesting level. For more practical examples of the brokenness, consider the effect of preprocessing. I often use cpp -P and compile the result. I use -P here to mainly to remove unwanted #line statements. Preprocessing must keep static inline functions, and -P removes any hints about whether they are in include files. Of course, using preprocessed output is outside of the C standard, but it is useful. The compiler might have further bugs involving special cases for preprocessed output in files name *.i. But the preprocessed output may be placed in files named *.c. That and removing #line statements and unportable directives with hints about include files if the preprocessed output is the final version of the file and/or is compiled by a compiler that doesn't support *.i. Similar considerations apply to the -W[no-]system-headers magic. Errors in system headers (other than ones related to the preprocessing pass) become just as fatal as anywhere else after cpp -P. Similar considerations apply to machine-generated main source files from other sources. yacc and lex are well known for generating unreachable break statements that lint doesn't like, except lint ignores these by default and has a flag -b to report them. You don't want to either complicate the generating program or have special compiler flags and complications in makefiles to set the flags to do the same thing for compilers. Bruce
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20140216134006.R788>