ABORT("Out of memory"); }
# define ABORT(msg) { fprintf(stderr, "%s\n", msg); abort(); }
-#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+#if GC_GNUC_PREREQ(3, 4)
# define CORD_ATTR_UNUSED __attribute__((__unused__))
#else
# define CORD_ATTR_UNUSED /* empty */
#include "gc_cpp.h"
-#if !defined(GC_NEW_DELETE_NEED_THROW) && defined(__GNUC__) \
- && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2))
+#if GC_GNUC_PREREQ(4, 2) && !defined(GC_NEW_DELETE_NEED_THROW)
# define GC_NEW_DELETE_NEED_THROW
#endif
/* We separate it only to make gc.h more suitable as documentation. */
#if defined(GC_H)
+/* Convenient internal macro to test version of GCC. */
+#if defined(__GNUC__) && defined(__GNUC_MINOR__)
+# define GC_GNUC_PREREQ(major, minor) \
+ ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((major) << 16) + (minor))
+#else
+# define GC_GNUC_PREREQ(major, minor) 0 /* FALSE */
+#endif
+
/* Some tests for old macros. These violate our namespace rules and */
/* will disappear shortly. Use the GC_ names. */
#if defined(SOLARIS_THREADS) || defined(_SOLARIS_THREADS) \
# elif defined(__GNUC__)
/* Only matters if used in conjunction with -fvisibility=hidden option. */
# if defined(GC_BUILD) && !defined(GC_NO_VISIBILITY) \
- && (__GNUC__ >= 4 || defined(GC_VISIBILITY_HIDDEN_SET))
+ && (GC_GNUC_PREREQ(4, 0) || defined(GC_VISIBILITY_HIDDEN_SET))
# define GC_API extern __attribute__((__visibility__("default")))
# endif
# endif
/* by using custom GC_oom_func then define GC_OOM_FUNC_RETURNS_ALIAS. */
# ifdef GC_OOM_FUNC_RETURNS_ALIAS
# define GC_ATTR_MALLOC /* empty */
-# elif defined(__GNUC__) && (__GNUC__ > 3 \
- || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
+# elif GC_GNUC_PREREQ(3, 1)
# define GC_ATTR_MALLOC __attribute__((__malloc__))
# elif defined(_MSC_VER) && _MSC_VER >= 1400
# define GC_ATTR_MALLOC __declspec(noalias) __declspec(restrict)
# else
# define GC_ATTR_ALLOC_SIZE(argnum) /* empty */
# endif
-# elif __GNUC__ > 4 \
- || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3 && !defined(__ICC))
+# elif GC_GNUC_PREREQ(4, 3) && !defined(__ICC)
# define GC_ATTR_ALLOC_SIZE(argnum) __attribute__((__alloc_size__(argnum)))
# else
# define GC_ATTR_ALLOC_SIZE(argnum) /* empty */
#endif
#ifndef GC_ATTR_NONNULL
-# if defined(__GNUC__) && __GNUC__ >= 4
+# if GC_GNUC_PREREQ(4, 0)
# define GC_ATTR_NONNULL(argnum) __attribute__((__nonnull__(argnum)))
# else
# define GC_ATTR_NONNULL(argnum) /* empty */
# ifdef GC_BUILD
# undef GC_ATTR_DEPRECATED
# define GC_ATTR_DEPRECATED /* empty */
-# elif defined(__GNUC__) && __GNUC__ >= 4
+# elif GC_GNUC_PREREQ(4, 0)
# define GC_ATTR_DEPRECATED __attribute__((__deprecated__))
# elif defined(_MSC_VER) && _MSC_VER >= 1200
# define GC_ATTR_DEPRECATED __declspec(deprecated)
|| defined(PLATFORM_ANDROID) || defined(__ANDROID__)) \
&& !defined(GC_CAN_SAVE_CALL_STACKS)
# define GC_ADD_CALLER
-# if __GNUC__ >= 3 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
+# if GC_GNUC_PREREQ(2, 95)
/* gcc knows how to retrieve return address, but we don't know */
/* how to generate call stacks. */
# define GC_RETURN_ADDR (GC_word)__builtin_return_address(0)
-# if (__GNUC__ >= 4) && (defined(__i386__) || defined(__amd64__) \
- || defined(__x86_64__) /* and probably others... */)
+# if GC_GNUC_PREREQ(4, 0) && (defined(__i386__) || defined(__amd64__) \
+ || defined(__x86_64__) /* and probably others... */)
# define GC_HAVE_RETURN_ADDR_PARENT
# define GC_RETURN_ADDR_PARENT \
(GC_word)__builtin_extract_return_addr(__builtin_return_address(1))
&& (defined(GC_LINUX_THREADS) || defined(GC_SOLARIS_THREADS))
# define GC_HAVE_PTHREAD_EXIT
/* Intercept pthread_exit on Linux and Solaris. */
-# if defined(__GNUC__) /* since GCC v2.7 */
+# if GC_GNUC_PREREQ(2, 7)
# define GC_PTHREAD_EXIT_ATTRIBUTE __attribute__((__noreturn__))
# elif defined(__NORETURN) /* used in Solaris */
# define GC_PTHREAD_EXIT_ATTRIBUTE __NORETURN
#if !defined(GC_NO_OPERATOR_NEW_ARRAY) \
&& !defined(_ENABLE_ARRAYNEW) /* Digimars */ \
&& (defined(__BORLANDC__) && (__BORLANDC__ < 0x450) \
- || (defined(__GNUC__) && \
- (__GNUC__ < 2 || __GNUC__ == 2 && __GNUC_MINOR__ < 6)) \
+ || (defined(__GNUC__) && !GC_GNUC_PREREQ(2, 6)) \
|| (defined(_MSC_VER) && _MSC_VER <= 1020) \
|| (defined(__WATCOMC__) && __WATCOMC__ < 1050))
# define GC_NO_OPERATOR_NEW_ARRAY
#include "gc.h"
#include "gc_tiny_fl.h"
-#if __GNUC__ >= 3
+#if GC_GNUC_PREREQ(3, 0)
# define GC_EXPECT(expr, outcome) __builtin_expect(expr,outcome)
/* Equivalent to (expr), but predict that usually (expr)==outcome. */
#else
# define GC_EXPECT(expr, outcome) (expr)
-#endif /* __GNUC__ */
+#endif
#ifndef GC_ASSERT
# ifdef NDEBUG
#endif
#ifndef GC_PREFETCH_FOR_WRITE
-# if defined(__GNUC__) && __GNUC__ >= 3 && !defined(GC_NO_PREFETCH_FOR_WRITE)
+# if GC_GNUC_PREREQ(3, 0) && !defined(GC_NO_PREFETCH_FOR_WRITE)
# define GC_PREFETCH_FOR_WRITE(x) __builtin_prefetch((x), 1)
# else
# define GC_PREFETCH_FOR_WRITE(x) (void)0
#include "gc.h"
-#if (__GNUC__ < 3)
-# include <stack> // A more portable way to get stl_alloc.h .
-#else
+#if GC_GNUC_PREREQ(3, 0)
# include <bits/stl_alloc.h>
# ifndef __STL_BEGIN_NAMESPACE
-# define __STL_BEGIN_NAMESPACE namespace std {
-# define __STL_END_NAMESPACE };
+# define __STL_BEGIN_NAMESPACE namespace std {
+# define __STL_END_NAMESPACE };
# endif
-#ifndef __STL_USE_STD_ALLOCATORS
-#define __STL_USE_STD_ALLOCATORS
-#endif
+# ifndef __STL_USE_STD_ALLOCATORS
+# define __STL_USE_STD_ALLOCATORS
+# endif
+#else
+# include <stack> // A more portable way to get stl_alloc.h file.
#endif
/* A hack to deal with gcc 3.1. If you are using gcc3.1 and later, */
/* you should probably really use gc_allocator.h instead. */
-#if defined (__GNUC__) && \
- (__GNUC__ > 3 || (__GNUC__ == 3 && (__GNUC_MINOR__ >= 1)))
+#if GC_GNUC_PREREQ(3, 1)
# define simple_alloc __simple_alloc
#endif
# endif
#endif
+/* Convenient internal macro to test version of Clang. */
+#if defined(__clang__) && defined(__clang_major__)
+# define GC_CLANG_PREREQ(major, minor) \
+ ((__clang_major__ << 16) + __clang_minor__ >= ((major) << 16) + (minor))
+#else
+# define GC_CLANG_PREREQ(major, minor) 0 /* FALSE */
+#endif
+
#ifndef GC_TINY_FL_H
# include "../gc_tiny_fl.h"
#endif
/* located in the "extra" folder). */
# if defined(GC_DLL) && defined(__GNUC__) && !defined(MSWIN32) \
&& !defined(MSWINCE) && !defined(CYGWIN32)
-# if (__GNUC__ >= 4) && !defined(GC_NO_VISIBILITY)
+# if GC_GNUC_PREREQ(4, 0) && !defined(GC_NO_VISIBILITY)
/* See the corresponding GC_API definition. */
# define GC_INNER __attribute__((__visibility__("hidden")))
# else
#endif /* !GC_ATTR_NO_SANITIZE_MEMORY */
#ifndef GC_ATTR_UNUSED
-# if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+# if GC_GNUC_PREREQ(3, 4)
# define GC_ATTR_UNUSED __attribute__((__unused__))
# else
# define GC_ATTR_UNUSED /* empty */
# endif
#endif /* !GC_ATTR_UNUSED */
-#if __GNUC__ >= 3 && !defined(LINT2)
+#if GC_GNUC_PREREQ(3, 0) && !defined(LINT2)
# define EXPECT(expr, outcome) __builtin_expect(expr,outcome)
/* Equivalent to (expr), but predict that usually (expr)==outcome. */
#else
/* The "inline" keyword is determined by Autoconf AC_C_INLINE. */
# define GC_INLINE static inline
#elif defined(_MSC_VER) || defined(__INTEL_COMPILER) || defined(__DMC__) \
- || ((__GNUC__ >= 3) && defined(__STRICT_ANSI__)) \
+ || (GC_GNUC_PREREQ(3, 0) && defined(__STRICT_ANSI__)) \
|| defined(__WATCOMC__)
# define GC_INLINE static __inline
-#elif (__GNUC__ >= 3) || defined(__sun)
+#elif GC_GNUC_PREREQ(3, 0) || defined(__sun)
# define GC_INLINE static inline
#else
# define GC_INLINE static
#endif
#ifndef GC_ATTR_NOINLINE
-# if __GNUC__ >= 4
+# if GC_GNUC_PREREQ(4, 0)
# define GC_ATTR_NOINLINE __attribute__((__noinline__))
# elif _MSC_VER >= 1400
# define GC_ATTR_NOINLINE __declspec(noinline)
#ifndef GC_API_OSCALL
/* This is used to identify GC routines called by name from OS. */
# if defined(__GNUC__)
-# if (__GNUC__ >= 4) && !defined(GC_NO_VISIBILITY)
+# if GC_GNUC_PREREQ(4, 0) && !defined(GC_NO_VISIBILITY)
/* Same as GC_API if GC_DLL. */
# define GC_API_OSCALL extern __attribute__((__visibility__("default")))
# else
GC_API void GC_CALL GC_noop1(word);
#ifndef GC_ATTR_FORMAT_PRINTF
-# if defined(__GNUC__) && __GNUC__ >= 3
+# if GC_GNUC_PREREQ(3, 0)
# define GC_ATTR_FORMAT_PRINTF(spec_argnum, first_checked) \
__attribute__((__format__(__printf__, spec_argnum, first_checked)))
# else
#endif
/* Runtime check for an argument declared as non-null is actually not null. */
-#if defined(__GNUC__) && __GNUC__ >= 4
+#if GC_GNUC_PREREQ(4, 0)
/* Workaround tautological-pointer-compare Clang warning. */
# define NONNULL_ARG_NOT_NULL(arg) (*(volatile void **)&(arg) != NULL)
#else
/* Some convenience macros for cancellation support. */
#if defined(CANCEL_SAFE)
# if defined(GC_ASSERTIONS) && (defined(USE_COMPILER_TLS) \
- || (defined(LINUX) && !defined(ARM32) \
- && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) \
+ || (defined(LINUX) && !defined(ARM32) && GC_GNUC_PREREQ(3, 3)) \
|| defined(HPUX) /* and probably others ... */))
extern __thread unsigned char GC_cancel_disable_count;
# define NEED_CANCEL_DISABLE_COUNT
* allocation.
*/
-/* If we are using a recent version of gcc, we can use */
-/* __builtin_unwind_init() to push the relevant registers onto the stack. */
-# if defined(__GNUC__) && ((__GNUC__ >= 3) \
- || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)) \
+/* If available, we can use __builtin_unwind_init() to push the */
+/* relevant registers onto the stack. */
+# if GC_GNUC_PREREQ(2, 8) \
&& !defined(__INTEL_COMPILER) && !defined(__PATHCC__) \
&& !defined(__FUJITSU) /* for FX10 system */ \
&& !(defined(POWERPC) && defined(DARWIN)) /* for MacOS X 10.3.9 */ \
extern int _end[];
# define DATAEND ((ptr_t)(_end))
# if defined(PLATFORM_ANDROID) && !defined(GC_NO_SIGSETJMP) \
- && !(__ANDROID_API__ >= 18 || __GNUC__ > 4 \
- || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) \
- || __clang_major__ > 3 \
- || (__clang_major__ == 3 && __clang_minor__ >= 2))
+ && !(GC_GNUC_PREREQ(4, 8) || GC_CLANG_PREREQ(3, 2) \
+ || __ANDROID_API__ >= 18)
/* Older Android NDK releases lack sigsetjmp in x86 libc */
/* (setjmp is used instead to find data_start). The bug */
/* is fixed in Android NDK r8e (so, ok to use sigsetjmp */
/* STACKBOTTOM and DATASTART are handled specially in */
/* os_dep.c. */
# if !defined(__GNUC__) || defined(__INTEL_COMPILER) \
- || __GNUC__ >= 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)
+ || GC_GNUC_PREREQ(4, 7)
/* Older GCC has not supported SetUnhandledExceptionFilter */
/* properly on x64 (e.g. SEH unwinding information missed). */
# define MPROTECT_VDB
#endif
#ifndef PREFETCH
-# if defined(__GNUC__) && __GNUC__ >= 3 && !defined(NO_PREFETCH)
+# if GC_GNUC_PREREQ(3, 0) && !defined(NO_PREFETCH)
# define PREFETCH(x) __builtin_prefetch((x), 0, 0)
# else
# define PREFETCH(x) (void)0
#endif
#ifndef GC_PREFETCH_FOR_WRITE
-# if defined(__GNUC__) && __GNUC__ >= 3 && !defined(GC_NO_PREFETCH_FOR_WRITE)
+# if GC_GNUC_PREREQ(3, 0) && !defined(GC_NO_PREFETCH_FOR_WRITE)
# define GC_PREFETCH_FOR_WRITE(x) __builtin_prefetch((x), 1)
# else
# define GC_PREFETCH_FOR_WRITE(x) (void)0
&& !defined(USE_WIN32_COMPILER_TLS) && !defined(USE_COMPILER_TLS) \
&& !defined(USE_CUSTOM_SPECIFIC)
# if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
-# if defined(CYGWIN32) && (__GNUC__ >= 4)
+# if defined(CYGWIN32) && GC_GNUC_PREREQ(4, 0)
# if defined(__clang__)
/* As of Cygwin clang3.5.2, thread-local storage is unsupported. */
# define USE_PTHREAD_SPECIFIC
# define USE_WIN32_COMPILER_TLS
# endif /* !GNU */
# elif (defined(LINUX) && !defined(ARM32) && !defined(AVR32) \
- && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) \
+ && GC_GNUC_PREREQ(3, 3) \
&& !(defined(__clang__) && defined(PLATFORM_ANDROID))) \
|| (defined(PLATFORM_ANDROID) && !defined(__clang__) \
- && defined(ARM32) \
- && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
+ && defined(ARM32) && GC_GNUC_PREREQ(4, 6))
/* As of Android NDK r10e, Clang cannot find __tls_get_addr. */
# define USE_COMPILER_TLS
# elif defined(GC_DGUX386_THREADS) || defined(GC_OSF1_THREADS) \
ext_ex_regn er;
-# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) \
- || __clang_major__ > 3 \
- || (__clang_major__ == 3 && __clang_minor__ >= 3)
+# if GC_GNUC_PREREQ(4, 7) || GC_CLANG_PREREQ(3, 3)
# pragma GCC diagnostic push
/* Suppress "taking the address of label is non-standard" warning. */
# if defined(__clang__)
GC_INNER ptr_t GC_approx_sp(void)
{
volatile word sp;
-# if defined(__GNUC__) && (__GNUC__ >= 4)
+# if GC_GNUC_PREREQ(4, 0)
sp = (word)__builtin_frame_address(0);
# else
sp = (word)&sp;
__LINE__ ); \
exit( 1 ); }
-#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+#if GC_GNUC_PREREQ(3, 4)
# define ATTR_UNUSED __attribute__((__unused__))
#else
# define ATTR_UNUSED /* empty */
word nested_sp(void)
{
-# if defined(__GNUC__) && (__GNUC__ >= 4)
+# if GC_GNUC_PREREQ(4, 0)
return (word)__builtin_frame_address(0);
# else
volatile word sp;