This is clunky but greatly improves debugging of flow conditions - each
copy adds more indirections in the form of flow condition tokens.
(LatticeEffect presumably once did something here, but it's now both
unused and untested.)
For the exit flow condition of:
void target(base::Optional<int*> opt) { if (opt.value_or(nullptr) != nullptr) { opt.value(); } else { opt.value(); // unsafe } }
Before:
(B0:1 = V15) (B1:1 = V8) (B2:1 = V10) (B3:1 = (V4 & (!V7 => V6))) (V10 = (B3:1 & !V7)) (V12 = B1:1) (V13 = B2:1) (V15 = (V12 | V13)) (V3 = V2) (V4 = V3) (V8 = (B3:1 & !!V7)) B0:1 V2
After D153491:
(B0:1 = (V9 | V10)) (B1:1 = (B3:1 & !!V6)) (B2:1 = (B3:1 & !V6)) (B3:1 = (V3 & (!V6 => V5))) (V10 = B2:1) (V3 = V2) (V9 = B1:1) B0:1 V2
After this patch, we can finally see the relations between the flow
conditions directly:
(B0:1 = (B2:1 | B1:1)) (B1:1 = (B3:1 & !!V6)) (B2:1 = (B3:1 & !V6)) (B3:1 = (V3 & (!V6 => V5))) (V3 = V2) B0:1 V2
(I believe V2 is the FC for the InitEnv, and V3 is introduced when
computing the input state for B3 - not sure how to eliminate it)
nit: i think you can now drop the braces.