Hi Alexandre, > I'm upgrading a project that used a 8-month-old copy of gnulib to > today's version
Since then, gnulib has improved its support for clang. > I compile with -Werror. Gnulib generally does not support -Werror on arbitrary platforms. We try to make for a warning-free compilation on glibc systems with GCC, as far as it is reasonable (but it does not work always, due to GCC bugs). > Testing the result with clang++ 11.0.1-2 (Debian unstable) Now, using clang with -Wall and -Werror is a recipe for failures, for sure. This is because clang has _many_ warnings, and - Some of the warnings are of the kind "tell me when you did a certain optimization". Most of the warnings in this category are not helpful. - Some of the warnings merely enforce certain coding styles. You can try to enforce your preferred coding style on your code, but enforcing it on Gnulib code is a non-starter. - Some of the warnings are contradictory. You are supposed to choose the warnings that are reasonable for your project. For some project of mine, I had to disable 20-40 warning options before I could get reasonable output. > > ../lib/gettext.h:234:22: error: zero as null pointer constant > > [-Werror,-Wzero-as-null-pointer-constant] > > if (msg_ctxt_id != NULL) > > ^~~~ This will not be changed. NULL is the preferred way to denote a null pointer. > Just replacing these two tests with "if (msg_ctxt_id)" gets rid of the issue. ... but makes the code harder to understand. > (2) ARGMATCH_VERIFY ends up using _Static_assert which is a C11 keyword > that does not exist in C++. However static_assert exists in C++11 > with two args, and since C++17 with one arg. We prefer to use _Static_assert with 2 arguments, since it causes the compiler to give the diagnostic specified by the programmer. A macro or built-in that accepts only 1 argument is an inferior solution for this case. > > clang++ -DHAVE_CONFIG_H -I. -I.. -I.. -I.. -I../buddy/src -I../lib > > -I../lib -W -Wall -Werror -Wint-to-void-pointer-cast > > -Wzero-as-null-pointer-constant -Wcast-align -Wpointer-arith > > -Wwrite-strings -Wcast-qual -DXTSTRINGDEFINES -Wdocumentation > > -Wmissing-declarations -Woverloaded-virtual -Wmisleading-indentation > > -Wimplicit-fallthrough -Wnull-dereference -Wsuggest-override -Wpedantic > > -fvisibility=hidden -fvisibility-inlines-hidden -DSPOT_BUILD -std=c++17 -g > > -O -MT common_aoutput.o -MD -MP -MF .deps/common_aoutput.Tpo -c -o > > common_aoutput.o common_aoutput.cc > > common_aoutput.cc:85:1: error: '_Static_assert' is a C11 extension > > [-Werror,-Wc11-extensions] > > ARGMATCH_VERIFY(check_args, check_types); > > ^ > > ../lib/argmatch.h:45:5: note: expanded from macro 'ARGMATCH_VERIFY' > > verify (ARRAY_CARDINALITY (Arglist) == ARRAY_CARDINALITY (Vallist) + 1) > > ^ > > ../lib/verify.h:289:20: note: expanded from macro 'verify' > > # define verify(R) _GL_VERIFY (R, "verify (" #R ")", -) > > ^ > > ../lib/verify.h:229:41: note: expanded from macro '_GL_VERIFY' > > # define _GL_VERIFY(R, DIAGNOSTIC, ...) _Static_assert (R, DIAGNOSTIC) > > ^ > > common_aoutput.cc:397:7: error: '_Static_assert' is a C11 extension > > [-Werror,-Wc11-extensions] > > ARGMATCH_VERIFY(args, format); > > ^ > > ../lib/argmatch.h:45:5: note: expanded from macro 'ARGMATCH_VERIFY' > > verify (ARRAY_CARDINALITY (Arglist) == ARRAY_CARDINALITY (Vallist) + 1) > > ^ > > ../lib/verify.h:289:20: note: expanded from macro 'verify' > > # define verify(R) _GL_VERIFY (R, "verify (" #R ")", -) > > ^ > > ../lib/verify.h:229:41: note: expanded from macro '_GL_VERIFY' > > # define _GL_VERIFY(R, DIAGNOSTIC, ...) _Static_assert (R, DIAGNOSTIC) > > ^ > > 2 errors generated. > > to work around this, I've just changed the definition of _GL_VERIFY in > lib/verify.h from > > > #if defined _GL_HAVE__STATIC_ASSERT > > # define _GL_VERIFY(R, DIAGNOSTIC, ...) _Static_assert (R, DIAGNOSTIC) > > #else > > # define _GL_VERIFY(R, DIAGNOSTIC, ...) \ > > extern int (*_GL_GENSYM (_gl_verify_function) (void)) \ > > [_GL_VERIFY_TRUE (R, DIAGNOSTIC)] > > #endif > > to > > > #if defined __cpp_static_assert > > # define _GL_VERIFY(R, DIAGNOSTIC, ...) static_assert (R, DIAGNOSTIC) > > #elif defined _GL_HAVE__STATIC_ASSERT > > # define _GL_VERIFY(R, DIAGNOSTIC, ...) _Static_assert (R, DIAGNOSTIC) > > #else > > # define _GL_VERIFY(R, DIAGNOSTIC, ...) \ > > extern int (*_GL_GENSYM (_gl_verify_function) (void)) \ > > [_GL_VERIFY_TRUE (R, DIAGNOSTIC)] > > #endif Thanks for the suggestion. Committed through the patch below. > However there are a few __cplusplus tests at the top of the file that > attempt to tell when _Static_assert can be used (and failed here), and I > do not really follow that logic. These lines define our own witnesses whether a certain feature is available, rather than merely relying on __cpp_static_assert. This allows us to cater with compilers which lie about their features (e.g. HP compilers are frequently broken in this way) or consider GCC's -pedantic option. > Those macros check for > __cpp_static_assert to assume something about _Static_assert, which > seems dubious. Paul can tell more about this one. 2021-01-12 Bruno Haible <br...@clisp.org> verify: Use C++11 static_assert when available. Reported by Alexandre Duret-Lutz <a...@lrde.epita.fr> in <https://lists.gnu.org/archive/html/bug-gnulib/2021-01/msg00177.html>. * lib/verify.h (_GL_HAVE_STATIC_ASSERT_CXX11): New macro. (_GL_HAVE_STATIC_ASSERT_CXX17): Renamed from _GL_HAVE_STATIC_ASSERT1. (_GL_VERIFY): Use static_assert when available with C++11 syntax. diff --git a/lib/verify.h b/lib/verify.h index 3cdcdca..a9e7589 100644 --- a/lib/verify.h +++ b/lib/verify.h @@ -29,7 +29,11 @@ per C2X. This is supported by GCC 9.1 and later, and by clang in C++1z mode. - Define _GL_HAVE_STATIC_ASSERT1 if static_assert (R) works as per + Define _GL_HAVE_STATIC_ASSERT_CXX11 if static_assert (R, DIAGNOSTIC) + works as per C++11. This is supported by GCC 6.1 and later, and by + clang in C++11 mode. + + Define _GL_HAVE_STATIC_ASSERT_CXX17 if static_assert (R) works as per C++17. This is supported by GCC 9.1 and later, and by clang in C++1z mode. @@ -54,10 +58,15 @@ # if 4 <= __clang_major__ && 201411 <= __cpp_static_assert # define _GL_HAVE__STATIC_ASSERT1 1 # endif +# if 201103L <= __cplusplus \ + || 6 <= __GNUC__ \ + || (4 <= __clang_major__ && 200410 <= __cpp_static_assert) +# define _GL_HAVE_STATIC_ASSERT_CXX11 1 +# endif # if 201703L <= __cplusplus \ || 9 <= __GNUC__ \ || (4 <= __clang_major__ && 201411 <= __cpp_static_assert) -# define _GL_HAVE_STATIC_ASSERT1 1 +# define _GL_HAVE_STATIC_ASSERT_CXX17 1 # endif #endif @@ -225,7 +234,9 @@ template <int w> Unfortunately, unlike C11, this implementation must appear as an ordinary declaration, and cannot appear inside struct { ... }. */ -#if defined _GL_HAVE__STATIC_ASSERT +#if defined _GL_HAVE_STATIC_ASSERT_CXX11 +# define _GL_VERIFY(R, DIAGNOSTIC, ...) static_assert (R, DIAGNOSTIC) +#elif defined _GL_HAVE__STATIC_ASSERT # define _GL_VERIFY(R, DIAGNOSTIC, ...) _Static_assert (R, DIAGNOSTIC) #else # define _GL_VERIFY(R, DIAGNOSTIC, ...) \ @@ -239,7 +250,7 @@ template <int w> # define _Static_assert(...) \ _GL_VERIFY (__VA_ARGS__, "static assertion failed", -) # endif -# if !defined _GL_HAVE_STATIC_ASSERT1 && !defined static_assert +# if !defined _GL_HAVE_STATIC_ASSERT_CXX17 && !defined static_assert # define static_assert _Static_assert /* C11 requires this #define. */ # endif #endif