https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119214
--- Comment #8 from Jakub Jelinek <jakub at gcc dot gnu.org> --- It would work the same as volatile int v; static inline __attribute__((always_inline)) int foo (int x) { ++v; ++v; ++v; return x; } int main () { int x; x = foo (1); x += foo (2); x += foo (3); return x != 6; } works for -g -O0 in C/C++. If you do next on the x = foo (1); it goes to the x += foo (2); line, if you do step instead, it steps through the inlined function. At the IL level, after inlining there are just statements all in main, what differentiates them are BLOCKs in the BLOCK tree which say that something has been inlined from the foo function and which copy. And then at the DWARF level, the DW_TAG_subprogram for main has 3 DW_TAG_inlined_subroutine sub-DIEs which refer using DW_AT_abstract_origin to the abstract DW_TAG_subprogram of foo and has also for -O0 typically just DW_AT_low_pc/DW_AT_high_pc, for -O1 and higher most likely DW_AT_ranges instead.