Skip to content

Commit 1388904

Browse files
pnkfelixcelinval
authored andcommitted
Contracts core intrinsics.
These are hooks to: 1. control whether contract checks are run 2. allow 3rd party tools to intercept and reintepret the results of running contracts.
1 parent 8231e85 commit 1388904

File tree

30 files changed

+182
-6
lines changed

30 files changed

+182
-6
lines changed

compiler/rustc_borrowck/src/type_check/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1631,6 +1631,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
16311631
ConstraintCategory::SizedBound,
16321632
);
16331633
}
1634+
&Rvalue::NullaryOp(NullOp::ContractChecks, _) => {}
16341635
&Rvalue::NullaryOp(NullOp::UbChecks, _) => {}
16351636

16361637
Rvalue::ShallowInitBox(operand, ty) => {

compiler/rustc_codegen_cranelift/src/base.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -864,6 +864,15 @@ fn codegen_stmt<'tcx>(
864864
lval.write_cvalue(fx, val);
865865
return;
866866
}
867+
NullOp::ContractChecks => {
868+
let val = fx.tcx.sess.contract_checks();
869+
let val = CValue::by_val(
870+
fx.bcx.ins().iconst(types::I8, i64::try_from(val).unwrap()),
871+
fx.layout_of(fx.tcx.types.bool),
872+
);
873+
lval.write_cvalue(fx, val);
874+
return;
875+
}
867876
};
868877
let val = CValue::by_val(
869878
fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(val).unwrap()),

compiler/rustc_codegen_ssa/src/mir/rvalue.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
740740
let val = bx.tcx().sess.ub_checks();
741741
bx.cx().const_bool(val)
742742
}
743+
mir::NullOp::ContractChecks => {
744+
let val = bx.tcx().sess.contract_checks();
745+
bx.cx().const_bool(val)
746+
}
743747
};
744748
let tcx = self.cx.tcx();
745749
OperandRef {

compiler/rustc_const_eval/src/check_consts/check.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -581,7 +581,11 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
581581
Rvalue::Cast(_, _, _) => {}
582582

583583
Rvalue::NullaryOp(
584-
NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(_) | NullOp::UbChecks,
584+
NullOp::SizeOf
585+
| NullOp::AlignOf
586+
| NullOp::OffsetOf(_)
587+
| NullOp::UbChecks
588+
| NullOp::ContractChecks,
585589
_,
586590
) => {}
587591
Rvalue::ShallowInitBox(_, _) => {}

compiler/rustc_const_eval/src/interpret/machine.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,9 @@ pub trait Machine<'tcx>: Sized {
287287
/// Determines the result of a `NullaryOp::UbChecks` invocation.
288288
fn ub_checks(_ecx: &InterpCx<'tcx, Self>) -> InterpResult<'tcx, bool>;
289289

290+
/// Determines the result of a `NullaryOp::ContractChecks` invocation.
291+
fn contract_checks(_ecx: &InterpCx<'tcx, Self>) -> InterpResult<'tcx, bool>;
292+
290293
/// Called when the interpreter encounters a `StatementKind::ConstEvalCounter` instruction.
291294
/// You can use this to detect long or endlessly running programs.
292295
#[inline]
@@ -673,6 +676,13 @@ pub macro compile_time_machine(<$tcx: lifetime>) {
673676
interp_ok(true)
674677
}
675678

679+
#[inline(always)]
680+
fn contract_checks(_ecx: &InterpCx<$tcx, Self>) -> InterpResult<$tcx, bool> {
681+
// We can't look at `tcx.sess` here as that can differ across crates, which can lead to
682+
// unsound differences in evaluating the same constant at different instantiation sites.
683+
interp_ok(true)
684+
}
685+
676686
#[inline(always)]
677687
fn adjust_global_allocation<'b>(
678688
_ecx: &InterpCx<$tcx, Self>,

compiler/rustc_const_eval/src/interpret/operator.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
537537
ImmTy::from_uint(val, usize_layout())
538538
}
539539
UbChecks => ImmTy::from_bool(M::ub_checks(self)?, *self.tcx),
540+
ContractChecks => ImmTy::from_bool(M::contract_checks(self)?, *self.tcx),
540541
})
541542
}
542543
}

compiler/rustc_feature/src/builtin_attrs.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ const GATED_CFGS: &[GatedCfg] = &[
1919
// (name in cfg, feature, function to check if the feature is enabled)
2020
(sym::overflow_checks, sym::cfg_overflow_checks, Features::cfg_overflow_checks),
2121
(sym::ub_checks, sym::cfg_ub_checks, Features::cfg_ub_checks),
22+
(sym::contract_checks, sym::cfg_contract_checks, Features::cfg_contract_checks),
2223
(sym::target_thread_local, sym::cfg_target_thread_local, Features::cfg_target_thread_local),
2324
(
2425
sym::target_has_atomic_equal_alignment,

compiler/rustc_feature/src/unstable.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,8 @@ declare_features! (
403403
(unstable, c_variadic, "1.34.0", Some(44930)),
404404
/// Allows the use of `#[cfg(<true/false>)]`.
405405
(unstable, cfg_boolean_literals, "1.83.0", Some(131204)),
406+
/// Allows the use of `#[cfg(contract_checks)` to check if contract checks are enabled.
407+
(unstable, cfg_contract_checks, "CURRENT_RUSTC_VERSION", Some(133866)),
406408
/// Allows the use of `#[cfg(overflow_checks)` to check if integer overflow behaviour.
407409
(unstable, cfg_overflow_checks, "1.71.0", Some(111466)),
408410
/// Provides the relocation model information as cfg entry

compiler/rustc_hir_analysis/src/check/intrinsic.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,9 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -
132132
| sym::aggregate_raw_ptr
133133
| sym::ptr_metadata
134134
| sym::ub_checks
135+
| sym::contract_checks
136+
| sym::contract_check_requires
137+
| sym::contract_check_ensures
135138
| sym::fadd_algebraic
136139
| sym::fsub_algebraic
137140
| sym::fmul_algebraic
@@ -218,6 +221,18 @@ pub fn check_intrinsic_type(
218221
}
219222
};
220223
(n_tps, 0, 0, inputs, output, hir::Safety::Unsafe)
224+
} else if intrinsic_name == sym::contract_check_ensures {
225+
// contract_check_ensures::<'a, Ret, C>(&'a Ret, C) -> bool
226+
// where C: impl Fn(&'a Ret) -> bool,
227+
//
228+
// so: two type params, one lifetime param, 0 const params, two inputs, returns boolean
229+
230+
let p = generics.param_at(0, tcx);
231+
let r = ty::Region::new_early_param(tcx, p.to_early_bound_region_data());
232+
let ref_ret = Ty::new_imm_ref(tcx, r, param(1));
233+
// let br = ty::BoundRegion { var: ty::BoundVar::ZERO, kind: ty::BrAnon };
234+
// let ref_ret = Ty::new_imm_ref(tcx, ty::Region::new_bound(tcx, ty::INNERMOST, br), param(0));
235+
(2, 1, 0, vec![ref_ret, param(2)], tcx.types.bool, hir::Safety::Safe)
221236
} else {
222237
let safety = intrinsic_operation_unsafety(tcx, intrinsic_id);
223238
let (n_tps, n_cts, inputs, output) = match intrinsic_name {
@@ -609,6 +624,11 @@ pub fn check_intrinsic_type(
609624

610625
sym::box_new => (1, 0, vec![param(0)], Ty::new_box(tcx, param(0))),
611626

627+
// contract_checks() -> bool
628+
sym::contract_checks => (0, 0, Vec::new(), tcx.types.bool),
629+
// contract_check_requires::<C>(C) -> bool, where C: impl Fn() -> bool
630+
sym::contract_check_requires => (1, 0, vec![param(0)], tcx.types.bool),
631+
612632
sym::simd_eq
613633
| sym::simd_ne
614634
| sym::simd_lt

compiler/rustc_middle/src/mir/pretty.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1082,6 +1082,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
10821082
NullOp::AlignOf => write!(fmt, "AlignOf({t})"),
10831083
NullOp::OffsetOf(fields) => write!(fmt, "OffsetOf({t}, {fields:?})"),
10841084
NullOp::UbChecks => write!(fmt, "UbChecks()"),
1085+
NullOp::ContractChecks => write!(fmt, "ContractChecks()"),
10851086
}
10861087
}
10871088
ThreadLocalRef(did) => ty::tls::with(|tcx| {

0 commit comments

Comments
 (0)