Skip to content

Commit 22b14f4

Browse files
tautschnigcelinval
andauthored
Upgrade toolchain to 2023-02-05 (rust-lang#2347)
Co-authored-by: Celina G. Val <[email protected]>
1 parent c4ed7ec commit 22b14f4

File tree

6 files changed

+282
-72
lines changed

6 files changed

+282
-72
lines changed

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,17 @@ impl<'tcx> GotocCtx<'tcx> {
624624
}
625625
}
626626

627+
/// Given a projection, generate an lvalue that represents the given variant index.
628+
pub fn codegen_variant_lvalue(
629+
&mut self,
630+
initial_projection: ProjectedPlace<'tcx>,
631+
variant_idx: VariantIdx,
632+
) -> ProjectedPlace<'tcx> {
633+
debug!(?initial_projection, ?variant_idx, "codegen_variant_lvalue");
634+
let downcast = ProjectionElem::Downcast(None, variant_idx);
635+
self.codegen_projection(Ok(initial_projection), downcast).unwrap()
636+
}
637+
627638
// https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/enum.ProjectionElem.html
628639
// ConstantIndex
629640
// [−]

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

Lines changed: 144 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// SPDX-License-Identifier: Apache-2.0 OR MIT
33

44
use super::typ::pointee_type;
5+
use crate::codegen_cprover_gotoc::codegen::place::{ProjectedPlace, TypeOrVariant};
56
use crate::codegen_cprover_gotoc::codegen::PropertyClass;
67
use crate::codegen_cprover_gotoc::utils::{dynamic_fat_ptr, slice_fat_ptr};
78
use crate::codegen_cprover_gotoc::{GotocCtx, VtableCtx};
@@ -17,9 +18,9 @@ use rustc_middle::mir::{AggregateKind, BinOp, CastKind, NullOp, Operand, Place,
1718
use rustc_middle::ty::adjustment::PointerCast;
1819
use rustc_middle::ty::layout::LayoutOf;
1920
use rustc_middle::ty::{self, Instance, IntTy, Ty, TyCtxt, UintTy, VtblEntry};
20-
use rustc_target::abi::{FieldsShape, Size, TagEncoding, Variants};
21+
use rustc_target::abi::{FieldsShape, Size, TagEncoding, VariantIdx, Variants};
2122
use std::collections::BTreeMap;
22-
use tracing::{debug, warn};
23+
use tracing::{debug, trace, warn};
2324

2425
impl<'tcx> GotocCtx<'tcx> {
2526
fn codegen_comparison(&mut self, op: &BinOp, e1: &Operand<'tcx>, e2: &Operand<'tcx>) -> Expr {
@@ -279,13 +280,112 @@ impl<'tcx> GotocCtx<'tcx> {
279280
}
280281
}
281282

283+
/// Create an initializer for a generator struct.
284+
fn codegen_rvalue_generator(&mut self, operands: &[Operand<'tcx>], ty: Ty<'tcx>) -> Expr {
285+
let layout = self.layout_of(ty);
286+
let discriminant_field = match &layout.variants {
287+
Variants::Multiple { tag_encoding: TagEncoding::Direct, tag_field, .. } => tag_field,
288+
_ => unreachable!(
289+
"Expected generators to have multiple variants and direct encoding, but found: {layout:?}"
290+
),
291+
};
292+
let overall_t = self.codegen_ty(ty);
293+
let direct_fields = overall_t.lookup_field("direct_fields", &self.symbol_table).unwrap();
294+
let mut operands_iter = operands.iter();
295+
let direct_fields_expr = Expr::struct_expr_from_values(
296+
direct_fields.typ(),
297+
layout
298+
.fields
299+
.index_by_increasing_offset()
300+
.map(|idx| {
301+
let field_ty = layout.field(self, idx).ty;
302+
if idx == *discriminant_field {
303+
Expr::int_constant(0, self.codegen_ty(field_ty))
304+
} else {
305+
self.codegen_operand(operands_iter.next().unwrap())
306+
}
307+
})
308+
.collect(),
309+
&self.symbol_table,
310+
);
311+
assert!(operands_iter.next().is_none());
312+
Expr::union_expr(overall_t, "direct_fields", direct_fields_expr, &self.symbol_table)
313+
}
314+
315+
/// This code will generate an expression that initializes an enumeration.
316+
///
317+
/// It will first create a temporary variant with the same enum type.
318+
/// Initialize the case structure and set its discriminant.
319+
/// Finally, it will return the temporary value.
320+
fn codegen_rvalue_enum_aggregate(
321+
&mut self,
322+
variant_index: VariantIdx,
323+
operands: &[Operand<'tcx>],
324+
res_ty: Ty<'tcx>,
325+
loc: Location,
326+
) -> Expr {
327+
let mut stmts = vec![];
328+
let typ = self.codegen_ty(res_ty);
329+
// 1- Create a temporary value of the enum type.
330+
tracing::debug!(?typ, ?res_ty, "aggregate_enum");
331+
let (temp_var, decl) = self.decl_temp_variable(typ.clone(), None, loc);
332+
stmts.push(decl);
333+
if !operands.is_empty() {
334+
// 2- Initialize the members of the temporary variant.
335+
let initial_projection = ProjectedPlace::try_new(
336+
temp_var.clone(),
337+
TypeOrVariant::Type(res_ty),
338+
None,
339+
None,
340+
self,
341+
)
342+
.unwrap();
343+
let variant_proj = self.codegen_variant_lvalue(initial_projection, variant_index);
344+
let variant_expr = variant_proj.goto_expr.clone();
345+
let layout = self.layout_of(res_ty);
346+
let fields = match &layout.variants {
347+
Variants::Single { index } => {
348+
if *index != variant_index {
349+
// This may occur if all variants except for the one pointed by
350+
// index can never be constructed. Generic code might still try
351+
// to initialize the non-existing invariant.
352+
trace!(?res_ty, ?variant_index, "Unreachable invariant");
353+
return Expr::nondet(typ);
354+
}
355+
&layout.fields
356+
}
357+
Variants::Multiple { variants, .. } => &variants[variant_index].fields,
358+
};
359+
360+
trace!(?variant_expr, ?fields, ?operands, "codegen_aggregate enum");
361+
let init_struct = Expr::struct_expr_from_values(
362+
variant_expr.typ().clone(),
363+
fields
364+
.index_by_increasing_offset()
365+
.map(|idx| self.codegen_operand(&operands[idx]))
366+
.collect(),
367+
&self.symbol_table,
368+
);
369+
let assign_case = variant_proj.goto_expr.assign(init_struct, loc);
370+
stmts.push(assign_case);
371+
}
372+
// 3- Set discriminant.
373+
let set_discriminant =
374+
self.codegen_set_discriminant(res_ty, temp_var.clone(), variant_index, loc);
375+
stmts.push(set_discriminant);
376+
// 4- Return temporary variable.
377+
stmts.push(temp_var.as_stmt(loc));
378+
Expr::statement_expression(stmts, typ)
379+
}
380+
282381
fn codegen_rvalue_aggregate(
283382
&mut self,
284-
k: &AggregateKind<'tcx>,
383+
aggregate: &AggregateKind<'tcx>,
285384
operands: &[Operand<'tcx>],
286385
res_ty: Ty<'tcx>,
386+
loc: Location,
287387
) -> Expr {
288-
match *k {
388+
match *aggregate {
289389
AggregateKind::Array(et) => {
290390
if et.is_unit() {
291391
Expr::struct_expr_from_values(
@@ -304,7 +404,44 @@ impl<'tcx> GotocCtx<'tcx> {
304404
)
305405
}
306406
}
307-
AggregateKind::Tuple => {
407+
AggregateKind::Adt(_, _, _, _, Some(active_field_index)) => {
408+
assert!(res_ty.is_union());
409+
assert_eq!(operands.len(), 1);
410+
let typ = self.codegen_ty(res_ty);
411+
let components = typ.lookup_components(&self.symbol_table).unwrap();
412+
Expr::union_expr(
413+
typ,
414+
components[active_field_index].name(),
415+
self.codegen_operand(&operands[0]),
416+
&self.symbol_table,
417+
)
418+
}
419+
AggregateKind::Adt(_, _, _, _, _) if res_ty.is_simd() => {
420+
let typ = self.codegen_ty(res_ty);
421+
let layout = self.layout_of(res_ty);
422+
let vector_element_type = typ.base_type().unwrap().clone();
423+
Expr::vector_expr(
424+
typ,
425+
layout
426+
.fields
427+
.index_by_increasing_offset()
428+
.map(|idx| {
429+
let cgo = self.codegen_operand(&operands[idx]);
430+
// The input operand might actually be a one-element array, as seen
431+
// when running assess on firecracker.
432+
if *cgo.typ() == vector_element_type {
433+
cgo
434+
} else {
435+
cgo.transmute_to(vector_element_type.clone(), &self.symbol_table)
436+
}
437+
})
438+
.collect(),
439+
)
440+
}
441+
AggregateKind::Adt(_, variant_index, ..) if res_ty.is_enum() => {
442+
self.codegen_rvalue_enum_aggregate(variant_index, operands, res_ty, loc)
443+
}
444+
AggregateKind::Adt(..) | AggregateKind::Closure(..) | AggregateKind::Tuple => {
308445
let typ = self.codegen_ty(res_ty);
309446
let layout = self.layout_of(res_ty);
310447
Expr::struct_expr_from_values(
@@ -317,9 +454,7 @@ impl<'tcx> GotocCtx<'tcx> {
317454
&self.symbol_table,
318455
)
319456
}
320-
AggregateKind::Adt(_, _, _, _, _) => unimplemented!(),
321-
AggregateKind::Closure(_, _) => unimplemented!(),
322-
AggregateKind::Generator(_, _, _) => unimplemented!(),
457+
AggregateKind::Generator(_, _, _) => self.codegen_rvalue_generator(&operands, res_ty),
323458
}
324459
}
325460

@@ -406,7 +541,7 @@ impl<'tcx> GotocCtx<'tcx> {
406541
self.codegen_get_discriminant(place, pt, res_ty)
407542
}
408543
Rvalue::Aggregate(ref k, operands) => {
409-
self.codegen_rvalue_aggregate(k, operands, res_ty)
544+
self.codegen_rvalue_aggregate(k, operands, res_ty, loc)
410545
}
411546
Rvalue::ThreadLocalRef(def_id) => {
412547
// Since Kani is single-threaded, we treat a thread local like a static variable:

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

Lines changed: 64 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use rustc_middle::ty;
1616
use rustc_middle::ty::layout::LayoutOf;
1717
use rustc_middle::ty::{Instance, InstanceDef, Ty};
1818
use rustc_span::Span;
19+
use rustc_target::abi::VariantIdx;
1920
use rustc_target::abi::{FieldsShape, Primitive, TagEncoding, Variants};
2021
use tracing::{debug, debug_span, trace};
2122

@@ -55,68 +56,11 @@ impl<'tcx> GotocCtx<'tcx> {
5556
}
5657
StatementKind::Deinit(place) => self.codegen_deinit(place, location),
5758
StatementKind::SetDiscriminant { place, variant_index } => {
58-
// this requires place points to an enum type.
59-
let pt = self.place_ty(place);
60-
let layout = self.layout_of(pt);
61-
match &layout.variants {
62-
Variants::Single { .. } => Stmt::skip(location),
63-
Variants::Multiple { tag, tag_encoding, .. } => match tag_encoding {
64-
TagEncoding::Direct => {
65-
let discr =
66-
pt.discriminant_for_variant(self.tcx, *variant_index).unwrap();
67-
let discr_t = self.codegen_enum_discr_typ(pt);
68-
// The constant created below may not fit into the type.
69-
// https://github.com/model-checking/kani/issues/996
70-
//
71-
// It doesn't matter if the type comes from `self.codegen_enum_discr_typ(pt)`
72-
// or `discr.ty`. It looks like something is wrong with `discriminat_for_variant`
73-
// because when it tries to codegen `std::cmp::Ordering` (which should produce
74-
// discriminant values -1, 0 and 1) it produces values 255, 0 and 1 with i8 types:
75-
//
76-
// debug!("DISCRIMINANT - val:{:?} ty:{:?}", discr.val, discr.ty);
77-
// DISCRIMINANT - val:255 ty:i8
78-
// DISCRIMINANT - val:0 ty:i8
79-
// DISCRIMINANT - val:1 ty:i8
80-
let discr = Expr::int_constant(discr.val, self.codegen_ty(discr_t));
81-
let place_goto_expr = unwrap_or_return_codegen_unimplemented_stmt!(
82-
self,
83-
self.codegen_place(place)
84-
)
85-
.goto_expr;
86-
self.codegen_discriminant_field(place_goto_expr, pt)
87-
.assign(discr, location)
88-
}
89-
TagEncoding::Niche { untagged_variant, niche_variants, niche_start } => {
90-
if untagged_variant != variant_index {
91-
let offset = match &layout.fields {
92-
FieldsShape::Arbitrary { offsets, .. } => offsets[0],
93-
_ => unreachable!("niche encoding must have arbitrary fields"),
94-
};
95-
let discr_ty = self.codegen_enum_discr_typ(pt);
96-
let discr_ty = self.codegen_ty(discr_ty);
97-
let niche_value =
98-
variant_index.as_u32() - niche_variants.start().as_u32();
99-
let niche_value = (niche_value as u128).wrapping_add(*niche_start);
100-
let value = if niche_value == 0
101-
&& matches!(tag.primitive(), Primitive::Pointer(_))
102-
{
103-
discr_ty.null()
104-
} else {
105-
Expr::int_constant(niche_value, discr_ty.clone())
106-
};
107-
let place = unwrap_or_return_codegen_unimplemented_stmt!(
108-
self,
109-
self.codegen_place(place)
110-
)
111-
.goto_expr;
112-
self.codegen_get_niche(place, offset, discr_ty)
113-
.assign(value, location)
114-
} else {
115-
Stmt::skip(location)
116-
}
117-
}
118-
},
119-
}
59+
let dest_ty = self.place_ty(place);
60+
let dest_expr =
61+
unwrap_or_return_codegen_unimplemented_stmt!(self, self.codegen_place(place))
62+
.goto_expr;
63+
self.codegen_set_discriminant(dest_ty, dest_expr, *variant_index, location)
12064
}
12165
StatementKind::StorageLive(_) => Stmt::skip(location), // TODO: fix me
12266
StatementKind::StorageDead(_) => Stmt::skip(location), // TODO: fix me
@@ -259,6 +203,64 @@ impl<'tcx> GotocCtx<'tcx> {
259203
}
260204
}
261205

206+
/// Create a statement that sets the variable discriminant to the value that corresponds to the
207+
/// variant index.
208+
pub fn codegen_set_discriminant(
209+
&mut self,
210+
dest_ty: Ty<'tcx>,
211+
dest_expr: Expr,
212+
variant_index: VariantIdx,
213+
location: Location,
214+
) -> Stmt {
215+
// this requires place points to an enum type.
216+
let layout = self.layout_of(dest_ty);
217+
match &layout.variants {
218+
Variants::Single { .. } => Stmt::skip(location),
219+
Variants::Multiple { tag, tag_encoding, .. } => match tag_encoding {
220+
TagEncoding::Direct => {
221+
let discr = dest_ty.discriminant_for_variant(self.tcx, variant_index).unwrap();
222+
let discr_t = self.codegen_enum_discr_typ(dest_ty);
223+
// The constant created below may not fit into the type.
224+
// https://github.com/model-checking/kani/issues/996
225+
//
226+
// It doesn't matter if the type comes from `self.codegen_enum_discr_typ(pt)`
227+
// or `discr.ty`. It looks like something is wrong with `discriminat_for_variant`
228+
// because when it tries to codegen `std::cmp::Ordering` (which should produce
229+
// discriminant values -1, 0 and 1) it produces values 255, 0 and 1 with i8 types:
230+
//
231+
// debug!("DISCRIMINANT - val:{:?} ty:{:?}", discr.val, discr.ty);
232+
// DISCRIMINANT - val:255 ty:i8
233+
// DISCRIMINANT - val:0 ty:i8
234+
// DISCRIMINANT - val:1 ty:i8
235+
let discr = Expr::int_constant(discr.val, self.codegen_ty(discr_t));
236+
self.codegen_discriminant_field(dest_expr, dest_ty).assign(discr, location)
237+
}
238+
TagEncoding::Niche { untagged_variant, niche_variants, niche_start } => {
239+
if *untagged_variant != variant_index {
240+
let offset = match &layout.fields {
241+
FieldsShape::Arbitrary { offsets, .. } => offsets[0],
242+
_ => unreachable!("niche encoding must have arbitrary fields"),
243+
};
244+
let discr_ty = self.codegen_enum_discr_typ(dest_ty);
245+
let discr_ty = self.codegen_ty(discr_ty);
246+
let niche_value = variant_index.as_u32() - niche_variants.start().as_u32();
247+
let niche_value = (niche_value as u128).wrapping_add(*niche_start);
248+
let value = if niche_value == 0
249+
&& matches!(tag.primitive(), Primitive::Pointer(_))
250+
{
251+
discr_ty.null()
252+
} else {
253+
Expr::int_constant(niche_value, discr_ty.clone())
254+
};
255+
self.codegen_get_niche(dest_expr, offset, discr_ty).assign(value, location)
256+
} else {
257+
Stmt::skip(location)
258+
}
259+
}
260+
},
261+
}
262+
}
263+
262264
/// From rustc doc: "This writes `uninit` bytes to the entire place."
263265
/// Our model of GotoC has a similar statement, which is later lowered
264266
/// to assigning a Nondet in CBMC, with a comment specifying that it

rust-toolchain.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
# SPDX-License-Identifier: Apache-2.0 OR MIT
33

44
[toolchain]
5-
channel = "nightly-2023-02-04"
5+
channel = "nightly-2023-02-05"
66
components = ["llvm-tools-preview", "rustc-dev", "rust-src", "rustfmt"]

0 commit comments

Comments
 (0)