Search code examples
cgcc

Static assertion to check if a variable name is defined in the current scope


I am defining a macro like the following and my goal is to complete the TODO.

#define TEST(_expr, args...) \
    do { \
        \ // TODO _Static_assert to make sure __xyz is not declared
        int __xyz = _expr; \
        if (__xyz < 0) { \
            \ // do some error handling stuff utilizing args and __xyz
        } \
    } while (0)

Macro runs _expr (usually a function call) and does some error handling stuff in the case of failure. the stuff done utilize __xyz and args.... The corner case is that the developer using this macro might have the variable __xyz defined on a higher scope and pass it as one of the args.... Here is an example.

int foo(void);
int bar() {
    int __xyz;
    // .... some lines of code
    TEST(foo(), x, y, z, __xyz);
    // .... some more lines of code
    return 0;
}

In this example, there would be a silent issue. I want to use _Static_assert to make sure that no variable __xyz is defined in any of the parent scopes. Basically, the macro TEST would cause a compile-time error at the above function because __xyz is defined at the beginning of the scope.

  • Is this doable? If so how?
  • If it is not doable, how can I avoid such a corner case?

Theoretically, this should be possible because whether some word is declared/defined at some line is compile-time information.

Thank you all in advance!!


Solution

  • Although @aschepler's comment is practically adequate, it is not technically bulletproof. The OCD in me came up with this answer. We can use -Wshadow and treat it as an error in the macro

    #define TEST(_expr, args...) \
        do { \
            _Pragma(GCC diagnostic push) \
            _Pragma(GCC diagnostic error "-Wshadow") \
            int TEST_MACRO_PV_xyz = _expr; \
            _Pragma(GCC diagnostic pop) \
            if (TEST_MACRO_PV_xyz < 0) { \
                 handle_and_propagate_error(TEST_MACRO_PV_xyz, ##args); \
            } \
        } while (0)
    

    Note that for different compilers and different versions you need to enable/disable this error differently.