[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)
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- Fix compilation errors of list, set, oset, map, omap in C++ mode,
Bruno Haible <=