Skip to content

Commit ed24f69

Browse files
authored
Fix unsized coercion of a struct element (rust-lang#1880)
Fix issues with how we are generating code for casting (rust-lang#566, and rust-lang#1528). Restructure the unsize casting to be done in one pass instead with deep recursion (rust-lang#1531). This also reuses the code from the reachability analysis, so we don't have to keep two ways of traversing the same structure.
1 parent a321b70 commit ed24f69

File tree

7 files changed

+188
-335
lines changed

7 files changed

+188
-335
lines changed

cprover_bindings/src/goto_program/expr.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -732,7 +732,7 @@ impl Expr {
732732
for field in non_padding_fields {
733733
let field_typ = field.field_typ().unwrap();
734734
let value = components.get(&field.name()).unwrap();
735-
assert_eq!(value.typ(), field_typ);
735+
assert_eq!(value.typ(), field_typ, "Unexpected type for {:?}", field.name());
736736
}
737737

738738
let values = fields

kani-compiler/src/codegen_cprover_gotoc/codegen/rvalue.rs

Lines changed: 149 additions & 312 deletions
Large diffs are not rendered by default.

kani-compiler/src/codegen_cprover_gotoc/codegen/typ.rs

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,7 @@ use rustc_target::abi::{
2424
VariantIdx, Variants,
2525
};
2626
use rustc_target::spec::abi::Abi;
27-
use std::collections::BTreeMap;
2827
use std::iter;
29-
use std::iter::FromIterator;
3028
use tracing::{debug, trace, warn};
3129
use ty::layout::HasParamEnv;
3230

@@ -1166,7 +1164,7 @@ impl<'tcx> GotocCtx<'tcx> {
11661164
/// 3. references to structs whose last field is a unsized object (slice / trait)
11671165
/// - `matches!(pointee_type.kind(), ty::Adt(..) if self.is_unsized(t))
11681166
///
1169-
pub fn codegen_fat_ptr(&mut self, pointee_type: Ty<'tcx>) -> Type {
1167+
fn codegen_fat_ptr(&mut self, pointee_type: Ty<'tcx>) -> Type {
11701168
assert!(
11711169
!self.use_thin_pointer(pointee_type),
11721170
"Generating a fat pointer for a type requiring a thin pointer: {:?}",
@@ -1781,24 +1779,6 @@ impl<'tcx> GotocCtx<'tcx> {
17811779

17821780
/// Use maps instead of lists to manage mir struct components.
17831781
impl<'tcx> GotocCtx<'tcx> {
1784-
/// A mapping from mir field names to mir field types for a mir struct (for a single-variant adt)
1785-
pub fn mir_struct_field_types(
1786-
&self,
1787-
struct_type: Ty<'tcx>,
1788-
) -> BTreeMap<InternedString, Ty<'tcx>> {
1789-
match struct_type.kind() {
1790-
ty::Adt(adt_def, adt_substs) if adt_def.variants().len() == 1 => {
1791-
let fields = &adt_def.variants().get(VariantIdx::from_u32(0)).unwrap().fields;
1792-
BTreeMap::from_iter(
1793-
fields.iter().map(|field| {
1794-
(field.name.to_string().into(), field.ty(self.tcx, adt_substs))
1795-
}),
1796-
)
1797-
}
1798-
_ => unreachable!("Expected a single-variant ADT. Found {:?}", struct_type),
1799-
}
1800-
}
1801-
18021782
/// Extract a trait type from a `Struct<dyn T>`.
18031783
/// Note that `T` must be the last element of the struct.
18041784
/// This also handles nested cases: `Struct<Struct<dyn T>>` returns `dyn T`

kani-compiler/src/codegen_cprover_gotoc/utils/utils.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ impl<'tcx> GotocCtx<'tcx> {
108108
})
109109
.collect::<Vec<_>>();
110110

111-
type_members.iter().rev().fold(boxed_value, |value, (name, typ)| {
111+
type_members.iter().rfold(boxed_value, |value, (name, typ)| {
112112
Expr::struct_expr_with_nondet_fields(
113113
typ.clone(),
114114
btree_string_map![(*name, value),],
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright Kani Contributors
2+
// SPDX-License-Identifier: Apache-2.0 OR MIT
3+
// kani-flags: --mir-linker --enable-unstable
4+
//! Check the basic coercion when using box of box.
5+
//! Tests are broken down into different crates to ensure that the reachability works for each case.
6+
7+
mod defs;
8+
use defs::*;
9+
use std::boxed::Box;
10+
11+
#[kani::proof]
12+
fn check_double_coercion() {
13+
let id = kani::any();
14+
let inner: Box<Box<dyn Identity>> = Box::new(Box::new(Inner { id }));
15+
assert_eq!(inner.id(), id.into());
16+
assert_eq!(id_from_coerce(*inner), id.into());
17+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright Kani Contributors
2+
// SPDX-License-Identifier: Apache-2.0 OR MIT
3+
// kani-flags: --mir-linker --enable-unstable
4+
//! Check the basic coercion from using built-in references and pointers.
5+
//! Tests are broken down into different crates to ensure that the reachability works for each case.
6+
7+
mod defs;
8+
use defs::*;
9+
10+
#[kani::proof]
11+
fn check_base_coercion() {
12+
let inner_id = kani::any();
13+
let outer_id = kani::any();
14+
// Generate a fat pointer with a pointer to the vtable for `impl Identity for Inner`.
15+
let outer: &Outer<(dyn Identity + Send)> = &Outer { inner: Inner { id: inner_id }, outer_id };
16+
let identity: &Outer<(dyn Identity)> = outer;
17+
// Create a new fat pointer to inner using the metadata from outer fat pointer.
18+
assert_eq!(id_from_dyn(&identity.inner), inner_id.into());
19+
}

0 commit comments

Comments
 (0)