https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117440
--- Comment #4 from Jan Hubicka <hubicka at gcc dot gnu.org> --- OK, so the problem is that we analyze function body of g::f which is declared with pure attribute: modref analyzing 'virtual g* g::f() const/1' (ipa=0) (pure) Analyzing flags of ssa name: this_4(D) Analyzing stmt: _1 = &this_4(D)->D.2861; Analyzing flags of ssa name: _1 Analyzing stmt: if (_1 != e.4_2) current flags of _1 no_direct_clobber no_indirect_clobber no_direct_escape no_indirect_escape not_returned_directly not_returned_indirectly no_direct_read no_indirect_read flags of ssa name _1 no_direct_clobber no_indirect_clobber no_direct_escape no_indirect_escape not_returned_directly not_returned_indirectly no_direct_read no_indirect_read current flags of this_4(D) no_direct_clobber no_indirect_clobber no_direct_escape no_indirect_escape not_returned_directly not_returned_indirectly no_direct_read no_indirect_read flags of ssa name this_4(D) no_direct_clobber no_indirect_clobber no_direct_escape no_indirect_escape not_returned_directly not_returned_indirectly no_direct_read no_indirect_read ... parm 0 flags: not_returned_directly not_returned_indirectly no_direct_read no_indirect_read __attribute__((pure)) here parm 0 is originally detected with many attributes including no_*_clobber but they are taken away because we know they are implied by pure attribute. Now however function is called through thunk and ECF_FLAGS use thunk alias while modref flags looks through the alias to actual definition, which means that we end up with the insane combination. So the bug is that we create aliases without the pure attribute on it or altenratively ecf_flags may look through non-interposable aliases and merge in the flags. (gdb) p debug_tree (gimple_call_fndecl (call)) <function_decl 0x7ffff77ba700 *.LTHUNK0 type <method_type 0x7ffff77cee70 type <pointer_type 0x7ffff77ced20 type <record_type 0x7ffff77ce9d8 g> sizes-gimplified public unsigned DI size <integer_cst 0x7ffff7620240 constant 64> unit-size <integer_cst 0x7ffff7620258 constant 8> align:64 warn_if_not_align:0 symtab:0 alias-set -1 canonical-type 0x7ffff77ced20> QI size <integer_cst 0x7ffff7620330 constant 8> unit-size <integer_cst 0x7ffff7620348 constant 1> align:8 warn_if_not_align:0 symtab:0 alias-set -1 canonical-type 0x7ffff77cee70 method basetype <record_type 0x7ffff77ce9d8 g> arg-types <tree_list 0x7ffff77cf258 value <pointer_type 0x7ffff77cebd0> chain <tree_list 0x7ffff761bd98 value <void_type 0x7ffff7627f18 void>>> pointer_to_this <pointer_type 0x7ffff77d1150>> addressable used autoinline decl_5 QI m.C:7:28 align:8 warn_if_not_align:0 context <record_type 0x7ffff77ce9d8 g> initial <error_mark 0x7ffff7620228> full-name "g* g::*.LTHUNK0() const"> (gdb) p cgraph_node::get (gimple_call_fndecl (call))->debug () *.LTHUNK0/2 (g* g::*.LTHUNK0() const) Type: function definition analyzed alias cpp_implicit_alias Visibility: semantic_interposition comdat_group:_ZNK1g1fEv section:.text._ZNK1g1fEv (implicit_section) artificial Same comdat group as: _ZNK1g1fEv/1 References: _ZNK1g1fEv/1 (alias) Referring: Availability: available Function flags: optimize_size Called by: