From 8e9963582224e48011b4f35c626109e6fa1811f2 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sat, 19 Nov 2022 13:33:46 -0500 Subject: [PATCH] Check for occupied niches --- compiler/rustc_codegen_ssa/src/mir/block.rs | 13 +- compiler/rustc_codegen_ssa/src/mir/mod.rs | 1 + .../rustc_codegen_ssa/src/mir/niche_check.rs | 286 ++++++++++++++++++ compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 6 +- .../rustc_codegen_ssa/src/mir/statement.rs | 19 ++ compiler/rustc_hir/src/lang_items.rs | 6 + compiler/rustc_middle/src/ty/context.rs | 8 + compiler/rustc_monomorphize/src/collector.rs | 21 ++ compiler/rustc_span/src/symbol.rs | 6 + library/core/src/panicking.rs | 29 +- .../wasm-symbols-different-module/rmake.rs | 4 +- .../future-sizes/async-awaiting-fut.rs | 2 +- .../ui/async-await/future-sizes/large-arg.rs | 2 +- tests/ui/niche_checks/invalid_enums.rs | 23 ++ .../niche_checks/invalid_nonnull_transmute.rs | 10 + .../niche_checks/invalid_nonzero_argument.rs | 14 + tests/ui/niche_checks/invalid_option.rs | 10 + tests/ui/niche_checks/operand_pair.rs | 12 + .../ui/niche_checks/valid_nonzero_argument.rs | 13 + .../saturating-float-casts-wasm.rs | 2 +- .../saturating-float-casts.rs | 2 +- tests/ui/print_type_sizes/async.rs | 2 +- tests/ui/print_type_sizes/coroutine.rs | 2 +- .../ui/print_type_sizes/niche-filling.stdout | 4 + 24 files changed, 484 insertions(+), 13 deletions(-) create mode 100644 compiler/rustc_codegen_ssa/src/mir/niche_check.rs create mode 100644 tests/ui/niche_checks/invalid_enums.rs create mode 100644 tests/ui/niche_checks/invalid_nonnull_transmute.rs create mode 100644 tests/ui/niche_checks/invalid_nonzero_argument.rs create mode 100644 tests/ui/niche_checks/invalid_option.rs create mode 100644 tests/ui/niche_checks/operand_pair.rs create mode 100644 tests/ui/niche_checks/valid_nonzero_argument.rs diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index b0a1dedd646b0..88b48cc61e7ab 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1279,6 +1279,17 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ) -> MergingSucc { debug!("codegen_terminator: {:?}", terminator); + if bx.tcx().may_insert_niche_checks() { + if let mir::TerminatorKind::Return = terminator.kind { + let op = mir::Operand::Copy(mir::Place::return_place()); + let ty = op.ty(self.mir, bx.tcx()); + let ty = self.monomorphize(ty); + if let Some(niche) = bx.layout_of(ty).largest_niche { + self.codegen_niche_check(bx, op, niche, terminator.source_info); + } + } + } + let helper = TerminatorCodegenHelper { bb, terminator }; let mergeable_succ = || { @@ -1583,7 +1594,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { tuple.layout.fields.count() } - fn get_caller_location( + pub fn get_caller_location( &mut self, bx: &mut Bx, source_info: mir::SourceInfo, diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 62f69af3f2f75..3cc94f36ddfc3 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -21,6 +21,7 @@ pub mod debuginfo; mod intrinsic; mod locals; mod naked_asm; +mod niche_check; pub mod operand; pub mod place; mod rvalue; diff --git a/compiler/rustc_codegen_ssa/src/mir/niche_check.rs b/compiler/rustc_codegen_ssa/src/mir/niche_check.rs new file mode 100644 index 0000000000000..9a7fc102abb2b --- /dev/null +++ b/compiler/rustc_codegen_ssa/src/mir/niche_check.rs @@ -0,0 +1,286 @@ +use rustc_abi::BackendRepr; +use rustc_hir::LangItem; +use rustc_middle::mir; +use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; +use rustc_middle::ty::{Mutability, Ty, TyCtxt}; +use rustc_span::Span; +use rustc_span::def_id::LOCAL_CRATE; +use rustc_target::abi::{Float, Integer, Niche, Primitive, Scalar, Size, WrappingRange}; +use tracing::instrument; + +use super::FunctionCx; +use crate::mir::OperandValue; +use crate::mir::place::PlaceValue; +use crate::traits::*; +use crate::{base, common}; + +pub(super) struct NicheFinder<'s, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { + pub(super) fx: &'s mut FunctionCx<'a, 'tcx, Bx>, + pub(super) bx: &'s mut Bx, + pub(super) places: Vec<(mir::Operand<'tcx>, Niche)>, +} + +impl<'s, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> for NicheFinder<'s, 'a, 'tcx, Bx> { + fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: mir::Location) { + match rvalue { + mir::Rvalue::Cast(mir::CastKind::Transmute, op, ty) => { + let ty = self.fx.monomorphize(*ty); + if let Some(niche) = self.bx.layout_of(ty).largest_niche { + self.places.push((op.clone(), niche)); + } + } + _ => self.super_rvalue(rvalue, location), + } + } + + fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, _location: mir::Location) { + if let mir::TerminatorKind::Return = terminator.kind { + let op = mir::Operand::Copy(mir::Place::return_place()); + let ty = op.ty(self.fx.mir, self.bx.tcx()); + let ty = self.fx.monomorphize(ty); + if let Some(niche) = self.bx.layout_of(ty).largest_niche { + self.places.push((op, niche)); + } + } + } + + fn visit_place( + &mut self, + place: &mir::Place<'tcx>, + context: PlaceContext, + _location: mir::Location, + ) { + match context { + PlaceContext::NonMutatingUse( + NonMutatingUseContext::Copy | NonMutatingUseContext::Move, + ) => {} + _ => { + return; + } + } + + let ty = place.ty(self.fx.mir, self.bx.tcx()).ty; + let ty = self.fx.monomorphize(ty); + if let Some(niche) = self.bx.layout_of(ty).largest_niche { + self.places.push((mir::Operand::Copy(*place), niche)); + }; + } +} + +impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { + fn value_in_niche( + &mut self, + bx: &mut Bx, + op: crate::mir::OperandRef<'tcx, Bx::Value>, + niche: Niche, + ) -> Option { + let niche_ty = niche.ty(bx.tcx()); + let niche_layout = bx.layout_of(niche_ty); + + let (imm, from_scalar, from_backend_ty) = match op.val { + OperandValue::Immediate(imm) => { + let BackendRepr::Scalar(from_scalar) = op.layout.backend_repr else { + unreachable!() + }; + let from_backend_ty = bx.backend_type(op.layout); + (imm, from_scalar, from_backend_ty) + } + OperandValue::Pair(first, second) => { + let BackendRepr::ScalarPair(first_scalar, second_scalar) = op.layout.backend_repr + else { + unreachable!() + }; + if niche.offset == Size::ZERO { + (first, first_scalar, bx.scalar_pair_element_backend_type(op.layout, 0, true)) + } else { + // yolo + (second, second_scalar, bx.scalar_pair_element_backend_type(op.layout, 1, true)) + } + } + OperandValue::ZeroSized => unreachable!(), + OperandValue::Ref(PlaceValue { llval: ptr, .. }) => { + // General case: Load the niche primitive via pointer arithmetic. + let niche_ptr_ty = Ty::new_ptr(bx.tcx(), niche_ty, Mutability::Not); + let ptr = bx.pointercast(ptr, bx.backend_type(bx.layout_of(niche_ptr_ty))); + + let offset = niche.offset.bytes() / niche_layout.size.bytes(); + let niche_backend_ty = bx.backend_type(bx.layout_of(niche_ty)); + let ptr = bx.inbounds_gep(niche_backend_ty, ptr, &[bx.const_usize(offset)]); + let value = bx.load(niche_backend_ty, ptr, rustc_target::abi::Align::ONE); + return Some(value); + } + }; + + // Any type whose ABI is a Scalar bool is turned into an i1, so it cannot contain a value + // outside of its niche. + if from_scalar.is_bool() { + return None; + } + + let to_scalar = Scalar::Initialized { + value: niche.value, + valid_range: WrappingRange::full(niche.size(bx.tcx())), + }; + let to_backend_ty = bx.backend_type(niche_layout); + if from_backend_ty == to_backend_ty { + return Some(imm); + } + let value = self.transmute_immediate( + bx, + imm, + from_scalar, + from_backend_ty, + to_scalar, + to_backend_ty, + ); + Some(value) + } + + #[instrument(level = "debug", skip(self, bx))] + pub fn codegen_niche_check( + &mut self, + bx: &mut Bx, + mir_op: mir::Operand<'tcx>, + niche: Niche, + source_info: mir::SourceInfo, + ) { + let tcx = bx.tcx(); + let op_ty = self.monomorphize(mir_op.ty(self.mir, tcx)); + if op_ty == tcx.types.bool { + return; + } + + let op = self.codegen_operand(bx, &mir_op); + + let Some(value_in_niche) = self.value_in_niche(bx, op, niche) else { + return; + }; + let size = niche.size(tcx); + + let start = niche.scalar(niche.valid_range.start, bx); + let end = niche.scalar(niche.valid_range.end, bx); + + let binop_le = base::bin_op_to_icmp_predicate(mir::BinOp::Le, false); + let binop_ge = base::bin_op_to_icmp_predicate(mir::BinOp::Ge, false); + let is_valid = if niche.valid_range.start == 0 { + bx.icmp(binop_le, value_in_niche, end) + } else if niche.valid_range.end == (u128::MAX >> 128 - size.bits()) { + bx.icmp(binop_ge, value_in_niche, start) + } else { + // We need to check if the value is within a *wrapping* range. We could do this: + // (niche >= start) && (niche <= end) + // But what we're going to actually do is this: + // max = end - start + // (niche - start) <= max + // The latter is much more complicated conceptually, but is actually less operations + // because we can compute max in codegen. + let mut max = niche.valid_range.end.wrapping_sub(niche.valid_range.start); + let size = niche.size(tcx); + if size.bits() < 128 { + let mask = (1 << size.bits()) - 1; + max &= mask; + } + let max_adjusted_allowed_value = niche.scalar(max, bx); + + let biased = bx.sub(value_in_niche, start); + bx.icmp(binop_le, biased, max_adjusted_allowed_value) + }; + + // Create destination blocks, branching on is_valid + let panic = bx.append_sibling_block("panic"); + let success = bx.append_sibling_block("success"); + bx.cond_br(is_valid, success, panic); + + // Switch to the failure block and codegen a call to the panic intrinsic + bx.switch_to_block(panic); + self.set_debug_loc(bx, source_info); + let location = self.get_caller_location(bx, source_info).immediate(); + self.codegen_panic( + bx, + niche.lang_item(), + &[value_in_niche, start, end, location], + source_info.span, + ); + + // Continue codegen in the success block. + bx.switch_to_block(success); + self.set_debug_loc(bx, source_info); + } + + #[instrument(level = "debug", skip(self, bx))] + fn codegen_panic(&mut self, bx: &mut Bx, lang_item: LangItem, args: &[Bx::Value], span: Span) { + if bx.tcx().is_compiler_builtins(LOCAL_CRATE) { + bx.abort() + } else { + let (fn_abi, fn_ptr, instance) = common::build_langcall(bx, Some(span), lang_item); + let fn_ty = bx.fn_decl_backend_type(&fn_abi); + let fn_attrs = if bx.tcx().def_kind(self.instance.def_id()).has_codegen_attrs() { + Some(bx.tcx().codegen_fn_attrs(self.instance.def_id())) + } else { + None + }; + bx.call(fn_ty, fn_attrs, Some(&fn_abi), fn_ptr, args, None, Some(instance)); + } + bx.unreachable(); + } +} + +trait NicheExt { + fn ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>; + fn size<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Size; + fn scalar<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(&self, val: u128, bx: &mut Bx) -> Bx::Value; + fn lang_item(&self) -> LangItem; +} + +impl NicheExt for Niche { + fn lang_item(&self) -> LangItem { + match self.value { + Primitive::Int(Integer::I8, _) => LangItem::PanicOccupiedNicheU8, + Primitive::Int(Integer::I16, _) => LangItem::PanicOccupiedNicheU16, + Primitive::Int(Integer::I32, _) => LangItem::PanicOccupiedNicheU32, + Primitive::Int(Integer::I64, _) => LangItem::PanicOccupiedNicheU64, + Primitive::Int(Integer::I128, _) => LangItem::PanicOccupiedNicheU128, + Primitive::Pointer(_) => LangItem::PanicOccupiedNichePtr, + Primitive::Float(Float::F16) => LangItem::PanicOccupiedNicheU16, + Primitive::Float(Float::F32) => LangItem::PanicOccupiedNicheU32, + Primitive::Float(Float::F64) => LangItem::PanicOccupiedNicheU64, + Primitive::Float(Float::F128) => LangItem::PanicOccupiedNicheU128, + } + } + + fn ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { + let types = &tcx.types; + match self.value { + Primitive::Int(Integer::I8, _) => types.u8, + Primitive::Int(Integer::I16, _) => types.u16, + Primitive::Int(Integer::I32, _) => types.u32, + Primitive::Int(Integer::I64, _) => types.u64, + Primitive::Int(Integer::I128, _) => types.u128, + Primitive::Pointer(_) => Ty::new_ptr(tcx, types.unit, Mutability::Not), + Primitive::Float(Float::F16) => types.u16, + Primitive::Float(Float::F32) => types.u32, + Primitive::Float(Float::F64) => types.u64, + Primitive::Float(Float::F128) => types.u128, + } + } + + fn size<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Size { + self.value.size(&tcx) + } + + fn scalar<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(&self, val: u128, bx: &mut Bx) -> Bx::Value { + use rustc_middle::mir::interpret::{Pointer, Scalar}; + let tcx = bx.tcx(); + let niche_ty = self.ty(tcx); + let value = if niche_ty.is_any_ptr() { + Scalar::from_maybe_pointer(Pointer::from_addr_invalid(val as u64), &tcx) + } else { + Scalar::from_uint(val, self.size(tcx)) + }; + let layout = rustc_target::abi::Scalar::Initialized { + value: self.value, + valid_range: WrappingRange::full(self.size(tcx)), + }; + bx.scalar_to_backend(value, layout, bx.backend_type(bx.layout_of(self.ty(tcx)))) + } +} diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index cf53739223467..7af5a1edcad3e 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -160,7 +160,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } - fn codegen_transmute( + pub fn codegen_transmute( &mut self, bx: &mut Bx, src: OperandRef<'tcx, Bx::Value>, @@ -195,7 +195,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { /// /// Returns `None` for cases that can't work in that framework, such as for /// `Immediate`->`Ref` that needs an `alloc` to get the location. - fn codegen_transmute_operand( + pub fn codegen_transmute_operand( &mut self, bx: &mut Bx, operand: OperandRef<'tcx, Bx::Value>, @@ -337,7 +337,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { /// /// `to_backend_ty` must be the *non*-immediate backend type (so it will be /// `i8`, not `i1`, for `bool`-like types.) - fn transmute_immediate( + pub fn transmute_immediate( &self, bx: &mut Bx, mut imm: Bx::Value, diff --git a/compiler/rustc_codegen_ssa/src/mir/statement.rs b/compiler/rustc_codegen_ssa/src/mir/statement.rs index cd55a838a7561..e796f32a19877 100644 --- a/compiler/rustc_codegen_ssa/src/mir/statement.rs +++ b/compiler/rustc_codegen_ssa/src/mir/statement.rs @@ -1,14 +1,33 @@ +use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::{self, NonDivergingIntrinsic}; use rustc_middle::span_bug; use tracing::instrument; use super::{FunctionCx, LocalRef}; +use crate::mir::niche_check::NicheFinder; use crate::traits::*; impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { + fn niches_to_check( + &mut self, + bx: &mut Bx, + statement: &mir::Statement<'tcx>, + ) -> Vec<(mir::Operand<'tcx>, rustc_target::abi::Niche)> { + let mut finder = NicheFinder { fx: self, bx, places: Vec::new() }; + finder.visit_statement(statement, rustc_middle::mir::Location::START); + finder.places + } + #[instrument(level = "debug", skip(self, bx))] pub(crate) fn codegen_statement(&mut self, bx: &mut Bx, statement: &mir::Statement<'tcx>) { self.set_debug_loc(bx, statement.source_info); + + if bx.tcx().may_insert_niche_checks() { + for (op, niche) in self.niches_to_check(bx, statement) { + self.codegen_niche_check(bx, op, niche, statement.source_info); + } + } + match statement.kind { mir::StatementKind::Assign(box (ref place, ref rvalue)) => { if let Some(index) = place.as_local() { diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 15cb331d07a5f..dfdee445d4a4a 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -293,6 +293,12 @@ language_item_table! { ConstPanicFmt, sym::const_panic_fmt, const_panic_fmt, Target::Fn, GenericRequirement::None; PanicBoundsCheck, sym::panic_bounds_check, panic_bounds_check_fn, Target::Fn, GenericRequirement::Exact(0); PanicMisalignedPointerDereference, sym::panic_misaligned_pointer_dereference, panic_misaligned_pointer_dereference_fn, Target::Fn, GenericRequirement::Exact(0); + PanicOccupiedNicheU8, sym::panic_occupied_niche_u8, panic_occupied_niche_u8, Target::Fn, GenericRequirement::None; + PanicOccupiedNicheU16, sym::panic_occupied_niche_u16, panic_occupied_niche_u16, Target::Fn, GenericRequirement::None; + PanicOccupiedNicheU32, sym::panic_occupied_niche_u32, panic_occupied_niche_u32, Target::Fn, GenericRequirement::None; + PanicOccupiedNicheU64, sym::panic_occupied_niche_u64, panic_occupied_niche_u64, Target::Fn, GenericRequirement::None; + PanicOccupiedNicheU128, sym::panic_occupied_niche_u128, panic_occupied_niche_u128, Target::Fn, GenericRequirement::None; + PanicOccupiedNichePtr, sym::panic_occupied_niche_ptr, panic_occupied_niche_ptr, Target::Fn, GenericRequirement::None; PanicInfo, sym::panic_info, panic_info, Target::Struct, GenericRequirement::None; PanicLocation, sym::panic_location, panic_location, Target::Struct, GenericRequirement::None; PanicImpl, sym::panic_impl, panic_impl, Target::Fn, GenericRequirement::None; diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 2841470d24878..e47315d409d0d 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -3210,6 +3210,14 @@ impl<'tcx> TyCtxt<'tcx> { pub fn do_not_recommend_impl(self, def_id: DefId) -> bool { self.get_diagnostic_attr(def_id, sym::do_not_recommend).is_some() } + + /// Whether a codegen backend may emit alignment checks for pointers when they are + /// read or written through. If this returns true, the backend is allowed to emit such checks. + /// If this returns false, the backend must not emit such checks. + pub fn may_insert_niche_checks(self) -> bool { + let has_panic_shim = self.lang_items().get(LangItem::PanicOccupiedNicheU8).is_some(); + has_panic_shim && self.sess.ub_checks() + } } /// Parameter attributes that can only be determined by examining the body of a function instead diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 480d82c1a385b..0d0d5703dee2c 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -231,6 +231,7 @@ use rustc_middle::util::Providers; use rustc_middle::{bug, span_bug}; use rustc_session::Limit; use rustc_session::config::EntryFnType; +use rustc_span::def_id::LOCAL_CRATE; use rustc_span::source_map::{Spanned, dummy_spanned, respan}; use rustc_span::symbol::sym; use rustc_span::{DUMMY_SP, Span}; @@ -1369,6 +1370,26 @@ fn collect_roots(tcx: TyCtxt<'_>, mode: MonoItemCollectionStrategy) -> Vec ! { ) } -/// Panics because we cannot unwind out of a function. +macro_rules! panic_occupied_niche { + ($name:ident, $ty:ty) => { + #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] + #[cfg_attr(feature = "panic_immediate_abort", inline)] + #[track_caller] + #[cfg_attr(not(bootstrap), lang = stringify!($name))] // needed by codegen for panic on occupied niches + #[rustc_nounwind] + fn $name(found: $ty, min: $ty, max: $ty) -> ! { + if cfg!(feature = "panic_immediate_abort") { + super::intrinsics::abort() + } + + panic_nounwind_fmt( + format_args!("occupied niche: found {found:?} but must be in {min:?}..={max:?}"), + /* force_no_backtrace */ false, + ) + } + }; +} + +panic_occupied_niche!(panic_occupied_niche_u8, u8); +panic_occupied_niche!(panic_occupied_niche_u16, u16); +panic_occupied_niche!(panic_occupied_niche_u32, u32); +panic_occupied_niche!(panic_occupied_niche_u64, u64); +panic_occupied_niche!(panic_occupied_niche_u128, u128); +panic_occupied_niche!(panic_occupied_niche_ptr, *const ()); + +/// Panic because we cannot unwind out of a function. /// /// This is a separate function to avoid the codesize impact of each crate containing the string to /// pass to `panic_nounwind`. diff --git a/tests/run-make/wasm-symbols-different-module/rmake.rs b/tests/run-make/wasm-symbols-different-module/rmake.rs index 3cd459db02fae..2c5672a8fd30a 100644 --- a/tests/run-make/wasm-symbols-different-module/rmake.rs +++ b/tests/run-make/wasm-symbols-different-module/rmake.rs @@ -22,7 +22,7 @@ fn test_file(file: &str, expected_imports: &[(&str, &[&str])]) { fn test(file: &str, args: &[&str], expected_imports: &[(&str, &[&str])]) { println!("test {file:?} {args:?} for {expected_imports:?}"); - rustc().input(file).target("wasm32-wasip1").args(args).run(); + rustc().input(file).target("wasm32-wasip1").args(args).arg("-Zub-checks=no").run(); let file = rfs::read(Path::new(file).with_extension("wasm")); @@ -46,5 +46,5 @@ fn test(file: &str, args: &[&str], expected_imports: &[(&str, &[&str])]) { assert!(names.contains(name)); } } - assert!(imports.is_empty()); + assert!(imports.is_empty(), "unexpected imports: {:?}", imports); } diff --git a/tests/ui/async-await/future-sizes/async-awaiting-fut.rs b/tests/ui/async-await/future-sizes/async-awaiting-fut.rs index a3f0bdc851481..38c85ba38e499 100644 --- a/tests/ui/async-await/future-sizes/async-awaiting-fut.rs +++ b/tests/ui/async-await/future-sizes/async-awaiting-fut.rs @@ -1,4 +1,4 @@ -//@ compile-flags: -Z print-type-sizes --crate-type lib +//@ compile-flags: -Z print-type-sizes -Zub-checks=no --crate-type lib //@ edition:2021 //@ build-pass //@ ignore-pass diff --git a/tests/ui/async-await/future-sizes/large-arg.rs b/tests/ui/async-await/future-sizes/large-arg.rs index 5fbae22a7714d..0dafcd98478dd 100644 --- a/tests/ui/async-await/future-sizes/large-arg.rs +++ b/tests/ui/async-await/future-sizes/large-arg.rs @@ -1,4 +1,4 @@ -//@ compile-flags: -Z print-type-sizes --crate-type=lib +//@ compile-flags: -Z print-type-sizes -Zub-checks=no --crate-type=lib //@ edition: 2021 //@ build-pass //@ ignore-pass diff --git a/tests/ui/niche_checks/invalid_enums.rs b/tests/ui/niche_checks/invalid_enums.rs new file mode 100644 index 0000000000000..cb3bc07793e5d --- /dev/null +++ b/tests/ui/niche_checks/invalid_enums.rs @@ -0,0 +1,23 @@ +//@ run-fail +//@ ignore-wasm32-bare: No panic messages +//@ compile-flags: -Zmir-opt-level=0 -Cdebug-assertions=no -Zub-checks=yes + +#[repr(C)] +struct Thing { + x: usize, + y: Contents, + z: usize, +} + +#[repr(usize)] +enum Contents { + A = 8usize, + B = 9usize, + C = 10usize, +} + +fn main() { + unsafe { + let _thing = std::mem::transmute::<(usize, usize, usize), Thing>((0, 3, 0)); + } +} diff --git a/tests/ui/niche_checks/invalid_nonnull_transmute.rs b/tests/ui/niche_checks/invalid_nonnull_transmute.rs new file mode 100644 index 0000000000000..5cbce1aa6711c --- /dev/null +++ b/tests/ui/niche_checks/invalid_nonnull_transmute.rs @@ -0,0 +1,10 @@ +//@ run-fail +//@ ignore-wasm32-bare: No panic messages +//@ compile-flags: -Zmir-opt-level=0 -Cdebug-assertions=no -Zub-checks=yes +//@ error-pattern: occupied niche: found 0x0 but must be in 0x1..=0xffffffff + +fn main() { + unsafe { + std::mem::transmute::<*const u8, std::ptr::NonNull>(std::ptr::null()); + } +} diff --git a/tests/ui/niche_checks/invalid_nonzero_argument.rs b/tests/ui/niche_checks/invalid_nonzero_argument.rs new file mode 100644 index 0000000000000..6746aa9ad2486 --- /dev/null +++ b/tests/ui/niche_checks/invalid_nonzero_argument.rs @@ -0,0 +1,14 @@ +//@ run-fail +//@ ignore-wasm32-bare: No panic messages +//@ compile-flags: -Zmir-opt-level=0 -Cdebug-assertions=no -Zub-checks=yes +//@ error-pattern: occupied niche: found 0 but must be in 1..=255 + +fn main() { + let mut bad = std::num::NonZeroU8::new(1u8).unwrap(); + unsafe { + std::ptr::write_bytes(&mut bad, 0u8, 1usize); + } + func(bad); +} + +fn func(_t: T) {} diff --git a/tests/ui/niche_checks/invalid_option.rs b/tests/ui/niche_checks/invalid_option.rs new file mode 100644 index 0000000000000..9698738d1e8d0 --- /dev/null +++ b/tests/ui/niche_checks/invalid_option.rs @@ -0,0 +1,10 @@ +//@ run-fail +//@ ignore-wasm32-bare: No panic messages +//@ compile-flags: -Zmir-opt-level=0 -Cdebug-assertions=no -Zub-checks=yes +//@ error-pattern: occupied niche: found 2 but must be in 0..=1 + +fn main() { + unsafe { + std::mem::transmute::<(u8, u8), Option>((2, 0)); + } +} diff --git a/tests/ui/niche_checks/operand_pair.rs b/tests/ui/niche_checks/operand_pair.rs new file mode 100644 index 0000000000000..97caf07239373 --- /dev/null +++ b/tests/ui/niche_checks/operand_pair.rs @@ -0,0 +1,12 @@ +//@ run-fail +//@ ignore-wasm32-bare: No panic messages +//@ compile-flags: -Zmir-opt-level=0 -Cdebug-assertions=no -Zub-checks=yes +//@ error-pattern: occupied niche: found 0x0 but must be in 0x1..=0xffffffff + +use std::ptr::NonNull; + +fn main() { + unsafe { + std::mem::transmute::<(usize, *const u8), (usize, NonNull)>((0usize, std::ptr::null())); + } +} diff --git a/tests/ui/niche_checks/valid_nonzero_argument.rs b/tests/ui/niche_checks/valid_nonzero_argument.rs new file mode 100644 index 0000000000000..2d6d83c4cb377 --- /dev/null +++ b/tests/ui/niche_checks/valid_nonzero_argument.rs @@ -0,0 +1,13 @@ +//@ run-pass +//@ compile-flags: -Zmir-opt-level=0 -Cdebug-assertions=no -Zub-checks=yes + +fn main() { + for val in i8::MIN..=i8::MAX { + if val != 0 { + let x = std::num::NonZeroI8::new(val).unwrap(); + if val != i8::MIN { + let _y = -x; + } + } + } +} diff --git a/tests/ui/numbers-arithmetic/saturating-float-casts-wasm.rs b/tests/ui/numbers-arithmetic/saturating-float-casts-wasm.rs index 8f1fe59ddc59b..d78af52574203 100644 --- a/tests/ui/numbers-arithmetic/saturating-float-casts-wasm.rs +++ b/tests/ui/numbers-arithmetic/saturating-float-casts-wasm.rs @@ -1,6 +1,6 @@ //@ run-pass //@ only-wasm32 -//@ compile-flags: -Zmir-opt-level=0 -C target-feature=+nontrapping-fptoint +//@ compile-flags: -Zmir-opt-level=0 -Zub-checks=no -C target-feature=+nontrapping-fptoint #![feature(test, stmt_expr_attributes)] #![deny(overflowing_literals)] diff --git a/tests/ui/numbers-arithmetic/saturating-float-casts.rs b/tests/ui/numbers-arithmetic/saturating-float-casts.rs index 3a1af09d2d423..c9e35f5d17b13 100644 --- a/tests/ui/numbers-arithmetic/saturating-float-casts.rs +++ b/tests/ui/numbers-arithmetic/saturating-float-casts.rs @@ -1,5 +1,5 @@ //@ run-pass -//@ compile-flags:-Zmir-opt-level=0 +//@ compile-flags: -Zmir-opt-level=0 -Zub-checks=no #![feature(test, stmt_expr_attributes)] #![deny(overflowing_literals)] diff --git a/tests/ui/print_type_sizes/async.rs b/tests/ui/print_type_sizes/async.rs index 805bccbcf6381..5918e04fb5d81 100644 --- a/tests/ui/print_type_sizes/async.rs +++ b/tests/ui/print_type_sizes/async.rs @@ -1,4 +1,4 @@ -//@ compile-flags: -Z print-type-sizes --crate-type lib +//@ compile-flags: -Z print-type-sizes -Zub-checks=no --crate-type lib //@ edition:2021 //@ build-pass //@ ignore-pass diff --git a/tests/ui/print_type_sizes/coroutine.rs b/tests/ui/print_type_sizes/coroutine.rs index 1533578878944..f07e496c0a66e 100644 --- a/tests/ui/print_type_sizes/coroutine.rs +++ b/tests/ui/print_type_sizes/coroutine.rs @@ -1,4 +1,4 @@ -//@ compile-flags: -Z print-type-sizes --crate-type=lib +//@ compile-flags: -Z print-type-sizes -Zub-checks=no --crate-type=lib //@ build-pass //@ ignore-pass diff --git a/tests/ui/print_type_sizes/niche-filling.stdout b/tests/ui/print_type_sizes/niche-filling.stdout index eeb5de5324121..22de9ffd74af0 100644 --- a/tests/ui/print_type_sizes/niche-filling.stdout +++ b/tests/ui/print_type_sizes/niche-filling.stdout @@ -1,3 +1,7 @@ +print-type-size type: `std::panic::Location<'_>`: 24 bytes, alignment: 8 bytes +print-type-size field `.file`: 16 bytes +print-type-size field `.line`: 4 bytes +print-type-size field `.col`: 4 bytes print-type-size type: `IndirectNonZero`: 12 bytes, alignment: 4 bytes print-type-size field `.nested`: 8 bytes print-type-size field `.post`: 2 bytes