chiark / gitweb /
Add half-hearted support for Clang, because its `blocks' are deficient.
[finally] / finally.h
index 8488161a6675f0fbcbf78413d8960f621f68d359..7b43d38aafcdd85814ed0a28bbefb4e283f29861 100644 (file)
--- a/finally.h
+++ b/finally.h
 /* If configuration machinery hasn't determined a flavour, then we'll take a
  * rough guess based on compiler versions.
  */
-#if !defined(FINALLY_CONFIG_FLAVOUR) && \
-       !defined(__clang__) && FINALLY__GCC_P(3, 3)
+#if !defined(FINALLY_CONFIG_FLAVOUR) && defined(__clang__)
+#  if FINALLY__CLANG_P(2, 5)
+#    ifndef __BLOCKS__
+#      error "Clang detected, but blocks support is not available.  \
+This isn't going to work.  Try setting the `-fblocks' compiler option."
+#    endif
+#    define FINALLY_CONFIG_FLAVOUR CLANG_BLOCKS
+#  else
+#    define FINALLY_CONFIG_FLAVOUR NIL
+#  endif
+#endif
+
+#if !defined(FINALLY_CONFIG_FLAVOUR) && FINALLY__GCC_P(3, 3)
 #  define FINALLY_CONFIG_FLAVOUR GCC_NESTED_FUNCTIONS
 #endif
 
 
 /* Before we start, a note about compatibility.  We're using pretty esoteric
  * compiler features here, and not all compilers support them.  I'm most
- * interested in GCC, which will work fine.  This isn't going to work for
- * other compilers, but lots of them try to impersonate GCC, and it's just
- * not worth the effort to try to see through their lies.
+ * interested in GCC, which will work fine, and I'm just a tiny bit
+ * interested in Clang, so there's support for that too.  This isn't going to
+ * work for other compilers, but lots of them try to impersonate GCC, and
+ * it's just not worth the effort to try to see through their lies.
  *
  * So the rules are: if you include this header file, you've either already
  * made an effort to check that it's likely to work (e.g., by using the
 /* Flavour selection machinery. */
 #define FINALLY__FLAVOUR_NIL -1
 #define FINALLY__FLAVOUR_GCC_NESTED_FUNCTIONS 1
+#define FINALLY__FLAVOUR_CLANG_BLOCKS 2
 
 #define FINALLY__SELECTED_FLAVOUR                                      \
        FINALLY__GLUE(FINALLY__FLAVOUR_, FINALLY_CONFIG_FLAVOUR)
        __attribute__((__unused__, __cleanup__(FINALLY__TMP(tag##__fn)))) \
          int FINALLY__TMP(tag##__var)
 
+#elif FINALLY__GLUE(FINALLY__FLAVOUR_, FINALLY_CONFIG_FLAVOUR) == \
+       FINALLY__FLAVOUR_CLANG_BLOCKS
+   /* We're being compiled by Clang, so we're messing with the ugly `blocks'
+    * syntax.  Unfortunately, blocks capture names from their outer
+    * environment by copying rather than by reference, so a `FINALLY' block
+    * is insensitive to changes to variables since its establishment.  As a
+    * result of this, we declare a bug.
+    */
+
+#  define FINALLY_BUG_CAPTURE_COPIES 1
+
+   /* We'll need a separate cleanup handler, because we're not allowed to
+    * define a local function to do this.  We'll attach this as the cleanup
+    * handler for the block containing the code that we want to run.
+    */
+   static __inline__ void _finally__runblk(void (^*_blk)(void))
+     { (*_blk)(); }
+
+   /* Now we're ready for the actual macro definition. */
+#  define FINALLY_TAGGED(tag, body)                                    \
+       __attribute__((__unused__, __cleanup__(_finally__runblk)))      \
+         void (^FINALLY__TMP(tag##__blk))(void) = ^{ body }
+
 #elif FINALLY__GLUE(FINALLY__FLAVOUR_, FINALLY_CONFIG_FLAVOUR) == \
        FINALLY__GLUE(FINALLY__FLAVOUR_, NIL)
    /* We don't have a flavour to support this environment. */
 #  error "Internal error: `FINALLY_CONFIG_FLAVOUR' bungled."
 #endif
 
+/* Check for bugs. */
+#if defined(FINALLY_BUG_CAPTURE_COPIES) &&                             \
+         (!defined(FINALLY_TOLERATE_BUG_CAPTURE_COPIES) ||             \
+          !FINALLY_TOLERATE_BUG_CAPTURE_COPIES)
+#  error "Implementation captures variables by copying rather than by \
+reference.  Define `FINALLY_BUG_CAPTURE_COPIES' if you don't mind."
+#endif
+
 /* We now have `FINALLY_TAGGED'; defining `FINALLY' is easy.  The TAG here is
  * guaranteed not conflict with any call on `FINALLY_TAGGED', since TAGs are
  * required to be identifiers.