From 32d4e0e5989634b9ef69912a1a3afd12255e7b93 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sat, 19 Nov 2022 13:33:46 -0500 Subject: [PATCH 1/8] Check for occupied niches (cherry picked from commit d0bd0da221eda59b843c18d619763e714f26ca4f) --- compiler/rustc_codegen_cranelift/src/base.rs | 23 + compiler/rustc_codegen_ssa/src/mir/block.rs | 29 ++ .../src/const_eval/machine.rs | 15 + compiler/rustc_hir/src/lang_items.rs | 1 + compiler/rustc_middle/messages.ftl | 3 + compiler/rustc_middle/src/mir/syntax.rs | 1 + compiler/rustc_middle/src/mir/terminator.rs | 19 +- compiler/rustc_middle/src/mir/visit.rs | 6 + .../rustc_mir_transform/src/check_niches.rs | 488 ++++++++++++++++++ compiler/rustc_mir_transform/src/lib.rs | 2 + compiler/rustc_smir/src/rustc_smir/mod.rs | 10 + compiler/rustc_span/src/symbol.rs | 1 + compiler/stable_mir/src/mir/body.rs | 18 +- library/core/src/panicking.rs | 25 + src/tools/miri/src/lib.rs | 2 +- tests/codegen/array-equality.rs | 1 + tests/codegen/debug-vtable.rs | 2 +- tests/codegen/intrinsics/transmute-niched.rs | 2 +- .../cfi-emit-type-checks-attr-no-sanitize.rs | 2 +- .../codegen/sanitizer/cfi-emit-type-checks.rs | 2 +- tests/codegen/thread-local.rs | 1 + tests/codegen/transmute-scalar.rs | 2 +- tests/mir-opt/remove_storage_markers.rs | 2 +- tests/ui-fulldeps/stable-mir/crate-info.rs | 1 + .../large_assignments/box_rc_arc_allowed.rs | 2 +- .../check_niches/invalid_bool_transmutes.rs | 10 + tests/ui/mir/check_niches/invalid_enums.rs | 23 + .../check_niches/invalid_nonnull_transmute.rs | 10 + .../check_niches/invalid_nonzero_argument.rs | 14 + .../mir/check_niches/valid_bool_transmutes.rs | 12 + .../check_niches/valid_nonzero_argument.rs | 13 + .../saturating-float-casts-wasm.rs | 2 +- .../saturating-float-casts.rs | 2 +- tests/ui/print_type_sizes/niche-filling.rs | 2 +- 34 files changed, 733 insertions(+), 15 deletions(-) create mode 100644 compiler/rustc_mir_transform/src/check_niches.rs create mode 100644 tests/ui/mir/check_niches/invalid_bool_transmutes.rs create mode 100644 tests/ui/mir/check_niches/invalid_enums.rs create mode 100644 tests/ui/mir/check_niches/invalid_nonnull_transmute.rs create mode 100644 tests/ui/mir/check_niches/invalid_nonzero_argument.rs create mode 100644 tests/ui/mir/check_niches/valid_bool_transmutes.rs create mode 100644 tests/ui/mir/check_niches/valid_nonzero_argument.rs diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 0a451dad9d232..44787d288b9c0 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -380,6 +380,29 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { source_info.span, ); } + AssertKind::OccupiedNiche { + ref found, + ref start, + ref end, + ref type_name, + ref offset, + ref niche_ty, + } => { + let found = codegen_operand(fx, found).load_scalar(fx); + let start = codegen_operand(fx, start).load_scalar(fx); + let end = codegen_operand(fx, end).load_scalar(fx); + let type_name = fx.anonymous_str(type_name); + let offset = codegen_operand(fx, offset).load_scalar(fx); + let niche_ty = fx.anonymous_str(niche_ty); + let location = fx.get_caller_location(source_info).load_scalar(fx); + + codegen_panic_inner( + fx, + rustc_hir::LangItem::PanicOccupiedNiche, + &[found, start, end, type_name, offset, niche_ty, location], + source_info.span, + ) + } _ => { let msg_str = msg.description(); codegen_panic(fx, msg_str, source_info); diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index a0cb97d51a01f..acccfba9b6859 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -624,6 +624,35 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // and `#[track_caller]` adds an implicit third argument. (LangItem::PanicMisalignedPointerDereference, vec![required, found, location]) } + AssertKind::OccupiedNiche { + ref found, + ref start, + ref end, + ref type_name, + ref offset, + ref niche_ty, + } => { + let found = self.codegen_operand(bx, found).immediate(); + let start = self.codegen_operand(bx, start).immediate(); + let end = self.codegen_operand(bx, end).immediate(); + let type_name = bx.const_str(type_name); + let offset = self.codegen_operand(bx, offset).immediate(); + let niche_ty = bx.const_str(niche_ty); + ( + LangItem::PanicOccupiedNiche, + vec![ + found, + start, + end, + type_name.0, + type_name.1, + offset, + niche_ty.0, + niche_ty.1, + location, + ], + ) + } _ => { let msg = bx.const_str(msg.description()); // It's `pub fn panic(expr: &str)`, with the wide reference being passed diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 865e01d0aee0f..d1eb5a6a5edff 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -587,6 +587,21 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, found: eval_to_int(found)?, } } + OccupiedNiche { + ref found, + ref start, + ref end, + ref type_name, + ref offset, + ref niche_ty, + } => OccupiedNiche { + found: eval_to_int(found)?, + start: eval_to_int(start)?, + end: eval_to_int(end)?, + type_name: type_name.clone(), + offset: eval_to_int(offset)?, + niche_ty: niche_ty.clone(), + }, }; Err(ConstEvalErrKind::AssertFailure(err).into()) } diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 4a89a6f7e3926..b4bdb3d8a8613 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -233,6 +233,7 @@ 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); + PanicOccupiedNiche, sym::panic_occupied_niche, panic_occupied_niche_fn, Target::Fn, GenericRequirement::Exact(0); 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/messages.ftl b/compiler/rustc_middle/messages.ftl index 82162fd85711b..039df6927ecac 100644 --- a/compiler/rustc_middle/messages.ftl +++ b/compiler/rustc_middle/messages.ftl @@ -15,6 +15,9 @@ middle_assert_generator_resume_after_return = generator resumed after completion middle_assert_misaligned_ptr_deref = misaligned pointer dereference: address must be a multiple of {$required} but is {$found} +middle_assert_occupied_niche = + occupied niche: {$found} must be in {$start}..={$end} + middle_assert_op_overflow = attempt to compute `{$left} {$op} {$right}`, which would overflow diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index bc28735a45d98..6c31a490c9647 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -882,6 +882,7 @@ pub enum AssertKind { ResumedAfterReturn(GeneratorKind), ResumedAfterPanic(GeneratorKind), MisalignedPointerDereference { required: O, found: O }, + OccupiedNiche { found: O, start: O, end: O, type_name: String, offset: O, niche_ty: String }, } #[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)] diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index 02aab4a892d05..7de84bc4d0bff 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -143,7 +143,7 @@ impl AssertKind { ResumedAfterReturn(GeneratorKind::Async(_)) => "`async fn` resumed after completion", ResumedAfterPanic(GeneratorKind::Gen) => "generator resumed after panicking", ResumedAfterPanic(GeneratorKind::Async(_)) => "`async fn` resumed after panicking", - BoundsCheck { .. } | MisalignedPointerDereference { .. } => { + BoundsCheck { .. } | MisalignedPointerDereference { .. } | OccupiedNiche { .. } => { bug!("Unexpected AssertKind") } } @@ -206,6 +206,13 @@ impl AssertKind { "\"misaligned pointer dereference: address must be a multiple of {{}} but is {{}}\", {required:?}, {found:?}" ) } + OccupiedNiche { found, start, end, type_name, offset, niche_ty } => { + write!( + f, + "\"occupied niche: {{}} must be in {{}}..={{}} in a {{}} at offset {{}} with type {{}}\" {:?} {:?} {:?} {:?} {:?} {:?}", + found, start, end, type_name, offset, niche_ty + ) + } _ => write!(f, "\"{}\"", self.description()), } } @@ -232,8 +239,8 @@ impl AssertKind { ResumedAfterReturn(GeneratorKind::Gen) => middle_assert_generator_resume_after_return, ResumedAfterPanic(GeneratorKind::Async(_)) => middle_assert_async_resume_after_panic, ResumedAfterPanic(GeneratorKind::Gen) => middle_assert_generator_resume_after_panic, - MisalignedPointerDereference { .. } => middle_assert_misaligned_ptr_deref, + OccupiedNiche { .. } => middle_assert_occupied_niche, } } @@ -270,6 +277,14 @@ impl AssertKind { add!("required", format!("{required:#?}")); add!("found", format!("{found:#?}")); } + OccupiedNiche { found, start, end, type_name, offset, niche_ty } => { + add!("found", format!("{found:?}")); + add!("start", format!("{start:?}")); + add!("end", format!("{end:?}")); + add!("type_name", format!("{type_name}")); + add!("offset", format!("{offset:?}")); + add!("niche_ty", format!("{niche_ty}")); + } } } } diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 60f78bef0afc7..7d8e4fd8e638d 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -623,6 +623,12 @@ macro_rules! make_mir_visitor { self.visit_operand(required, location); self.visit_operand(found, location); } + OccupiedNiche { found, start, end, type_name: _, offset, niche_ty: _ } => { + self.visit_operand(found, location); + self.visit_operand(start, location); + self.visit_operand(end, location); + self.visit_operand(offset, location); + } } } diff --git a/compiler/rustc_mir_transform/src/check_niches.rs b/compiler/rustc_mir_transform/src/check_niches.rs new file mode 100644 index 0000000000000..24f5cc36e5201 --- /dev/null +++ b/compiler/rustc_mir_transform/src/check_niches.rs @@ -0,0 +1,488 @@ +use crate::MirPass; +use rustc_hir::lang_items::LangItem; +use rustc_index::IndexVec; +use rustc_middle::mir::interpret::Scalar; +use rustc_middle::mir::visit::NonMutatingUseContext; +use rustc_middle::mir::visit::PlaceContext; +use rustc_middle::mir::visit::Visitor; +use rustc_middle::mir::*; +use rustc_middle::ty::print::with_no_trimmed_paths; +use rustc_middle::ty::{ParamEnv, ParamEnvAnd, Ty, TyCtxt}; +use rustc_session::Session; +use rustc_target::abi::{Integer, Niche, Primitive, Size}; + +pub struct CheckNiches; + +impl<'tcx> MirPass<'tcx> for CheckNiches { + fn is_enabled(&self, sess: &Session) -> bool { + sess.opts.debug_assertions + } + + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + // This pass emits new panics. If for whatever reason we do not have a panic + // implementation, running this pass may cause otherwise-valid code to not compile. + if tcx.lang_items().get(LangItem::PanicImpl).is_none() { + return; + } + + let is_generator = tcx.type_of(body.source.def_id()).instantiate_identity().is_generator(); + if is_generator { + return; + } + + with_no_trimmed_paths!(debug!("Inserting niche checks for {:?}", body.source)); + + let basic_blocks = body.basic_blocks.as_mut(); + let param_env = tcx.param_env_reveal_all_normalized(body.source.instance.def_id()); + let local_decls: &mut IndexVec<_, _> = &mut body.local_decls; + + // This pass inserts new blocks. Each insertion changes the Location for all + // statements/blocks after. Iterating or visiting the MIR in order would require updating + // our current location after every insertion. By iterating backwards, we dodge this issue: + // The only Locations that an insertion changes have already been handled. + for block in (0..basic_blocks.len()).rev() { + let block = block.into(); + for statement_index in (0..basic_blocks[block].statements.len()).rev() { + let location = Location { block, statement_index }; + let statement = &basic_blocks[block].statements[statement_index]; + let source_info = statement.source_info; + + let mut finder = NicheFinder { tcx, local_decls, param_env, places: Vec::new() }; + finder.visit_statement(statement, location); + + for (place, ty, niche) in core::mem::take(&mut finder.places) { + with_no_trimmed_paths!(debug!("Inserting niche check for {:?}", ty)); + let (block_data, new_block) = split_block(basic_blocks, location); + finder.insert_niche_check(block_data, new_block, place, niche, source_info); + } + } + } + } +} + +struct NicheFinder<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + local_decls: &'a mut IndexVec>, + param_env: ParamEnv<'tcx>, + places: Vec<(Operand<'tcx>, Ty<'tcx>, NicheKind)>, +} + +impl<'a, 'tcx> Visitor<'tcx> for NicheFinder<'a, 'tcx> { + fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { + if let Rvalue::Cast(CastKind::Transmute, op, ty) = rvalue { + if let Some(niche) = self.get_niche(*ty) { + self.places.push((op.clone(), *ty, niche)); + } + } + + self.super_rvalue(rvalue, location); + } + + fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) { + match context { + PlaceContext::NonMutatingUse( + NonMutatingUseContext::Inspect + | NonMutatingUseContext::Copy + | NonMutatingUseContext::Move, + ) => {} + _ => { + return; + } + } + + let ty = place.ty(self.local_decls, self.tcx).ty; + let Some(niche) = self.get_niche(ty) else { + return; + }; + + if ty.is_ref() { + // References are extremely common, checking them imposes a lot of runtime overhead. + return; + } + + self.places.push((Operand::Copy(*place), ty, niche)); + + self.super_place(place, context, location); + } +} + +impl<'a, 'tcx> NicheFinder<'a, 'tcx> { + fn insert_niche_check( + &mut self, + block_data: &mut BasicBlockData<'tcx>, + new_block: BasicBlock, + operand: Operand<'tcx>, + niche: NicheKind, + source_info: SourceInfo, + ) { + let type_name = + with_no_trimmed_paths!(format!("{:?}", operand.ty(self.local_decls, self.tcx))); + + let value_in_niche = self + .local_decls + .push(LocalDecl::with_source_info(niche.niche().ty(self.tcx), source_info)) + .into(); + + match niche { + NicheKind::Full(niche) => { + // The niche occupies the entire source Operand, so we can just transmute + // directly to the niche primitive. + let rvalue = Rvalue::Cast(CastKind::Transmute, operand, niche.ty(self.tcx)); + block_data.statements.push(Statement { + source_info, + kind: StatementKind::Assign(Box::new((value_in_niche, rvalue))), + }); + } + NicheKind::Partial(niche, size) => { + let mu = Ty::new_maybe_uninit(self.tcx, self.tcx.types.u8); + + // Transmute the niche-containing type to a [MaybeUninit; N] + let mu_array_ty = Ty::new_array(self.tcx, mu, size.bytes()); + let mu_array = self + .local_decls + .push(LocalDecl::with_source_info(mu_array_ty, source_info)) + .into(); + let rvalue = Rvalue::Cast(CastKind::Transmute, operand, mu_array_ty); + block_data.statements.push(Statement { + source_info, + kind: StatementKind::Assign(Box::new((mu_array, rvalue))), + }); + + // Load each byte of the [MaybeUninit; N] that is part of the niche + let niche_as_mu: Place<'tcx> = self + .local_decls + .push(LocalDecl::with_source_info( + Ty::new_array(self.tcx, mu, niche.size(self.tcx).bytes()), + source_info, + )) + .into(); + + for i in 0..niche.size(self.tcx).bytes() { + let lhs_index = self + .local_decls + .push(LocalDecl::with_source_info(self.tcx.types.usize, source_info)); + let index_value = Operand::Constant(Box::new(ConstOperand { + span: source_info.span, + user_ty: None, + const_: Const::Val( + ConstValue::Scalar(Scalar::from_target_usize(i, &self.tcx)), + self.tcx.types.usize, + ), + })); + block_data.statements.push(Statement { + source_info, + kind: StatementKind::Assign(Box::new(( + lhs_index.into(), + Rvalue::Use(index_value), + ))), + }); + + let rhs_index = self + .local_decls + .push(LocalDecl::with_source_info(self.tcx.types.usize, source_info)); + let index_value = Operand::Constant(Box::new(ConstOperand { + span: source_info.span, + user_ty: None, + const_: Const::Val( + ConstValue::Scalar(Scalar::from_target_usize( + niche.offset.bytes() + i, + &self.tcx, + )), + self.tcx.types.usize, + ), + })); + block_data.statements.push(Statement { + source_info, + kind: StatementKind::Assign(Box::new(( + rhs_index.into(), + Rvalue::Use(index_value), + ))), + }); + + let lhs = + niche_as_mu.project_deeper(&[ProjectionElem::Index(lhs_index)], self.tcx); + let rhs = + mu_array.project_deeper(&[ProjectionElem::Index(rhs_index)], self.tcx); + block_data.statements.push(Statement { + source_info, + kind: StatementKind::Assign(Box::new(( + lhs, + Rvalue::Use(Operand::Copy(rhs)), + ))), + }); + } + + // Transmute the smaller array of MaybeUninit to the niche primitive + let rvalue = Rvalue::Cast( + CastKind::Transmute, + Operand::Copy(niche_as_mu), + niche.ty(self.tcx), + ); + block_data.statements.push(Statement { + source_info, + kind: StatementKind::Assign(Box::new((value_in_niche, rvalue))), + }); + } + } + + let is_in_range = self + .local_decls + .push(LocalDecl::with_source_info(self.tcx.types.bool, source_info)) + .into(); + + NicheCheckBuilder { + tcx: self.tcx, + local_decls: self.local_decls, + block_data, + new_block, + niche: niche.niche(), + value_in_niche, + is_in_range, + source_info, + } + .insert_niche_check(type_name); + } + + fn get_niche(&self, ty: Ty<'tcx>) -> Option { + // If we can't get the layout of this, just skip the check. + let query = ParamEnvAnd { value: ty, param_env: self.param_env }; + let Ok(layout) = self.tcx.layout_of(query) else { + return None; + }; + + let niche = layout.largest_niche?; + + if niche.size(self.tcx) == layout.size { + Some(NicheKind::Full(niche)) + } else { + Some(NicheKind::Partial(niche, layout.size)) + } + } +} + +#[derive(Clone, Copy)] +enum NicheKind { + Full(Niche), + // We need the full Size of the type in order to do the transmute-to-MU approach + Partial(Niche, Size), +} + +impl NicheKind { + fn niche(self) -> Niche { + use NicheKind::*; + match self { + Full(niche) => niche, + Partial(niche, _size) => niche, + } + } +} + +fn split_block<'a, 'tcx>( + basic_blocks: &'a mut IndexVec>, + location: Location, +) -> (&'a mut BasicBlockData<'tcx>, BasicBlock) { + let block_data = &mut basic_blocks[location.block]; + + // Drain every statement after this one and move the current terminator to a new basic block + let new_block = BasicBlockData { + statements: block_data.statements.drain(location.statement_index..).collect(), + terminator: block_data.terminator.take(), + is_cleanup: block_data.is_cleanup, + }; + + let new_block = basic_blocks.push(new_block); + let block_data = &mut basic_blocks[location.block]; + + (block_data, new_block) +} + +struct NicheCheckBuilder<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + block_data: &'a mut BasicBlockData<'tcx>, + local_decls: &'a mut IndexVec>, + new_block: BasicBlock, + niche: Niche, + value_in_niche: Place<'tcx>, + is_in_range: Place<'tcx>, + source_info: SourceInfo, +} + +impl<'a, 'tcx> NicheCheckBuilder<'a, 'tcx> { + fn insert_niche_check(&mut self, type_name: String) { + let niche = self.niche; + let tcx = self.tcx; + + let size = self.niche.size(self.tcx); + + if niche.valid_range.start == 0 { + // The niche starts at 0, so we can just check if it is Le the end + self.check_end_only(); + } else if niche.valid_range.end == (u128::MAX >> (128 - size.bits())) { + // The niche ends at the max, so we can just check if it is Ge the start + self.check_start_only(); + } else { + self.general_case(); + } + + let start = Operand::Constant(Box::new(ConstOperand { + span: self.source_info.span, + user_ty: None, + const_: Const::Val( + ConstValue::Scalar(Scalar::from_uint( + niche.valid_range.start as u128, + Size::from_bits(128), + )), + tcx.types.u128, + ), + })); + let end = Operand::Constant(Box::new(ConstOperand { + span: self.source_info.span, + user_ty: None, + const_: Const::Val( + ConstValue::Scalar(Scalar::from_uint( + niche.valid_range.end as u128, + Size::from_bits(128), + )), + tcx.types.u128, + ), + })); + let offset = Operand::Constant(Box::new(ConstOperand { + span: self.source_info.span, + user_ty: None, + const_: Const::Val( + ConstValue::Scalar(Scalar::from_uint( + niche.offset.bytes() as u128, + Size::from_bits(128), + )), + tcx.types.u128, + ), + })); + + let u128_in_niche = self + .local_decls + .push(LocalDecl::with_source_info(tcx.types.u128, self.source_info)) + .into(); + let rvalue = + Rvalue::Cast(CastKind::IntToInt, Operand::Copy(self.value_in_niche), tcx.types.u128); + self.block_data.statements.push(Statement { + source_info: self.source_info, + kind: StatementKind::Assign(Box::new((u128_in_niche, rvalue))), + }); + + self.block_data.terminator = Some(Terminator { + source_info: self.source_info, + kind: TerminatorKind::Assert { + cond: Operand::Copy(self.is_in_range), + expected: true, + target: self.new_block, + msg: Box::new(AssertKind::OccupiedNiche { + found: Operand::Copy(u128_in_niche), + start, + end, + type_name, + offset, + niche_ty: format!("{:?}", niche.value), + }), + // This calls panic_misaligned_pointer_dereference, which is #[rustc_nounwind]. + // We never want to insert an unwind into unsafe code, because unwinding could + // make a failing UB check turn into much worse UB when we start unwinding. + unwind: UnwindAction::Unreachable, + }, + }); + } + + fn niche_const(&self, val: u128) -> Operand<'tcx> { + Operand::Constant(Box::new(ConstOperand { + span: self.source_info.span, + user_ty: None, + const_: Const::Val( + ConstValue::Scalar(Scalar::from_uint(val, self.niche.size(self.tcx))), + self.niche.ty(self.tcx), + ), + })) + } + + fn add_assignment(&mut self, place: Place<'tcx>, rvalue: Rvalue<'tcx>) { + self.block_data.statements.push(Statement { + source_info: self.source_info, + kind: StatementKind::Assign(Box::new((place, rvalue))), + }); + } + + fn check_start_only(&mut self) { + let start = self.niche_const(self.niche.valid_range.start); + + let rvalue = + Rvalue::BinaryOp(BinOp::Ge, Box::new((Operand::Copy(self.value_in_niche), start))); + self.add_assignment(self.is_in_range, rvalue); + } + + fn check_end_only(&mut self) { + let end = self.niche_const(self.niche.valid_range.end); + + let rvalue = + Rvalue::BinaryOp(BinOp::Le, Box::new((Operand::Copy(self.value_in_niche), end))); + self.add_assignment(self.is_in_range, rvalue); + } + + fn general_case(&mut self) { + let mut max = self.niche.valid_range.end.wrapping_sub(self.niche.valid_range.start); + let size = self.niche.size(self.tcx); + if size.bits() < 128 { + let mask = (1 << size.bits()) - 1; + max &= mask; + } + + let start = self.niche_const(self.niche.valid_range.start); + let max_adjusted_allowed_value = self.niche_const(max); + + let biased = self + .local_decls + .push(LocalDecl::with_source_info(self.niche.ty(self.tcx), self.source_info)) + .into(); + let rvalue = + Rvalue::BinaryOp(BinOp::Sub, Box::new((Operand::Copy(self.value_in_niche), start))); + self.add_assignment(biased, rvalue); + + let rvalue = Rvalue::BinaryOp( + BinOp::Le, + Box::new((Operand::Copy(biased), max_adjusted_allowed_value)), + ); + self.add_assignment(self.is_in_range, rvalue); + } +} + +trait NicheExt { + fn ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>; + fn size<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Size; +} + +impl NicheExt for Niche { + 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(_) => types.usize, + Primitive::F32 => types.u32, + Primitive::F64 => types.u64, + } + } + + fn size<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Size { + let bits = match self.value { + Primitive::Int(Integer::I8, _) => 8, + Primitive::Int(Integer::I16, _) => 16, + Primitive::Int(Integer::I32, _) => 32, + Primitive::Int(Integer::I64, _) => 64, + Primitive::Int(Integer::I128, _) => 128, + Primitive::Pointer(_) => tcx.sess.target.pointer_width as usize, + Primitive::F32 => 32, + Primitive::F64 => 64, + }; + Size::from_bits(bits) + } +} diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 22381844d6dc2..51dc18158d171 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -50,6 +50,7 @@ mod add_call_guards; mod add_moves_for_packed_drops; mod add_retag; mod check_const_item_mutation; +mod check_niches; mod check_packed_ref; pub mod check_unsafety; mod remove_place_mention; @@ -529,6 +530,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { body, &[ &check_alignment::CheckAlignment, + &check_niches::CheckNiches, &lower_slice_len::LowerSliceLenCalls, // has to be done before inlining, otherwise actual call will be almost always inlined. Also simple, so can just do first &unreachable_prop::UnreachablePropagation, &uninhabited_enum_branching::UninhabitedEnumBranching, diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index c6c97ce35e8b9..8601ec2e4ff42 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -685,6 +685,16 @@ impl<'tcx> Stable<'tcx> for mir::AssertMessage<'tcx> { found: found.stable(tables), } } + AssertKind::OccupiedNiche { found, start, end, type_name, offset, niche_ty } => { + stable_mir::mir::AssertMessage::OccupiedNiche { + found: found.stable(tables), + start: start.stable(tables), + end: end.stable(tables), + type_name: type_name.clone(), + offset: offset.stable(tables), + niche_ty: niche_ty.clone(), + } + } } } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index e4fafbc12d355..f9e9c29d7459b 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1113,6 +1113,7 @@ symbols! { panic_location, panic_misaligned_pointer_dereference, panic_nounwind, + panic_occupied_niche, panic_runtime, panic_str, panic_unwind, diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index 6f8f7b06fa393..b4cd1e09c146c 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -77,14 +77,28 @@ pub enum UnwindAction { #[derive(Clone, Debug)] pub enum AssertMessage { - BoundsCheck { len: Operand, index: Operand }, + BoundsCheck { + len: Operand, + index: Operand, + }, Overflow(BinOp, Operand, Operand), OverflowNeg(Operand), DivisionByZero(Operand), RemainderByZero(Operand), ResumedAfterReturn(GeneratorKind), ResumedAfterPanic(GeneratorKind), - MisalignedPointerDereference { required: Operand, found: Operand }, + MisalignedPointerDereference { + required: Operand, + found: Operand, + }, + OccupiedNiche { + found: Operand, + start: Operand, + end: Operand, + type_name: String, + offset: Operand, + niche_ty: String, + }, } #[derive(Clone, Debug)] diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index 1a32cf92ffbea..0f71ff039af65 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -208,6 +208,31 @@ fn panic_misaligned_pointer_dereference(required: usize, found: usize) -> ! { ) } +#[cold] +#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] +#[track_caller] +#[cfg_attr(not(bootstrap), lang = "panic_occupied_niche")] // needed by codegen for panic on occupied niches +#[rustc_nounwind] +fn panic_occupied_niche( + found: u128, + min: u128, + max: u128, + type_name: &'static str, + offset: u128, + niche_ty: &'static str, +) -> ! { + if cfg!(feature = "panic_immediate_abort") { + super::intrinsics::abort() + } + + panic_nounwind_fmt( + format_args!( + "occupied niche: found {found:#x} but must be in {min:#x}..={max:#x} in type {type_name} at offset {offset} with type {niche_ty}" + ), + /* force_no_backtrace */ false, + ) +} + /// 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 diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 816055cc4fe91..c92dcd2f65a18 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -138,5 +138,5 @@ pub const MIRI_DEFAULT_ARGS: &[&str] = &[ "-Zmir-emit-retag", "-Zmir-keep-place-mention", "-Zmir-opt-level=0", - "-Zmir-enable-passes=-CheckAlignment", + "-Zmir-enable-passes=-CheckAlignment,-CheckNiches", ]; diff --git a/tests/codegen/array-equality.rs b/tests/codegen/array-equality.rs index 1941452ea6159..0edd45ecf8d90 100644 --- a/tests/codegen/array-equality.rs +++ b/tests/codegen/array-equality.rs @@ -1,5 +1,6 @@ // compile-flags: -O -Z merge-functions=disabled // only-x86_64 +// ignore-debug: array comparison sometimes transmutes references, so we have niche checks in std #![crate_type = "lib"] diff --git a/tests/codegen/debug-vtable.rs b/tests/codegen/debug-vtable.rs index e52392b260bd4..8bcb28735ade0 100644 --- a/tests/codegen/debug-vtable.rs +++ b/tests/codegen/debug-vtable.rs @@ -6,7 +6,7 @@ // legacy mangling scheme rustc version and generic parameters are both hashed into a single part // of the name, thus randomizing item order with respect to rustc version. -// compile-flags: -Cdebuginfo=2 -Copt-level=0 -Csymbol-mangling-version=v0 +// compile-flags: -Cdebuginfo=2 -Copt-level=0 -Csymbol-mangling-version=v0 -Zmir-enable-passes=-CheckNiches // ignore-tidy-linelength // Make sure that vtables don't have the unnamed_addr attribute when debuginfo is enabled. diff --git a/tests/codegen/intrinsics/transmute-niched.rs b/tests/codegen/intrinsics/transmute-niched.rs index e9c8d803cb9e9..86acb47bc8266 100644 --- a/tests/codegen/intrinsics/transmute-niched.rs +++ b/tests/codegen/intrinsics/transmute-niched.rs @@ -1,6 +1,6 @@ // revisions: OPT DBG // [OPT] compile-flags: -C opt-level=3 -C no-prepopulate-passes -// [DBG] compile-flags: -C opt-level=0 -C no-prepopulate-passes +// [DBG] compile-flags: -C opt-level=0 -C no-prepopulate-passes -Zmir-enable-passes=-CheckNiches // only-64bit (so I don't need to worry about usize) #![crate_type = "lib"] diff --git a/tests/codegen/sanitizer/cfi-emit-type-checks-attr-no-sanitize.rs b/tests/codegen/sanitizer/cfi-emit-type-checks-attr-no-sanitize.rs index a3cd16e3dd5a5..e53ea03574319 100644 --- a/tests/codegen/sanitizer/cfi-emit-type-checks-attr-no-sanitize.rs +++ b/tests/codegen/sanitizer/cfi-emit-type-checks-attr-no-sanitize.rs @@ -1,7 +1,7 @@ // Verifies that pointer type membership tests for indirect calls are omitted. // // needs-sanitizer-cfi -// compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0 +// compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0 -Zmir-enable-passes=-CheckNiches #![crate_type="lib"] #![feature(no_sanitize)] diff --git a/tests/codegen/sanitizer/cfi-emit-type-checks.rs b/tests/codegen/sanitizer/cfi-emit-type-checks.rs index f0fe5de9f66c1..567597393f774 100644 --- a/tests/codegen/sanitizer/cfi-emit-type-checks.rs +++ b/tests/codegen/sanitizer/cfi-emit-type-checks.rs @@ -1,7 +1,7 @@ // Verifies that pointer type membership tests for indirect calls are emitted. // // needs-sanitizer-cfi -// compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0 +// compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0 -Zmir-enable-passes=-CheckNiches #![crate_type="lib"] diff --git a/tests/codegen/thread-local.rs b/tests/codegen/thread-local.rs index caf0366d2c144..383014d0c3132 100644 --- a/tests/codegen/thread-local.rs +++ b/tests/codegen/thread-local.rs @@ -1,4 +1,5 @@ // compile-flags: -O +// ignore-debug: niche checks in std interfere with the codegen we are looking for // aux-build:thread_local_aux.rs // ignore-windows FIXME(#84933) // ignore-wasm globals are used instead of thread locals diff --git a/tests/codegen/transmute-scalar.rs b/tests/codegen/transmute-scalar.rs index 39126b024a6e9..8b29a06f66969 100644 --- a/tests/codegen/transmute-scalar.rs +++ b/tests/codegen/transmute-scalar.rs @@ -1,4 +1,4 @@ -// compile-flags: -C opt-level=0 -C no-prepopulate-passes +// compile-flags: -C opt-level=0 -C no-prepopulate-passes -Zmir-enable-passes=-CheckNiches #![crate_type = "lib"] diff --git a/tests/mir-opt/remove_storage_markers.rs b/tests/mir-opt/remove_storage_markers.rs index 330264461d7cc..3f80e1f29fbc5 100644 --- a/tests/mir-opt/remove_storage_markers.rs +++ b/tests/mir-opt/remove_storage_markers.rs @@ -3,7 +3,7 @@ // Checks that storage markers are removed at opt-level=0. // -// compile-flags: -C opt-level=0 -Coverflow-checks=off +// compile-flags: -C opt-level=0 -Cdebug-assertions=off // EMIT_MIR remove_storage_markers.main.RemoveStorageMarkers.diff fn main() { diff --git a/tests/ui-fulldeps/stable-mir/crate-info.rs b/tests/ui-fulldeps/stable-mir/crate-info.rs index ce4ee3c2463eb..ab00c0eda2bec 100644 --- a/tests/ui-fulldeps/stable-mir/crate-info.rs +++ b/tests/ui-fulldeps/stable-mir/crate-info.rs @@ -181,6 +181,7 @@ fn main() { let args = vec![ "rustc".to_string(), "--crate-type=lib".to_string(), + "-Zmir-enable-passes=-CheckNiches".to_string(), "--crate-name".to_string(), CRATE_NAME.to_string(), path.to_string(), diff --git a/tests/ui/lint/large_assignments/box_rc_arc_allowed.rs b/tests/ui/lint/large_assignments/box_rc_arc_allowed.rs index 33113642023a2..99282829dbf29 100644 --- a/tests/ui/lint/large_assignments/box_rc_arc_allowed.rs +++ b/tests/ui/lint/large_assignments/box_rc_arc_allowed.rs @@ -5,7 +5,7 @@ // only-x86_64 // edition:2018 -// compile-flags: -Zmir-opt-level=0 +// compile-flags: -Zmir-opt-level=0 -Zmir-enable-passes=-CheckNiches use std::{sync::Arc, rc::Rc}; diff --git a/tests/ui/mir/check_niches/invalid_bool_transmutes.rs b/tests/ui/mir/check_niches/invalid_bool_transmutes.rs new file mode 100644 index 0000000000000..0916055b0cc00 --- /dev/null +++ b/tests/ui/mir/check_niches/invalid_bool_transmutes.rs @@ -0,0 +1,10 @@ +// run-fail +// ignore-wasm32-bare: No panic messages +// compile-flags: -C debug-assertions +// error-pattern: occupied niche: found 0x2 but must be in 0x0..=0x1 + +fn main() { + unsafe { + std::mem::transmute::(2); + } +} diff --git a/tests/ui/mir/check_niches/invalid_enums.rs b/tests/ui/mir/check_niches/invalid_enums.rs new file mode 100644 index 0000000000000..a5117f8ba27a2 --- /dev/null +++ b/tests/ui/mir/check_niches/invalid_enums.rs @@ -0,0 +1,23 @@ +// run-fail +// ignore-wasm32-bare: No panic messages +// compile-flags: -C debug-assertions -Zmir-opt-level=0 + +#[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/mir/check_niches/invalid_nonnull_transmute.rs b/tests/ui/mir/check_niches/invalid_nonnull_transmute.rs new file mode 100644 index 0000000000000..99ed52b81f8d4 --- /dev/null +++ b/tests/ui/mir/check_niches/invalid_nonnull_transmute.rs @@ -0,0 +1,10 @@ +// run-fail +// ignore-wasm32-bare: No panic messages +// compile-flags: -C debug-assertions -Zmir-opt-level=0 +// 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/mir/check_niches/invalid_nonzero_argument.rs b/tests/ui/mir/check_niches/invalid_nonzero_argument.rs new file mode 100644 index 0000000000000..d0da59d0e41a3 --- /dev/null +++ b/tests/ui/mir/check_niches/invalid_nonzero_argument.rs @@ -0,0 +1,14 @@ +// run-fail +// ignore-wasm32-bare: No panic messages +// compile-flags: -C debug-assertions -Zmir-opt-level=0 +// error-pattern: occupied niche: found 0x0 but must be in 0x1..=0xff + +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/mir/check_niches/valid_bool_transmutes.rs b/tests/ui/mir/check_niches/valid_bool_transmutes.rs new file mode 100644 index 0000000000000..adb67ff7517e9 --- /dev/null +++ b/tests/ui/mir/check_niches/valid_bool_transmutes.rs @@ -0,0 +1,12 @@ +// run-pass +// ignore-wasm32-bare: No panic messages +// compile-flags: -C debug-assertions + +fn main() { + unsafe { + std::mem::transmute::(0); + } + unsafe { + std::mem::transmute::(1); + } +} diff --git a/tests/ui/mir/check_niches/valid_nonzero_argument.rs b/tests/ui/mir/check_niches/valid_nonzero_argument.rs new file mode 100644 index 0000000000000..727d3e0d67c53 --- /dev/null +++ b/tests/ui/mir/check_niches/valid_nonzero_argument.rs @@ -0,0 +1,13 @@ +// run-pass +// compile-flags: -C debug-assertions -Zmir-opt-level=0 + +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 cad05917391be..7557e5ce34bb0 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 -C target-feature=+nontrapping-fptoint -Zmir-enable-passes=-CheckNiches #![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 cc248a9bea087..d26273bc8345f 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 -Zmir-enable-passes=-CheckNiches #![feature(test, stmt_expr_attributes)] #![deny(overflowing_literals)] diff --git a/tests/ui/print_type_sizes/niche-filling.rs b/tests/ui/print_type_sizes/niche-filling.rs index 5e620f248b65d..82afbd2495706 100644 --- a/tests/ui/print_type_sizes/niche-filling.rs +++ b/tests/ui/print_type_sizes/niche-filling.rs @@ -1,4 +1,4 @@ -// compile-flags: -Z print-type-sizes --crate-type=lib +// compile-flags: -Z print-type-sizes --crate-type=lib -Zmir-enable-passes=-CheckNiches // build-pass // ignore-pass // ^-- needed because `--pass check` does not emit the output needed. From aa42a2d6e6782d0f2ddde38aeb5aab66e4c88cf9 Mon Sep 17 00:00:00 2001 From: DianQK Date: Wed, 4 Oct 2023 16:34:19 +0800 Subject: [PATCH 2/8] update llvm-project --- .gitmodules | 2 +- src/llvm-project | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index f5025097a18dc..a804b4eb216c8 100644 --- a/.gitmodules +++ b/.gitmodules @@ -32,7 +32,7 @@ shallow = true [submodule "src/llvm-project"] path = src/llvm-project - url = https://github.com/rust-lang/llvm-project.git + url = https://github.com/DianQK/llvm-project.git branch = rustc/17.0-2023-09-19 shallow = true [submodule "src/doc/embedded-book"] diff --git a/src/llvm-project b/src/llvm-project index d404cba4e39df..a028025356430 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit d404cba4e39df595710869988ded7cbe1104b52f +Subproject commit a02802535643059076812c58957c4eac7af70ab2 From c831a34a4e2d246ccf1801481ad40e6eabd31f23 Mon Sep 17 00:00:00 2001 From: DianQK Date: Wed, 4 Oct 2023 17:03:46 +0800 Subject: [PATCH 3/8] bless? --- .../async-await/future-sizes/async-awaiting-fut.stdout | 10 ++++++++++ tests/ui/async-await/future-sizes/large-arg.stdout | 10 ++++++++++ tests/ui/print_type_sizes/async.stdout | 10 ++++++++++ 3 files changed, 30 insertions(+) diff --git a/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout b/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout index d63911b0d3c19..fe79a02e9bc36 100644 --- a/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout +++ b/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout @@ -50,12 +50,22 @@ print-type-size variant `Returned`: 1024 bytes print-type-size upvar `.arg`: 1024 bytes print-type-size variant `Panicked`: 1024 bytes print-type-size upvar `.arg`: 1024 bytes +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: `std::mem::ManuallyDrop`: 1 bytes, alignment: 1 bytes print-type-size field `.value`: 1 bytes +print-type-size type: `std::mem::ManuallyDrop`: 1 bytes, alignment: 1 bytes +print-type-size field `.value`: 1 bytes print-type-size type: `std::mem::MaybeUninit`: 1 bytes, alignment: 1 bytes print-type-size variant `MaybeUninit`: 1 bytes print-type-size field `.uninit`: 0 bytes print-type-size field `.value`: 1 bytes +print-type-size type: `std::mem::MaybeUninit`: 1 bytes, alignment: 1 bytes +print-type-size variant `MaybeUninit`: 1 bytes +print-type-size field `.uninit`: 0 bytes +print-type-size field `.value`: 1 bytes print-type-size type: `std::task::Poll<()>`: 1 bytes, alignment: 1 bytes print-type-size discriminant: 1 bytes print-type-size variant `Ready`: 0 bytes diff --git a/tests/ui/async-await/future-sizes/large-arg.stdout b/tests/ui/async-await/future-sizes/large-arg.stdout index 005460df626fc..bfc7ffc28b98d 100644 --- a/tests/ui/async-await/future-sizes/large-arg.stdout +++ b/tests/ui/async-await/future-sizes/large-arg.stdout @@ -58,3 +58,13 @@ print-type-size variant `Returned`: 1024 bytes print-type-size upvar `.t`: 1024 bytes print-type-size variant `Panicked`: 1024 bytes print-type-size upvar `.t`: 1024 bytes +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: `std::mem::ManuallyDrop`: 1 bytes, alignment: 1 bytes +print-type-size field `.value`: 1 bytes +print-type-size type: `std::mem::MaybeUninit`: 1 bytes, alignment: 1 bytes +print-type-size variant `MaybeUninit`: 1 bytes +print-type-size field `.uninit`: 0 bytes +print-type-size field `.value`: 1 bytes diff --git a/tests/ui/print_type_sizes/async.stdout b/tests/ui/print_type_sizes/async.stdout index e1be98f85d847..6f355ea0d6538 100644 --- a/tests/ui/print_type_sizes/async.stdout +++ b/tests/ui/print_type_sizes/async.stdout @@ -16,8 +16,18 @@ print-type-size type: `std::mem::MaybeUninit<[u8; 8192]>`: 8192 bytes, alignment print-type-size variant `MaybeUninit`: 8192 bytes print-type-size field `.uninit`: 0 bytes print-type-size field `.value`: 8192 bytes +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: `std::mem::ManuallyDrop`: 1 bytes, alignment: 1 bytes +print-type-size field `.value`: 1 bytes print-type-size type: `std::mem::ManuallyDrop<{async fn body@$DIR/async.rs:8:17: 8:19}>`: 1 bytes, alignment: 1 bytes print-type-size field `.value`: 1 bytes +print-type-size type: `std::mem::MaybeUninit`: 1 bytes, alignment: 1 bytes +print-type-size variant `MaybeUninit`: 1 bytes +print-type-size field `.uninit`: 0 bytes +print-type-size field `.value`: 1 bytes print-type-size type: `std::mem::MaybeUninit<{async fn body@$DIR/async.rs:8:17: 8:19}>`: 1 bytes, alignment: 1 bytes print-type-size variant `MaybeUninit`: 1 bytes print-type-size field `.uninit`: 0 bytes From ba746ccd8d6082e56f83a429f11bd1008685544f Mon Sep 17 00:00:00 2001 From: DianQK Date: Thu, 5 Oct 2023 06:06:45 +0800 Subject: [PATCH 4/8] add -Zmir-enable-passes=-CheckNiches --- .../ui/async-await/future-sizes/async-awaiting-fut.rs | 2 +- .../async-await/future-sizes/async-awaiting-fut.stdout | 10 ---------- tests/ui/async-await/future-sizes/large-arg.rs | 2 +- tests/ui/async-await/future-sizes/large-arg.stdout | 10 ---------- tests/ui/print_type_sizes/async.rs | 2 +- tests/ui/print_type_sizes/async.stdout | 10 ---------- 6 files changed, 3 insertions(+), 33 deletions(-) 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 1816d842d6c41..b935c60a7f18f 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 --crate-type lib -Zmir-enable-passes=-CheckNiches // edition:2021 // build-pass // ignore-pass diff --git a/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout b/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout index fe79a02e9bc36..d63911b0d3c19 100644 --- a/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout +++ b/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout @@ -50,22 +50,12 @@ print-type-size variant `Returned`: 1024 bytes print-type-size upvar `.arg`: 1024 bytes print-type-size variant `Panicked`: 1024 bytes print-type-size upvar `.arg`: 1024 bytes -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: `std::mem::ManuallyDrop`: 1 bytes, alignment: 1 bytes print-type-size field `.value`: 1 bytes -print-type-size type: `std::mem::ManuallyDrop`: 1 bytes, alignment: 1 bytes -print-type-size field `.value`: 1 bytes print-type-size type: `std::mem::MaybeUninit`: 1 bytes, alignment: 1 bytes print-type-size variant `MaybeUninit`: 1 bytes print-type-size field `.uninit`: 0 bytes print-type-size field `.value`: 1 bytes -print-type-size type: `std::mem::MaybeUninit`: 1 bytes, alignment: 1 bytes -print-type-size variant `MaybeUninit`: 1 bytes -print-type-size field `.uninit`: 0 bytes -print-type-size field `.value`: 1 bytes print-type-size type: `std::task::Poll<()>`: 1 bytes, alignment: 1 bytes print-type-size discriminant: 1 bytes print-type-size variant `Ready`: 0 bytes diff --git a/tests/ui/async-await/future-sizes/large-arg.rs b/tests/ui/async-await/future-sizes/large-arg.rs index 7e7ff9d8d00e8..c3f23fd4a256a 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 --crate-type=lib -Zmir-enable-passes=-CheckNiches // edition: 2021 // build-pass // ignore-pass diff --git a/tests/ui/async-await/future-sizes/large-arg.stdout b/tests/ui/async-await/future-sizes/large-arg.stdout index bfc7ffc28b98d..005460df626fc 100644 --- a/tests/ui/async-await/future-sizes/large-arg.stdout +++ b/tests/ui/async-await/future-sizes/large-arg.stdout @@ -58,13 +58,3 @@ print-type-size variant `Returned`: 1024 bytes print-type-size upvar `.t`: 1024 bytes print-type-size variant `Panicked`: 1024 bytes print-type-size upvar `.t`: 1024 bytes -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: `std::mem::ManuallyDrop`: 1 bytes, alignment: 1 bytes -print-type-size field `.value`: 1 bytes -print-type-size type: `std::mem::MaybeUninit`: 1 bytes, alignment: 1 bytes -print-type-size variant `MaybeUninit`: 1 bytes -print-type-size field `.uninit`: 0 bytes -print-type-size field `.value`: 1 bytes diff --git a/tests/ui/print_type_sizes/async.rs b/tests/ui/print_type_sizes/async.rs index f38a6e674da99..7f4d6bd5efd2e 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 --crate-type lib -Zmir-enable-passes=-CheckNiches // edition:2021 // build-pass // ignore-pass diff --git a/tests/ui/print_type_sizes/async.stdout b/tests/ui/print_type_sizes/async.stdout index 6f355ea0d6538..e1be98f85d847 100644 --- a/tests/ui/print_type_sizes/async.stdout +++ b/tests/ui/print_type_sizes/async.stdout @@ -16,18 +16,8 @@ print-type-size type: `std::mem::MaybeUninit<[u8; 8192]>`: 8192 bytes, alignment print-type-size variant `MaybeUninit`: 8192 bytes print-type-size field `.uninit`: 0 bytes print-type-size field `.value`: 8192 bytes -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: `std::mem::ManuallyDrop`: 1 bytes, alignment: 1 bytes -print-type-size field `.value`: 1 bytes print-type-size type: `std::mem::ManuallyDrop<{async fn body@$DIR/async.rs:8:17: 8:19}>`: 1 bytes, alignment: 1 bytes print-type-size field `.value`: 1 bytes -print-type-size type: `std::mem::MaybeUninit`: 1 bytes, alignment: 1 bytes -print-type-size variant `MaybeUninit`: 1 bytes -print-type-size field `.uninit`: 0 bytes -print-type-size field `.value`: 1 bytes print-type-size type: `std::mem::MaybeUninit<{async fn body@$DIR/async.rs:8:17: 8:19}>`: 1 bytes, alignment: 1 bytes print-type-size variant `MaybeUninit`: 1 bytes print-type-size field `.uninit`: 0 bytes From 7c813305405e5be86f2ed454780b61e94e527730 Mon Sep 17 00:00:00 2001 From: DianQK Date: Thu, 5 Oct 2023 09:43:50 +0800 Subject: [PATCH 5/8] add NO_DOWNLOAD_CI_LLVM --- .github/workflows/ci.yml | 2 ++ src/ci/github-actions/ci.yml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 624608cc47744..d4525d2d084b2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -299,6 +299,8 @@ jobs: - name: x86_64-gnu-tools env: DEPLOY_TOOLSTATES_JSON: toolstates-linux.json + NO_DOWNLOAD_CI_LLVM: 1 + CUSTOM_MINGW: 1 os: ubuntu-20.04-8core-32gb - name: dist-x86_64-apple env: diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index 6d25b2c9cc2b3..d8a65cb5151cb 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -473,6 +473,8 @@ jobs: - name: x86_64-gnu-tools env: DEPLOY_TOOLSTATES_JSON: toolstates-linux.json + NO_DOWNLOAD_CI_LLVM: 1 + CUSTOM_MINGW: 1 <<: *job-linux-8c #################### From 4f8208f1a86bd3e588f3335998ab7e6483fb842f Mon Sep 17 00:00:00 2001 From: DianQK Date: Thu, 5 Oct 2023 15:32:24 +0800 Subject: [PATCH 6/8] --set llvm.download-ci-llvm=false --- src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile index 85f2f84a44c32..5f0342b476c34 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile @@ -80,6 +80,7 @@ COPY host-x86_64/x86_64-gnu-tools/browser-ui-test.version /tmp/ RUN npm install -g browser-ui-test@$(head -n 1 /tmp/browser-ui-test.version) --unsafe-perm=true ENV RUST_CONFIGURE_ARGS \ + --set llvm.download-ci-llvm=false \ --build=x86_64-unknown-linux-gnu \ --save-toolstates=/tmp/toolstate/toolstates.json From 5b66c9947def50e2ad6e07834da10e527818000a Mon Sep 17 00:00:00 2001 From: DianQK Date: Sat, 7 Oct 2023 18:28:21 +0800 Subject: [PATCH 7/8] Update Dockerfile --- src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile index 5f0342b476c34..002d03764ccb2 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile @@ -79,6 +79,8 @@ COPY host-x86_64/x86_64-gnu-tools/browser-ui-test.version /tmp/ # the local version of the package is different than the one used by the CI. RUN npm install -g browser-ui-test@$(head -n 1 /tmp/browser-ui-test.version) --unsafe-perm=true +ENV NO_DOWNLOAD_CI_LLVM 1 + ENV RUST_CONFIGURE_ARGS \ --set llvm.download-ci-llvm=false \ --build=x86_64-unknown-linux-gnu \ From a3b0d7916e83dab06d2411af656032031fefdfea Mon Sep 17 00:00:00 2001 From: DianQK Date: Tue, 10 Oct 2023 09:28:57 +0800 Subject: [PATCH 8/8] update llvm-project --- src/llvm-project | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llvm-project b/src/llvm-project index a028025356430..6d0d0104bd332 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit a02802535643059076812c58957c4eac7af70ab2 +Subproject commit 6d0d0104bd332c1f0fc45634f474f06665b7635c