lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


On Fri, Jan 02, 2015 at 03:35:56PM -0200, Roberto Ierusalimschy wrote:
> > On 2 January 2015 at 08:36, Luiz Henrique de Figueiredo
> > <lhf@tecgraf.puc-rio.br> wrote:
> > > We expect the compilation will go smoothly as usual
> > > but please report any warnings or other glitches.
> > 
> > Compiling with gcc's --pedantic gives a single warning:
> > 
> > loadlib.c: In function ???lsys_sym???:
> > loadlib.c:151:21: warning: ISO C forbids conversion of object pointer
> > to function pointer type [-Wpedantic]
> >    lua_CFunction f = (lua_CFunction)dlsym(lib, sym);
> >                      ^
> 
> This code has been like this for more than 10 years. Why did you wait for
> 'rc3' to complain?  :-)
> 
> 
> > To get around this, you need to use this hack: (as seem in dlsym
> > manpage/POSIX):
> > 
> >     double (*cosine)(double);
> > 
> >     /* Writing: cosine = (double (*)(double)) dlsym(handle, "cos");
> >        would seem more natural, but the C99 standard leaves
> >        casting from "void *" to a function pointer undefined.
> >        The assignment used below is the POSIX.1-2003 (Technical
> >        Corrigendum 1) workaround; see the Rationale for the
> >        POSIX specification of dlsym(). */
> > 
> >    *(void **) (&cosine) = dlsym(handle, "cos");
> 
> This hack is as undefined in C99 as ours, but we can change that if
> it removes the warning.
> 

I wouldn't surprised if that hack eventually causes problems with warnings
about type-punning.

Note that the latest Open Group specification drops the language about
deprecating or supplementing dlsym. Issue 7 says, "[n]ote that conversion
from a void * pointer to a function pointer as in: [...] is not defined by
the ISO C standard. This standard requires this conversion to work correctly
on conforming implementations."

An alternative to changing the code is to use the __extension__ qualifier.

https://gcc.gnu.org/onlinedocs/gcc/Alternate-Keywords.html

It's a very old GCC keyword, supported by clang and some other compilers,
that will quiet conformance warnings. It has expression scope. This works
for me

	lua_CFunction f = __extension__ (lua_CFunction)dlsym(lib, sym);

so this should also work

	#if defined(__GCC__)
	#define point2cfunc(p) (__extension__ (lua_CFunction)(p))
	#else
	#define point2cfunc(p) ((lua_CFunction)(p))
	#endif

or even

	#if defined(__GCC__)
	#define l_extension __extension__
	#else
	#define l_extension
	#endif

	#define point2cfunc(p) (l_extension (lua_CFunction)(p))

The latter permits using l_extension in other places where annoying
conformance warnings crop up. This doesn't solve Visual Studio headaches,
but can be used to silence many conformance warnings from GCC and clang
without stultifying the code as much.

Another alternative which is both C89 conformant and doesn't necessarily
require preprocessor hackery is to use pragmas. For example:

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) {
  lua_CFunction f = (lua_CFunction)dlsym(lib, sym);
  if (f == NULL) lua_pushstring(L, dlerror());
  return f;
}
#pragma GCC diagnostic pop

The downside is that only version of GCC since 4.6 understand diagnostic
pragmas. Earlier versions of GCC, as well as other compilers, will complain
about them, defeating the purpose. Unknown pragmas are supposed to be
ignored per C89 but can still legally trigger warnings, so you end up making
them conditional using the preprocessor. And while clang supports a near
identical syntax (including push/pop), it requires you to specify clang
rather than GCC in the directive. It all becomes quite verbose unless you do
this as boiler-plate effecting the entire codebase. But as boiler plate you
run the risk of silencing useful warnings.

I really think the __extension__ keyword would be a profitable solution.