bug-gnulib
[Top][All Lists]
Advanced

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

Fix compilation errors of list, set, oset, map, omap in C++ mode


From: Bruno Haible
Subject: Fix compilation errors of list, set, oset, map, omap in C++ mode
Date: Sat, 15 Apr 2023 18:07:25 +0200

On FreeBSD 13.0 and newer, a testdir of all of gnulib fails to compile:

c++ -ferror-limit=0 -DHAVE_CONFIG_H -DEXEEXT=\"\" -DEXEEXT=\"\" -I. 
-I../../gltests -I..   -DGNULIB_STRICT_CHECKING=1  -DIN_GNULIB_TESTS=1  -I. 
-I../../gltests  -I.. -I../../gltests/..  -I../gllib -I../../gltests/../gllib 
-I/home/bruno/include -I/usr/local/include -Wall -D_THREAD_SAFE  -Wno-error -g 
-O2 -MT test-list-c++.o -MD -MP -MF $depbase.Tpo -c -o test-list-c++.o 
../../gltests/test-list-c++.cc && mv -f $depbase.Tpo $depbase.Po
In file included from ../../gltests/test-list-c++.cc:20:
In file included from ../../gltests/../gllib/gl_list.hh:21:
../../gltests/../gllib/gl_list.h:645:25: error: an attribute list cannot appear 
here
_GL_ATTRIBUTE_NODISCARD GL_LIST_INLINE int
                        ^~~~~~~~~~~~~~
../../gltests/../gllib/gl_list.h:31:25: note: expanded from macro 
'GL_LIST_INLINE'
# define GL_LIST_INLINE _GL_INLINE
                        ^~~~~~~~~~
../config.h:6453:21: note: expanded from macro '_GL_INLINE'
# define _GL_INLINE _GL_UNUSED static
                    ^~~~~~~~~~
../config.h:7607:20: note: expanded from macro '_GL_UNUSED'
#define _GL_UNUSED _GL_ATTRIBUTE_MAYBE_UNUSED
                   ^~~~~~~~~~~~~~~~~~~~~~~~~~
../config.h:7594:39: note: expanded from macro '_GL_ATTRIBUTE_MAYBE_UNUSED'
#   define _GL_ATTRIBUTE_MAYBE_UNUSED [[__maybe_unused__]]
                                      ^~~~~~~~~~~~~~~~~~~~
...

The compiler is complaining about the combination of _GL_ATTRIBUTE_NODISCARD
and _GL_INLINE. Here, _GL_INLINE macroexpands to
  _GL_UNUSED static

We have put _GL_ATTRIBUTE_NODISCARD and _GL_UNUSED before the 'static' keyword,
because when one of the _GL_ATTRIBUTE_* macros expands to [[__something__]],
it needs to be before the 'static' keyword, not after.

Both of _GL_ATTRIBUTE_NODISCARD and _GL_UNUSED can expand to [[__...__]]
or to __attribute__((__...__)), depending on conditions. So far, the
_GL_ATTRIBUTE_* that can expand to [[__...__]] are:
  _GL_ATTRIBUTE_DEPRECATED
  _GL_ATTRIBUTE_MAYBE_UNUSED
  _GL_ATTRIBUTE_NODISCARD

Several __attribute__((__...__)) can be placed next to each other in any order.
Similarly several [[__...__]] can be placed next to each other in any order.
The problem is that
  - in C mode, with gcc 10..12, and also
  - in C++ mode, with clang++ 6..15,
the [[__...__]] markers must come *before* the __attribute__((__...__)).

Here's a test case, annotated with the error or warning results:
============================= foo.c / foo.cc ==============================
[[__warn_unused_result__]] // gcc, g++, clang++: warning, clang 4..16: ERROR
[[__maybe_unused__]]
static int
foo1 (int x, int y)
{ return x + y; }

__attribute__ ((__warn_unused_result__))
[[__maybe_unused__]] // gcc 10..12, clang++ 6..15: ERROR [[ ]] must come first, 
clang 4..16: ERROR
static int
foo2a (int x, int y)
{ return x + y; }

[[__maybe_unused__]] // clang 4..16: ERROR
__attribute__ ((__warn_unused_result__))
static int
foo2b (int x, int y)
{ return x + y; }

[[__warn_unused_result__]] // gcc, g++, clang++: warning, clang 4..16: ERROR
__attribute__ ((__unused__))
static int
foo3a (int x, int y)
{ return x + y; }

__attribute__ ((__unused__))
[[__warn_unused_result__]] // g++, clang: warning, gcc 10..12, clang++ 6..15: 
ERROR [[ ]] must come first, clang 4..16: ERROR
static int
foo3b (int x, int y)
{ return x + y; }

__attribute__ ((__warn_unused_result__))
__attribute__ ((__unused__))
static int
foo4 (int x, int y)
{ return x + y; }
===============================================================================

The lines "clang 4..16: ERROR" indicate that in C mode, clang does not support
[[__...__]] at all (at least with the default -std option).

The lines "gcc 10..12, clang++ 6..15: ERROR [[ ]] must come first" indicate
that [[__...__]] is not accepted after __attribute__((__...__)).

There are three possible ways to work around this restriction:

  (a) Define two macros _GL_ATTRIBUTE_NODISCARD1, _GL_ATTRIBUTE_NODISCARD2,
      in such way that _GL_ATTRIBUTE_NODISCARD1 contains only [[__...__]]
      and _GL_ATTRIBUTE_NODISCARD2 contains only __attribute__((__...__)).
      In other words, either
        #define _GL_ATTRIBUTE_NODISCARD1 [[__warn_unused_result__]]
        #define _GL_ATTRIBUTE_NODISCARD2
      or
        #define _GL_ATTRIBUTE_NODISCARD1
        #define _GL_ATTRIBUTE_NODISCARD2 __attribute__ 
((__warn_unused_result__))
      And for each such inline function, write
        _GL_ATTRIBUTE_NODISCARD1 GL_LIST_INLINE1 _GL_ATTRIBUTE_NODISCARD2 
GL_LIST_INLINE2 ...
      so that all [[__...__]] come first.

      The problem with this approach is that many inline function declarations
      need to be changed, and in a way that looks more ugly than before.

  (b) Instead of defining a macro _GL_INLINE (or additionally), define a
      macro _GL_INLINE_AND(attributes), that takes the _GL_ATTRIBUTE_NODISCARD
      as an arguments:
        #define _GL_INLINE_AND(attributes) [[__maybe_unused__]] attributes 
static

      The problem with this approach is again that many inline function
      declarations need to be changed, and that the macro stuff becomes
      more complex.

  (c) When a compiler supports both the [[__...__]] and the
      __attribute__((__...__)) syntax and enforces the order,
      use only the latter.

For simplicity, I choose (c).


2023-04-15  Bruno Haible  <bruno@clisp.org>

        Fix compilation errors of list, set, oset, map, omap in C++ mode.
        * m4/gnulib-common.m4 (gl_COMMON_BODY): Define
        _GL_BRACKET_BEFORE_ATTRIBUTE. In _GL_ATTRIBUTE_DEPRECATED,
        _GL_ATTRIBUTE_MAYBE_UNUSED, _GL_ATTRIBUTE_NODISCARD, don't use the
        bracket syntax if _GL_BRACKET_BEFORE_ATTRIBUTE is defined.

diff --git a/m4/gnulib-common.m4 b/m4/gnulib-common.m4
index 0216017461..8116804574 100644
--- a/m4/gnulib-common.m4
+++ b/m4/gnulib-common.m4
@@ -1,4 +1,4 @@
-# gnulib-common.m4 serial 84
+# gnulib-common.m4 serial 85
 dnl Copyright (C) 2007-2023 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -120,6 +120,20 @@ AC_DEFUN([gl_COMMON_BODY]
 # pragma GCC diagnostic ignored "-Wpedantic"
 #endif
 
+/* Define if, in a function declaration, the attributes in bracket syntax
+   [[...]] must come before the attributes in __attribute__((...)) syntax.
+   If this is defined, it is best to avoid the bracket syntax, so that the
+   various _GL_ATTRIBUTE_* can be cumulated on the same declaration in any
+   order.  */
+#ifdef __cplusplus
+# if defined __clang__
+#  define _GL_BRACKET_BEFORE_ATTRIBUTE 1
+# endif
+#else
+# if defined __GNUC__ && !defined __clang__
+#  define _GL_BRACKET_BEFORE_ATTRIBUTE 1
+# endif
+#endif
 ]dnl There is no _GL_ATTRIBUTE_ALIGNED; use stdalign's alignas instead.
 [
 /* _GL_ATTRIBUTE_ALLOC_SIZE ((N)) declares that the Nth argument of the 
function
@@ -227,9 +241,11 @@ AC_DEFUN([gl_COMMON_BODY]
      - typedef,
    in C++ also: namespace, class, template specialization.  */
 #ifndef _GL_ATTRIBUTE_DEPRECATED
-# ifdef __has_c_attribute
-#  if __has_c_attribute (__deprecated__)
-#   define _GL_ATTRIBUTE_DEPRECATED [[__deprecated__]]
+# ifndef _GL_BRACKET_BEFORE_ATTRIBUTE
+#  ifdef __has_c_attribute
+#   if __has_c_attribute (__deprecated__)
+#    define _GL_ATTRIBUTE_DEPRECATED [[__deprecated__]]
+#   endif
 #  endif
 # endif
 # if !defined _GL_ATTRIBUTE_DEPRECATED && _GL_HAS_ATTRIBUTE (deprecated)
@@ -359,13 +375,15 @@ AC_DEFUN([gl_COMMON_BODY]
    __has_c_attribute (__maybe_unused__) yields true but the use of
    [[__maybe_unused__]] nevertheless produces a warning.  */
 #ifndef _GL_ATTRIBUTE_MAYBE_UNUSED
-# if defined __clang__ && defined __cplusplus
-#  if !defined __apple_build_version__ && __clang_major__ >= 10
-#   define _GL_ATTRIBUTE_MAYBE_UNUSED [[__maybe_unused__]]
-#  endif
-# elif defined __has_c_attribute
-#  if __has_c_attribute (__maybe_unused__)
-#   define _GL_ATTRIBUTE_MAYBE_UNUSED [[__maybe_unused__]]
+# ifndef _GL_BRACKET_BEFORE_ATTRIBUTE
+#  if defined __clang__ && defined __cplusplus
+#   if !defined __apple_build_version__ && __clang_major__ >= 10
+#    define _GL_ATTRIBUTE_MAYBE_UNUSED [[__maybe_unused__]]
+#   endif
+#  elif defined __has_c_attribute
+#   if __has_c_attribute (__maybe_unused__)
+#    define _GL_ATTRIBUTE_MAYBE_UNUSED [[__maybe_unused__]]
+#   endif
 #  endif
 # endif
 # ifndef _GL_ATTRIBUTE_MAYBE_UNUSED
@@ -383,18 +401,20 @@ AC_DEFUN([gl_COMMON_BODY]
    the return value, unless the caller uses something like ignore_value.  */
 /* Applies to: function, enumeration, class.  */
 #ifndef _GL_ATTRIBUTE_NODISCARD
-# if defined __clang__ && defined __cplusplus
+# ifndef _GL_BRACKET_BEFORE_ATTRIBUTE
+#  if defined __clang__ && defined __cplusplus
   /* With clang up to 15.0.6 (at least), in C++ mode, [[__nodiscard__]] 
produces
      a warning.
      The 1000 below means a yet unknown threshold.  When clang++ version X
      starts supporting [[__nodiscard__]] without warning about it, you can
      replace the 1000 with X.  */
-#  if __clang_major__ >= 1000
-#   define _GL_ATTRIBUTE_NODISCARD [[__nodiscard__]]
-#  endif
-# elif defined __has_c_attribute
-#  if __has_c_attribute (__nodiscard__)
-#   define _GL_ATTRIBUTE_NODISCARD [[__nodiscard__]]
+#   if __clang_major__ >= 1000
+#    define _GL_ATTRIBUTE_NODISCARD [[__nodiscard__]]
+#   endif
+#  elif defined __has_c_attribute
+#   if __has_c_attribute (__nodiscard__)
+#    define _GL_ATTRIBUTE_NODISCARD [[__nodiscard__]]
+#   endif
 #  endif
 # endif
 # if !defined _GL_ATTRIBUTE_NODISCARD && _GL_HAS_ATTRIBUTE (warn_unused_result)






reply via email to

[Prev in Thread] Current Thread [Next in Thread]