From 0958e19ffb047781fe1506760c7cbd8d7fe74e57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8D=9C=E9=83=A8=E6=98=8C=E5=B9=B3?= Date: Mon, 2 Dec 2019 14:58:43 +0900 Subject: add several __has_something macro With these macros implemented we can write codes just like we can assume the compiler being clang. MSC_VERSION_SINCE is defined to implement those macros, but turned out to be handy for other places. The -fdeclspec compiler flag is necessary for clang to properly handle __has_declspec(). --- bignum.c | 2 -- configure.ac | 2 ++ internal/compilers.h | 99 +++++++++++++++++++++++++++++++++++++++++++++++++--- internal/gc.h | 2 -- numeric.c | 22 ++++++------ random.c | 2 +- ruby_atomic.h | 6 ++-- vm_insnhelper.c | 4 +-- 8 files changed, 112 insertions(+), 27 deletions(-) diff --git a/bignum.c b/bignum.c index 4569183e45..370c63c787 100644 --- a/bignum.c +++ b/bignum.c @@ -5373,11 +5373,9 @@ rb_integer_float_cmp(VALUE x, VALUE y) #if SIZEOF_LONG * CHAR_BIT >= DBL_MANT_DIG /* assume FLT_RADIX == 2 */ COMPILER_WARNING_PUSH -#ifdef __has_warning #if __has_warning("-Wimplicit-int-float-conversion") COMPILER_WARNING_IGNORED(-Wimplicit-int-float-conversion) #endif -#endif static const double LONG_MAX_as_double = LONG_MAX; COMPILER_WARNING_POP #endif diff --git a/configure.ac b/configure.ac index f1ed36bb96..f9e8573d45 100644 --- a/configure.ac +++ b/configure.ac @@ -481,6 +481,8 @@ AS_IF([test x"${RPATHFLAG}" = x], [ rpathflag=`echo "$RPATHFLAG" | sed 's/%.*//'` ]) +RUBY_TRY_CFLAGS(-fdeclspec, [RUBY_APPEND_OPTIONS(XCFLAGS, -fdeclspec)]) + AS_CASE([$RUBY_PATCHLEVEL], [-*], [RUBY_DEVEL=yes], [RUBY_DEVEL=no]) particular_werror_flags=$RUBY_DEVEL diff --git a/internal/compilers.h b/internal/compilers.h index 697bad5f4e..5a9e566e71 100644 --- a/internal/compilers.h +++ b/internal/compilers.h @@ -10,22 +10,111 @@ * file COPYING are met. Consult the file for details. */ -#ifndef MAYBE_UNUSED -# define MAYBE_UNUSED(x) x +#include "ruby/defines.h" /* for GCC_VERSION_SINCE */ + +#ifdef _MSC_VER +# define MSC_VERSION_SINCE(_) (_MSC_VER >= _) +# define MSC_VERSION_BEFORE(_) (_MSC_VER < _) +#else +# define MSC_VERSION_SINCE(_) 0 +# define MSC_VERSION_BEFORE(_) 0 #endif -#ifndef WARN_UNUSED_RESULT -# define WARN_UNUSED_RESULT(x) x +#ifndef __has_attribute +# define __has_attribute(...) __has_attribute_##__VA_ARGS__ +# /* GCC <= 4 lacks __has_attribute predefined macro, while has attributes +# * themselves. We can simulate the macro like the following: */ +# define __has_attribute_aligned GCC_VERSION_SINCE(0, 0, 0) +# define __has_attribute_alloc_size GCC_VERSION_SINCE(4, 3, 0) +# define __has_attribute_artificial GCC_VERSION_SINCE(4, 3, 0) +# define __has_attribute_always_inline GCC_VERSION_SINCE(3, 1, 0) +# define __has_attribute_cdecl GCC_VERSION_SINCE(0, 0, 0) +# define __has_attribute_cold GCC_VERSION_SINCE(4, 3, 0) +# define __has_attribute_const GCC_VERSION_SINCE(2, 6, 0) +# define __has_attribute_deprecated GCC_VERSION_SINCE(3, 1, 0) +# define __has_attribute_dllexport GCC_VERSION_SINCE(0, 0, 0) +# define __has_attribute_dllimport GCC_VERSION_SINCE(0, 0, 0) +# define __has_attribute_error GCC_VERSION_SINCE(4, 3, 0) +# define __has_attribute_format GCC_VERSION_SINCE(0, 0, 0) +# define __has_attribute_hot GCC_VERSION_SINCE(4, 3, 0) +# define __has_attribute_leaf GCC_VERSION_SINCE(4, 6, 0) +# define __has_attribute_malloc GCC_VERSION_SINCE(3, 0, 0) +# define __has_attribute_no_address_safety_analysis GCC_VERSION_SINCE(4, 8, 0) +# define __has_attribute_no_sanitize_address GCC_VERSION_SINCE(4, 8, 0) +# define __has_attribute_no_sanitize_undefined GCC_VERSION_SINCE(4, 9, 0) +# define __has_attribute_noinline GCC_VERSION_SINCE(3, 1, 0) +# define __has_attribute_nonnull GCC_VERSION_SINCE(3, 3, 0) +# define __has_attribute_noreturn GCC_VERSION_SINCE(2, 5, 0) +# define __has_attribute_nothrow GCC_VERSION_SINCE(3, 3, 0) +# define __has_attribute_pure GCC_VERSION_SINCE(2, 96, 0) +# define __has_attribute_returns_nonnull GCC_VERSION_SINCE(4, 9, 0) +# define __has_attribute_returns_twice GCC_VERSION_SINCE(4, 1, 0) +# define __has_attribute_stdcall GCC_VERSION_SINCE(0, 0, 0) +# define __has_attribute_unused GCC_VERSION_SINCE(0, 0, 0) +# define __has_attribute_visibility GCC_VERSION_SINCE(3, 3, 0) +# define __has_attribute_visibility GCC_VERSION_SINCE(3, 3, 0) +# define __has_attribute_warn_unused_result GCC_VERSION_SINCE(3, 4, 0) +# define __has_attribute_warning GCC_VERSION_SINCE(4, 3, 0) +# define __has_attribute_weak GCC_VERSION_SINCE(0, 0, 0) +# /* Note that 0,0,0 might be inaccurate. */ +#endif + +#ifndef __has_c_attribute +# /* As of writing everything that lacks __has_c_attribute also completely +# * lacks C2x attributes as well. Might change in future? */ +# define __has_c_attribute(...) 0 +#endif + +#ifndef __has_declspec_attribute +# define __has_declspec_attribute(...) __has_declspec_attribute_##__VA_ARGS__ +# define __has_declspec_attribute_align MSC_VERSION_SINCE( 800) +# define __has_declspec_attribute_deprecated MSC_VERSION_SINCE(1300) +# define __has_declspec_attribute_dllexport MSC_VERSION_SINCE( 800) +# define __has_declspec_attribute_dllimport MSC_VERSION_SINCE( 800) +# define __has_declspec_attribute_noalias MSC_VERSION_SINCE( 800) +# define __has_declspec_attribute_noinline MSC_VERSION_SINCE(1300) +# define __has_declspec_attribute_noreturn MSC_VERSION_SINCE(1100) +# define __has_declspec_attribute_nothrow MSC_VERSION_SINCE( 800) +# define __has_declspec_attribute_restrict MSC_VERSION_SINCE( 800) +# /* Note that 800 might be inaccurate. */ +#endif + +#ifndef __has_builtin +# /* :FIXME: Historically GCC has had tons of builtins, but it implemented +# * __has_builtin only since GCC 10. This section can be made more +# * granular. */ +# /* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66970 */ +# define __has_builtin(...) GCC_VERSION_SINCE(0, 0, 0) #endif #ifndef __has_feature -# define __has_feature(x) 0 +# define __has_feature(...) 0 #endif #ifndef __has_extension +# /* Pre-3.0 clang had __has_feature but not __has_extension. */ # define __has_extension __has_feature #endif +#ifndef __has_warning +# /* We cannot simulate __has_warning like the ones above, because it takes +# * string liteals (we can stringize a macro arugment but there is no such +# * thing like an unquote of strrings). */ +# define __has_warning(...) 0 +#endif + +#ifndef __GNUC__ +# define __extension__ /* void */ +#endif + +#ifndef MAYBE_UNUSED +# define MAYBE_UNUSED(x) x +#endif + +#ifndef WARN_UNUSED_RESULT +# define WARN_UNUSED_RESULT(x) x +#endif + #define RB_OBJ_BUILTIN_TYPE(obj) rb_obj_builtin_type(obj) #define OBJ_BUILTIN_TYPE(obj) RB_OBJ_BUILTIN_TYPE(obj) #ifdef __GNUC__ diff --git a/internal/gc.h b/internal/gc.h index cf59eaed0b..6e3fb8996d 100644 --- a/internal/gc.h +++ b/internal/gc.h @@ -47,11 +47,9 @@ RUBY_SYMBOL_EXPORT_END rb_wb_unprotected_newobj_of(klass, flags)) #define NEWOBJ_OF(obj,type,klass,flags) RB_NEWOBJ_OF(obj,type,klass,flags) -#ifdef __has_attribute #if __has_attribute(alloc_align) __attribute__((__alloc_align__(1))) #endif -#endif void *rb_aligned_malloc(size_t, size_t) RUBY_ATTR_MALLOC RUBY_ATTR_ALLOC_SIZE((2)); size_t rb_size_mul_or_raise(size_t, size_t, VALUE); /* used in compile.c */ diff --git a/numeric.c b/numeric.c index fa8961652b..218dabe462 100644 --- a/numeric.c +++ b/numeric.c @@ -1389,7 +1389,7 @@ rb_float_equal(VALUE x, VALUE y) } else if (RB_TYPE_P(y, T_FLOAT)) { b = RFLOAT_VALUE(y); -#if defined(_MSC_VER) && _MSC_VER < 1300 +#if MSC_VERSION_BEFORE(1300) if (isnan(b)) return Qfalse; #endif } @@ -1397,7 +1397,7 @@ rb_float_equal(VALUE x, VALUE y) return num_equal(x, y); } a = RFLOAT_VALUE(x); -#if defined(_MSC_VER) && _MSC_VER < 1300 +#if MSC_VERSION_BEFORE(1300) if (isnan(a)) return Qfalse; #endif return (a == b)?Qtrue:Qfalse; @@ -1513,14 +1513,14 @@ rb_float_gt(VALUE x, VALUE y) } else if (RB_TYPE_P(y, T_FLOAT)) { b = RFLOAT_VALUE(y); -#if defined(_MSC_VER) && _MSC_VER < 1300 +#if MSC_VERSION_BEFORE(1300) if (isnan(b)) return Qfalse; #endif } else { return rb_num_coerce_relop(x, y, '>'); } -#if defined(_MSC_VER) && _MSC_VER < 1300 +#if MSC_VERSION_BEFORE(1300) if (isnan(a)) return Qfalse; #endif return (a > b)?Qtrue:Qfalse; @@ -1550,14 +1550,14 @@ flo_ge(VALUE x, VALUE y) } else if (RB_TYPE_P(y, T_FLOAT)) { b = RFLOAT_VALUE(y); -#if defined(_MSC_VER) && _MSC_VER < 1300 +#if MSC_VERSION_BEFORE(1300) if (isnan(b)) return Qfalse; #endif } else { return rb_num_coerce_relop(x, y, idGE); } -#if defined(_MSC_VER) && _MSC_VER < 1300 +#if MSC_VERSION_BEFORE(1300) if (isnan(a)) return Qfalse; #endif return (a >= b)?Qtrue:Qfalse; @@ -1587,14 +1587,14 @@ flo_lt(VALUE x, VALUE y) } else if (RB_TYPE_P(y, T_FLOAT)) { b = RFLOAT_VALUE(y); -#if defined(_MSC_VER) && _MSC_VER < 1300 +#if MSC_VERSION_BEFORE(1300) if (isnan(b)) return Qfalse; #endif } else { return rb_num_coerce_relop(x, y, '<'); } -#if defined(_MSC_VER) && _MSC_VER < 1300 +#if MSC_VERSION_BEFORE(1300) if (isnan(a)) return Qfalse; #endif return (a < b)?Qtrue:Qfalse; @@ -1624,14 +1624,14 @@ flo_le(VALUE x, VALUE y) } else if (RB_TYPE_P(y, T_FLOAT)) { b = RFLOAT_VALUE(y); -#if defined(_MSC_VER) && _MSC_VER < 1300 +#if MSC_VERSION_BEFORE(1300) if (isnan(b)) return Qfalse; #endif } else { return rb_num_coerce_relop(x, y, idLE); } -#if defined(_MSC_VER) && _MSC_VER < 1300 +#if MSC_VERSION_BEFORE(1300) if (isnan(a)) return Qfalse; #endif return (a <= b)?Qtrue:Qfalse; @@ -1656,7 +1656,7 @@ rb_float_eql(VALUE x, VALUE y) if (RB_TYPE_P(y, T_FLOAT)) { double a = RFLOAT_VALUE(x); double b = RFLOAT_VALUE(y); -#if defined(_MSC_VER) && _MSC_VER < 1300 +#if MSC_VERSION_BEFORE(1300) if (isnan(a) || isnan(b)) return Qfalse; #endif if (a == b) diff --git a/random.c b/random.c index 68b47bcf1b..d763a214cd 100644 --- a/random.c +++ b/random.c @@ -137,7 +137,7 @@ int_pair_to_real_inclusive(uint32_t a, uint32_t b) const uint128_t m = ((uint128_t)1 << dig) | 1; uint128_t x = ((uint128_t)a << 32) | b; r = (double)(uint64_t)((x * m) >> 64); -#elif defined HAVE_UINT64_T && !(defined _MSC_VER && _MSC_VER <= 1200) +#elif defined HAVE_UINT64_T && !MSC_VERSION_BEFORE(1300) uint64_t x = ((uint64_t)a << dig_u) + (((uint64_t)b + (a >> dig_u)) >> dig_r64); r = (double)x; diff --git a/ruby_atomic.h b/ruby_atomic.h index 1b395cd23f..4a6723a92e 100644 --- a/ruby_atomic.h +++ b/ruby_atomic.h @@ -38,7 +38,7 @@ typedef unsigned int rb_atomic_t; /* Anything OK */ # define RUBY_ATOMIC_GENERIC_MACRO 1 #elif defined _WIN32 -#if defined _MSC_VER && _MSC_VER > 1200 +#if MSC_VERSION_SINCE(1300) #pragma intrinsic(_InterlockedOr) #endif typedef LONG rb_atomic_t; @@ -48,7 +48,7 @@ typedef LONG rb_atomic_t; # define ATOMIC_DEC(var) InterlockedDecrement(&(var)) #if defined __GNUC__ # define ATOMIC_OR(var, val) __asm__("lock\n\t" "orl\t%1, %0" : "=m"(var) : "Ir"(val)) -#elif defined _MSC_VER && _MSC_VER <= 1200 +#elif MSC_VERSION_BEFORE(1300) # define ATOMIC_OR(var, val) rb_w32_atomic_or(&(var), (val)) static inline void rb_w32_atomic_or(volatile rb_atomic_t *var, rb_atomic_t val) @@ -66,7 +66,7 @@ rb_w32_atomic_or(volatile rb_atomic_t *var, rb_atomic_t val) #endif # define ATOMIC_EXCHANGE(var, val) InterlockedExchange(&(var), (val)) # define ATOMIC_CAS(var, oldval, newval) InterlockedCompareExchange(&(var), (newval), (oldval)) -# if defined _MSC_VER && _MSC_VER <= 1200 +# if MSC_VERSION_BEFORE(1300) static inline rb_atomic_t rb_w32_atomic_cas(volatile rb_atomic_t *var, rb_atomic_t oldval, rb_atomic_t newval) { diff --git a/vm_insnhelper.c b/vm_insnhelper.c index 2ac006a605..0cd4bdefe9 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -1424,11 +1424,9 @@ vm_expandarray(VALUE *sp, VALUE ary, rb_num_t num, int flag) static VALUE vm_call_general(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling, struct rb_call_data *cd); -#ifdef __has_attribute #if __has_attribute(artificial) __attribute__((__artificial__)) #endif -#endif static inline vm_call_handler calccall(const struct rb_call_data *cd, const rb_callable_method_entry_t *me) { @@ -1817,7 +1815,7 @@ check_match(rb_execution_context_t *ec, VALUE pattern, VALUE target, enum vm_che } -#if defined(_MSC_VER) && _MSC_VER < 1300 +#if MSC_VERSION_BEFORE(1300) #define CHECK_CMP_NAN(a, b) if (isnan(a) || isnan(b)) return Qfalse; #else #define CHECK_CMP_NAN(a, b) /* do nothing */ -- cgit v1.2.3