Zbigniew Jędrzejewski-Szmek 62fe94
From fb835651aff79a1e7fc5795086c9b26e59a8e6ca Mon Sep 17 00:00:00 2001
Zbigniew Jędrzejewski-Szmek 62fe94
From: David Herrmann <dh.herrmann@gmail.com>
Zbigniew Jędrzejewski-Szmek 62fe94
Date: Fri, 22 Aug 2014 14:41:37 +0200
Zbigniew Jędrzejewski-Szmek 62fe94
Subject: [PATCH] shared: make container_of() use unique variable names
Zbigniew Jędrzejewski-Szmek 62fe94
Zbigniew Jędrzejewski-Szmek 62fe94
If you stack container_of() macros, you will get warnings due to shadowing
Zbigniew Jędrzejewski-Szmek 62fe94
variables of the parent context. To avoid this, use unique names for
Zbigniew Jędrzejewski-Szmek 62fe94
variables.
Zbigniew Jędrzejewski-Szmek 62fe94
Zbigniew Jędrzejewski-Szmek 62fe94
Two new helpers are added:
Zbigniew Jędrzejewski-Szmek 62fe94
  UNIQ: This evaluates to a truly unique value never returned by any
Zbigniew Jędrzejewski-Szmek 62fe94
        evaluation of this macro. It's a shortcut for __COUNTER__.
Zbigniew Jędrzejewski-Szmek 62fe94
  UNIQ_T: Takes two arguments and concatenates them. It is a shortcut for
Zbigniew Jędrzejewski-Szmek 62fe94
          CONCATENATE, but meant to defined typed local variables.
Zbigniew Jędrzejewski-Szmek 62fe94
Zbigniew Jędrzejewski-Szmek 62fe94
As you usually want to use variables that you just defined, you need to
Zbigniew Jędrzejewski-Szmek 62fe94
reference the same unique value at least two times. However, UNIQ returns
Zbigniew Jędrzejewski-Szmek 62fe94
a new value on each evaluation, therefore, you have to pass the unique
Zbigniew Jędrzejewski-Szmek 62fe94
values into the macro like this:
Zbigniew Jędrzejewski-Szmek 62fe94
Zbigniew Jędrzejewski-Szmek 62fe94
    #define my_macro(a, b) __max_macro(UNIQ, UNIQ, (a), (b))
Zbigniew Jędrzejewski-Szmek 62fe94
    #define __my_macro(uniqa, uniqb, a, b) ({
Zbigniew Jędrzejewski-Szmek 62fe94
                typeof(a) UNIQ_T(A, uniqa) = (a);
Zbigniew Jędrzejewski-Szmek 62fe94
                typeof(b) UNIQ_T(B, uniqb) = (b);
Zbigniew Jędrzejewski-Szmek 62fe94
                MY_UNSAFE_MACRO(UNIQ_T(A, uniqa), UNIQ_T(B, uniqb));
Zbigniew Jędrzejewski-Szmek 62fe94
        })
Zbigniew Jędrzejewski-Szmek 62fe94
Zbigniew Jędrzejewski-Szmek 62fe94
This way, MY_UNSAFE_MACRO() can safely evaluate it's arguments multiple
Zbigniew Jędrzejewski-Szmek 62fe94
times as they are local variables. But you can also stack invocations to
Zbigniew Jędrzejewski-Szmek 62fe94
the macro my_macro() without clashing names.
Zbigniew Jędrzejewski-Szmek 62fe94
Zbigniew Jędrzejewski-Szmek 62fe94
This is the same as if you did:
Zbigniew Jędrzejewski-Szmek 62fe94
Zbigniew Jędrzejewski-Szmek 62fe94
    #define my_macro(a, b) __max_macro(__COUNTER__, __COUNTER__, (a), (b))
Zbigniew Jędrzejewski-Szmek 62fe94
    #define __my_macro(prefixa, prefixb, a, b) ({
Zbigniew Jędrzejewski-Szmek 62fe94
                typeof(a) CONCATENATE(A, prefixa) = (a);
Zbigniew Jędrzejewski-Szmek 62fe94
                typeof(b) CONCATENATE(B, prefixb) = (b);
Zbigniew Jędrzejewski-Szmek 62fe94
                MY_UNSAFE_MACRO(CONCATENATE(A, prefixa), CONCATENATE(B, prefixb));
Zbigniew Jędrzejewski-Szmek 62fe94
        })
Zbigniew Jędrzejewski-Szmek 62fe94
Zbigniew Jędrzejewski-Szmek 62fe94
...but in my opinion, the first macro is easier to write and read.
Zbigniew Jędrzejewski-Szmek 62fe94
Zbigniew Jędrzejewski-Szmek 62fe94
This patch starts by converting container_of() to use this new helper.
Zbigniew Jędrzejewski-Szmek 62fe94
Other macros may follow (like MIN, MAX, CLAMP, ...).
Zbigniew Jędrzejewski-Szmek 62fe94
---
Zbigniew Jędrzejewski-Szmek 62fe94
 src/shared/macro.h   | 13 ++++++++-----
Zbigniew Jędrzejewski-Szmek 62fe94
 src/test/test-util.c | 19 +++++++++++++++++++
Zbigniew Jędrzejewski-Szmek 62fe94
 2 files changed, 27 insertions(+), 5 deletions(-)
Zbigniew Jędrzejewski-Szmek 62fe94
Zbigniew Jędrzejewski-Szmek 62fe94
diff --git a/src/shared/macro.h b/src/shared/macro.h
Zbigniew Jędrzejewski-Szmek 62fe94
index 2807bc74e8..e6734804bd 100644
Zbigniew Jędrzejewski-Szmek 62fe94
--- a/src/shared/macro.h
Zbigniew Jędrzejewski-Szmek 62fe94
+++ b/src/shared/macro.h
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -79,6 +79,9 @@
Zbigniew Jędrzejewski-Szmek 62fe94
 #define XCONCATENATE(x, y) x ## y
Zbigniew Jędrzejewski-Szmek 62fe94
 #define CONCATENATE(x, y) XCONCATENATE(x, y)
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
+#define UNIQ_T(x, uniq) CONCATENATE(__unique_prefix_, CONCATENATE(x, uniq))
Zbigniew Jędrzejewski-Szmek 62fe94
+#define UNIQ __COUNTER__
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
 /* Rounds up */
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
 #define ALIGN4(l) (((l) + 3) & ~3)
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -122,13 +125,13 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) {
Zbigniew Jędrzejewski-Szmek 62fe94
  * @ptr: the pointer to the member.
Zbigniew Jędrzejewski-Szmek 62fe94
  * @type: the type of the container struct this is embedded in.
Zbigniew Jędrzejewski-Szmek 62fe94
  * @member: the name of the member within the struct.
Zbigniew Jędrzejewski-Szmek 62fe94
- *
Zbigniew Jędrzejewski-Szmek 62fe94
  */
Zbigniew Jędrzejewski-Szmek 62fe94
-#define container_of(ptr, type, member)                                 \
Zbigniew Jędrzejewski-Szmek 62fe94
+#define container_of(ptr, type, member) __container_of(UNIQ, (ptr), type, member)
Zbigniew Jędrzejewski-Szmek 62fe94
+#define __container_of(uniq, ptr, type, member)                         \
Zbigniew Jędrzejewski-Szmek 62fe94
         __extension__ ({                                                \
Zbigniew Jędrzejewski-Szmek 62fe94
-                        const typeof( ((type *)0)->member ) *__mptr = (ptr); \
Zbigniew Jędrzejewski-Szmek 62fe94
-                        (type *)( (char *)__mptr - offsetof(type,member) ); \
Zbigniew Jędrzejewski-Szmek 62fe94
-                })
Zbigniew Jędrzejewski-Szmek 62fe94
+                const typeof( ((type*)0)->member ) *UNIQ_T(A, uniq) = (ptr); \
Zbigniew Jędrzejewski-Szmek 62fe94
+                (type*)( (char *)UNIQ_T(A, uniq) - offsetof(type,member) ); \
Zbigniew Jędrzejewski-Szmek 62fe94
+        })
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
 #undef MAX
Zbigniew Jędrzejewski-Szmek 62fe94
 #define MAX(a,b)                                        \
Zbigniew Jędrzejewski-Szmek 62fe94
diff --git a/src/test/test-util.c b/src/test/test-util.c
Zbigniew Jędrzejewski-Szmek 62fe94
index 4d9b28f9c8..795f3a1b3d 100644
Zbigniew Jędrzejewski-Szmek 62fe94
--- a/src/test/test-util.c
Zbigniew Jędrzejewski-Szmek 62fe94
+++ b/src/test/test-util.c
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -96,6 +96,24 @@ static void test_max(void) {
Zbigniew Jędrzejewski-Szmek 62fe94
         assert_cc(MAXSIZE(char, long) == sizeof(long));
Zbigniew Jędrzejewski-Szmek 62fe94
 }
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
+static void test_container_of(void) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        struct mytype {
Zbigniew Jędrzejewski-Szmek 62fe94
+                uint8_t pad1[3];
Zbigniew Jędrzejewski-Szmek 62fe94
+                uint64_t v1;
Zbigniew Jędrzejewski-Szmek 62fe94
+                uint8_t pad2[2];
Zbigniew Jędrzejewski-Szmek 62fe94
+                uint32_t v2;
Zbigniew Jędrzejewski-Szmek 62fe94
+        } _packed_ myval = { };
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_cc(sizeof(myval) == 17);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_se(container_of(&myval.v1, struct mytype, v1) == &myval);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_se(container_of(&myval.v2, struct mytype, v2) == &myval);
Zbigniew Jędrzejewski-Szmek 62fe94
+        assert_se(container_of(&container_of(&myval.v2,
Zbigniew Jędrzejewski-Szmek 62fe94
+                                             struct mytype,
Zbigniew Jędrzejewski-Szmek 62fe94
+                                             v2)->v1,
Zbigniew Jędrzejewski-Szmek 62fe94
+                               struct mytype,
Zbigniew Jędrzejewski-Szmek 62fe94
+                               v1) == &myval);
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
 static void test_first_word(void) {
Zbigniew Jędrzejewski-Szmek 62fe94
         assert_se(first_word("Hello", ""));
Zbigniew Jędrzejewski-Szmek 62fe94
         assert_se(first_word("Hello", "Hello"));
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -1218,6 +1236,7 @@ int main(int argc, char *argv[]) {
Zbigniew Jędrzejewski-Szmek 62fe94
         test_streq_ptr();
Zbigniew Jędrzejewski-Szmek 62fe94
         test_align_power2();
Zbigniew Jędrzejewski-Szmek 62fe94
         test_max();
Zbigniew Jędrzejewski-Szmek 62fe94
+        test_container_of();
Zbigniew Jędrzejewski-Szmek 62fe94
         test_first_word();
Zbigniew Jędrzejewski-Szmek 62fe94
         test_close_many();
Zbigniew Jędrzejewski-Szmek 62fe94
         test_parse_boolean();