diff --git a/SConstruct b/SConstruct index edd0b8174..8aeb703a2 100644 --- a/SConstruct +++ b/SConstruct @@ -240,6 +240,55 @@ int A::a(); ''' self.Compile(context, text=text, msg='whether C++ compiler treats specializations as distinct', successflags=f) @_custom_test + def check_attribute_error(self,context): + """ +help:assume compiler supports __attribute__((error)) +""" + f = ''' +void a()__attribute__((__error__("a called"))); +void b(); +void b(){ + %s +} +''' + if self.Compile(context, text=f % '', msg='whether compiler accepts function __attribute__((__error__))') and \ + self.Compile(context, text=f % 'a();', msg='whether compiler understands function __attribute__((__error__))', expect_failure=True) and \ + self.Compile(context, text=f % 'if("0"[0]==\'1\')a();', msg='whether compiler optimizes function __attribute__((__error__))'): + context.sconf.Define('DXX_HAVE_ATTRIBUTE_ERROR') + context.sconf.Define('__attribute_error(M)', '__attribute__((__error__(M)))') + else: + context.sconf.Define('__attribute_error(M)', self.comment_not_supported) + @_custom_test + def check_builtin_constant_p(self,context): + """ +help:assume compiler supports compile-time __builtin_constant_p +""" + f = ''' +int c(int); +static inline int a(int b){ + return __builtin_constant_p(b) ? 1 : %s; +} +int main(int argc, char **argv){ + return a(1); +} +''' + if self.Compile(context, text=f % '2', msg='whether compiler accepts __builtin_constant_p') and \ + self.Link(context, text=f % 'c(b)', msg='whether compiler optimizes __builtin_constant_p'): + context.sconf.Define('DXX_HAVE_BUILTIN_CONSTANT_P') + context.sconf.Define('dxx_builtin_constant_p(A)', '__builtin_constant_p(A)') + else: + context.sconf.Define('dxx_builtin_constant_p(A)', '((void)(A),0)') + @_custom_test + def check_embedded_compound_statement(self,context): + f = ''' +int a(); +int a(){ + return ({ 1 + 2; }); +} +''' + if self.Compile(context, text=f, msg='whether compiler understands embedded compound statements'): + context.sconf.Define('DXX_HAVE_EMBEDDED_COMPOUND_STATEMENT') + @_custom_test def check_attribute_format_arg(self,context): """ help:assume compiler supports __attribute__((format_arg)) diff --git a/common/include/fmtcheck.h b/common/include/fmtcheck.h index 2ea8b2731..2f71f45b0 100644 --- a/common/include/fmtcheck.h +++ b/common/include/fmtcheck.h @@ -2,12 +2,27 @@ #include "dxxsconf.h" +#if defined(DXX_HAVE_EMBEDDED_COMPOUND_STATEMENT) +#define _dxx_printf_raise_error(N,S) ( \ + ({ \ + void N(void) __attribute_error(S); \ + N(); \ + }), 0) +#else +#define _dxx_printf_raise_error(N,S) (0) +#endif + #define _dxx_call_printf_unwrap_args(...) , ## __VA_ARGS__ #define _dxx_call_printf_delete_comma2(A,...) __VA_ARGS__ #define _dxx_call_printf_delete_comma(A,...) _dxx_call_printf_delete_comma2( A , ## __VA_ARGS__ ) +#define _dxx_printf_check_has_nontrivial_format_string(V,P,FMT) \ + ((void)((dxx_builtin_constant_p((FMT)) && (FMT)[0] == '%' && (FMT)[1] == 's' && (FMT)[2] == 0) && \ + _dxx_printf_raise_error(dxx_trap_trivial_string_specifier_argument_##V, "bare %s argument to " #V "; use " #P " directly"))) + #define dxx_call_printf_checked(V,P,A,FMT,...) \ ( \ + _dxx_printf_check_has_nontrivial_format_string(V, P, FMT), \ (sizeof(#__VA_ARGS__) == 1) ? \ (P(_dxx_call_printf_delete_comma(1 _dxx_call_printf_unwrap_args A, FMT))) : \ (V(_dxx_call_printf_delete_comma(1 _dxx_call_printf_unwrap_args A, FMT) ,##__VA_ARGS__)) \