in checker/src/body_visitor.rs [1948:2086]
fn copy_field_bits(
&mut self,
source_fields: Vec<(Rc<Path>, Ty<'tcx>)>,
target_fields: Vec<(Rc<Path>, Ty<'tcx>)>,
) {
let source_len = source_fields.len();
let mut source_field_index = 0;
let mut copied_source_bits = 0;
for (target_path, target_type) in target_fields.into_iter() {
let target_type = self.type_visitor().specialize_generic_argument_type(
target_type,
&self.type_visitor().generic_argument_map,
);
if source_field_index >= source_len {
let warning = self.cv.session.struct_span_warn(
self.current_span,
"The union is not fully initialized by this assignment",
);
self.emit_diagnostic(warning);
break;
}
let (source_path, source_type) = &source_fields[source_field_index];
let source_type = self.type_visitor().specialize_generic_argument_type(
*source_type,
&self.type_visitor().generic_argument_map,
);
let source_path = source_path.canonicalize(&self.current_environment);
if let PathEnum::QualifiedPath {
qualifier,
selector,
..
} = &source_path.value
{
if **selector == PathSelector::Field(0) {
if let PathEnum::Computed { value } = &qualifier.value {
if let Expression::CompileTimeConstant(ConstantDomain::Str(s)) =
&value.expression
{
// The value is a string literal. See if the target might treat it as &[u8].
if let TyKind::RawPtr(TypeAndMut { ty, .. }) = target_type.kind() {
if let TyKind::Uint(UintTy::U8) = ty.kind() {
let thin_ptr_deref = Path::new_deref(
source_path.clone(),
ExpressionType::NonPrimitive,
)
.canonicalize(&self.current_environment);
for (i, ch) in s.as_bytes().iter().enumerate() {
let index = Rc::new((i as u128).into());
let ch_const: Rc<AbstractValue> =
Rc::new((*ch as u128).into());
let path = Path::new_index(thin_ptr_deref.clone(), index);
self.current_environment
.strong_update_value_at(path, ch_const);
}
}
}
}
}
}
}
let mut val = self.lookup_path_and_refine_result(source_path.clone(), source_type);
if copied_source_bits > 0 {
// discard the lower order bits from val since they have already been copied to a previous target field
val = val.unsigned_shift_right(copied_source_bits);
}
let source_expression_type = ExpressionType::from(source_type.kind());
let source_bits = ExpressionType::from(source_type.kind()).bit_length();
let target_expression_type = ExpressionType::from(target_type.kind());
let mut target_bits_to_write = target_expression_type.bit_length();
if source_bits == target_bits_to_write
&& copied_source_bits == 0
&& target_expression_type == val.expression.infer_type()
{
self.current_environment
.strong_update_value_at(target_path, val);
source_field_index += 1;
} else if source_bits - copied_source_bits >= target_bits_to_write {
// target field can be completely assigned from bits of source field value
if source_bits - copied_source_bits > target_bits_to_write {
// discard higher order bits since they wont fit into the target field
val = val.unsigned_modulo(target_bits_to_write);
}
if source_expression_type != target_expression_type {
val = val.transmute(target_expression_type);
}
self.current_environment
.strong_update_value_at(target_path, val);
copied_source_bits += target_bits_to_write;
if copied_source_bits == source_bits {
source_field_index += 1;
copied_source_bits = 0;
}
} else {
// target field needs bits from multiple source fields
let mut written_target_bits = source_bits - copied_source_bits;
target_bits_to_write -= written_target_bits;
val = val.unsigned_modulo(written_target_bits);
loop {
// Get another field
source_field_index += 1;
if source_field_index >= source_len {
let warning = self.cv.session.struct_span_warn(
self.current_span,
"The union is not fully initialized by this assignment",
);
self.emit_diagnostic(warning);
break;
}
let (source_path, source_type) = &source_fields[source_field_index];
let source_path = source_path.canonicalize(&self.current_environment);
let source_bits = ExpressionType::from(source_type.kind()).bit_length();
let mut next_val =
self.lookup_path_and_refine_result(source_path.clone(), *source_type);
// discard higher order bits that wont fit into the target field
next_val = next_val.unsigned_modulo(target_bits_to_write);
// shift next value to the left, making space for val in the lower order bits
next_val = next_val.unsigned_shift_left(written_target_bits);
// update val to include next_val (in its higher order bits, thanks to the shift left above)
val = next_val.addition(val);
if source_bits >= target_bits_to_write {
// We are done with this target field
self.current_environment.strong_update_value_at(
target_path.clone(),
val.transmute(target_expression_type),
);
if source_bits == target_bits_to_write {
copied_source_bits = 0;
source_field_index += 1;
} else {
copied_source_bits = target_bits_to_write;
}
break;
}
target_bits_to_write -= source_bits;
written_target_bits += source_bits;
}
}
}
}