> I think we really need Eric (as one who e.g. introduced the > DECL_INVARIANT_P apparently for this kind of stuff) to have a look at that > on the Ada side.
I have been investigating this for a few days and it's no small change for Ada and probably for other languages with dynamic types. SAVE_EXPRs are delicate to handle because 1) they are TREE_SIDE_EFFECTS (it's explained in save_expr) so out of TREE_READONLY && !TREE_SIDE_EFFECTS trees, you now get side effects which then propagate to all parent nodes 2) their placement is problematic in conditional expressions, for example if you replace cond > 0 ? A : A + 1 with cond > 0 ? SAVE_EXPR (A) : SAVE_EXPR (A) + 1 then gimplification will, say, create the temporary and initialize it in the first arm so, if at runtime you take the second arm, you'll read the temporary uninitialized. That's caught for scalar values by the SSA form (if your patch is applied to a GCC 12 tree, you'll get ICEs in the ACATS testsuite because of this through finalize_type_size -> variable_size -> save_expr, it is probably mitigated/addressed in GCC 14 by 68e0063397ba820e71adc220b2da0581dce29ffa). That's also why making gnat_invariant_expr return (some of) them does not look really safe. In addition to this, in Ada we have bounds of unconstrained arrays which are both read-only and stored indirectly, i.e. you have an INDIRECT_REF in the tree (it is marked TREE_THIS_NOTRAP because the bounds are always present), and which obviously play a crucial role in loops running over the arrays. This issue is responsible for the regressions in the gnat.dg testsuite. I think that we can reasonably deal with the second issue in the Ada front-end because we know the semantics of the bounds of unconstrained arrays, and I'm testing a patch to that effect, but the first issue might be annoying too. -- Eric Botcazou