Auto merge of #121662 - saethlin:precondition-unification, r= · rust-lang/rust@c492ab1 (original) (raw)

46 files changed

lines changed

Original file line number Diff line number Diff line change
@@ -2001,7 +2001,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
2001 2001 ConstraintCategory::SizedBound,
2002 2002 );
2003 2003 }
2004 -&Rvalue::NullaryOp(NullOp::DebugAssertions, _) => {}
2004 +&Rvalue::NullaryOp(NullOp::UbCheck(_), _) => {}
2005 2005
2006 2006 Rvalue::ShallowInitBox(operand, ty) => {
2007 2007 self.check_operand(operand, location);
Original file line number Diff line number Diff line change
@@ -767,7 +767,7 @@ fn codegen_stmt<'tcx>(
767 767 NullOp::OffsetOf(fields) => {
768 768 layout.offset_of_subfield(fx, fields.iter()).bytes()
769 769 }
770 -NullOp::DebugAssertions => {
770 +NullOp::UbCheck(_) => {
771 771 let val = fx.tcx.sess.opts.debug_assertions;
772 772 let val = CValue::by_val(
773 773 fx.bcx.ins().iconst(types::I8, i64::try_from(val).unwrap()),
Original file line number Diff line number Diff line change
@@ -684,7 +684,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
684 684 let val = layout.offset_of_subfield(bx.cx(), fields.iter()).bytes();
685 685 bx.cx().const_usize(val)
686 686 }
687 - mir::NullOp::DebugAssertions => {
687 + mir::NullOp::UbCheck(_) => {
688 +// In codegen, we want to check for language UB and library UB
688 689 let val = bx.tcx().sess.opts.debug_assertions;
689 690 bx.cx().const_bool(val)
690 691 }
Original file line number Diff line number Diff line change
@@ -258,10 +258,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
258 258 let val = layout.offset_of_subfield(self, fields.iter()).bytes();
259 259 Scalar::from_target_usize(val, self)
260 260 }
261 - mir::NullOp::DebugAssertions => {
262 -// The checks hidden behind this are always better done by the interpreter
263 -// itself, because it knows the runtime state better.
264 -Scalar::from_bool(false)
261 + mir::NullOp::UbCheck(kind) => {
262 +// We want to enable checks for library UB, because the interpreter doesn't
263 +// know about those on its own.
264 +// But we want to disable checks for language UB, because the interpreter
265 +// has its own better checks for that.
266 +let should_check = match kind {
267 + mir::UbKind::LibraryUb => true,
268 + mir::UbKind::LanguageUb => false,
269 +};
270 +Scalar::from_bool(should_check)
265 271 }
266 272 };
267 273 self.write_scalar(val, &dest)?;
Original file line number Diff line number Diff line change
@@ -558,7 +558,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
558 558 Rvalue::Cast(_, _, _) => {}
559 559
560 560 Rvalue::NullaryOp(
561 -NullOp::SizeOf | NullOp::AlignOf NullOp::OffsetOf(_) NullOp::DebugAssertions,
561 +NullOp::SizeOf | NullOp::AlignOf NullOp::OffsetOf(_) NullOp::UbCheck(_),
562 562 _,
563 563 ) => {}
564 564 Rvalue::ShallowInitBox(_, _) => {}
Original file line number Diff line number Diff line change
@@ -1157,7 +1157,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
1157 1157 Rvalue::Repeat(_, _)
1158 1158 | Rvalue::ThreadLocalRef(_)
1159 1159 | Rvalue::AddressOf(_, _)
1160 - | Rvalue::NullaryOp(NullOp::SizeOf NullOp::AlignOf NullOp::DebugAssertions, _)
1160 + | Rvalue::NullaryOp(NullOp::SizeOf NullOp::AlignOf NullOp::UbCheck(_), _)
1161 1161 | Rvalue::Discriminant(_) => {}
1162 1162 }
1163 1163 self.super_rvalue(rvalue, location);
Original file line number Diff line number Diff line change
@@ -123,7 +123,8 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -
123 123 | sym::variant_count
124 124 | sym::is_val_statically_known
125 125 | sym::ptr_mask
126 - | sym::debug_assertions
126 + | sym::check_language_ub
127 + | sym::check_library_ub
127 128 | sym::fadd_algebraic
128 129 | sym::fsub_algebraic
129 130 | sym::fmul_algebraic
@@ -508,7 +509,7 @@ pub fn check_intrinsic_type(
508 509 (0, 0, vec![Ty::new_imm_ptr(tcx, Ty::new_unit(tcx))], tcx.types.usize)
509 510 }
510 511
511 - sym::debug_assertions => (0, 1, Vec::new(), tcx.types.bool),
512 + sym::check_language_ub | sym::check_library_ub => (0, 1, Vec::new(), tcx.types.bool),
512 513
513 514 sym::simd_eq
514 515 | sym::simd_ne
Original file line number Diff line number Diff line change
@@ -909,7 +909,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
909 909 NullOp::SizeOf => write!(fmt, "SizeOf({t})"),
910 910 NullOp::AlignOf => write!(fmt, "AlignOf({t})"),
911 911 NullOp::OffsetOf(fields) => write!(fmt, "OffsetOf({t}, {fields:?})"),
912 -NullOp::DebugAssertions => write!(fmt, "cfg!(debug_assertions)"),
912 +NullOp::UbCheck(kind) => write!(fmt, "UbCheck({kind:?})"),
913 913 }
914 914 }
915 915 ThreadLocalRef(did) => ty::tls::with(|tcx
Original file line number Diff line number Diff line change
@@ -1361,8 +1361,13 @@ pub enum NullOp<'tcx> {
1361 1361 AlignOf,
1362 1362 /// Returns the offset of a field
1363 1363 OffsetOf(&'tcx List<(VariantIdx, FieldIdx)>),
1364 -/// cfg!(debug_assertions), but expanded in codegen
1365 - DebugAssertions,
1364 +UbCheck(UbKind),
1365 +}
1366 +
1367 +#[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
1368 +pub enum UbKind {
1369 +LanguageUb,
1370 +LibraryUb,
1366 1371 }
1367 1372
1368 1373 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
Original file line number Diff line number Diff line change
@@ -194,7 +194,7 @@ impl<'tcx> Rvalue<'tcx> {
194 194 Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf NullOp::OffsetOf(..), _) => {
195 195 tcx.types.usize
196 196 }
197 -Rvalue::NullaryOp(NullOp::DebugAssertions, _) => tcx.types.bool,
197 +Rvalue::NullaryOp(NullOp::UbCheck(_), _) => tcx.types.bool,
198 198 Rvalue::Aggregate(ref ak, ref ops) => match **ak {
199 199 AggregateKind::Array(ty) => Ty::new_array(tcx, ty, ops.len() as u64),
200 200 AggregateKind::Tuple => {
Original file line number Diff line number Diff line change
@@ -433,7 +433,7 @@ impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> {
433 433 | Rvalue::Discriminant(..)
434 434 | Rvalue::Len(..)
435 435 | Rvalue::NullaryOp(
436 -NullOp::SizeOf | NullOp::AlignOf NullOp::OffsetOf(..) NullOp::DebugAssertions,
436 +NullOp::SizeOf | NullOp::AlignOf NullOp::OffsetOf(..) NullOp::UbCheck(_),
437 437 _,
438 438 ) => {}
439 439 }
Original file line number Diff line number Diff line change
@@ -488,7 +488,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
488 488 NullOp::OffsetOf(fields) => {
489 489 layout.offset_of_subfield(&self.ecx, fields.iter()).bytes()
490 490 }
491 -NullOp::DebugAssertions => return None,
491 +NullOp::UbCheck(_) => return None,
492 492 };
493 493 let usize_layout = self.ecx.layout_of(self.tcx.types.usize).unwrap();
494 494 let imm = ImmTy::try_from_uint(val, usize_layout)?;
Original file line number Diff line number Diff line change
@@ -639,7 +639,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
639 639 NullOp::OffsetOf(fields) => {
640 640 op_layout.offset_of_subfield(self, fields.iter()).bytes()
641 641 }
642 -NullOp::DebugAssertions => return None,
642 +NullOp::UbCheck(_) => return None,
643 643 };
644 644 ImmTy::from_scalar(Scalar::from_target_usize(val, self), layout).into()
645 645 }
Original file line number Diff line number Diff line change
@@ -20,13 +20,30 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
20 20 sym::unreachable => {
21 21 terminator.kind = TerminatorKind::Unreachable;
22 22 }
23 - sym::debug_assertions => {
23 + sym::check_language_ub => {
24 24 let target = target.unwrap();
25 25 block.statements.push(Statement {
26 26 source_info: terminator.source_info,
27 27 kind: StatementKind::Assign(Box::new((
28 28 *destination,
29 -Rvalue::NullaryOp(NullOp::DebugAssertions, tcx.types.bool),
29 +Rvalue::NullaryOp(
30 +NullOp::UbCheck(UbKind::LanguageUb),
31 + tcx.types.bool,
32 +),
33 +))),
34 +});
35 + terminator.kind = TerminatorKind::Goto { target };
36 +}
37 + sym::check_library_ub => {
38 +let target = target.unwrap();
39 + block.statements.push(Statement {
40 +source_info: terminator.source_info,
41 +kind: StatementKind::Assign(Box::new((
42 +*destination,
43 +Rvalue::NullaryOp(
44 +NullOp::UbCheck(UbKind::LibraryUb),
45 + tcx.types.bool,
46 +),
30 47 ))),
31 48 });
32 49 terminator.kind = TerminatorKind::Goto { target };
Original file line number Diff line number Diff line change
@@ -446,7 +446,7 @@ impl<'tcx> Validator<'_, 'tcx> {
446 446 NullOp::SizeOf => {}
447 447 NullOp::AlignOf => {}
448 448 NullOp::OffsetOf(_) => {}
449 -NullOp::DebugAssertions => {}
449 +NullOp::UbCheck(_) => {}
450 450 },
451 451
452 452 Rvalue::ShallowInitBox(_, _) => return Err(Unpromotable),
Original file line number Diff line number Diff line change
@@ -251,13 +251,19 @@ impl<'tcx> Stable<'tcx> for mir::NullOp<'tcx> {
251 251 type T = stable_mir::mir::NullOp;
252 252 fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
253 253 use rustc_middle::mir::NullOp::*;
254 +use rustc_middle::mir::UbKind;
254 255 match self {
255 256 SizeOf => stable_mir::mir::NullOp::SizeOf,
256 257 AlignOf => stable_mir::mir::NullOp::AlignOf,
257 258 OffsetOf(indices) => stable_mir::mir::NullOp::OffsetOf(
258 259 indices.iter().map(|idx
259 260 ),
260 -DebugAssertions => stable_mir::mir::NullOp::DebugAssertions,
261 +UbCheck(UbKind::LanguageUb) => {
262 + stable_mir::mir::NullOp::UbCheck(stable_mir::mir::UbKind::LanguageUb)
263 +}
264 +UbCheck(UbKind::LibraryUb) => {
265 + stable_mir::mir::NullOp::UbCheck(stable_mir::mir::UbKind::LibraryUb)
266 +}
261 267 }
262 268 }
263 269 }
Original file line number Diff line number Diff line change
@@ -515,6 +515,8 @@ symbols! {
515 515 cfi,
516 516 cfi_encoding,
517 517 char,
518 + check_language_ub,
519 + check_library_ub,
518 520 client,
519 521 clippy,
520 522 clobber_abi,
Original file line number Diff line number Diff line change
@@ -639,7 +639,7 @@ impl Rvalue {
639 639 Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf NullOp::OffsetOf(..), _) => {
640 640 Ok(Ty::usize_ty())
641 641 }
642 -Rvalue::NullaryOp(NullOp::DebugAssertions, _) => Ok(Ty::bool_ty()),
642 +Rvalue::NullaryOp(NullOp::UbCheck(_), _) => Ok(Ty::bool_ty()),
643 643 Rvalue::Aggregate(ak, ops) => match *ak {
644 644 AggregateKind::Array(ty) => Ty::try_new_array(ty, ops.len() as u64),
645 645 AggregateKind::Tuple => Ok(Ty::new_tuple(
@@ -1007,7 +1007,13 @@ pub enum NullOp {
1007 1007 /// Returns the offset of a field.
1008 1008 OffsetOf(Vec<(VariantIdx, FieldIdx)>),
1009 1009 /// cfg!(debug_assertions), but at codegen time
1010 - DebugAssertions,
1010 + UbCheck(UbKind),
1011 +}
1012 +
1013 +#[derive(Clone, Debug, Eq, PartialEq)]
1014 +pub enum UbKind {
1015 +LanguageUb,
1016 +LibraryUb,
1011 1017 }
1012 1018
1013 1019 impl Operand {
Original file line number Diff line number Diff line change
@@ -26,6 +26,7 @@ pub(super) const unsafe fn from_u32_unchecked(i: u32) -> char {
26 26 // SAFETY: the caller must guarantee that `i` is a valid char value.
27 27 unsafe {
28 28 assert_unsafe_precondition!(
29 + check_language_ub,
29 30 "invalid value for `char`",
30 31 (i: u32 = i) => char_try_from_u32(i).is_ok()
31 32 );
Original file line number Diff line number Diff line change
@@ -101,7 +101,11 @@ pub const unsafe fn unreachable_unchecked() -> ! {
101 101 // SAFETY: the safety contract for `intrinsics::unreachable` must
102 102 // be upheld by the caller.
103 103 unsafe {
104 - intrinsics::assert_unsafe_precondition!("hint::unreachable_unchecked must never be reached", () => false);
104 + intrinsics::assert_unsafe_precondition!(
105 + check_language_ub,
106 +"hint::unreachable_unchecked must never be reached",
107 +() => false
108 +);
105 109 intrinsics::unreachable()
106 110 }
107 111 }
@@ -147,6 +151,7 @@ pub const unsafe fn assert_unchecked(cond: bool) {
147 151 // SAFETY: The caller promised `cond` is true.
148 152 unsafe {
149 153 intrinsics::assert_unsafe_precondition!(
154 + check_language_ub,
150 155 "hint::assert_unchecked must never be called when the condition is false",
151 156 (cond: bool = cond) => cond,
152 157 );