Repository: rust-lang/rust
File: compiler/rustc_mir_transform/src/gvn.rs (Rust)

Code before:
        // Notably, valtrees purposefully generate new allocations.
        Const::Ty(..) => false,
        // We do not know the contents, so don't attempt to do anything clever.
        Const::Unevaluated(..) => false,
        // When an evaluated constant contains provenance, it is encoded as an `AllocId`.
        // Cloning the constant will reuse the same `AllocId`. If this is in the same MIR
        // body, this same `AllocId` will result in the same pointer in codegen.
        Const::Val(..) => true,
    }
}

/// Check if a constant may contain provenance information.
/// Can return `true` even if there is no provenance.
fn may_have_provenance(tcx: TyCtxt<'_>, value: ConstValue, size: Size) -> bool {
    match value {
        ConstValue::ZeroSized | ConstValue::Scalar(Scalar::Int(_)) => return false,
        ConstValue::Scalar(Scalar::Ptr(..)) | ConstValue::Slice { .. } => return true,
        ConstValue::Indirect { alloc_id, offset } => !tcx
            .global_alloc(alloc_id)
            .unwrap_memory()
            .inner()
            .provenance()
            .range_empty(AllocRange::from(offset..offset + size), &tcx),
    }
}

fn op_to_prop_const<'tcx>(
    ecx: &mut InterpCx<'tcx, DummyMachine>,
    op: &OpTy<'tcx>,
) -> Option<ConstValue> {
    // Do not attempt to propagate unsized locals.
    if op.layout.is_unsized() {
        return None;
    }

    // This constant is a ZST, just return an empty value.
    if op.layout.is_zst() {
        return Some(ConstValue::ZeroSized);
    }

    // Do not synthetize too large constants. Codegen will just memcpy them, which we'd like to
    // avoid.
    // But we *do* want to synthesize any size constant if it is entirely uninit because that
    // benefits codegen, which has special handling for them.
    if !op.is_immediate_uninit()
        && !matches!(op.layout.backend_repr, BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..))
    {
        return None;
    }

    // If this constant has scalar ABI, return it as a `ConstValue::Scalar`.

Review comment (suggestion):
```suggestion
/// In other words, this answers: is "cloning" the `Const` ok?
///
/// This returns `false` for constants that synthesize new `AllocId` when they are instantiated.
/// It is `true` for anything else, since a given `AllocId` *does* have a unique runtime value
/// within the scope of a single MIR body.
```

Code after:
        if let Ok(layout) = self.ecx.layout_of(ty)
            && let abi::Variants::Single { index } = layout.variants
            && index == variant
            && let Some((field_idx, field_layout)) = layout.non_1zst_field(&self.ecx)
            && layout.size == field_layout.size
        {
            // We needed to check the variant to avoid trying to read the tag
            // field from an enum where no fields have variants, since that tag
            // field isn't in the `Aggregate` from which we're getting values.
            Some((field_idx, field_layout.ty))
        } else if let ty::Adt(adt, args) = ty.kind()
            && adt.is_struct()
            && adt.repr().transparent()
            && let [single_field] = adt.non_enum_variant().fields.raw.as_slice()
        {
            Some((FieldIdx::ZERO, single_field.ty(self.tcx, args)))
        } else {
            None
        }
    }
}

/// Return true if any evaluation of this constant in the same MIR body
/// always returns the same value, taking into account even pointer identity tests.
///
/// In other words, this answers: is "cloning" the `Const` ok?
///
/// This returns `false` for constants that synthesize new `AllocId` when they are instantiated.
/// It is `true` for anything else, since a given `AllocId` *does* have a unique runtime value
/// within the scope of a single MIR body.
fn is_deterministic(c: Const<'_>) -> bool {
    // Primitive types cannot contain provenance and always have the same value.
    if c.ty().is_primitive() {
        return true;
    }

    match c {
        // Some constants may generate fresh allocations for pointers they contain,
        // so using the same constant twice can yield two different results.
        // Notably, valtrees purposefully generate new allocations.
        Const::Ty(..) => false,
        // We do not know the contents, so don't attempt to do anything clever.
        Const::Unevaluated(..) => false,
        // When an evaluated constant contains provenance, it is encoded as an `AllocId`.
        // Cloning the constant will reuse the same `AllocId`. If this is in the same MIR
        // body, this same `AllocId` will result in the same pointer in codegen.
        Const::Val(..) => true,
    }
}

/// Check if a constant may contain provenance information.