summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaisuke Nojiri <dnojiri@chromium.org>2019-05-24 10:10:10 -0700
committerCommit Bot <commit-bot@chromium.org>2019-05-24 17:17:55 +0000
commitef4e629502eeb56f59d780ec9244864d3040e88e (patch)
tree24e6cf7097fd081df0c79b8882bd692d7178383e
parentcd867d5a9c99f3b659e21ae88bd39228039289f8 (diff)
downloadchrome-ec-ef4e629502eeb56f59d780ec9244864d3040e88e.tar.gz
common: Make IS_ENABLED fail on unknown values
Partial cherry-pick of CL:1592728. Signed-off-by: Daisuke Nojiri <dnojiri@chromium.org> BUG=none BRANCH=none TEST=make BOARD=nami Change-Id: I8c057989bbaf006f06c803ca107d904fdeb22cca Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1626188 Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org> Commit-Queue: Daisuke Nojiri <dnojiri@chromium.org> Tested-by: Daisuke Nojiri <dnojiri@chromium.org>
-rw-r--r--include/common.h52
1 files changed, 36 insertions, 16 deletions
diff --git a/include/common.h b/include/common.h
index c7a2d94460..bc1da44433 100644
--- a/include/common.h
+++ b/include/common.h
@@ -220,29 +220,49 @@ enum ec_error_list {
/*
* Getting something that works in C and CPP for an arg that may or may
- * not be defined is tricky. Here, if we have "#define CONFIG_BOOGER"
- * we match on the placeholder define, insert the "0," for arg1 and generate
- * the triplet (0, 1, 0). Then the last step cherry picks the 2nd arg (a one).
- * When CONFIG_BOOGER is not defined, we generate a (... 1, 0) pair, and when
- * the last step cherry picks the 2nd arg, we get a zero.
+ * not be defined is tricky. Here, if we have "#define CONFIG_FOO"
+ * we match on the placeholder define, insert the "_, 1," for arg1 and generate
+ * the triplet (_, 1, _, (...)). Then the last step cherry picks the 2nd arg
+ * (a one).
+ * When CONFIG_FOO is not defined, we generate a (_, (...)) pair, and when
+ * the last step cherry picks the 2nd arg, we get a code block that verifies
+ * the value of the option. Since the preprocessor won't replace an unknown
+ * token, we compare the option name with the value string. If they are
+ * identical we assume that the value was undefined and return 0. If the value
+ * happens to be anything else we call an undefined method that will raise
+ * a compiler error. This technique requires that the optimizer be enabled so it
+ * can remove the undefined function call.
+ *
*/
-#define __ARG_PLACEHOLDER_ 0,
-#define config_enabled(cfg) _config_enabled(cfg)
-#define _config_enabled(value) __config_enabled(__ARG_PLACEHOLDER_##value)
-#define __config_enabled(arg1_or_junk) ___config_enabled(arg1_or_junk 1, 0, 0)
+#define __ARG_PLACEHOLDER_ _, 1,
+#define _config_enabled(cfg, value) \
+ __config_enabled(__ARG_PLACEHOLDER_##value, cfg, value)
+#define __config_enabled(arg1_or_junk, cfg, value) ___config_enabled( \
+ arg1_or_junk _,\
+ ({ \
+ int __undefined = __builtin_strcmp(cfg, #value) == 0; \
+ extern int IS_ENABLED_BAD_ARGS(void) __attribute__(( \
+ error(cfg " must be <blank>, or not defined.")));\
+ if (!__undefined) \
+ IS_ENABLED_BAD_ARGS(); \
+ 0; \
+ }))
#define ___config_enabled(__ignored, val, ...) val
/**
- * Checks if a config option is defined to an empty value.
+ * Checks if a config option is enabled or disabled
+ *
+ * Enabled examples:
+ * #define CONFIG_FOO
*
- * IS_ENABLED(CONFIG_MY_OPTION) will return 1 in the following case:
- * #define CONFIG_MY_OPTION
+ * Disabled examples:
+ * #undef CONFIG_FOO
*
- * Otherwise if the option has not been defined or defined with a value, it will
- * return 0.
+ * If the option is defined to any value a compiler error will be thrown.
*
- * @param CONFIG_OPTION
+ * Note: This macro will only function inside a code block due to the way
+ * it checks for unknown values.
*/
-#define IS_ENABLED(option) config_enabled(option)
+#define IS_ENABLED(option) _config_enabled(#option, option)
#endif /* __CROS_EC_COMMON_H */