assert: Make dead_code() work at link-time instead of compile-time

The dead_code() macro can be used to ensure that a certain code path is
compile-time eliminated (e.g. if you want to make sure it's never
executed for certain Kconfig combinations). Unfortunately, the current
implementation via __attribute__((error)) hits only at the GCC level.
This can catch code that can be compile-time eliminated based on state
within the same file, but it cannot be used in cases where a certain
library function is built but then garbage collected at link time.

This patch improves the macro by relying solely on the linker finding an
undefined reference. Unfortunately this makes the error message a little
less expressive (can no longer pass a custom string), but it is still
readable and one can add code comments next to the assertion to
elaborate further if necessary

Change-Id: I63399dc484e2150d8c027bc0256d9285e471f7cc
Signed-off-by: Julius Werner <jwerner@chromium.org>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/32113
Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net>
Reviewed-by: Furquan Shaikh <furquan@google.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
Julius Werner 2019-03-28 13:39:06 -07:00 committed by Patrick Georgi
parent 9993b6f0b5
commit 988ac294c7
2 changed files with 17 additions and 13 deletions

View File

@ -43,18 +43,22 @@
* will generate a compiler error even if the scope it was called from is dead
* code. This may be useful to double-check things like constants that are only
* valid if a certain Kconfig option is set.
*
* The error message when this hits will look like this:
*
* ramstage/lib/bootmode.o: In function `display_init_required':
* bootmode.c:42: undefined reference to `dead_code_assertion_failed_at_line_42'
*/
#define __dead_code(message, line) do { \
__attribute__((error(#message " in " __FILE__ ":" #line))) \
extern void dead_code_assertion_failed_##line(void); \
dead_code_assertion_failed_##line(); \
#define __dead_code(line) do { \
extern void dead_code_assertion_failed_at_line_##line(void); \
dead_code_assertion_failed_at_line_##line(); \
} while (0)
#define _dead_code(message, line) __dead_code(message, line)
#define dead_code(message) _dead_code(message, __LINE__)
#define _dead_code(line) __dead_code(line)
#define dead_code() _dead_code(__LINE__)
/* This can be used in the context of an expression of type 'type'. */
#define dead_code_t(type, message) ({ \
dead_code(message); \
#define dead_code_t(type) ({ \
dead_code(); \
*(type *)(uintptr_t)0; \
})

View File

@ -29,16 +29,16 @@
#define GPIO_BACKLIGHT GPIO(4, C, 6)
#define GPIO_EC_IN_RW GPIO(0, A, 1)
#define GPIO_EC_IRQ GPIO(1, C, 2)
#define GPIO_P15V_EN dead_code_t(gpio_t, "PP1500 doesn't exist on scarlet.")
#define GPIO_P18V_AUDIO_PWREN dead_code_t(gpio_t, "doesn't exist on scarlet.")
#define GPIO_P15V_EN dead_code_t(gpio_t)
#define GPIO_P18V_AUDIO_PWREN dead_code_t(gpio_t)
#define GPIO_P30V_EN GPIO(0, B, 1)
#define GPIO_SPK_PA_EN GPIO(0, A, 2)
#define GPIO_TP_RST_L dead_code_t(gpio_t, "don't need TP_RST_L on scarlet.")
#define GPIO_TP_RST_L dead_code_t(gpio_t)
#define GPIO_TPM_IRQ GPIO(1, C, 1)
#define GPIO_WP GPIO(0, B, 5)
#else
#define GPIO_BL_EN GPIO(1, C, 1)
#define GPIO_BACKLIGHT dead_code_t(gpio_t, "backlight controlled by ec")
#define GPIO_BACKLIGHT dead_code_t(gpio_t)
#define GPIO_EC_IN_RW GPIO(3, B, 0)
#define GPIO_EC_IRQ GPIO(0, A, 1)
#define GPIO_P15V_EN GPIO(0, B, 2)
@ -53,7 +53,7 @@
#if CONFIG(GRU_HAS_WLAN_RESET)
#define GPIO_WLAN_RST_L GPIO(1, B, 3)
#else
#define GPIO_WLAN_RST_L dead_code_t(gpio_t, "no WLAN reset on this board in FW")
#define GPIO_WLAN_RST_L dead_code_t(gpio_t)
#endif
void setup_chromeos_gpios(void);