http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59783

            Bug ID: 59783
           Summary: inline expansion stack when attribute error/warning
                    triggered is displayed incorrectly
           Product: gcc
           Version: 4.8.2
            Status: UNCONFIRMED
          Severity: minor
          Priority: P3
         Component: other
          Assignee: unassigned at gcc dot gnu.org
          Reporter: daniel.santos at pobox dot com

In C < C11, __attribute__((error())) is a wonderful replacement for
_Static_assert() (e.g.,
http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/linux/compiler.h#n316).
However, when used in nested __always_inline functions where parameters to the
function are treated as compiletime constants and tested via such a mechanism,
the compiler doesn't tell us the correct root cause of the problem.


static void inline __attribute__((always_inline)) validate_pair(int x, int y) {
    extern void diedie() __attribute__((error("x + y = too many")));

    if (x + y > 32)
        diedie();
}

static void inline __attribute__((always_inline)) a1(int x, int y) {
    validate_pair(x, y);
    /* do some stuff */
}

static void inline __attribute__((always_inline)) a2(int x, int y) {
    validate_pair(x, y);
    /* do some other stuff */
}

static void inline __attribute__((always_inline)) b(int x, int y) {
    if (x & 1)
        a1(x, y);
    else
        a2(x, y);
}

int main(int argc, char *argv[]) {
    b(4, 12);
    b(5, 13);
    b(6, 13);
    b(28, 14);
    b(27, 14);
    b(2, 15);
    return 0;
}

When built with -O1 or greater, it yields this output:
In function ‘validate_pair’,
    inlined from ‘main’ at asdf.c:15:18:
asdf.c:6:15: error: call to ‘diedie’ declared with attribute error: x + y = too
many
         diedie();
               ^
In function ‘validate_pair’,
    inlined from ‘main’ at asdf.c:10:18:
asdf.c:6:15: error: call to ‘diedie’ declared with attribute error: x + y = too
many
         diedie();
               ^

It is correct that these two errors were inlined from the function main, but
the line number given is the function that actually calls validate_pair(),
although the actual inline instantiation stack for the first error was main()
-> b() -> a1() -> validate_pair() and for the second error main() -> b() ->
a1() -> validate_pair().  The work-around is essentially to use a preprocessor
macro, although a lot of simplicity, type-safety, etc. are then lost.

Since we are working with compile-time constant values, what would be nice
(similar to what is requested for bug #41373) is to display the entire inline
function instantiation/expansion stack, e.g.:

In function ‘validate_pair’,
    inlined from ‘a2’ at asdf.c:15:18:
    inlined from ‘b’ at asdf.c:23:25:
    inlined from ‘main’ at asdf.c:30:15:
asdf.c:6:15: error: call to ‘diedie’ declared with attribute error: x + y = too
many
         diedie();

This way, we can trace it to the exact function call (or inline function
expansion) that caused the problem.  Welcome to the new age of C
metaprogramming! (and thank you for helping to make it possible) This is an age
of compile-time data (if not types, like C++ metaprogramming). So if you
*really* wanted to be helpful, you could do something like this:

In function ‘validate_pair’,
    inlined from ‘a2’ [with x=28, y=14] at asdf.c:15:18:
    inlined from ‘b’ [with x=28, y=14] at asdf.c:23:25:
    inlined from ‘main’ [with x=28, y=14] at asdf.c:30:15:
asdf.c:6:15: error: call to ‘diedie’ declared with attribute error: x + y = too
many
         diedie();

Now I realize that actually involves a lot as many data types can be treated as
compiletime constants, even structs and pointers to structs and functions, but
I didn't think it could hurt to throw it out there.  Essentially, displaying
the constant parameters of an inlined function call like you do the template
parameters in a C++ templatized function or type.

See also: bug #41373

Reply via email to