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

refactor check_{lang,library}_ub: use a single intrinsic #122629

Merged
merged 2 commits into from
Mar 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2000,7 +2000,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
ConstraintCategory::SizedBound,
);
}
&Rvalue::NullaryOp(NullOp::UbCheck(_), _) => {}
&Rvalue::NullaryOp(NullOp::UbChecks, _) => {}

Rvalue::ShallowInitBox(operand, ty) => {
self.check_operand(operand, location);
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_cranelift/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -780,7 +780,7 @@ fn codegen_stmt<'tcx>(
NullOp::OffsetOf(fields) => {
layout.offset_of_subfield(fx, fields.iter()).bytes()
}
NullOp::UbCheck(_) => {
NullOp::UbChecks => {
let val = fx.tcx.sess.opts.debug_assertions;
let val = CValue::by_val(
fx.bcx.ins().iconst(types::I8, i64::try_from(val).unwrap()),
Expand Down
3 changes: 1 addition & 2 deletions compiler/rustc_codegen_ssa/src/mir/rvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -680,8 +680,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let val = layout.offset_of_subfield(bx.cx(), fields.iter()).bytes();
bx.cx().const_usize(val)
}
mir::NullOp::UbCheck(_) => {
// In codegen, we want to check for language UB and library UB
mir::NullOp::UbChecks => {
let val = bx.tcx().sess.opts.debug_assertions;
bx.cx().const_bool(val)
}
Expand Down
12 changes: 1 addition & 11 deletions compiler/rustc_const_eval/src/interpret/step.rs
Original file line number Diff line number Diff line change
Expand Up @@ -258,17 +258,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let val = layout.offset_of_subfield(self, fields.iter()).bytes();
Scalar::from_target_usize(val, self)
}
mir::NullOp::UbCheck(kind) => {
// We want to enable checks for library UB, because the interpreter doesn't
// know about those on its own.
// But we want to disable checks for language UB, because the interpreter
// has its own better checks for that.
let should_check = match kind {
mir::UbKind::LibraryUb => self.tcx.sess.opts.debug_assertions,
mir::UbKind::LanguageUb => false,
};
Scalar::from_bool(should_check)
}
mir::NullOp::UbChecks => Scalar::from_bool(self.tcx.sess.opts.debug_assertions),
};
self.write_scalar(val, &dest)?;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -558,7 +558,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
Rvalue::Cast(_, _, _) => {}

Rvalue::NullaryOp(
NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(_) | NullOp::UbCheck(_),
NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(_) | NullOp::UbChecks,
_,
) => {}
Rvalue::ShallowInitBox(_, _) => {}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_const_eval/src/transform/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1168,7 +1168,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
Rvalue::Repeat(_, _)
| Rvalue::ThreadLocalRef(_)
| Rvalue::AddressOf(_, _)
| Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::UbCheck(_), _)
| Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::UbChecks, _)
| Rvalue::Discriminant(_) => {}
}
self.super_rvalue(rvalue, location);
Expand Down
5 changes: 2 additions & 3 deletions compiler/rustc_hir_analysis/src/check/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,7 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -
| sym::variant_count
| sym::is_val_statically_known
| sym::ptr_mask
| sym::check_language_ub
| sym::check_library_ub
| sym::ub_checks
| sym::fadd_algebraic
| sym::fsub_algebraic
| sym::fmul_algebraic
Expand Down Expand Up @@ -571,7 +570,7 @@ pub fn check_intrinsic_type(
(0, 0, vec![Ty::new_imm_ptr(tcx, Ty::new_unit(tcx))], tcx.types.usize)
}

sym::check_language_ub | sym::check_library_ub => (0, 1, Vec::new(), tcx.types.bool),
sym::ub_checks => (0, 1, Vec::new(), tcx.types.bool),

sym::simd_eq
| sym::simd_ne
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -796,7 +796,7 @@ impl<'tcx> Body<'tcx> {
}

match rvalue {
Rvalue::NullaryOp(NullOp::UbCheck(_), _) => {
Rvalue::NullaryOp(NullOp::UbChecks, _) => {
Some((tcx.sess.opts.debug_assertions as u128, targets))
}
Rvalue::Use(Operand::Constant(constant)) => {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/mir/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -944,7 +944,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
NullOp::SizeOf => write!(fmt, "SizeOf({t})"),
NullOp::AlignOf => write!(fmt, "AlignOf({t})"),
NullOp::OffsetOf(fields) => write!(fmt, "OffsetOf({t}, {fields:?})"),
NullOp::UbCheck(kind) => write!(fmt, "UbCheck({kind:?})"),
NullOp::UbChecks => write!(fmt, "UbChecks()"),
Copy link
Member

@saethlin saethlin Mar 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see any corresponding changes to the mir-opt tests, which has me worried. CI is green but the mir-opt suite does not pass locally. Do you know what's happening here? I'm confident that this either will fail in bors or should fail in bors, so at the least the mir-opt tests need to be blessed, and maybe we also have a CI/bootstrap bug.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. I think this happens because of

//@ ignore-debug assertions change the output MIR

The PR runner has debug assertions turned on.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes this old problem. I'll see if I can do a PR to fix it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that even still needed? The stdlib is less dependent on the sysroot cfg(debug_assertions) now with your new intrinsic.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is less need for it, but it's not gone entirely. I'll start by just enabling the tests that can be enabled for free: #122921

}
}
ThreadLocalRef(did) => ty::tls::with(|tcx| {
Expand Down
13 changes: 3 additions & 10 deletions compiler/rustc_middle/src/mir/syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1367,16 +1367,9 @@ pub enum NullOp<'tcx> {
AlignOf,
/// Returns the offset of a field
OffsetOf(&'tcx List<(VariantIdx, FieldIdx)>),
/// Returns whether we want to check for library UB or language UB at monomorphization time.
/// Both kinds of UB evaluate to `true` in codegen, and only library UB evalutes to `true` in
/// const-eval/Miri, because the interpreter has its own better checks for language UB.
UbCheck(UbKind),
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
pub enum UbKind {
LanguageUb,
LibraryUb,
/// Returns whether we want to check for UB.
/// This returns the value of `cfg!(debug_assertions)` at monomorphization time.
UbChecks,
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/mir/tcx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ impl<'tcx> Rvalue<'tcx> {
Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => {
tcx.types.usize
}
Rvalue::NullaryOp(NullOp::UbCheck(_), _) => tcx.types.bool,
Rvalue::NullaryOp(NullOp::UbChecks, _) => tcx.types.bool,
Rvalue::Aggregate(ref ak, ref ops) => match **ak {
AggregateKind::Array(ty) => Ty::new_array(tcx, ty, ops.len() as u64),
AggregateKind::Tuple => {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_dataflow/src/move_paths/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,7 @@ impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> {
| Rvalue::Discriminant(..)
| Rvalue::Len(..)
| Rvalue::NullaryOp(
NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..) | NullOp::UbCheck(_),
NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..) | NullOp::UbChecks,
_,
) => {}
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_transform/src/gvn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
NullOp::OffsetOf(fields) => {
layout.offset_of_subfield(&self.ecx, fields.iter()).bytes()
}
NullOp::UbCheck(_) => return None,
NullOp::UbChecks => return None,
};
let usize_layout = self.ecx.layout_of(self.tcx.types.usize).unwrap();
let imm = ImmTy::try_from_uint(val, usize_layout)?;
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_transform/src/known_panics_lint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -639,7 +639,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
NullOp::OffsetOf(fields) => {
op_layout.offset_of_subfield(self, fields.iter()).bytes()
}
NullOp::UbCheck(_) => return None,
NullOp::UbChecks => return None,
};
ImmTy::from_scalar(Scalar::from_target_usize(val, self), layout).into()
}
Expand Down
21 changes: 2 additions & 19 deletions compiler/rustc_mir_transform/src/lower_intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,30 +20,13 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
sym::unreachable => {
terminator.kind = TerminatorKind::Unreachable;
}
sym::check_language_ub => {
sym::ub_checks => {
let target = target.unwrap();
block.statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Assign(Box::new((
*destination,
Rvalue::NullaryOp(
NullOp::UbCheck(UbKind::LanguageUb),
tcx.types.bool,
),
))),
});
terminator.kind = TerminatorKind::Goto { target };
}
sym::check_library_ub => {
let target = target.unwrap();
block.statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Assign(Box::new((
*destination,
Rvalue::NullaryOp(
NullOp::UbCheck(UbKind::LibraryUb),
tcx.types.bool,
),
Rvalue::NullaryOp(NullOp::UbChecks, tcx.types.bool),
))),
});
terminator.kind = TerminatorKind::Goto { target };
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_transform/src/promote_consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,7 @@ impl<'tcx> Validator<'_, 'tcx> {
NullOp::SizeOf => {}
NullOp::AlignOf => {}
NullOp::OffsetOf(_) => {}
NullOp::UbCheck(_) => {}
NullOp::UbChecks => {}
},

Rvalue::ShallowInitBox(_, _) => return Err(Unpromotable),
Expand Down
8 changes: 1 addition & 7 deletions compiler/rustc_smir/src/rustc_smir/convert/mir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,19 +251,13 @@ impl<'tcx> Stable<'tcx> for mir::NullOp<'tcx> {
type T = stable_mir::mir::NullOp;
fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
use rustc_middle::mir::NullOp::*;
use rustc_middle::mir::UbKind;
match self {
SizeOf => stable_mir::mir::NullOp::SizeOf,
AlignOf => stable_mir::mir::NullOp::AlignOf,
OffsetOf(indices) => stable_mir::mir::NullOp::OffsetOf(
indices.iter().map(|idx| idx.stable(tables)).collect(),
),
UbCheck(UbKind::LanguageUb) => {
stable_mir::mir::NullOp::UbCheck(stable_mir::mir::UbKind::LanguageUb)
}
UbCheck(UbKind::LibraryUb) => {
stable_mir::mir::NullOp::UbCheck(stable_mir::mir::UbKind::LibraryUb)
}
UbChecks => stable_mir::mir::NullOp::UbChecks,
}
}
}
Expand Down
3 changes: 1 addition & 2 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -518,8 +518,6 @@ symbols! {
cfi,
cfi_encoding,
char,
check_language_ub,
check_library_ub,
client,
clippy,
clobber_abi,
Expand Down Expand Up @@ -1867,6 +1865,7 @@ symbols! {
u8_legacy_fn_max_value,
u8_legacy_fn_min_value,
u8_legacy_mod,
ub_checks,
unaligned_volatile_load,
unaligned_volatile_store,
unboxed_closures,
Expand Down
10 changes: 2 additions & 8 deletions compiler/stable_mir/src/mir/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -621,7 +621,7 @@ impl Rvalue {
Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => {
Ok(Ty::usize_ty())
}
Rvalue::NullaryOp(NullOp::UbCheck(_), _) => Ok(Ty::bool_ty()),
Rvalue::NullaryOp(NullOp::UbChecks, _) => Ok(Ty::bool_ty()),
Rvalue::Aggregate(ak, ops) => match *ak {
AggregateKind::Array(ty) => Ty::try_new_array(ty, ops.len() as u64),
AggregateKind::Tuple => Ok(Ty::new_tuple(
Expand Down Expand Up @@ -989,13 +989,7 @@ pub enum NullOp {
/// Returns the offset of a field.
OffsetOf(Vec<(VariantIdx, FieldIdx)>),
/// cfg!(debug_assertions), but at codegen time
UbCheck(UbKind),
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum UbKind {
LanguageUb,
LibraryUb,
UbChecks,
Copy link
Member Author

@RalfJung RalfJung Mar 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see no choice but to change smir here; the things it exposed were never meant to be very stable to begin with and I don't think we want to keep them.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've just been breaking smir every time I change MIR. Is there any guidance or enforcement that we don't do that?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No idea. SMIR people get pinged when this happens so I guess they'll complain when it gets too much for them. ;)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to avoid these breakages. If something is unstable, we recommend to not expose them, or expose as an Opaque type.

See Coverage statement as an example.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this specific case, we could just always use the same UbKind value, and mark UbValue as deprecated.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we leave compatibility shims in stable MIR (not that I think we should do that in this PR), is there a plan for how to remove them eventually?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

StableMIR is not yet versioned, but once it is, we would likely go over things that has been marked as deprecated and remove them when a new major is about to be released.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RalfJung I think it is fine to remove it now.

I do have a question about how to evaluate this operator though. Is the idea here that we are assessing the value of cfg!(debug_assertions) for the crate being compiled? So if the MIR comes from a dependency that was compiled with debug_assertions off, but the current crate has the debug_assertions on, this rvalue will be evaluated to true. Is that correct?

Is it possible to document the answer here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, exactly. This is what the existing documentation means when it says "the value of debug_assertions at monomorphization time".

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have also extended the intrinsic's docs to make this more clear.

}

impl Operand {
Expand Down
2 changes: 1 addition & 1 deletion library/core/src/char/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ use crate::char::TryFromCharError;
use crate::convert::TryFrom;
use crate::error::Error;
use crate::fmt;
use crate::intrinsics::assert_unsafe_precondition;
use crate::mem::transmute;
use crate::str::FromStr;
use crate::ub_checks::assert_unsafe_precondition;

/// Converts a `u32` to a `char`. See [`char::from_u32`].
#[must_use]
Expand Down
5 changes: 3 additions & 2 deletions library/core/src/hint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
//! Hints may be compile time or runtime.

use crate::intrinsics;
use crate::ub_checks;

/// Informs the compiler that the site which is calling this function is not
/// reachable, possibly enabling further optimizations.
Expand Down Expand Up @@ -98,7 +99,7 @@ use crate::intrinsics;
#[rustc_const_stable(feature = "const_unreachable_unchecked", since = "1.57.0")]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub const unsafe fn unreachable_unchecked() -> ! {
intrinsics::assert_unsafe_precondition!(
ub_checks::assert_unsafe_precondition!(
check_language_ub,
"hint::unreachable_unchecked must never be reached",
() => false
Expand Down Expand Up @@ -148,7 +149,7 @@ pub const unsafe fn unreachable_unchecked() -> ! {
pub const unsafe fn assert_unchecked(cond: bool) {
// SAFETY: The caller promised `cond` is true.
unsafe {
intrinsics::assert_unsafe_precondition!(
ub_checks::assert_unsafe_precondition!(
check_language_ub,
"hint::assert_unchecked must never be called when the condition is false",
(cond: bool = cond) => cond,
Expand Down
Loading
Loading