Skip to content

Commit c5e7d3d

Browse files
adpaco-awszhassan-aws
authored andcommitted
Partial support for subslice projection (rust-lang#452)
* Partial support for subslice pattern * Added two tests for sub-slices * Added fixme to broken test * Add copyright notice in tests * Add comments linking to full support issue * Remove `dbg` macros * Use `ssize_t` for index Co-authored-by: Zyad Hassan <zyadh@amazon.com>
1 parent a6836d8 commit c5e7d3d

File tree

4 files changed

+96
-2
lines changed

4 files changed

+96
-2
lines changed

Diff for: compiler/rustc_codegen_llvm/src/gotoc/mir_to_goto/codegen/place.rs

+43-2
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@
66
//! in [codegen_place] below.
77
88
use crate::gotoc::cbmc::goto_program::{Expr, Type};
9+
use crate::gotoc::mir_to_goto::utils::slice_fat_ptr;
910
use crate::gotoc::mir_to_goto::GotocCtx;
11+
use rustc_hir::Mutability;
1012
use rustc_middle::{
1113
mir::{Field, Local, Place, ProjectionElem},
12-
ty::{self, Ty, TyS, VariantDef},
14+
ty::{self, Ty, TyS, TypeAndMut, VariantDef},
1315
};
1416
use rustc_target::abi::{LayoutOf, TagEncoding, Variants};
1517
use tracing::{debug, warn};
@@ -357,7 +359,46 @@ impl<'tcx> GotocCtx<'tcx> {
357359
ProjectionElem::ConstantIndex { offset, min_length, from_end } => {
358360
self.codegen_constant_index(before, offset, min_length, from_end)
359361
}
360-
ProjectionElem::Subslice { .. } => unimplemented!(),
362+
// Best effort to codegen subslice projection.
363+
// This is known to fail with a CBMC invariant violation
364+
// in some cases. Full support to be added in
365+
// https://github.com/model-checking/rmc/issues/357
366+
ProjectionElem::Subslice { from, to, from_end } => {
367+
// https://rust-lang.github.io/rfcs/2359-subslice-pattern-syntax.html
368+
match before.mir_typ().kind() {
369+
ty::Array(..) => unimplemented!(),
370+
ty::Slice(elemt) => {
371+
let len = if from_end {
372+
let olen = before
373+
.fat_ptr_goto_expr
374+
.clone()
375+
.unwrap()
376+
.member("len", &self.symbol_table);
377+
let sum = Expr::int_constant(to + from, Type::size_t());
378+
olen.sub(sum) // olen - (to + from) = olen - to - from
379+
} else {
380+
Expr::int_constant(to - from, Type::size_t())
381+
};
382+
let typ = self.tcx.mk_slice(elemt);
383+
let typ_and_mut = TypeAndMut { ty: typ, mutbl: Mutability::Mut };
384+
let ptr_typ = self.tcx.mk_ptr(typ_and_mut);
385+
let goto_type = self.codegen_ty(ptr_typ);
386+
387+
let index = Expr::int_constant(from, Type::ssize_t());
388+
let from_elem = before.goto_expr.index(index);
389+
let data = from_elem.address_of();
390+
let fat_ptr = slice_fat_ptr(goto_type, data, len, &self.symbol_table);
391+
ProjectedPlace::new(
392+
fat_ptr.clone(),
393+
TypeOrVariant::Type(ptr_typ),
394+
Some(fat_ptr),
395+
Some(ptr_typ),
396+
self,
397+
)
398+
}
399+
_ => unreachable!("must be array or slice"),
400+
}
401+
}
361402
ProjectionElem::Downcast(_, idx) => {
362403
// downcast converts a variable of an enum type to one of its discriminated cases
363404
let t = before.mir_typ();

Diff for: compiler/rustc_codegen_llvm/src/gotoc/mir_to_goto/codegen/rvalue.rs

+5
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,11 @@ impl<'tcx> GotocCtx<'tcx> {
109109
* Construct a fat pointer to the value of this place
110110
*/
111111

112+
// skip constructing a fat ptr if this place is already one
113+
if place_goto_expr.typ().is_rust_fat_ptr(&self.symbol_table) {
114+
return place_goto_expr;
115+
}
116+
112117
// In the sequence of projections leading to this place, we dereferenced
113118
// this fat pointer.
114119
let intermediate_fat_pointer = projection.fat_ptr_goto_expr.unwrap();

Diff for: src/test/cbmc/SubSlice/subslice1.rs

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0 OR MIT
3+
fn main() {
4+
let arr = [1, 2, 3];
5+
// s is a slice (&[i32])
6+
let [s @ ..] = &arr[..];
7+
assert!(s[0] == 1);
8+
assert!(s[1] == 2);
9+
}

Diff for: src/test/cbmc/SubSlice/subslice2_fixme.rs

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0 OR MIT
3+
4+
// At present, this test fails with a CBMC invariant violation:
5+
//
6+
// Invariant check failed
7+
// File: ../src/solvers/flattening/boolbv_add_sub.cpp:68 function: convert_add_sub
8+
// Condition: it->type() == type
9+
// Reason: add/sub with mixed types:
10+
// +
11+
// * type: signedbv
12+
// * width: 64
13+
// * #c_type: signed_long_int
14+
// 0: constant
15+
// * type: signedbv
16+
// * width: 64
17+
// * #c_type: signed_long_int
18+
// * value: 1
19+
// 1: constant
20+
// * type: unsignedbv
21+
// * #source_location:
22+
// * file: <built-in-additions>
23+
// * line: 1
24+
// * working_directory: /home/ubuntu/rmc-rebase
25+
// * width: 64
26+
// * #typedef: __CPROVER_size_t
27+
// * #c_type: unsigned_long_int
28+
// * value: 1
29+
//
30+
// Full support for subslice projection to be added in
31+
// https://github.com/model-checking/rmc/issues/357
32+
33+
fn main() {
34+
let arr = [1, 2, 3];
35+
// s is a slice (&[i32])
36+
let [s @ ..] = &arr[1..];
37+
assert!(s[0] == 2);
38+
assert!(s[1] == 3);
39+
}

0 commit comments

Comments
 (0)