Skip to content

Commit

Permalink
Merge pull request #1318 from Nadrieril/memory-constants
Browse files Browse the repository at this point in the history
 Not all evaluated MIR constants are byte strings
  • Loading branch information
Nadrieril authored Feb 20, 2025
2 parents b5321c1 + 2046c22 commit dba3097
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 45 deletions.
9 changes: 5 additions & 4 deletions engine/lib/import_thir.ml
Original file line number Diff line number Diff line change
Expand Up @@ -852,9 +852,10 @@ end) : EXPR = struct
| Borrow arg ->
Borrow { arg = constant_expr_to_expr arg; borrow_kind = Thir.Shared }
| ConstRef { id } -> ConstRef { id }
| Cast _ | RawBorrow _ | TraitConst _ | FnPtr _ ->
| Cast _ | RawBorrow _ | TraitConst _ | FnPtr _ | Memory _ ->
assertion_failure [ span ]
"constant_lit_to_lit: TraitConst | FnPtr | MutPtr"
"constant_lit_to_lit: TraitConst | FnPtr | RawBorrow | Cast | \
Memory"
| Todo _ -> assertion_failure [ span ] "ConstantExpr::Todo"
and constant_lit_to_lit (l : Thir.constant_literal) _span :
Thir.lit_kind * bool =
Expand All @@ -870,8 +871,8 @@ end) : EXPR = struct
match String.chop_prefix v ~prefix:"-" with
| Some v -> (Float (v, Suffixed ty), true)
| None -> (Float (v, Suffixed ty), false))
| Str (v, style) -> (Str (v, style), false)
| ByteStr (v, style) -> (ByteStr (v, style), false)
| Str v -> (Str (v, Cooked), false)
| ByteStr v -> (ByteStr (v, Cooked), false)
and constant_field_expr ({ field; value } : Thir.constant_field_expr) :
Thir.field_expr =
{ field; value = constant_expr_to_expr value }
Expand Down
94 changes: 53 additions & 41 deletions frontend/exporter/src/constant_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ pub enum ConstantLiteral {
Char(char),
Float(String, FloatTy),
Int(ConstantInt),
Str(String, StrStyle),
ByteStr(Vec<u8>, StrStyle),
Str(String),
ByteStr(Vec<u8>),
}

/// The subset of [Expr] that corresponds to constants.
Expand Down Expand Up @@ -104,6 +104,10 @@ pub enum ConstantExprKind {
/// is an implementation of `Foo`
method_impl: Option<ImplExpr>,
},
/// A blob of memory containing the byte representation of the value. This can occur when
/// evaluating MIR constants. Interpreting this back to a structured value is left as an
/// exercice to the consumer.
Memory(Vec<u8>),
Todo(String),
}

Expand Down Expand Up @@ -143,10 +147,10 @@ mod rustc {
/// Rustc always represents string constants as `&[u8]`, but this
/// is not nice to consume. This associated function interpret
/// bytes as an unicode string, and as a byte string otherwise.
fn byte_str(bytes: Vec<u8>, style: StrStyle) -> Self {
fn byte_str(bytes: Vec<u8>) -> Self {
match String::from_utf8(bytes.clone()) {
Ok(s) => Self::Str(s, style),
Err(_) => Self::ByteStr(bytes, style),
Ok(s) => Self::Str(s),
Err(_) => Self::ByteStr(bytes),
}
}
}
Expand All @@ -172,8 +176,8 @@ mod rustc {
}
}
Float(f, ty) => LitKind::Float(f, LitFloatType::Suffixed(ty)),
ByteStr(raw, str_style) => LitKind::ByteStr(raw, str_style),
Str(raw, str_style) => LitKind::Str(raw, str_style),
ByteStr(raw) => LitKind::ByteStr(raw, StrStyle::Cooked),
Str(raw) => LitKind::Str(raw, StrStyle::Cooked),
};
let span = c.span.clone();
let lit = Spanned { span, node };
Expand Down Expand Up @@ -213,9 +217,9 @@ mod rustc {
Cast { source } => ExprKind::Cast {
source: source.into(),
},
kind @ (FnPtr { .. } | TraitConst { .. }) => {
kind @ (FnPtr { .. } | TraitConst { .. } | Memory { .. }) => {
// SH: I see the `Closure` kind, but it's not the same as function pointer?
ExprKind::Todo(format!("FnPtr or TraitConst. kind={:#?}", kind))
ExprKind::Todo(format!("FnPtr or TraitConst or Memory. kind={:#?}", kind))
}
Todo(msg) => ExprKind::Todo(msg),
};
Expand Down Expand Up @@ -327,16 +331,21 @@ mod rustc {
variant_information: None,
},
GlobalAlloc::Memory(alloc) => {
let values = alloc.inner().get_bytes_unchecked(
rustc_middle::mir::interpret::AllocRange {
let bytes = alloc
.inner()
.get_bytes_unchecked(rustc_middle::mir::interpret::AllocRange {
start: rustc_abi::Size::ZERO,
size: alloc.inner().size(),
},
);
ConstantExprKind::Literal(ConstantLiteral::ByteStr(
values.to_vec(),
StrStyle::Cooked,
))
})
.to_vec();
match inner_ty.kind() {
ty::Slice(slice_ty) | ty::Array(slice_ty, _)
if matches!(slice_ty.kind(), ty::Uint(ty::UintTy::U8)) =>
{
ConstantExprKind::Literal(ConstantLiteral::ByteStr(bytes))
}
_ => ConstantExprKind::Memory(bytes),
}
}
provenance => fatal!(
s[span],
Expand Down Expand Up @@ -562,37 +571,43 @@ mod rustc {
(_, ty::Ref(_, inner_ty, _)) => {
ConstantExprKind::Borrow(valtree_to_constant_expr(s, valtree, *inner_ty, span))
}
(ty::ValTree::Branch(valtrees), ty::Str) => ConstantExprKind::Literal(
ConstantLiteral::byte_str(valtrees.iter().map(|x| match x {
ty::ValTree::Leaf(leaf) => leaf.to_u8(),
_ => fatal!(s[span], "Expected a flat list of leaves while translating a str literal, got a arbitrary valtree.")
}).collect(), StrStyle::Cooked))
,
(ty::ValTree::Branch(valtrees), ty::Str) => {
let bytes = valtrees
.iter()
.map(|x| match x {
ty::ValTree::Leaf(leaf) => leaf.to_u8(),
_ => fatal!(
s[span],
"Expected a flat list of leaves while translating \
a str literal, got a arbitrary valtree."
),
})
.collect();
ConstantExprKind::Literal(ConstantLiteral::byte_str(bytes))
}
(ty::ValTree::Branch(_), ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) => {
let contents: rustc_middle::ty::DestructuredConst = s
.base().tcx
.base()
.tcx
.destructure_const(ty::Const::new_value(s.base().tcx, valtree, ty));
let fields = contents.fields.iter().copied();
match ty.kind() {
ty::Array(_, _) => ConstantExprKind::Array {
fields: fields
.map(|field| field.sinto(s))
.collect(),
fields: fields.map(|field| field.sinto(s)).collect(),
},
ty::Tuple(_) => ConstantExprKind::Tuple {
fields: fields
.map(|field| field.sinto(s))
.collect(),
fields: fields.map(|field| field.sinto(s)).collect(),
},
ty::Adt(def, _) => {
let variant_idx = contents
.variant
.s_expect(s, "destructed const of adt without variant idx");
let variant_def = &def.variant(variant_idx);

ConstantExprKind::Adt{
ConstantExprKind::Adt {
info: get_variant_information(def, variant_idx, s),
fields: fields.into_iter()
fields: fields
.into_iter()
.zip(&variant_def.fields)
.map(|(value, field)| ConstantFieldExpr {
field: field.did.sinto(s),
Expand All @@ -611,12 +626,12 @@ mod rustc {
let usize_ty = rustc_middle::ty::Ty::new_usize(s.base().tcx).sinto(s);
let lit = ConstantLiteral::Int(ConstantInt::Uint(raw_address, uint_ty));
ConstantExprKind::Cast {
source: ConstantExprKind::Literal(lit).decorate(usize_ty, span.sinto(s))
source: ConstantExprKind::Literal(lit).decorate(usize_ty, span.sinto(s)),
}
}
(ty::ValTree::Leaf(x), _) => ConstantExprKind::Literal (
scalar_int_to_constant_literal(s, x, ty)
),
(ty::ValTree::Leaf(x), _) => {
ConstantExprKind::Literal(scalar_int_to_constant_literal(s, x, ty))
}
_ => supposely_unreachable_fatal!(
s[span], "valtree_to_expr";
{valtree, ty}
Expand Down Expand Up @@ -697,11 +712,8 @@ mod rustc {
let slice: &[u8] = data
.inner()
.inspect_with_uninit_and_ptr_outside_interpreter(0..end);
ConstantExprKind::Literal(ConstantLiteral::byte_str(
slice.to_vec(),
StrStyle::Cooked,
))
.decorate(ty.sinto(s), span.sinto(s))
ConstantExprKind::Literal(ConstantLiteral::byte_str(slice.to_vec()))
.decorate(ty.sinto(s), span.sinto(s))
}
ConstValue::ZeroSized { .. } => {
// Should be unit
Expand Down

0 comments on commit dba3097

Please sign in to comment.