+2024-07-29 Bruno Haible <bruno@clisp.org>
+
+ Avoid g++ "warning: attributes are not permitted in this position".
+ * m4/gnulib-common.m4 (gl_COMMON_BODY): Add more comments. Define
+ _GL_BRACKET_USABLE. Use it for _GL_ATTRIBUTE_DEPRECATED,
+ _GL_ATTRIBUTE_MAYBE_UNUSED, _GL_ATTRIBUTE_NODISCARD,
+ _GL_ATTRIBUTE_REPRODUCIBLE, _GL_ATTRIBUTE_UNSEQUENCED.
+ * lib/stdio.in.h (aszprintf, vaszprintf, asprintf, vasprintf): Move
+ _GL_ATTRIBUTE_NODISCARD to the same position as the other attributes.
+ * lib/c-vasprintf.h (c_aszprintf, c_vaszprintf, c_asprintf,
+ c_vasprintf): Likewise.
+
2024-07-29 Bruno Haible <bruno@clisp.org>
An update for clang >= 16.
Formatting takes place in the C locale, that is, the decimal point
used in floating-point formatting directives is always '.'. */
-_GL_ATTRIBUTE_NODISCARD
ptrdiff_t c_aszprintf (char **resultp, const char *format, ...)
- _GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_STANDARD, 2, 3));
-_GL_ATTRIBUTE_NODISCARD
+ _GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_STANDARD, 2, 3))
+ _GL_ATTRIBUTE_NODISCARD;
ptrdiff_t c_vaszprintf (char **resultp, const char *format, va_list args)
- _GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_STANDARD, 2, 0));
+ _GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_STANDARD, 2, 0))
+ _GL_ATTRIBUTE_NODISCARD;
/* Prints formatted output to a string dynamically allocated with malloc().
If the memory allocation succeeds, it stores the address of the string in
Formatting takes place in the C locale, that is, the decimal point
used in floating-point formatting directives is always '.'. */
-_GL_ATTRIBUTE_NODISCARD
int c_asprintf (char **resultp, const char *format, ...)
- _GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_STANDARD, 2, 3));
-_GL_ATTRIBUTE_NODISCARD
+ _GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_STANDARD, 2, 3))
+ _GL_ATTRIBUTE_NODISCARD;
int c_vasprintf (char **resultp, const char *format, va_list args)
- _GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_STANDARD, 2, 0));
+ _GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_STANDARD, 2, 0))
+ _GL_ATTRIBUTE_NODISCARD;
#ifdef __cplusplus
}
Failure code EOVERFLOW can only occur when a width > INT_MAX is used.
Therefore, if the format string is valid and does not use %ls/%lc
directives nor widths, the only possible failure code is ENOMEM. */
-_GL_ATTRIBUTE_NODISCARD
_GL_FUNCDECL_SYS (aszprintf, ptrdiff_t,
(char **result, const char *format, ...)
_GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3)
- _GL_ARG_NONNULL ((1, 2)));
+ _GL_ARG_NONNULL ((1, 2))
+ _GL_ATTRIBUTE_NODISCARD);
_GL_CXXALIAS_SYS (aszprintf, ptrdiff_t,
(char **result, const char *format, ...));
-_GL_ATTRIBUTE_NODISCARD
_GL_FUNCDECL_SYS (vaszprintf, ptrdiff_t,
(char **result, const char *format, va_list args)
_GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0)
- _GL_ARG_NONNULL ((1, 2)));
+ _GL_ARG_NONNULL ((1, 2))
+ _GL_ATTRIBUTE_NODISCARD);
_GL_CXXALIAS_SYS (vaszprintf, ptrdiff_t,
(char **result, const char *format, va_list args));
#endif
# define asprintf rpl_asprintf
# endif
# define GNULIB_overrides_asprintf
-_GL_ATTRIBUTE_NODISCARD
_GL_FUNCDECL_RPL (asprintf, int,
(char **result, const char *format, ...)
_GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3)
- _GL_ARG_NONNULL ((1, 2)));
+ _GL_ARG_NONNULL ((1, 2))
+ _GL_ATTRIBUTE_NODISCARD);
_GL_CXXALIAS_RPL (asprintf, int,
(char **result, const char *format, ...));
# else
# if !@HAVE_VASPRINTF@
-_GL_ATTRIBUTE_NODISCARD
_GL_FUNCDECL_SYS (asprintf, int,
(char **result, const char *format, ...)
_GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3)
- _GL_ARG_NONNULL ((1, 2)));
+ _GL_ARG_NONNULL ((1, 2))
+ _GL_ATTRIBUTE_NODISCARD);
# endif
_GL_CXXALIAS_SYS (asprintf, int,
(char **result, const char *format, ...));
# define vasprintf rpl_vasprintf
# endif
# define GNULIB_overrides_vasprintf 1
-_GL_ATTRIBUTE_NODISCARD
_GL_FUNCDECL_RPL (vasprintf, int,
(char **result, const char *format, va_list args)
_GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0)
- _GL_ARG_NONNULL ((1, 2)));
+ _GL_ARG_NONNULL ((1, 2))
+ _GL_ATTRIBUTE_NODISCARD);
_GL_CXXALIAS_RPL (vasprintf, int,
(char **result, const char *format, va_list args));
# else
# if !@HAVE_VASPRINTF@
-_GL_ATTRIBUTE_NODISCARD
_GL_FUNCDECL_SYS (vasprintf, int,
(char **result, const char *format, va_list args)
_GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0)
- _GL_ARG_NONNULL ((1, 2)));
+ _GL_ARG_NONNULL ((1, 2))
+ _GL_ATTRIBUTE_NODISCARD);
# endif
_GL_CXXALIAS_SYS (vasprintf, int,
(char **result, const char *format, va_list args));
# gnulib-common.m4
-# serial 97
+# serial 98
dnl Copyright (C) 2007-2024 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
# define _GL_HAVE___HAS_C_ATTRIBUTE 0
#endif
+/* Attributes in bracket syntax [[...]] vs. attributes in __attribute__((...))
+ syntax, in function declarations. There are two problems here.
+ (Last tested with gcc/g++ 14 and clang/clang++ 18.)
+
+ 1) We want that the _GL_ATTRIBUTE_* can be cumulated on the same declaration
+ in any order.
+ =========================== foo.c = foo.cc ===========================
+ __attribute__ ((__deprecated__)) [[__nodiscard__]] int bar1 (int);
+ [[__nodiscard__]] __attribute__ ((__deprecated__)) int bar2 (int);
+ ======================================================================
+ This gives a syntax error
+ - in C mode with gcc, and
+ - in C++ mode with clang++ version < 16.
+ */
/* 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
# define _GL_BRACKET_BEFORE_ATTRIBUTE 1
# endif
#endif
+/*
+ 2) We want that the _GL_ATTRIBUTE_* can be placed in a declaration
+ - without 'extern', in C as well as in C++,
+ - with 'extern', in C,
+ - with 'extern "C"', in C++
+ in the same position. That is, we don't want to be forced to use a
+ macro which arranges for the attribute to come before 'extern' in
+ one case and after 'extern' in the other case, because such a macro
+ would make the source code of .h files pretty ugly.
+ =========================== foo.c = foo.cc ===========================
+ #ifdef __cplusplus
+ # define CC "C"
+ #else
+ # define CC
+ #endif
+
+ #define ND [[__nodiscard__]]
+ #define WUR __attribute__((__warn_unused_result__))
+
+ #ifdef __cplusplus
+ extern "C" {
+ #endif
+ // gcc clang g++ clang++
+
+ ND int foo (int);
+ int ND foo (int); // warn error warn error
+ int foo (int) ND; // warn error warn error
+
+ WUR int foo (int);
+ int WUR foo (int);
+ int foo (int) WUR;
+
+ #ifdef __cplusplus
+ }
+ #endif
+
+ // gcc clang g++ clang++
+
+ ND extern CC int foo (int); // error error
+ extern CC ND int foo (int); // error error
+ extern CC int ND foo (int); // warn error warn error
+ extern CC int foo (int) ND; // warn error warn error
+
+ WUR extern CC int foo (int); // warn
+ extern CC WUR int foo (int);
+ extern CC int WUR foo (int);
+ extern CC int foo (int) WUR;
+ ======================================================================
+ So,
+ * If _GL_ATTRIBUTE_* expands to bracket syntax [[...]]
+ in both C and C++, there is no available position:
+ it would need to come before 'extern' in C but after 'extern "C"'
+ in C++.
+ * If _GL_ATTRIBUTE_* expands to __attribute__((...)) syntax
+ in both C and C++, there are several available positions:
+ - before the return type,
+ - between return type and function name,
+ - at the end of the declaration.
+ * If _GL_ATTRIBUTE_* expands to bracket syntax [[...]] in C and
+ to __attribute__((...)) syntax in C++, there is no available position:
+ it would need to come before 'extern' in C but after 'extern "C"'
+ in C++.
+ * If _GL_ATTRIBUTE_* expands to __attribute__((...)) syntax in C and
+ to bracket syntax [[...]] in C++, there is one available position:
+ - before the return type.
+ */
+/* Define if, in a function declaration, the attributes in bracket syntax
+ [[...]] are usable at all. */
+#ifdef __cplusplus
+# define _GL_BRACKET_USABLE 1
+#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
- typedef,
in C++ also: namespace, class, template specialization. */
#ifndef _GL_ATTRIBUTE_DEPRECATED
-# ifndef _GL_BRACKET_BEFORE_ATTRIBUTE
+# if defined _GL_BRACKET_USABLE && !defined _GL_BRACKET_BEFORE_ATTRIBUTE
# if _GL_HAVE___HAS_C_ATTRIBUTE
# if __has_c_attribute (__deprecated__)
# define _GL_ATTRIBUTE_DEPRECATED [[__deprecated__]]
__has_c_attribute (__maybe_unused__) yields true but the use of
[[__maybe_unused__]] nevertheless produces a warning. */
#ifndef _GL_ATTRIBUTE_MAYBE_UNUSED
-# ifndef _GL_BRACKET_BEFORE_ATTRIBUTE
+# if defined _GL_BRACKET_USABLE && !defined _GL_BRACKET_BEFORE_ATTRIBUTE
# if defined __clang__ && defined __cplusplus
# if !defined __apple_build_version__ && __clang_major__ >= 10
# define _GL_ATTRIBUTE_MAYBE_UNUSED [[__maybe_unused__]]
the return value, unless the caller uses something like ignore_value. */
/* Applies to: function, enumeration, class. */
#ifndef _GL_ATTRIBUTE_NODISCARD
-# ifndef _GL_BRACKET_BEFORE_ATTRIBUTE
+# if defined _GL_BRACKET_USABLE && !defined _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.
#ifndef _GL_ATTRIBUTE_REPRODUCIBLE
/* This may be revisited when gcc and clang support [[reproducible]] or possibly
__attribute__ ((__reproducible__)). */
-# ifndef _GL_BRACKET_BEFORE_ATTRIBUTE
+# if defined _GL_BRACKET_USABLE && !defined _GL_BRACKET_BEFORE_ATTRIBUTE
# if _GL_HAS_ATTRIBUTE (reproducible)
# define _GL_ATTRIBUTE_REPRODUCIBLE [[reproducible]]
# endif
#ifndef _GL_ATTRIBUTE_UNSEQUENCED
/* This may be revisited when gcc and clang support [[unsequenced]] or possibly
__attribute__ ((__unsequenced__)). */
-# ifndef _GL_BRACKET_BEFORE_ATTRIBUTE
+# if defined _GL_BRACKET_USABLE && !defined _GL_BRACKET_BEFORE_ATTRIBUTE
# if _GL_HAS_ATTRIBUTE (unsequenced)
# define _GL_ATTRIBUTE_UNSEQUENCED [[unsequenced]]
# endif