cgccgcc-warningnoreturn

Tell gcc that a function call will not return


I am using C99 under GCC.

I have a function declared static inline in a header that I cannot modify.

The function never returns but is not marked __attribute__((noreturn)).

How can I call the function in a way that tells the compiler it will not return?

I am calling it from my own noreturn function, and partly want to suppress the "noreturn function returns" warning but also want to help the optimizer etc.

I have tried including a declaration with the attribute but get a warning about the repeated declaration.

I have tried creating a function pointer and applying the attribute to that, but it says the function attribute cannot apply to a pointed function.


Solution

  • From the function you defined, and which calls the external function, add a call to __builtin_unreachable which is built into at least GCC and Clang compilers and is marked noreturn. In fact, this function does nothing else and should not be called. It's only here so that the compiler can infer that program execution will stop at this point.

    static inline external_function() // lacks the noreturn attribute
    { /* does not return */ }
    
    __attribute__((noreturn)) void your_function() {
        external_function();     // the compiler thinks execution may continue ...
        __builtin_unreachable(); // ... and now it knows it won't go beyond here
    }
    

    Edit: Just to clarify a few points raised in the comments, and generally give a bit of context:

    Once the compiler has established (either by itself, or with the programmer's help) that some code is unreachable, it may use this information to do optimizations like these:

    Illustration:

    Here's another example showing how code before the unreachable point may be removed

    int compute(int) __attribute((pure)) { return /* expensive compute */ }
    if(condition) {
        int x = compute(input); // (1) no side effect => keep if x is used
                                // (8) x is not used  => remove
        printf("hello ");       // (2) reachable + side effect => keep
        your_function();        // (3) reachable + side effect => keep
                                // (4) unreachable beyond this point
        printf("word!\n");      // (5) unreachable => remove
        printf("%d\n", x);      // (6) unreachable => remove
                                // (7) mark 'x' as unused
    } else {
                                // follows unreachable code, but can jump here
                                // from reachable code, so this is reachable
       do_stuff();              // keep
    }