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