[glib/atomic-older-cplusplus: 7/10] gmacros: Define G_CXX_STD_VERSION and check macros




commit 0c6ca4d48907673b4a2c8ac3f23571fa9212ed1d
Author: Marco Trevisan (TreviƱo) <mail 3v1n0 net>
Date:   Wed Sep 14 01:03:22 2022 +0200

    gmacros: Define G_CXX_STD_VERSION and check macros
    
    Sadly, in C++ there's not an universal way to get what language standard
    is used to compile GLib-based programs, in fact while most compilers
    relies on `__cplusplus`, MSVC is defining that, but it does not use it
    to expose such information (unless `/Zc:__cplusplus` arg is used).
    On the other side, MSVC reports the language standard via _MSVC_LANG [1].
    
    This complication makes us defining some macros in a very complex way
    (such as glib_typeof()), because we need to perform many checks just to
    understand if a C++ compiler is used and what standard is expecting.
    
    To avoid this, define multiple macros that can be used to figure out
    what C++ standard is being used.
    
    [1] https://docs.microsoft.com/en-us/cpp/build/reference/zc-cplusplus?view=msvc-170

 docs/reference/glib/glib-sections.txt |  2 +
 glib/gmacros.h                        | 22 ++++++++++
 glib/tests/cxx.cpp                    | 75 +++++++++++++++++++++++++++++++++--
 glib/tests/macros.c                   |  6 +++
 4 files changed, 102 insertions(+), 3 deletions(-)
---
diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt
index 38b35386e3..daf53417a9 100644
--- a/docs/reference/glib/glib-sections.txt
+++ b/docs/reference/glib/glib-sections.txt
@@ -780,6 +780,8 @@ GLIB_UNAVAILABLE_STATIC_INLINE
 GLIB_UNAVAILABLE_TYPE
 G_ANALYZER_ANALYZING
 G_ANALYZER_NORETURN
+G_CXX_STD_VERSION
+G_CXX_STD_CHECK_VERSION
 g_autoptr_cleanup_generic_gfree
 glib_typeof
 g_macro__has_attribute
diff --git a/glib/gmacros.h b/glib/gmacros.h
index d4e5124cf1..6b9554796b 100644
--- a/glib/gmacros.h
+++ b/glib/gmacros.h
@@ -64,6 +64,28 @@
 #define G_GNUC_EXTENSION
 #endif
 
+#if defined (__cplusplus)
+
+# if defined (_MSVC_LANG)
+#  define G_CXX_STD_VERSION _MSVC_LANG
+# else
+#  define G_CXX_STD_VERSION __cplusplus
+# endif /* defined(_MSVC_LANG) */
+
+# define G_CXX_STD_CHECK_VERSION(v) ( \
+  ((v) >= 199711L && (v) <= G_CXX_STD_VERSION) || \
+  ((v) == 98 && G_CXX_STD_VERSION >= 199711L) || \
+  ((v) == 11 && G_CXX_STD_VERSION >= 201103L) || \
+  ((v) == 14 && G_CXX_STD_VERSION >= 201402L) || \
+  ((v) == 17 && G_CXX_STD_VERSION >= 201703L) || \
+  ((v) == 20 && G_CXX_STD_VERSION >= 202002L) || \
+  0)
+
+#else /* !defined (__cplusplus) */
+# undef G_CXX_STD_VERSION
+# define G_CXX_STD_CHECK_VERSION(v) (0)
+#endif /* defined (__cplusplus) */
+
 /* Every compiler that we target supports inlining, but some of them may
  * complain about it if we don't say "__inline".  If we have C99, or if
  * we are using C++, then we can use "inline" directly.  Unfortunately
diff --git a/glib/tests/cxx.cpp b/glib/tests/cxx.cpp
index 6ac60791c8..fcdd858e46 100644
--- a/glib/tests/cxx.cpp
+++ b/glib/tests/cxx.cpp
@@ -19,6 +19,75 @@
 
 #include <glib.h>
 
+#if !defined (G_CXX_STD_VERSION) || !defined (G_CXX_STD_CHECK_VERSION)
+#error G_CXX_STD_VERSION is not defined
+#endif
+
+G_STATIC_ASSERT (G_CXX_STD_VERSION);
+
+#if G_CXX_STD_VERSION >= 199711L
+  G_STATIC_ASSERT (G_CXX_STD_CHECK_VERSION (98));
+  G_STATIC_ASSERT (G_CXX_STD_CHECK_VERSION (199711L));
+#endif
+
+#if G_CXX_STD_VERSION == 199711L
+  G_STATIC_ASSERT (!G_CXX_STD_CHECK_VERSION (11));
+  G_STATIC_ASSERT (!G_CXX_STD_CHECK_VERSION (201103L));
+  G_STATIC_ASSERT (!G_CXX_STD_CHECK_VERSION (14));
+  G_STATIC_ASSERT (!G_CXX_STD_CHECK_VERSION (201402L));
+  G_STATIC_ASSERT (!G_CXX_STD_CHECK_VERSION (17));
+  G_STATIC_ASSERT (!G_CXX_STD_CHECK_VERSION (201703L));
+  G_STATIC_ASSERT (!G_CXX_STD_CHECK_VERSION (20));
+  G_STATIC_ASSERT (!G_CXX_STD_CHECK_VERSION (202002L));
+#endif
+
+#if G_CXX_STD_VERSION >= 201103L
+  G_STATIC_ASSERT (G_CXX_STD_CHECK_VERSION (11));
+  G_STATIC_ASSERT (G_CXX_STD_CHECK_VERSION (201103L));
+#endif
+
+#if G_CXX_STD_VERSION == 201103L
+  G_STATIC_ASSERT (!G_CXX_STD_CHECK_VERSION (14));
+  G_STATIC_ASSERT (!G_CXX_STD_CHECK_VERSION (201402L));
+  G_STATIC_ASSERT (!G_CXX_STD_CHECK_VERSION (17));
+  G_STATIC_ASSERT (!G_CXX_STD_CHECK_VERSION (201703L));
+  G_STATIC_ASSERT (!G_CXX_STD_CHECK_VERSION (20));
+  G_STATIC_ASSERT (!G_CXX_STD_CHECK_VERSION (202002L));
+#endif
+
+#if G_CXX_STD_VERSION >= 201402L
+  G_STATIC_ASSERT (G_CXX_STD_CHECK_VERSION (14));
+  G_STATIC_ASSERT (G_CXX_STD_CHECK_VERSION (201402L));
+#endif
+
+#if G_CXX_STD_VERSION == 201402L
+  G_STATIC_ASSERT (!G_CXX_STD_CHECK_VERSION (17));
+  G_STATIC_ASSERT (!G_CXX_STD_CHECK_VERSION (201703L));
+  G_STATIC_ASSERT (!G_CXX_STD_CHECK_VERSION (20));
+  G_STATIC_ASSERT (!G_CXX_STD_CHECK_VERSION (202002L));
+#endif
+
+#if G_CXX_STD_VERSION >= 201703L
+  G_STATIC_ASSERT (G_CXX_STD_CHECK_VERSION (17));
+  G_STATIC_ASSERT (G_CXX_STD_CHECK_VERSION (201703L));
+#endif
+
+#if G_CXX_STD_VERSION == 201703L
+  G_STATIC_ASSERT (!G_CXX_STD_CHECK_VERSION (20));
+  G_STATIC_ASSERT (!G_CXX_STD_CHECK_VERSION (202002L));
+#endif
+
+#if G_CXX_STD_VERSION >= 202002L
+  G_STATIC_ASSERT (G_CXX_STD_CHECK_VERSION (20));
+  G_STATIC_ASSERT (G_CXX_STD_CHECK_VERSION (202002L));
+#endif
+
+#if G_CXX_STD_VERSION == 202002L
+  G_STATIC_ASSERT (!G_CXX_STD_CHECK_VERSION (23));
+  G_STATIC_ASSERT (!G_CXX_STD_CHECK_VERSION (202300L));
+#endif
+
+
 typedef struct
 {
   int dummy;
@@ -34,7 +103,7 @@ test_typeof (void)
   MyObject *obj3 = g_atomic_pointer_get (&obj2);
   g_assert_true (obj3 == obj);
 
-#if __cplusplus >= 201103L
+#if G_CXX_STD_CHECK_VERSION (11)
   MyObject *obj4 = nullptr;
 #else
   MyObject *obj4 = NULL;
@@ -42,7 +111,7 @@ test_typeof (void)
   g_atomic_pointer_set (&obj4, obj3);
   g_assert_true (obj4 == obj);
 
-#if __cplusplus >= 201103L
+#if G_CXX_STD_CHECK_VERSION (11)
   MyObject *obj5 = nullptr;
   g_atomic_pointer_compare_and_exchange (&obj5, nullptr, obj4);
 #else
@@ -195,7 +264,7 @@ test_steal_pointer (void)
 int
 main (int argc, char *argv[])
 {
-#if __cplusplus >= 201103L
+#if G_CXX_STD_CHECK_VERSION (11)
   g_test_init (&argc, &argv, nullptr);
 #else
   g_test_init (&argc, &argv, NULL);
diff --git a/glib/tests/macros.c b/glib/tests/macros.c
index efe632b521..38372518be 100644
--- a/glib/tests/macros.c
+++ b/glib/tests/macros.c
@@ -22,6 +22,12 @@
 
 #include <glib.h>
 
+#ifdef G_CXX_STD_VERSION
+#error G_CXX_STD_VERSION should be undefined in C programs
+#endif
+
+G_STATIC_ASSERT (!G_CXX_STD_CHECK_VERSION (98));
+
 /* Test that G_STATIC_ASSERT_EXPR can be used as an expression */
 static void
 test_assert_static (void)


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]