Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade the toolchain to nightly-2023-04-16 #2406

Merged
merged 13 commits into from
May 16, 2023
Merged
38 changes: 29 additions & 9 deletions cprover_bindings/src/goto_program/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ pub enum ExprValue {
StringConstant {
s: InternedString,
},
/// Struct initializer
/// Struct initializer
tautschnig marked this conversation as resolved.
Show resolved Hide resolved
/// `struct foo the_foo = >>> {field1, field2, ... } <<<`
Struct {
values: Vec<Expr>,
Expand All @@ -142,7 +142,7 @@ pub enum ExprValue {
},
/// `(typ) self`. Target type is in the outer `Expr` struct.
Typecast(Expr),
/// Union initializer
/// Union initializer
/// `union foo the_foo = >>> {.field = value } <<<`
Union {
value: Expr,
Expand Down Expand Up @@ -681,7 +681,7 @@ impl Expr {
expr!(StatementExpression { statements: ops }, typ)
}

/// Internal helper function for Struct initalizer
/// Internal helper function for Struct initalizer
/// `struct foo the_foo = >>> {.field1 = val1, .field2 = val2, ... } <<<`
/// ALL fields must be given, including padding
fn struct_expr_with_explicit_padding(
Expand All @@ -698,7 +698,7 @@ impl Expr {
expr!(Struct { values }, typ)
}

/// Struct initializer
/// Struct initializer
/// `struct foo the_foo = >>> {.field1 = val1, .field2 = val2, ... } <<<`
/// Note that only the NON padding fields should be explicitly given.
/// Padding fields are automatically inserted using the type from the `SymbolTable`
Expand Down Expand Up @@ -764,7 +764,7 @@ impl Expr {
Expr::struct_expr_from_values(typ, values, symbol_table)
}

/// Struct initializer
/// Struct initializer
/// `struct foo the_foo = >>> {field1, field2, ... } <<<`
/// Note that only the NON padding fields should be explicitly given.
/// Padding fields are automatically inserted using the type from the `SymbolTable`
Expand Down Expand Up @@ -800,7 +800,7 @@ impl Expr {
Expr::struct_expr_with_explicit_padding(typ, fields, values)
}

/// Struct initializer
/// Struct initializer
/// `struct foo the_foo = >>> {field1, padding2, field3, ... } <<<`
/// Note that padding fields should be explicitly given.
/// This would be used when the values and padding have already been combined,
Expand Down Expand Up @@ -829,6 +829,17 @@ impl Expr {
Expr::struct_expr_with_explicit_padding(typ, fields, values)
}

/// Initializer for a zero sized type (ZST).
/// Since this is a ZST, we call nondet to simplify everything.
pub fn init_unit(typ: Type, symbol_table: &SymbolTable) -> Self {
assert!(
typ.is_struct_tag(),
"Zero sized types should be represented as struct: but found: {typ:?}"
);
assert_eq!(typ.sizeof_in_bits(symbol_table), 0);
Expr::nondet(typ)
}

/// `identifier`
pub fn symbol_expression<T: Into<InternedString>>(identifier: T, typ: Type) -> Self {
let identifier = identifier.into();
Expand Down Expand Up @@ -859,7 +870,7 @@ impl Expr {
self.transmute_to(t, st)
}

/// Union initializer
/// Union initializer
/// `union foo the_foo = >>> {.field = value } <<<`
pub fn union_expr<T: Into<InternedString>>(
typ: Type,
Expand Down Expand Up @@ -1381,9 +1392,9 @@ impl Expr {
ArithmeticOverflowResult { result, overflowed }
}

/// Uses CBMC's add-with-overflow operation that performs a single addition
/// Uses CBMC's [binop]-with-overflow operation that performs a single addition
/// operation
/// `struct (T, bool) overflow(+, self, e)` where `T` is the type of `self`
/// `struct (T, bool) overflow(binop, self, e)` where `T` is the type of `self`
/// Pseudocode:
/// ```
/// struct overflow_result_t {
Expand All @@ -1395,6 +1406,14 @@ impl Expr {
/// overflow_result.overflowed = raw_result > maximum value of T;
/// return overflow_result;
/// ```
pub fn overflow_op(self, op: BinaryOperator, e: Expr) -> Expr {
assert!(
matches!(op, OverflowResultMinus | OverflowResultMult | OverflowResultPlus),
"Expected an overflow operation, but found: `{op:?}`"
);
self.binop(op, e)
}

pub fn add_overflow_result(self, e: Expr) -> Expr {
self.binop(OverflowResultPlus, e)
}
Expand Down Expand Up @@ -1426,6 +1445,7 @@ impl Expr {

/// `ArithmeticOverflowResult r; >>>r.overflowed = builtin_sub_overflow(self, e, &r.result)<<<`
pub fn mul_overflow(self, e: Expr) -> ArithmeticOverflowResult {
// TODO: Should we always use the one below?
let result = self.clone().mul(e.clone());
let overflowed = self.mul_overflow_p(e);
ArithmeticOverflowResult { result, overflowed }
Expand Down
4 changes: 2 additions & 2 deletions kani-compiler/src/codegen_cprover_gotoc/codegen/assert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,11 +154,11 @@ impl<'tcx> GotocCtx<'tcx> {
if self.queries.get_check_assertion_reachability() {
// Generate a unique ID for the assert
let assert_id = self.next_check_id();
// Generate a message for the reachability check that includes the unique ID
let reach_msg = assert_id.clone();
// Also add the unique ID as a prefix to the assert message so that it can be
// easily paired with the reachability check
let msg = GotocCtx::add_prefix_to_msg(&msg, &assert_id);
// Generate a message for the reachability check that includes the unique ID
let reach_msg = assert_id;
tautschnig marked this conversation as resolved.
Show resolved Hide resolved
// inject a reachability check, which is a (non-blocking)
// assert(false) whose failure indicates that this line is reachable.
// The property class (`PropertyClass:ReachabilityCheck`) is used by
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ impl<'tcx> GotocCtx<'tcx> {
var_type,
self.codegen_span(&ldata.source_info.span),
)
.with_is_hidden(!ldata.is_user_variable())
.with_is_hidden(!self.is_user_variable(&lc))
celinval marked this conversation as resolved.
Show resolved Hide resolved
.with_is_parameter((idx > 0 && idx <= num_args) && !self.is_zst(var_ty));
let sym_e = sym.to_expr();
self.symbol_table.insert(sym);
Expand Down
86 changes: 44 additions & 42 deletions kani-compiler/src/codegen_cprover_gotoc/codegen/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ use super::typ::{self, pointee_type};
use super::PropertyClass;
use crate::codegen_cprover_gotoc::GotocCtx;
use cbmc::goto_program::{
arithmetic_overflow_result_type, ArithmeticOverflowResult, BuiltinFn, Expr, Location, Stmt,
Type, ARITH_OVERFLOW_OVERFLOWED_FIELD, ARITH_OVERFLOW_RESULT_FIELD,
arithmetic_overflow_result_type, ArithmeticOverflowResult, BinaryOperator, BuiltinFn, Expr,
Location, Stmt, Type, ARITH_OVERFLOW_OVERFLOWED_FIELD, ARITH_OVERFLOW_RESULT_FIELD,
};
use rustc_middle::mir::{BasicBlock, Operand, Place};
use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::layout::{LayoutOf, ValidityRequirement};
use rustc_middle::ty::{self, Ty};
use rustc_middle::ty::{Instance, InstanceDef};
use rustc_span::Span;
Expand Down Expand Up @@ -172,38 +172,6 @@ impl<'tcx> GotocCtx<'tcx> {
}};
}

// Intrinsics of the form *_with_overflow
macro_rules! codegen_op_with_overflow {
($f:ident) => {{
let pt = self.place_ty(p);
let t = self.codegen_ty(pt);
let a = fargs.remove(0);
let b = fargs.remove(0);
let op_type = a.typ().clone();
let res = a.$f(b);
// add to symbol table
let struct_tag = self.codegen_arithmetic_overflow_result_type(op_type.clone());
assert_eq!(*res.typ(), struct_tag);

// store the result in a temporary variable
let (var, decl) = self.decl_temp_variable(struct_tag, Some(res), loc);
// cast into result type
let e = Expr::struct_expr_from_values(
t.clone(),
vec![
var.clone().member(ARITH_OVERFLOW_RESULT_FIELD, &self.symbol_table),
var.member(ARITH_OVERFLOW_OVERFLOWED_FIELD, &self.symbol_table)
.cast_to(Type::c_bool()),
],
&self.symbol_table,
);
self.codegen_expr_to_place(
p,
Expr::statement_expression(vec![decl, e.as_stmt(loc)], t),
)
}};
}

// Intrinsics which encode a simple arithmetic operation with overflow check
macro_rules! codegen_op_with_overflow_check {
($f:ident) => {{
Expand Down Expand Up @@ -362,7 +330,9 @@ impl<'tcx> GotocCtx<'tcx> {
}

match intrinsic {
"add_with_overflow" => codegen_op_with_overflow!(add_overflow_result),
"add_with_overflow" => {
self.codegen_op_with_overflow(BinaryOperator::OverflowResultPlus, fargs, p, loc)
}
"arith_offset" => self.codegen_offset(intrinsic, instance, fargs, p, loc),
"assert_inhabited" => self.codegen_assert_intrinsic(instance, intrinsic, span),
"assert_mem_uninitialized_valid" => {
Expand Down Expand Up @@ -528,7 +498,9 @@ impl<'tcx> GotocCtx<'tcx> {
"min_align_of_val" => codegen_size_align!(align),
"minnumf32" => codegen_simple_intrinsic!(Fminf),
"minnumf64" => codegen_simple_intrinsic!(Fmin),
"mul_with_overflow" => codegen_op_with_overflow!(mul_overflow_result),
"mul_with_overflow" => {
self.codegen_op_with_overflow(BinaryOperator::OverflowResultMult, fargs, p, loc)
}
"nearbyintf32" => codegen_simple_intrinsic!(Nearbyintf),
"nearbyintf64" => codegen_simple_intrinsic!(Nearbyint),
"needs_drop" => codegen_intrinsic_const!(),
Expand Down Expand Up @@ -615,7 +587,9 @@ impl<'tcx> GotocCtx<'tcx> {
"size_of_val" => codegen_size_align!(size),
"sqrtf32" => unstable_codegen!(codegen_simple_intrinsic!(Sqrtf)),
"sqrtf64" => unstable_codegen!(codegen_simple_intrinsic!(Sqrt)),
"sub_with_overflow" => codegen_op_with_overflow!(sub_overflow_result),
"sub_with_overflow" => {
self.codegen_op_with_overflow(BinaryOperator::OverflowResultMinus, fargs, p, loc)
}
"transmute" => self.codegen_intrinsic_transmute(fargs, ret_ty, p),
"truncf32" => codegen_simple_intrinsic!(Truncf),
"truncf64" => codegen_simple_intrinsic!(Trunc),
Expand Down Expand Up @@ -719,6 +693,25 @@ impl<'tcx> GotocCtx<'tcx> {
dividend_is_int_min.and(divisor_is_minus_one).not()
}

/// Intrinsics of the form *_with_overflow
fn codegen_op_with_overflow(
&mut self,
binop: BinaryOperator,
mut fargs: Vec<Expr>,
place: &Place<'tcx>,
loc: Location,
) -> Stmt {
let place_ty = self.place_ty(place);
let result_type = self.codegen_ty(place_ty);
let left = fargs.remove(0);
let right = fargs.remove(0);
let res = self.binop_with_overflow(binop, left, right, result_type.clone(), loc);
self.codegen_expr_to_place(
place,
Expr::statement_expression(vec![res.as_stmt(loc)], result_type),
)
}

fn codegen_exact_div(&mut self, mut fargs: Vec<Expr>, p: &Place<'tcx>, loc: Location) -> Stmt {
// Check for undefined behavior conditions defined in
// https://doc.rust-lang.org/std/intrinsics/fn.exact_div.html
Expand Down Expand Up @@ -760,7 +753,7 @@ impl<'tcx> GotocCtx<'tcx> {
/// layout is invalid so we get a message that mentions the offending type.
///
/// <https://doc.rust-lang.org/std/intrinsics/fn.assert_inhabited.html>
/// <https://doc.rust-lang.org/std/intrinsics/fn.assert_uninit_valid.html>
/// <https://doc.rust-lang.org/std/intrinsics/fn.assert_mem_uninitialized_valid.html>
/// <https://doc.rust-lang.org/std/intrinsics/fn.assert_zero_valid.html>
fn codegen_assert_intrinsic(
&mut self,
Expand Down Expand Up @@ -788,7 +781,10 @@ impl<'tcx> GotocCtx<'tcx> {
// Then we check if the type allows "raw" initialization for the cases
// where memory is zero-initialized or entirely uninitialized
if intrinsic == "assert_zero_valid"
&& !self.tcx.permits_zero_init(param_env_and_type).ok().unwrap()
&& !self
.tcx
.check_validity_requirement((ValidityRequirement::Zero, param_env_and_type))
.unwrap()
{
return self.codegen_fatal_error(
PropertyClass::SafetyCheck,
Expand All @@ -797,8 +793,14 @@ impl<'tcx> GotocCtx<'tcx> {
);
}

if intrinsic == "assert_uninit_valid"
&& !self.tcx.permits_uninit_init(param_env_and_type).ok().unwrap()
if intrinsic == "assert_mem_uninitialized_valid"
&& !self
.tcx
.check_validity_requirement((
ValidityRequirement::UninitMitigated0x01Fill,
param_env_and_type,
))
.unwrap()
{
return self.codegen_fatal_error(
PropertyClass::SafetyCheck,
Expand Down
6 changes: 3 additions & 3 deletions kani-compiler/src/codegen_cprover_gotoc/codegen/operand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ impl<'tcx> GotocCtx<'tcx> {
ConstValue::ZeroSized => match lit_ty.kind() {
// Rust "function items" (not closures, not function pointers, see `codegen_fndef`)
ty::FnDef(d, substs) => self.codegen_fndef(*d, substs, span),
_ => unimplemented!(),
_ => Expr::init_unit(self.codegen_ty(lit_ty), &self.symbol_table),
},
}
}
Expand Down Expand Up @@ -310,7 +310,7 @@ impl<'tcx> GotocCtx<'tcx> {
}
} else {
// otherwise, there is just one field, which is stored as the scalar data
let field = &variant.fields[0];
let field = &variant.fields[0usize.into()];
let fty = field.ty(self.tcx, subst);

let overall_t = self.codegen_ty(ty);
Expand All @@ -336,7 +336,7 @@ impl<'tcx> GotocCtx<'tcx> {
&self.symbol_table,
),
1 => {
let fty = variant.fields[0].ty(self.tcx, subst);
let fty = variant.fields[0usize.into()].ty(self.tcx, subst);
self.codegen_single_variant_single_field(
s, span, overall_t, fty,
)
Expand Down
11 changes: 6 additions & 5 deletions kani-compiler/src/codegen_cprover_gotoc/codegen/place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ use crate::codegen_cprover_gotoc::utils::{dynamic_fat_ptr, slice_fat_ptr};
use crate::codegen_cprover_gotoc::GotocCtx;
use crate::unwrap_or_return_codegen_unimplemented;
use cbmc::goto_program::{Expr, Location, Type};
use rustc_abi::FieldIdx;
use rustc_hir::Mutability;
use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::{
mir::{Field, Local, Place, ProjectionElem},
mir::{Local, Place, ProjectionElem},
ty::{self, Ty, TypeAndMut, VariantDef},
};
use rustc_target::abi::{TagEncoding, VariantIdx, Variants};
Expand Down Expand Up @@ -238,7 +239,7 @@ impl<'tcx> GotocCtx<'tcx> {
&mut self,
res: Expr,
t: TypeOrVariant<'tcx>,
f: &Field,
f: &FieldIdx,
) -> Result<Expr, UnimplementedData> {
match t {
TypeOrVariant::Type(t) => {
Expand Down Expand Up @@ -278,12 +279,12 @@ impl<'tcx> GotocCtx<'tcx> {
}
// if we fall here, then we are handling either a struct or a union
ty::Adt(def, _) => {
let field = &def.variants().raw[0].fields[f.index()];
let field = &def.variants().raw[0].fields[*f];
Ok(res.member(&field.name.to_string(), &self.symbol_table))
}
ty::Closure(..) => Ok(res.member(&f.index().to_string(), &self.symbol_table)),
ty::Generator(..) => {
let field_name = self.generator_field_name(f.index());
let field_name = self.generator_field_name(f.as_usize());
Ok(res
.member("direct_fields", &self.symbol_table)
.member(field_name, &self.symbol_table))
Expand All @@ -293,7 +294,7 @@ impl<'tcx> GotocCtx<'tcx> {
}
// if we fall here, then we are handling an enum
TypeOrVariant::Variant(v) => {
let field = &v.fields[f.index()];
let field = &v.fields[*f];
Ok(res.member(&field.name.to_string(), &self.symbol_table))
}
TypeOrVariant::GeneratorVariant(_var_idx) => {
Expand Down
Loading