config.h: separate function and function pointer attributes; automate

Separate out function and function pointer attributes, as not all
versions of all compilers support both.

Have macros related to function attributes auto-generated by
autoheader. As a result, rename config.h.in to unconfig.h, to make it
more obvious that it is really intended to be included from some C
programs.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
This commit is contained in:
H. Peter Anvin (Intel) 2019-08-16 00:08:27 -07:00
parent 9fbd9fb859
commit 8b6e6bf04f
9 changed files with 104 additions and 100 deletions

2
.gitignore vendored
View File

@ -50,7 +50,7 @@ TAGS
/asm/tokhash.c
/asm/warnings.c
/config/config.h
/config/config.h.in
/config/unconfig.h
/config.log
/config.status
/configure

View File

@ -102,7 +102,7 @@ struct lfmt {
/*
* Called on a warning or error, with the error message.
*/
void printf_func(2, 3) (*error)(errflags severity, const char *fmt, ...);
void printf_func_ptr(2, 3) (*error)(errflags severity, const char *fmt, ...);
/*
* Update the current offset. Used to give the listing generator

View File

@ -1,10 +0,0 @@
/autoconf/aclocal.m4
/autoconf/compile
/autoconf/config.*
/autoconf/install-sh
/config/config.h
/config/config.h.in
/config.log
/config.status
/configure
/Makefile

View File

@ -4,14 +4,23 @@ dnl
dnl See if this compiler supports the equivalent of a specific gcc
dnl attribute on a function, using the __attribute__(()) syntax.
dnl All arguments except the attribute name are optional.
dnl
dnl PA_FUNC_ATTRIBUTE(attribute, attribute_opts, return_type,
dnl prototype_args, call_args)
dnl prototype_args, call_args, altname)
dnl
dnl This tests the attribute both on a function pointer and on a
dnl direct function, as some gcc [and others?] versions have problems
dnl with attributes on function pointers, and we might as well check both.
dnl --------------------------------------------------------------------------
AC_DEFUN([PA_FUNC_ATTRIBUTE],
AC_DEFUN([_PA_FUNC_ATTRIBUTE],
[AC_MSG_CHECKING([if $CC supports the $1 function attribute])
m4_define([_pa_faa],ifelse([$2],[],[],[($2)]))
m4_define([_pa_fam],ifelse([$2],[],[],[(m4_join([,],m4_for(_pa_n,1,m4_count($2),1,[m4_quote([x]_pa_n),])))]))
m4_define([_pa_suf],ifelse([$2],[],[],[m4_count($2)]))
m4_define([_pa_mac],ifelse([$6],[],[$1_func]_pa_suf,[$6]))
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
AC_INCLUDES_DEFAULT
extern ifelse([$3],[],[void *],[$3]) __attribute__(($1$2))
extern ifelse([$3],[],[void *],[$3]) __attribute__(([$1]_pa_faa))
bar(ifelse([$4],[],[int],[$4]));
ifelse([$3],[],[void *],[$3]) foo(void);
ifelse([$3],[],[void *],[$3]) foo(void)
@ -21,7 +30,60 @@ ifelse([$3],[],[void *],[$3]) foo(void)
}
])],
[AC_MSG_RESULT([yes])
AC_DEFINE(PA_SYM([HAVE_FUNC_ATTRIBUTE_],[$1]), 1,
AC_DEFINE(PA_SYM([HAVE_FUNC_ATTRIBUTE],_pa_suf,[_$1]), 1,
[Define to 1 if your compiler supports __attribute__(($1)) on functions])],
[AC_MSG_RESULT([no])])
AH_BOTTOM(m4_quote(m4_join([],
[#ifndef ],_pa_mac,[
# ifdef ],PA_SYM([HAVE_FUNC_ATTRIBUTE],_pa_suf,[_$1]),[
# define ],_pa_mac,m4_quote(_pa_fam),[ __attribute__(($1],m4_quote(_pa_fam),[))
# else
# define ],_pa_mac,m4_quote(_pa_fam),[
# endif
#endif])))
])
AC_DEFUN([_PA_FUNC_PTR_ATTRIBUTE],
[AC_MSG_CHECKING([if $CC supports the $1 function attribute on pointers])
m4_define([_pa_faa],ifelse([$2],[],[],[($2)]))
m4_define([_pa_fam],ifelse([$2],[],[],[(m4_join([,],m4_for(_pa_n,1,m4_count($2),1,[m4_quote([x]_pa_n),])))]))
m4_define([_pa_suf],ifelse([$2],[],[],[m4_count($2)]))
m4_define([_pa_mac],ifelse([$6],[],[$1_func]_pa_suf,[$6])_ptr)
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
AC_INCLUDES_DEFAULT
extern ifelse([$3],[],[void *],[$3]) __attribute__(([$1]_pa_faa))
(*bar1)(ifelse([$4],[],[int],[$4]));
ifelse([$3],[],[void *],[$3]) foo1(void);
ifelse([$3],[],[void *],[$3]) foo1(void)
{
ifelse([$3],[void],[],[return])
bar1(ifelse([$5],[],[1],[$5]));
}
typedef ifelse([$3],[],[void *],[$3]) __attribute__(([$1]_pa_faa))
(*bar_t)(ifelse([$4],[],[int],[$4]));
extern bar_t bar2;
ifelse([$3],[],[void *],[$3]) foo2(void);
ifelse([$3],[],[void *],[$3]) foo2(void)
{
ifelse([$3],[void],[],[return])
bar2(ifelse([$5],[],[1],[$5]));
}
])],
[AC_MSG_RESULT([yes])
AC_DEFINE(PA_SYM([HAVE_FUNC_PTR_ATTRIBUTE],_pa_suf,[_$1]), 1,
[Define to 1 if your compiler supports __attribute__(($1)) on function pointers])],
[AC_MSG_RESULT([no])])
AH_BOTTOM(m4_quote(m4_join([],
[#ifndef ],_pa_mac,[
# ifdef ],PA_SYM([HAVE_FUNC_PTR_ATTRIBUTE],_pa_suf,[_$1]),[
# define ],_pa_mac,m4_quote(_pa_fam),[ __attribute__(($1],m4_quote(_pa_fam),[))
# else
# define ],_pa_mac,m4_quote(_pa_fam),[
# endif
#endif])))
])
AC_DEFUN([PA_FUNC_ATTRIBUTE],
[_PA_FUNC_ATTRIBUTE([$1],[$2],[$3],[$4],[$5],[$6])
_PA_FUNC_PTR_ATTRIBUTE([$1],[$2],[$3],[$4],[$5],[$6])])

View File

@ -4,6 +4,9 @@ dnl
dnl See if this compiler supports __attribute__((error("foo")))
dnl The generic version of this doesn't work as it makes the compiler
dnl throw an error by design.
dnl
dnl This doesn't use a function pointer because there is no need:
dnl the error function will never be a function pointer.
dnl --------------------------------------------------------------------------
AC_DEFUN([PA_FUNC_ATTRIBUTE_ERROR],
[AC_MSG_CHECKING([if $CC supports the error function attribute])

View File

@ -4,4 +4,5 @@ dnl
dnl Convert a (semi-) arbitrary string to a CPP symbol
dnl --------------------------------------------------------------------------
AC_DEFUN([PA_SYM],
[m4_normalize([$1])m4_bpatsubsts(m4_toupper([$2]),[[^ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]+],[_],[^._?\(.*\)_.$],[[\1]])])
[m4_bpatsubsts(m4_quote(m4_toupper([$*])),
[,],[],[[^ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]+],[_],[^._?\(.*\)_.$],[[\1]])])

View File

@ -35,7 +35,7 @@
* config/msvc.h
*
* Compiler definitions for Microsoft Visual C++;
* instead of config.h.in. See config.h.in for the
* instead of unconfig.h. See config.h.in for the
* variables which can be defined here.
*
* MSDN seems to have information back to Visual Studio 2003, so aim

View File

@ -1,8 +1,8 @@
dnl Process this file with autoconf 2.69 or later to produce
dnl a configure script.
AC_PREREQ(2.69)
AC_INIT(config/config.h.in)
AC_CONFIG_HEADERS(config/config.h)
AC_INIT([config/undef.h])
AC_CONFIG_HEADERS([config/config.h:config/unconfig.h])
AC_PREFIX_PROGRAM(nasm)
AC_CONFIG_AUX_DIR(autoconf/helpers)
@ -225,14 +225,15 @@ dnl some other features of gcc.
dnl
PA_ADD_CFLAGS([-Werror=attributes])
PA_FUNC_ATTRIBUTE(noreturn)
PA_FUNC_ATTRIBUTE(returns_nonnull)
PA_FUNC_ATTRIBUTE(returns_nonnull,,,,,never_null)
PA_FUNC_ATTRIBUTE(malloc)
PA_FUNC_ATTRIBUTE(alloc_size, (1))
PA_FUNC_ATTRIBUTE(sentinel,,, [const char *, ...], ["a","b",NULL])
PA_FUNC_ATTRIBUTE(format, [(printf,1,2)], int, [const char *, ...], ["%d",1])
PA_FUNC_ATTRIBUTE(alloc_size,[1])
PA_FUNC_ATTRIBUTE(alloc_size,[1,2])
PA_FUNC_ATTRIBUTE(sentinel,,, [const char *, ...], ["a","b",NULL],end_with_null)
PA_FUNC_ATTRIBUTE(format, [printf,1,2], int, [const char *, ...], ["%d",1])
PA_FUNC_ATTRIBUTE(const)
PA_FUNC_ATTRIBUTE(pure)
PA_FUNC_ATTRIBUTE(cold)
PA_FUNC_ATTRIBUTE(cold,,,,,unlikely_func)
PA_FUNC_ATTRIBUTE_ERROR
dnl

View File

@ -56,12 +56,16 @@
#ifdef HAVE_CONFIG_H
# include "config/config.h"
#elif defined(_MSC_VER) && (_MSC_VER >= 1310)
# include "config/msvc.h"
#elif defined(__WATCOMC__)
# include "config/watcom.h"
#else
# include "config/unknown.h"
# if defined(_MSC_VER) && (_MSC_VER >= 1310)
# include "config/msvc.h"
# elif defined(__WATCOMC__)
# include "config/watcom.h"
# else
# include "config/unknown.h"
# endif
/* This unconditionally defines some macros we really want */
# include "config/unconfig.h"
#endif /* Configuration file */
/* This is required to get the standard <inttypes.h> macros when compiling
@ -271,36 +275,15 @@ static inline void *mempcpy(void *dst, const void *src, size_t n)
# define unlikely(x) (!!(x))
#endif
/*
* Hints about malloc-like functions that never return NULL
*/
#ifdef HAVE_FUNC_ATTRIBUTE_RETURNS_NONNULL
# define never_null __attribute__((returns_nonnull))
#else
# define never_null
#endif
#define safe_alloc never_null malloc_func
#define safe_alloc_ptr never_null_ptr malloc_func_ptr
#ifdef HAVE_FUNC_ATTRIBUTE_MALLOC
# define safe_alloc never_null __attribute__((malloc))
#else
# define safe_alloc never_null
#endif
#ifdef HAVE_FUNC_ATTRIBUTE_ALLOC_SIZE
# define safe_malloc(s) safe_alloc __attribute__((alloc_size(s)))
# define safe_malloc2(s1,s2) safe_alloc __attribute__((alloc_size(s1,s2)))
# define safe_realloc(s) never_null __attribute__((alloc_size(s)))
#else
# define safe_malloc(s) safe_alloc
# define safe_malloc2(s1,s2) safe_alloc
# define safe_realloc(s) never_null
#endif
#ifdef HAVE_FUNC_ATTRIBUTE_SENTINEL
# define end_with_null __attribute__((sentinel))
#else
# define end_with_null
#endif
#define safe_malloc(s) safe_alloc alloc_size_func1(s)
#define safe_malloc2(s1,s2) safe_alloc alloc_size_func2(s1,s2)
#define safe_realloc(s) never_null alloc_size_func1(s)
#define safe_malloc_ptr(s) safe_alloc_ptr alloc_size_func1_ptr(s)
#define safe_malloc2_ptr(s1,s2) safe_alloc_ptr alloc_size_func2_ptr(s1,s2)
#define safe_realloc_ptr(s) never_null_ptr alloc_size_func1_ptr(s)
/*
* How to tell the compiler that a function doesn't return
@ -308,59 +291,23 @@ static inline void *mempcpy(void *dst, const void *src, size_t n)
#ifdef HAVE_STDNORETURN_H
# include <stdnoreturn.h>
# define no_return noreturn void
#elif defined(HAVE_FUNC_ATTRIBUTE_NORETURN)
# define no_return void __attribute__((noreturn))
#elif defined(_MSC_VER)
# define no_return __declspec(noreturn) void
#else
# define no_return void
#endif
/*
* How to tell the compiler that a function is unlikely to be executed.
* This differs from unlikely() in that it is applied to a function call,
* not a boolean condition.
*/
#ifdef HAVE_FUNC_ATTRIBUTE_COLD
# define unlikely_func __attribute__((cold))
#else
# define unlikely_func
# define no_return void noreturn_func
#endif
/*
* A fatal function is both unlikely and no_return
*/
#define fatal_func no_return unlikely_func
#define fatal_func no_return unlikely_func
#define fatal_func_ptr no_return unlikely_func_ptr
/*
* How to tell the compiler that a function takes a printf-like string
*/
#ifdef HAVE_FUNC_ATTRIBUTE_FORMAT
# define printf_func(fmt, list) __attribute__((format(printf, fmt, list)))
#else
# define printf_func(fmt, list)
#endif
/*
* How to tell the compiler that a function is pure arithmetic
*/
#ifdef HAVE_FUNC_ATTRIBUTE_CONST
# define const_func __attribute__((const))
#else
# define const_func
#endif
/*
* This function has no side effects, but depends on its arguments,
* memory pointed to by its arguments, or global variables.
* NOTE: functions that return a value by modifying memory pointed to
* by a pointer argument are *NOT* considered pure.
*/
#ifdef HAVE_FUNC_ATTRIBUTE_PURE
# define pure_func __attribute__((pure))
#else
# define pure_func
#endif
#define printf_func(fmt, list) format_func3(printf,fmt,list)
#define printf_func_ptr(fmt, list) format_func3_ptr(printf,fmt,list)
/* Determine probabilistically if something is a compile-time constant */
#ifdef HAVE___BUILTIN_CONSTANT_P