Search code examples
cgccclangc-preprocessorc23

Consolidating GNU C's and C23's deprecated function attribute


The problem I am facing when using the below macro

// Assume that __GNUC__ or __clang__ is defined. 

#if defined(__has_c_attribute)
    #if __has_c_attribute(deprecated)
        #define ATTRIBUTE_DEPRECATED(...)          [[deprecated(__VA_ARGS__)]]
    #endif    /* deprecated */
#else  
    #define ATTRIBUTE_DEPRECATED(...)              __attribute__((deprecated(__VA_ARGS__)))
#endif    /* __has_c_attribute */

is that __attribute__((deprecated())) and __attribute__((deprecated)) are equivalent, but [[deprecated()]] and [[deprecated]] are not.

The #else block works correctly when called with either of these:

ATTRIB_DEPRECATED()
ATTRIB_DEPRECATED("privat")

because GNU C allows the parameter-list of the attribute to be empty.

But when compiling with std=c2x, the #if block does not, and fails with:

deprecated.c:12:14: error: parentheses must be omitted if attribute argument list is empty

Is there a way I can get the same code to work with C23 as well?

It'd also be nicer if I could write:

ATTRIB_DEPRECATED

instead of:

ATTRIB_DEPRECATED()

if no argument was to be provided.

For a MRE:

// Assume that __GNUC__ or __clang__ is defined. 

#if defined(__has_c_attribute) 
    #if __has_c_attribute(deprecated)
        #define ATTRIBUTE_DEPRECATED(...)          [[deprecated(__VA_ARGS__)]]
    #endif
#else  
    #define ATTRIBUTE_DEPRECATED(...)              __attribute__((deprecated(__VA_ARGS__)))
#endif    /* __has_c_attribute */

ATTRIBUTE_DEPRECATED() int min(int a, int b)
{
    return a < b ? a : b;
}

int main() {
    return min(10, 20);
}

The above code would only compile f __has_c_attribute was not defined.


Solution

  • I believe you have to have two separate macros for that

    
    #if defined(__has_c_attribute) 
        #if __has_c_attribute(deprecated)
            #define ATTRIBUTE_DEPRECATED          [[deprecated]]
            #define ATTRIBUTE_DEPRECATEDR(...)    [[deprecated(#__VA_ARGS__)]]
        #endif
    #else  
        #define ATTRIBUTE_DEPRECATED              __attribute__((deprecated))
        #define ATTRIBUTE_DEPRECATEDR(...)        __attribute__((deprecated))
    #endif    /* __has_c_attribute */
    
    
    
    ATTRIBUTE_DEPRECATEDR(this is test) int min(int a, int b)
    {
        return a < b ? a : b;
    }
    
    ATTRIBUTE_DEPRECATED int max(int a, int b)
    {
        return a > b ? a : b;
    }
    
    int main() {
        return min(max(10,20), max(10, 20));
    }
    

    https://godbolt.org/z/8arY74Gsd