diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0551d44649cd..c9d6c56076a9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -154,9 +154,12 @@ jobs: - name: checkout submodules run: src/ci/scripts/checkout-submodules.sh - - - name: install MSYS2 - run: src/ci/scripts/install-msys2.sh + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: '3.x' + if: runner.environment == 'github-hosted' - name: install MinGW run: src/ci/scripts/install-mingw.sh diff --git a/Cargo.lock b/Cargo.lock index 6e86f6c02f17..c0d1337ef93a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4082,6 +4082,7 @@ dependencies = [ "rustc_feature", "rustc_fluent_macro", "rustc_hir", + "rustc_hir_pretty", "rustc_index", "rustc_infer", "rustc_macros", diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index a95ef4c460f4..9165b4f2df3d 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -970,7 +970,7 @@ fn univariant< let mut align = if pack.is_some() { dl.i8_align } else { dl.aggregate_align }; let mut max_repr_align = repr.align; let mut inverse_memory_index: IndexVec = fields.indices().collect(); - let optimize = !repr.inhibit_struct_field_reordering_opt(); + let optimize = !repr.inhibit_struct_field_reordering(); if optimize && fields.len() > 1 { let end = if let StructKind::MaybeUnsized = kind { fields.len() - 1 } else { fields.len() }; let optimizing = &mut inverse_memory_index.raw[..end]; @@ -1007,13 +1007,15 @@ fn univariant< // Calculates a sort key to group fields by their alignment or possibly some // size-derived pseudo-alignment. let alignment_group_key = |layout: &F| { + // The two branches here return values that cannot be meaningfully compared with + // each other. However, we know that consistently for all executions of + // `alignment_group_key`, one or the other branch will be taken, so this is okay. if let Some(pack) = pack { // Return the packed alignment in bytes. layout.align.abi.min(pack).bytes() } else { - // Returns `log2(effective-align)`. This is ok since `pack` applies to all - // fields equally. The calculation assumes that size is an integer multiple of - // align, except for ZSTs. + // Returns `log2(effective-align)`. The calculation assumes that size is an + // integer multiple of align, except for ZSTs. let align = layout.align.abi.bytes(); let size = layout.size.bytes(); let niche_size = layout.largest_niche.map(|n| n.available(dl)).unwrap_or(0); diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 53aa8ad7cca5..b1a17d5a24b6 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -137,23 +137,16 @@ impl ReprOptions { self.c() || self.int.is_some() } - /// Returns `true` if this `#[repr()]` should inhibit struct field reordering - /// optimizations, such as with `repr(C)`, `repr(packed(1))`, or `repr()`. - pub fn inhibit_struct_field_reordering_opt(&self) -> bool { - if let Some(pack) = self.pack { - if pack.bytes() == 1 { - return true; - } - } - + /// Returns `true` if this `#[repr()]` guarantees a fixed field order, + /// e.g. `repr(C)` or `repr()`. + pub fn inhibit_struct_field_reordering(&self) -> bool { self.flags.intersects(ReprFlags::IS_UNOPTIMISABLE) || self.int.is_some() } /// Returns `true` if this type is valid for reordering and `-Z randomize-layout` /// was enabled for its declaration crate. pub fn can_randomize_type_layout(&self) -> bool { - !self.inhibit_struct_field_reordering_opt() - && self.flags.contains(ReprFlags::RANDOMIZE_LAYOUT) + !self.inhibit_struct_field_reordering() && self.flags.contains(ReprFlags::RANDOMIZE_LAYOUT) } /// Returns `true` if this `#[repr()]` should inhibit union ABI optimisations. diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 1a166956075c..7e59b4492993 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1393,7 +1393,7 @@ pub enum ExprKind { /// An array (e.g, `[a, b, c, d]`). Array(ThinVec>), /// Allow anonymous constants from an inline `const` block - ConstBlock(AnonConst), + ConstBlock(P), /// A function call /// /// The first field resolves to the function itself, diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 566b20c490ef..ede0dd70b305 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1411,7 +1411,7 @@ pub fn noop_visit_expr( match kind { ExprKind::Array(exprs) => visit_thin_exprs(exprs, vis), ExprKind::ConstBlock(anon_const) => { - vis.visit_anon_const(anon_const); + vis.visit_expr(anon_const); } ExprKind::Repeat(expr, count) => { vis.visit_expr(expr); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 93de42b55cc3..6382eb6861c7 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -852,10 +852,10 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>( ctxt: AssocCtxt, ) -> V::Result { let &Item { id: _, span: _, ident, ref vis, ref attrs, ref kind, tokens: _ } = item; - walk_list!(visitor, visit_attribute, attrs); try_visit!(visitor.visit_vis(vis)); try_visit!(visitor.visit_ident(ident)); try_visit!(kind.walk(item, ctxt, visitor)); + walk_list!(visitor, visit_attribute, attrs); V::Result::output() } @@ -951,7 +951,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V ExprKind::Array(subexpressions) => { walk_list!(visitor, visit_expr, subexpressions); } - ExprKind::ConstBlock(anon_const) => try_visit!(visitor.visit_anon_const(anon_const)), + ExprKind::ConstBlock(anon_const) => try_visit!(visitor.visit_expr(anon_const)), ExprKind::Repeat(element, count) => { try_visit!(visitor.visit_expr(element)); try_visit!(visitor.visit_anon_const(count)); diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index a55310909284..eb206a09be31 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -75,12 +75,8 @@ impl<'hir> LoweringContext<'_, 'hir> { let kind = match &e.kind { ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)), ExprKind::ConstBlock(c) => { - let c = self.with_new_scopes(c.value.span, |this| hir::ConstBlock { - def_id: this.local_def_id(c.id), - hir_id: this.lower_node_id(c.id), - body: this.lower_const_body(c.value.span, Some(&c.value)), - }); - hir::ExprKind::ConstBlock(c) + self.has_inline_consts = true; + hir::ExprKind::ConstBlock(self.lower_expr(c)) } ExprKind::Repeat(expr, count) => { let expr = self.lower_expr(expr); diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index 7254be2b2f42..ed3046400f60 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -236,14 +236,6 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { }); } - fn visit_inline_const(&mut self, constant: &'hir ConstBlock) { - self.insert(DUMMY_SP, constant.hir_id, Node::ConstBlock(constant)); - - self.with_parent(constant.hir_id, |this| { - intravisit::walk_inline_const(this, constant); - }); - } - fn visit_expr(&mut self, expr: &'hir Expr<'hir>) { self.insert(expr.span, expr.hir_id, Node::Expr(expr)); diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index a9af5ad74592..278049d1347b 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -96,6 +96,8 @@ struct LoweringContext<'a, 'hir> { /// Bodies inside the owner being lowered. bodies: Vec<(hir::ItemLocalId, &'hir hir::Body<'hir>)>, + /// Whether there were inline consts that typeck will split out into bodies + has_inline_consts: bool, /// Attributes inside the owner being lowered. attrs: SortedMap, /// Collect items that were created by lowering the current owner. @@ -158,6 +160,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { item_local_id_counter: hir::ItemLocalId::ZERO, node_id_to_local_id: Default::default(), trait_map: Default::default(), + has_inline_consts: false, // Lowering state. catch_scope: None, @@ -567,6 +570,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let current_attrs = std::mem::take(&mut self.attrs); let current_bodies = std::mem::take(&mut self.bodies); + let current_has_inline_consts = std::mem::take(&mut self.has_inline_consts); let current_node_ids = std::mem::take(&mut self.node_id_to_local_id); let current_trait_map = std::mem::take(&mut self.trait_map); let current_owner = @@ -593,6 +597,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.attrs = current_attrs; self.bodies = current_bodies; + self.has_inline_consts = current_has_inline_consts; self.node_id_to_local_id = current_node_ids; self.trait_map = current_trait_map; self.current_hir_id_owner = current_owner; @@ -629,6 +634,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let attrs = std::mem::take(&mut self.attrs); let mut bodies = std::mem::take(&mut self.bodies); let trait_map = std::mem::take(&mut self.trait_map); + let has_inline_consts = std::mem::take(&mut self.has_inline_consts); #[cfg(debug_assertions)] for (id, attrs) in attrs.iter() { @@ -646,7 +652,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.tcx.hash_owner_nodes(node, &bodies, &attrs); let num_nodes = self.item_local_id_counter.as_usize(); let (nodes, parenting) = index::index_hir(self.tcx, node, &bodies, num_nodes); - let nodes = hir::OwnerNodes { opt_hash_including_bodies, nodes, bodies }; + let nodes = hir::OwnerNodes { opt_hash_including_bodies, nodes, bodies, has_inline_consts }; let attrs = hir::AttributeMap { map: attrs, opt_hash: attrs_hash }; self.arena.alloc(hir::OwnerInfo { nodes, parenting, attrs, trait_map }) diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index 1e117c46b6e2..993ccc5b9560 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -380,8 +380,9 @@ impl<'a> State<'a> { ast::ExprKind::Array(exprs) => { self.print_expr_vec(exprs); } - ast::ExprKind::ConstBlock(anon_const) => { - self.print_expr_anon_const(anon_const, attrs); + ast::ExprKind::ConstBlock(expr) => { + self.word_space("const"); + self.print_expr(expr, FixupContext::default()); } ast::ExprKind::Repeat(element, count) => { self.print_expr_repeat(element, count); diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index 4bcef15ad047..bd5a88769059 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -593,6 +593,7 @@ pub(crate) fn codegen_drop<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, source_info: mir::SourceInfo, drop_place: CPlace<'tcx>, + target: BasicBlock, ) { let ty = drop_place.layout().ty; let drop_instance = Instance::resolve_drop_in_place(fx.tcx, ty).polymorphize(fx.tcx); @@ -620,6 +621,12 @@ pub(crate) fn codegen_drop<'tcx>( let ptr = ptr.get_addr(fx); let drop_fn = crate::vtable::drop_fn_of_obj(fx, vtable); + let is_null = fx.bcx.ins().icmp_imm(IntCC::Equal, drop_fn, 0); + let target_block = fx.get_block(target); + let continued = fx.bcx.create_block(); + fx.bcx.ins().brif(is_null, target_block, &[], continued, &[]); + fx.bcx.switch_to_block(continued); + // FIXME(eddyb) perhaps move some of this logic into // `Instance::resolve_drop_in_place`? let virtual_drop = Instance { @@ -659,6 +666,12 @@ pub(crate) fn codegen_drop<'tcx>( let (data, vtable) = drop_place.to_cvalue(fx).dyn_star_force_data_on_stack(fx); let drop_fn = crate::vtable::drop_fn_of_obj(fx, vtable); + let is_null = fx.bcx.ins().icmp_imm(IntCC::Equal, drop_fn, 0); + let target_block = fx.get_block(target); + let continued = fx.bcx.create_block(); + fx.bcx.ins().brif(is_null, target_block, &[], continued, &[]); + fx.bcx.switch_to_block(continued); + let virtual_drop = Instance { def: ty::InstanceDef::Virtual(drop_instance.def_id(), 0), args: drop_instance.args, @@ -697,4 +710,7 @@ pub(crate) fn codegen_drop<'tcx>( } } } + + let target_block = fx.get_block(target); + fx.bcx.ins().jump(target_block, &[]); } diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 8d778f736d67..963e5de91cef 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -548,10 +548,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { } TerminatorKind::Drop { place, target, unwind: _, replace: _ } => { let drop_place = codegen_place(fx, *place); - crate::abi::codegen_drop(fx, source_info, drop_place); - - let target_block = fx.get_block(*target); - fx.bcx.ins().jump(target_block, &[]); + crate::abi::codegen_drop(fx, source_info, drop_place, *target); } }; } @@ -619,22 +616,34 @@ fn codegen_stmt<'tcx>( Rvalue::UnaryOp(un_op, ref operand) => { let operand = codegen_operand(fx, operand); let layout = operand.layout(); - let val = operand.load_scalar(fx); let res = match un_op { - UnOp::Not => match layout.ty.kind() { - ty::Bool => { - let res = fx.bcx.ins().icmp_imm(IntCC::Equal, val, 0); - CValue::by_val(res, layout) + UnOp::Not => { + let val = operand.load_scalar(fx); + match layout.ty.kind() { + ty::Bool => { + let res = fx.bcx.ins().icmp_imm(IntCC::Equal, val, 0); + CValue::by_val(res, layout) + } + ty::Uint(_) | ty::Int(_) => { + CValue::by_val(fx.bcx.ins().bnot(val), layout) + } + _ => unreachable!("un op Not for {:?}", layout.ty), } - ty::Uint(_) | ty::Int(_) => { - CValue::by_val(fx.bcx.ins().bnot(val), layout) + } + UnOp::Neg => { + let val = operand.load_scalar(fx); + match layout.ty.kind() { + ty::Int(_) => CValue::by_val(fx.bcx.ins().ineg(val), layout), + ty::Float(_) => CValue::by_val(fx.bcx.ins().fneg(val), layout), + _ => unreachable!("un op Neg for {:?}", layout.ty), } - _ => unreachable!("un op Not for {:?}", layout.ty), - }, - UnOp::Neg => match layout.ty.kind() { - ty::Int(_) => CValue::by_val(fx.bcx.ins().ineg(val), layout), - ty::Float(_) => CValue::by_val(fx.bcx.ins().fneg(val), layout), - _ => unreachable!("un op Neg for {:?}", layout.ty), + } + UnOp::PtrMetadata => match layout.abi { + Abi::Scalar(_) => CValue::zst(dest_layout), + Abi::ScalarPair(_, _) => { + CValue::by_val(operand.load_scalar_pair(fx).1, dest_layout) + } + _ => bug!("Unexpected `PtrToMetadata` operand: {operand:?}"), }, }; lval.write_cvalue(fx, res); diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index 64e83e43d327..ba98f2e772cb 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -100,7 +100,7 @@ pub(crate) fn codegen_const_value<'tcx>( assert!(layout.is_sized(), "unsized const value"); if layout.is_zst() { - return CValue::by_ref(crate::Pointer::dangling(layout.align.pref), layout); + return CValue::zst(layout); } match const_val { diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index 4146137c2263..512a96450a4b 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -95,6 +95,14 @@ impl<'tcx> CValue<'tcx> { CValue(CValueInner::ByValPair(value, extra), layout) } + /// Create an instance of a ZST + /// + /// The is represented by a dangling pointer of suitable alignment. + pub(crate) fn zst(layout: TyAndLayout<'tcx>) -> CValue<'tcx> { + assert!(layout.is_zst()); + CValue::by_ref(crate::Pointer::dangling(layout.align.pref), layout) + } + pub(crate) fn layout(&self) -> TyAndLayout<'tcx> { self.1 } diff --git a/compiler/rustc_codegen_llvm/messages.ftl b/compiler/rustc_codegen_llvm/messages.ftl index d14fe0299e64..1c126e797621 100644 --- a/compiler/rustc_codegen_llvm/messages.ftl +++ b/compiler/rustc_codegen_llvm/messages.ftl @@ -18,6 +18,8 @@ codegen_llvm_error_creating_import_library = codegen_llvm_error_writing_def_file = Error writing .DEF file: {$error} +codegen_llvm_fixed_x18_invalid_arch = the `-Zfixed-x18` flag is not supported on the `{$arch}` architecture + codegen_llvm_from_llvm_diag = {$message} codegen_llvm_from_llvm_optimization_diag = {$filename}:{$line}:{$column} {$pass_name} ({$kind}): {$message} diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs index e15eda7c66c1..9d83dc811633 100644 --- a/compiler/rustc_codegen_llvm/src/errors.rs +++ b/compiler/rustc_codegen_llvm/src/errors.rs @@ -254,3 +254,9 @@ pub struct MismatchedDataLayout<'a> { pub(crate) struct InvalidTargetFeaturePrefix<'a> { pub feature: &'a str, } + +#[derive(Diagnostic)] +#[diag(codegen_llvm_fixed_x18_invalid_arch)] +pub(crate) struct FixedX18InvalidArch<'a> { + pub arch: &'a str, +} diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 5552b3810251..53b9b530e9bd 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -1,6 +1,6 @@ use crate::back::write::create_informational_target_machine; use crate::errors::{ - InvalidTargetFeaturePrefix, PossibleFeature, TargetFeatureDisableOrEnable, + FixedX18InvalidArch, InvalidTargetFeaturePrefix, PossibleFeature, TargetFeatureDisableOrEnable, UnknownCTargetFeature, UnknownCTargetFeaturePrefix, UnstableCTargetFeature, }; use crate::llvm; @@ -615,6 +615,15 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec VirtualIndex { VirtualIndex(index as u64) } - pub fn get_fn>( + fn get_fn_inner>( self, bx: &mut Bx, llvtable: Bx::Value, ty: Ty<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + nonnull: bool, ) -> Bx::Value { // Load the function pointer from the object. debug!("get_fn({llvtable:?}, {ty:?}, {self:?})"); @@ -41,13 +42,35 @@ impl<'a, 'tcx> VirtualIndex { } else { let gep = bx.inbounds_ptradd(llvtable, bx.const_usize(vtable_byte_offset)); let ptr = bx.load(llty, gep, ptr_align); - bx.nonnull_metadata(ptr); // VTable loads are invariant. bx.set_invariant_load(ptr); + if nonnull { + bx.nonnull_metadata(ptr); + } ptr } } + pub fn get_optional_fn>( + self, + bx: &mut Bx, + llvtable: Bx::Value, + ty: Ty<'tcx>, + fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + ) -> Bx::Value { + self.get_fn_inner(bx, llvtable, ty, fn_abi, false) + } + + pub fn get_fn>( + self, + bx: &mut Bx, + llvtable: Bx::Value, + ty: Ty<'tcx>, + fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + ) -> Bx::Value { + self.get_fn_inner(bx, llvtable, ty, fn_abi, true) + } + pub fn get_usize>( self, bx: &mut Bx, diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 1cb1ba99a5ab..bd9704b37aea 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -500,6 +500,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { &mut self, helper: TerminatorCodegenHelper<'tcx>, bx: &mut Bx, + source_info: &mir::SourceInfo, location: mir::Place<'tcx>, target: mir::BasicBlock, unwind: mir::UnwindAction, @@ -523,90 +524,106 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { args1 = [place.val.llval]; &args1[..] }; - let (drop_fn, fn_abi, drop_instance) = - match ty.kind() { - // FIXME(eddyb) perhaps move some of this logic into - // `Instance::resolve_drop_in_place`? - ty::Dynamic(_, _, ty::Dyn) => { - // IN THIS ARM, WE HAVE: - // ty = *mut (dyn Trait) - // which is: exists ( *mut T, Vtable ) - // args[0] args[1] - // - // args = ( Data, Vtable ) - // | - // v - // /-------\ - // | ... | - // \-------/ - // - let virtual_drop = Instance { - def: ty::InstanceDef::Virtual(drop_fn.def_id(), 0), // idx 0: the drop function - args: drop_fn.args, - }; - debug!("ty = {:?}", ty); - debug!("drop_fn = {:?}", drop_fn); - debug!("args = {:?}", args); - let fn_abi = bx.fn_abi_of_instance(virtual_drop, ty::List::empty()); - let vtable = args[1]; - // Truncate vtable off of args list - args = &args[..1]; - ( - meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_DROPINPLACE) - .get_fn(bx, vtable, ty, fn_abi), - fn_abi, - virtual_drop, - ) - } - ty::Dynamic(_, _, ty::DynStar) => { - // IN THIS ARM, WE HAVE: - // ty = *mut (dyn* Trait) - // which is: *mut exists (T, Vtable) - // - // args = [ * ] - // | - // v - // ( Data, Vtable ) - // | - // v - // /-------\ - // | ... | - // \-------/ - // - // - // WE CAN CONVERT THIS INTO THE ABOVE LOGIC BY DOING - // - // data = &(*args[0]).0 // gives a pointer to Data above (really the same pointer) - // vtable = (*args[0]).1 // loads the vtable out - // (data, vtable) // an equivalent Rust `*mut dyn Trait` - // - // SO THEN WE CAN USE THE ABOVE CODE. - let virtual_drop = Instance { - def: ty::InstanceDef::Virtual(drop_fn.def_id(), 0), // idx 0: the drop function - args: drop_fn.args, - }; - debug!("ty = {:?}", ty); - debug!("drop_fn = {:?}", drop_fn); - debug!("args = {:?}", args); - let fn_abi = bx.fn_abi_of_instance(virtual_drop, ty::List::empty()); - let meta_ptr = place.project_field(bx, 1); - let meta = bx.load_operand(meta_ptr); - // Truncate vtable off of args list - args = &args[..1]; - debug!("args' = {:?}", args); - ( - meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_DROPINPLACE) - .get_fn(bx, meta.immediate(), ty, fn_abi), - fn_abi, - virtual_drop, - ) - } - _ => ( - bx.get_fn_addr(drop_fn), - bx.fn_abi_of_instance(drop_fn, ty::List::empty()), - drop_fn, - ), - }; + let (maybe_null, drop_fn, fn_abi, drop_instance) = match ty.kind() { + // FIXME(eddyb) perhaps move some of this logic into + // `Instance::resolve_drop_in_place`? + ty::Dynamic(_, _, ty::Dyn) => { + // IN THIS ARM, WE HAVE: + // ty = *mut (dyn Trait) + // which is: exists ( *mut T, Vtable ) + // args[0] args[1] + // + // args = ( Data, Vtable ) + // | + // v + // /-------\ + // | ... | + // \-------/ + // + let virtual_drop = Instance { + def: ty::InstanceDef::Virtual(drop_fn.def_id(), 0), // idx 0: the drop function + args: drop_fn.args, + }; + debug!("ty = {:?}", ty); + debug!("drop_fn = {:?}", drop_fn); + debug!("args = {:?}", args); + let fn_abi = bx.fn_abi_of_instance(virtual_drop, ty::List::empty()); + let vtable = args[1]; + // Truncate vtable off of args list + args = &args[..1]; + ( + true, + meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_DROPINPLACE) + .get_optional_fn(bx, vtable, ty, fn_abi), + fn_abi, + virtual_drop, + ) + } + ty::Dynamic(_, _, ty::DynStar) => { + // IN THIS ARM, WE HAVE: + // ty = *mut (dyn* Trait) + // which is: *mut exists (T, Vtable) + // + // args = [ * ] + // | + // v + // ( Data, Vtable ) + // | + // v + // /-------\ + // | ... | + // \-------/ + // + // + // WE CAN CONVERT THIS INTO THE ABOVE LOGIC BY DOING + // + // data = &(*args[0]).0 // gives a pointer to Data above (really the same pointer) + // vtable = (*args[0]).1 // loads the vtable out + // (data, vtable) // an equivalent Rust `*mut dyn Trait` + // + // SO THEN WE CAN USE THE ABOVE CODE. + let virtual_drop = Instance { + def: ty::InstanceDef::Virtual(drop_fn.def_id(), 0), // idx 0: the drop function + args: drop_fn.args, + }; + debug!("ty = {:?}", ty); + debug!("drop_fn = {:?}", drop_fn); + debug!("args = {:?}", args); + let fn_abi = bx.fn_abi_of_instance(virtual_drop, ty::List::empty()); + let meta_ptr = place.project_field(bx, 1); + let meta = bx.load_operand(meta_ptr); + // Truncate vtable off of args list + args = &args[..1]; + debug!("args' = {:?}", args); + ( + true, + meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_DROPINPLACE) + .get_optional_fn(bx, meta.immediate(), ty, fn_abi), + fn_abi, + virtual_drop, + ) + } + _ => ( + false, + bx.get_fn_addr(drop_fn), + bx.fn_abi_of_instance(drop_fn, ty::List::empty()), + drop_fn, + ), + }; + + // We generate a null check for the drop_fn. This saves a bunch of relocations being + // generated for no-op drops. + if maybe_null { + let is_not_null = bx.append_sibling_block("is_not_null"); + let llty = bx.fn_ptr_backend_type(fn_abi); + let null = bx.const_null(llty); + let non_null = + bx.icmp(base::bin_op_to_icmp_predicate(mir::BinOp::Ne, false), drop_fn, null); + bx.cond_br(non_null, is_not_null, helper.llbb_with_cleanup(self, target)); + bx.switch_to_block(is_not_null); + self.set_debug_loc(bx, *source_info); + } + helper.do_call( self, bx, @@ -617,7 +634,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { unwind, &[], Some(drop_instance), - mergeable_succ, + !maybe_null && mergeable_succ, ) } @@ -1346,9 +1363,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { MergingSucc::False } - mir::TerminatorKind::Drop { place, target, unwind, replace: _ } => { - self.codegen_drop_terminator(helper, bx, place, target, unwind, mergeable_succ()) - } + mir::TerminatorKind::Drop { place, target, unwind, replace: _ } => self + .codegen_drop_terminator( + helper, + bx, + &terminator.source_info, + place, + target, + unwind, + mergeable_succ(), + ), mir::TerminatorKind::Assert { ref cond, expected, ref msg, target, unwind } => self .codegen_assert_terminator( diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 5b2f9a3be279..cc0e91396506 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -565,6 +565,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { for elem in place_ref.projection.iter() { match elem { mir::ProjectionElem::Field(ref f, _) => { + debug_assert!( + !o.layout.ty.is_any_ptr(), + "Bad PlaceRef: destructing pointers should use cast/PtrMetadata, \ + but tried to access field {f:?} of pointer {o:?}", + ); o = o.extract_field(bx, f.index()); } mir::ProjectionElem::Index(_) diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 7c3569a9dd2e..449fd9ae0db9 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -480,6 +480,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { cg_base = match *elem { mir::ProjectionElem::Deref => bx.load_operand(cg_base).deref(bx.cx()), mir::ProjectionElem::Field(ref field, _) => { + debug_assert!( + !cg_base.layout.ty.is_any_ptr(), + "Bad PlaceRef: destructing pointers should use cast/PtrMetadata, \ + but tried to access field {field:?} of pointer {cg_base:?}", + ); cg_base.project_field(bx, field.index()) } mir::ProjectionElem::OpaqueCast(ty) => { diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 4dd80d34ea70..c23867be3a10 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -623,19 +623,36 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::Rvalue::UnaryOp(op, ref operand) => { let operand = self.codegen_operand(bx, operand); - let lloperand = operand.immediate(); let is_float = operand.layout.ty.is_floating_point(); - let llval = match op { - mir::UnOp::Not => bx.not(lloperand), + let (val, layout) = match op { + mir::UnOp::Not => { + let llval = bx.not(operand.immediate()); + (OperandValue::Immediate(llval), operand.layout) + } mir::UnOp::Neg => { - if is_float { - bx.fneg(lloperand) + let llval = if is_float { + bx.fneg(operand.immediate()) } else { - bx.neg(lloperand) + bx.neg(operand.immediate()) + }; + (OperandValue::Immediate(llval), operand.layout) + } + mir::UnOp::PtrMetadata => { + debug_assert!(operand.layout.ty.is_unsafe_ptr()); + let (_, meta) = operand.val.pointer_parts(); + assert_eq!(operand.layout.fields.count() > 1, meta.is_some()); + if let Some(meta) = meta { + (OperandValue::Immediate(meta), operand.layout.field(self.cx, 1)) + } else { + (OperandValue::ZeroSized, bx.cx().layout_of(bx.tcx().types.unit)) } } }; - OperandRef { val: OperandValue::Immediate(llval), layout: operand.layout } + debug_assert!( + val.is_expected_variant_for_type(self.cx, layout), + "Made wrong variant {val:?} for type {layout:?}", + ); + OperandRef { val, layout } } mir::Rvalue::Discriminant(ref place) => { @@ -718,8 +735,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let values = op.val.immediates_or_place().left_or_else(|p| { bug!("Field {field_idx:?} is {p:?} making {layout:?}"); }); - inputs.extend(values); let scalars = self.value_kind(op.layout).scalars().unwrap(); + debug_assert_eq!(values.len(), scalars.len()); + inputs.extend(values); input_scalars.extend(scalars); } diff --git a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs index 62979af8a601..9a98677a8448 100644 --- a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs @@ -174,7 +174,7 @@ impl<'tcx> interpret::Machine<'tcx> for DummyMachine { unimplemented!() } - fn init_frame_extra( + fn init_frame( _ecx: &mut InterpCx<'tcx, Self>, _frame: interpret::Frame<'tcx, Self::Provenance>, ) -> interpret::InterpResult<'tcx, interpret::Frame<'tcx, Self::Provenance, Self::FrameExtra>> diff --git a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs index 8c66888d1007..3c11d67e7489 100644 --- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs @@ -38,7 +38,6 @@ fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Constness { match node { hir::Node::Ctor(_) | hir::Node::AnonConst(_) - | hir::Node::ConstBlock(_) | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. }) => { hir::Constness::Const } @@ -57,6 +56,7 @@ fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Constness { if is_const { hir::Constness::Const } else { hir::Constness::NotConst } } hir::Node::Expr(e) if let hir::ExprKind::Closure(c) = e.kind => c.constness, + hir::Node::Expr(e) if let hir::ExprKind::ConstBlock(_) = e.kind => hir::Constness::Const, _ => { if let Some(fn_kind) = node.fn_kind() { if fn_kind.constness() == hir::Constness::Const { diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 950e7c12da2e..79a161d3f03d 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -6,7 +6,6 @@ use std::ops::ControlFlow; use rustc_ast::Mutability; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::fx::IndexEntry; -use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_hir::def_id::LocalDefId; use rustc_hir::LangItem; @@ -392,18 +391,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeInterpreter<'tcx> { instance: ty::InstanceDef<'tcx>, ) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> { match instance { - ty::InstanceDef::Item(def) => { - if ecx.tcx.is_ctfe_mir_available(def) { - Ok(ecx.tcx.mir_for_ctfe(def)) - } else if ecx.tcx.def_kind(def) == DefKind::AssocConst { - ecx.tcx.dcx().bug("This is likely a const item that is missing from its impl"); - } else { - // `find_mir_or_eval_fn` checks that this is a const fn before even calling us, - // so this should be unreachable. - let path = ecx.tcx.def_path_str(def); - bug!("trying to call extern function `{path}` at compile-time"); - } - } + ty::InstanceDef::Item(def) => Ok(ecx.tcx.mir_for_ctfe(def)), _ => Ok(ecx.tcx.instance_mir(instance)), } } @@ -655,7 +643,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeInterpreter<'tcx> { } #[inline(always)] - fn init_frame_extra( + fn init_frame( ecx: &mut InterpCx<'tcx, Self>, frame: Frame<'tcx>, ) -> InterpResult<'tcx, Frame<'tcx>> { diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 737a70f335d0..19414c72c6a4 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -207,7 +207,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { assert!(cast_to.ty.is_unsafe_ptr()); // Handle casting any ptr to raw ptr (might be a fat ptr). if cast_to.size == src.layout.size { - // Thin or fat pointer that just hast the ptr kind of target type changed. + // Thin or fat pointer that just has the ptr kind of target type changed. return Ok(ImmTy::from_immediate(**src, cast_to)); } else { // Casting the metadata away from a fat ptr. diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 5cd50a928704..7c2100fcbe38 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -819,7 +819,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { tracing_span: SpanGuard::new(), extra: (), }; - let frame = M::init_frame_extra(self, pre_frame)?; + let frame = M::init_frame(self, pre_frame)?; self.stack_mut().push(frame); // Make sure all the constants required by this frame evaluate successfully (post-monomorphization check). diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 5713e7bd82b3..4ae0aca5a0c0 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -329,27 +329,41 @@ pub trait Machine<'tcx>: Sized { ptr: Pointer, ) -> Option<(AllocId, Size, Self::ProvenanceExtra)>; - /// Called to adjust allocations to the Provenance and AllocExtra of this machine. + /// Called to adjust global allocations to the Provenance and AllocExtra of this machine. /// /// If `alloc` contains pointers, then they are all pointing to globals. /// - /// The way we construct allocations is to always first construct it without extra and then add - /// the extra. This keeps uniform code paths for handling both allocations created by CTFE for - /// globals, and allocations created by Miri during evaluation. - /// - /// `kind` is the kind of the allocation being adjusted; it can be `None` when - /// it's a global and `GLOBAL_KIND` is `None`. - /// /// This should avoid copying if no work has to be done! If this returns an owned /// allocation (because a copy had to be done to adjust things), machine memory will /// cache the result. (This relies on `AllocMap::get_or` being able to add the /// owned allocation to the map even when the map is shared.) - fn adjust_allocation<'b>( + fn adjust_global_allocation<'b>( ecx: &InterpCx<'tcx, Self>, id: AllocId, - alloc: Cow<'b, Allocation>, - kind: Option>, - ) -> InterpResult<'tcx, Cow<'b, Allocation>>; + alloc: &'b Allocation, + ) -> InterpResult<'tcx, Cow<'b, Allocation>> + { + // The default implementation does a copy; CTFE machines have a more efficient implementation + // based on their particular choice for `Provenance`, `AllocExtra`, and `Bytes`. + let kind = Self::GLOBAL_KIND + .expect("if GLOBAL_KIND is None, adjust_global_allocation must be overwritten"); + let alloc = alloc.adjust_from_tcx(&ecx.tcx, |ptr| ecx.global_root_pointer(ptr))?; + let extra = + Self::init_alloc_extra(ecx, id, MemoryKind::Machine(kind), alloc.size(), alloc.align)?; + Ok(Cow::Owned(alloc.with_extra(extra))) + } + + /// Initialize the extra state of an allocation. + /// + /// This is guaranteed to be called exactly once on all allocations that are accessed by the + /// program. + fn init_alloc_extra( + ecx: &InterpCx<'tcx, Self>, + id: AllocId, + kind: MemoryKind, + size: Size, + align: Align, + ) -> InterpResult<'tcx, Self::AllocExtra>; /// Return a "root" pointer for the given allocation: the one that is used for direct /// accesses to this static/const/fn allocation, or the one returned from the heap allocator. @@ -473,7 +487,7 @@ pub trait Machine<'tcx>: Sized { } /// Called immediately before a new stack frame gets pushed. - fn init_frame_extra( + fn init_frame( ecx: &mut InterpCx<'tcx, Self>, frame: Frame<'tcx, Self::Provenance>, ) -> InterpResult<'tcx, Frame<'tcx, Self::Provenance, Self::FrameExtra>>; @@ -590,13 +604,23 @@ pub macro compile_time_machine(<$tcx: lifetime>) { } #[inline(always)] - fn adjust_allocation<'b>( + fn adjust_global_allocation<'b>( _ecx: &InterpCx<$tcx, Self>, _id: AllocId, - alloc: Cow<'b, Allocation>, - _kind: Option>, + alloc: &'b Allocation, ) -> InterpResult<$tcx, Cow<'b, Allocation>> { - Ok(alloc) + // Overwrite default implementation: no need to adjust anything. + Ok(Cow::Borrowed(alloc)) + } + + fn init_alloc_extra( + _ecx: &InterpCx<$tcx, Self>, + _id: AllocId, + _kind: MemoryKind, + _size: Size, + _align: Align, + ) -> InterpResult<$tcx, Self::AllocExtra> { + Ok(()) } fn extern_static_pointer( diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 40bbfaa92c6f..521f28b7123e 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -239,7 +239,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { pub fn allocate_raw_ptr( &mut self, - alloc: Allocation, + alloc: Allocation, kind: MemoryKind, ) -> InterpResult<'tcx, Pointer> { let id = self.tcx.reserve_alloc_id(); @@ -248,8 +248,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { M::GLOBAL_KIND.map(MemoryKind::Machine), "dynamically allocating global memory" ); - let alloc = M::adjust_allocation(self, id, Cow::Owned(alloc), Some(kind))?; - self.memory.alloc_map.insert(id, (kind, alloc.into_owned())); + // We have set things up so we don't need to call `adjust_from_tcx` here, + // so we avoid copying the entire allocation contents. + let extra = M::init_alloc_extra(self, id, kind, alloc.size(), alloc.align)?; + let alloc = alloc.with_extra(extra); + self.memory.alloc_map.insert(id, (kind, alloc)); M::adjust_alloc_root_pointer(self, Pointer::from(id), Some(kind)) } @@ -583,11 +586,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { }; M::before_access_global(self.tcx, &self.machine, id, alloc, def_id, is_write)?; // We got tcx memory. Let the machine initialize its "extra" stuff. - M::adjust_allocation( + M::adjust_global_allocation( self, id, // always use the ID we got as input, not the "hidden" one. - Cow::Borrowed(alloc.inner()), - M::GLOBAL_KIND.map(MemoryKind::Machine), + alloc.inner(), ) } diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index d23f0c4d45b0..6d005dfcd864 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -9,7 +9,7 @@ use rustc_middle::{bug, span_bug}; use rustc_span::symbol::sym; use tracing::trace; -use super::{err_ub, throw_ub, ImmTy, InterpCx, Machine}; +use super::{err_ub, throw_ub, ImmTy, InterpCx, Machine, MemPlaceMeta}; impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { fn three_way_compare(&self, lhs: T, rhs: T) -> ImmTy<'tcx, M::Provenance> { @@ -415,11 +415,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { use rustc_middle::mir::UnOp::*; let layout = val.layout; - let val = val.to_scalar(); trace!("Running unary op {:?}: {:?} ({})", un_op, val, layout.ty); match layout.ty.kind() { ty::Bool => { + let val = val.to_scalar(); let val = val.to_bool()?; let res = match un_op { Not => !val, @@ -428,6 +428,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Ok(ImmTy::from_bool(res, *self.tcx)) } ty::Float(fty) => { + let val = val.to_scalar(); // No NaN adjustment here, `-` is a bitwise operation! let res = match (un_op, fty) { (Neg, FloatTy::F32) => Scalar::from_f32(-val.to_f32()?), @@ -436,8 +437,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { }; Ok(ImmTy::from_scalar(res, layout)) } - _ => { - assert!(layout.ty.is_integral()); + _ if layout.ty.is_integral() => { + let val = val.to_scalar(); let val = val.to_bits(layout.size)?; let res = match un_op { Not => self.truncate(!val, layout), // bitwise negation, then truncate @@ -450,9 +451,28 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Truncate to target type. self.truncate(res, layout) } + _ => span_bug!(self.cur_span(), "Invalid integer op {:?}", un_op), }; Ok(ImmTy::from_uint(res, layout)) } + ty::RawPtr(..) => { + assert_eq!(un_op, PtrMetadata); + let (_, meta) = val.to_scalar_and_meta(); + Ok(match meta { + MemPlaceMeta::Meta(scalar) => { + let ty = un_op.ty(*self.tcx, val.layout.ty); + let layout = self.layout_of(ty)?; + ImmTy::from_scalar(scalar, layout) + } + MemPlaceMeta::None => { + let unit_layout = self.layout_of(self.tcx.types.unit)?; + ImmTy::uninit(unit_layout) + } + }) + } + _ => { + bug!("Unexpected unary op argument {val:?}") + } } } } diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 2bd58680eef5..08b97b4953e9 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -804,6 +804,39 @@ fn print_crate_info( println_info!("{cfg}"); } } + CheckCfg => { + let mut check_cfgs: Vec = Vec::with_capacity(410); + + // INSTABILITY: We are sorting the output below. + #[allow(rustc::potential_query_instability)] + for (name, expected_values) in &sess.psess.check_config.expecteds { + use crate::config::ExpectedValues; + match expected_values { + ExpectedValues::Any => check_cfgs.push(format!("{name}=any()")), + ExpectedValues::Some(values) => { + check_cfgs.extend(values.iter().map(|value| { + if let Some(value) = value { + format!("{name}=\"{value}\"") + } else { + name.to_string() + } + })) + } + } + } + + check_cfgs.sort_unstable(); + if !sess.psess.check_config.exhaustive_names { + if !sess.psess.check_config.exhaustive_values { + println_info!("any()=any()"); + } else { + println_info!("any()"); + } + } + for check_cfg in check_cfgs { + println_info!("{check_cfg}"); + } + } CallingConventions => { let mut calling_conventions = rustc_target::spec::abi::all_names(); calling_conventions.sort_unstable(); diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 2f4dcdbdf2b1..e64f7aeb11b3 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -876,6 +876,9 @@ pub struct OwnerNodes<'tcx> { pub nodes: IndexVec>, /// Content of local bodies. pub bodies: SortedMap>, + /// Whether the body contains inline constants that are created for the query system during typeck + /// of the body. + pub has_inline_consts: bool, } impl<'tcx> OwnerNodes<'tcx> { @@ -1592,14 +1595,6 @@ pub struct AnonConst { pub span: Span, } -/// An inline constant expression `const { something }`. -#[derive(Copy, Clone, Debug, HashStable_Generic)] -pub struct ConstBlock { - pub hir_id: HirId, - pub def_id: LocalDefId, - pub body: BodyId, -} - /// An expression. #[derive(Debug, Clone, Copy, HashStable_Generic)] pub struct Expr<'hir> { @@ -1886,7 +1881,7 @@ pub fn is_range_literal(expr: &Expr<'_>) -> bool { #[derive(Debug, Clone, Copy, HashStable_Generic)] pub enum ExprKind<'hir> { /// Allow anonymous constants from an inline `const` block - ConstBlock(ConstBlock), + ConstBlock(&'hir Expr<'hir>), /// An array (e.g., `[a, b, c, d]`). Array(&'hir [Expr<'hir>]), /// A function call. @@ -3609,7 +3604,6 @@ pub enum Node<'hir> { Variant(&'hir Variant<'hir>), Field(&'hir FieldDef<'hir>), AnonConst(&'hir AnonConst), - ConstBlock(&'hir ConstBlock), Expr(&'hir Expr<'hir>), ExprField(&'hir ExprField<'hir>), Stmt(&'hir Stmt<'hir>), @@ -3670,7 +3664,6 @@ impl<'hir> Node<'hir> { Node::PreciseCapturingNonLifetimeArg(a) => Some(a.ident), Node::Param(..) | Node::AnonConst(..) - | Node::ConstBlock(..) | Node::Expr(..) | Node::Stmt(..) | Node::Block(..) @@ -3768,7 +3761,6 @@ impl<'hir> Node<'hir> { } Node::AnonConst(constant) => Some((constant.def_id, constant.body)), - Node::ConstBlock(constant) => Some((constant.def_id, constant.body)), _ => None, } @@ -3837,7 +3829,6 @@ impl<'hir> Node<'hir> { expect_variant, &'hir Variant<'hir>, Node::Variant(n), n; expect_field, &'hir FieldDef<'hir>, Node::Field(n), n; expect_anon_const, &'hir AnonConst, Node::AnonConst(n), n; - expect_inline_const, &'hir ConstBlock, Node::ConstBlock(n), n; expect_expr, &'hir Expr<'hir>, Node::Expr(n), n; expect_expr_field, &'hir ExprField<'hir>, Node::ExprField(n), n; expect_stmt, &'hir Stmt<'hir>, Node::Stmt(n), n; diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index b202ea8dca37..aba0532f0d1e 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -344,9 +344,6 @@ pub trait Visitor<'v>: Sized { fn visit_anon_const(&mut self, c: &'v AnonConst) -> Self::Result { walk_anon_const(self, c) } - fn visit_inline_const(&mut self, c: &'v ConstBlock) -> Self::Result { - walk_inline_const(self, c) - } fn visit_expr(&mut self, ex: &'v Expr<'v>) -> Self::Result { walk_expr(self, ex) } @@ -716,14 +713,6 @@ pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonCo visitor.visit_nested_body(constant.body) } -pub fn walk_inline_const<'v, V: Visitor<'v>>( - visitor: &mut V, - constant: &'v ConstBlock, -) -> V::Result { - try_visit!(visitor.visit_id(constant.hir_id)); - visitor.visit_nested_body(constant.body) -} - pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) -> V::Result { try_visit!(visitor.visit_id(expression.hir_id)); match expression.kind { @@ -731,7 +720,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) walk_list!(visitor, visit_expr, subexpressions); } ExprKind::ConstBlock(ref const_block) => { - try_visit!(visitor.visit_inline_const(const_block)) + try_visit!(visitor.visit_expr(const_block)) } ExprKind::Repeat(ref element, ref count) => { try_visit!(visitor.visit_expr(element)); diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index c4be67cdd887..f5f7bae11b20 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -228,13 +228,18 @@ language_item_table! { AsyncFn, sym::async_fn, async_fn_trait, Target::Trait, GenericRequirement::Exact(1); AsyncFnMut, sym::async_fn_mut, async_fn_mut_trait, Target::Trait, GenericRequirement::Exact(1); AsyncFnOnce, sym::async_fn_once, async_fn_once_trait, Target::Trait, GenericRequirement::Exact(1); - AsyncFnKindHelper, sym::async_fn_kind_helper,async_fn_kind_helper, Target::Trait, GenericRequirement::Exact(1); + AsyncFnOnceOutput, sym::async_fn_once_output, async_fn_once_output, Target::AssocTy, GenericRequirement::Exact(1); + CallOnceFuture, sym::call_once_future, call_once_future, Target::AssocTy, GenericRequirement::Exact(1); + CallRefFuture, sym::call_ref_future, call_ref_future, Target::AssocTy, GenericRequirement::Exact(2); + AsyncFnKindHelper, sym::async_fn_kind_helper, async_fn_kind_helper, Target::Trait, GenericRequirement::Exact(1); + AsyncFnKindUpvars, sym::async_fn_kind_upvars, async_fn_kind_upvars, Target::AssocTy, GenericRequirement::Exact(5); FnOnceOutput, sym::fn_once_output, fn_once_output, Target::AssocTy, GenericRequirement::None; Iterator, sym::iterator, iterator_trait, Target::Trait, GenericRequirement::Exact(0); FusedIterator, sym::fused_iterator, fused_iterator_trait, Target::Trait, GenericRequirement::Exact(0); Future, sym::future_trait, future_trait, Target::Trait, GenericRequirement::Exact(0); + FutureOutput, sym::future_output, future_output, Target::AssocTy, GenericRequirement::Exact(0); AsyncIterator, sym::async_iterator, async_iterator_trait, Target::Trait, GenericRequirement::Exact(0); CoroutineState, sym::coroutine_state, coroutine_state, Target::Enum, GenericRequirement::None; diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs index baa1635f7313..1ebd4b80e183 100644 --- a/compiler/rustc_hir/src/stable_hash_impls.rs +++ b/compiler/rustc_hir/src/stable_hash_impls.rs @@ -93,7 +93,8 @@ impl<'tcx, HirCtx: crate::HashStableContext> HashStable for OwnerNodes<' // `local_id_to_def_id` is also ignored because is dependent on the body, then just hashing // the body satisfies the condition of two nodes being different have different // `hash_stable` results. - let OwnerNodes { opt_hash_including_bodies, nodes: _, bodies: _ } = *self; + let OwnerNodes { opt_hash_including_bodies, nodes: _, bodies: _, has_inline_consts: _ } = + *self; opt_hash_including_bodies.unwrap().hash_stable(hcx, hasher); } } diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 8506b8d75f95..f7989aeab41b 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -130,6 +130,7 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) - | sym::is_val_statically_known | sym::ptr_mask | sym::aggregate_raw_ptr + | sym::ptr_metadata | sym::ub_checks | sym::fadd_algebraic | sym::fsub_algebraic @@ -576,6 +577,7 @@ pub fn check_intrinsic_type( // This type check is not particularly useful, but the `where` bounds // on the definition in `core` do the heavy lifting for checking it. sym::aggregate_raw_ptr => (3, 1, vec![param(1), param(2)], param(0)), + sym::ptr_metadata => (2, 1, vec![Ty::new_imm_ptr(tcx, param(0))], param(1)), sym::ub_checks => (0, 1, Vec::new(), tcx.types.bool), diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index e51f95eed021..8b0adebfaf46 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -407,11 +407,14 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h match expr.kind { // Manually recurse over closures and inline consts, because they are the only // case of nested bodies that share the parent environment. - hir::ExprKind::Closure(&hir::Closure { body, .. }) - | hir::ExprKind::ConstBlock(hir::ConstBlock { body, .. }) => { + hir::ExprKind::Closure(&hir::Closure { body, .. }) => { let body = visitor.tcx.hir().body(body); visitor.visit_body(body); } + hir::ExprKind::ConstBlock(expr) => visitor.enter_body(expr.hir_id, |this| { + this.cx.var_parent = None; + resolve_local(this, None, Some(expr)); + }), hir::ExprKind::AssignOp(_, left_expr, right_expr) => { debug!( "resolve_expr - enabling pessimistic_yield, was previously {}", @@ -782,6 +785,32 @@ impl<'tcx> RegionResolutionVisitor<'tcx> { } self.enter_scope(Scope { id, data: ScopeData::Node }); } + + fn enter_body(&mut self, hir_id: hir::HirId, f: impl FnOnce(&mut Self)) { + // Save all state that is specific to the outer function + // body. These will be restored once down below, once we've + // visited the body. + let outer_ec = mem::replace(&mut self.expr_and_pat_count, 0); + let outer_cx = self.cx; + let outer_ts = mem::take(&mut self.terminating_scopes); + // The 'pessimistic yield' flag is set to true when we are + // processing a `+=` statement and have to make pessimistic + // control flow assumptions. This doesn't apply to nested + // bodies within the `+=` statements. See #69307. + let outer_pessimistic_yield = mem::replace(&mut self.pessimistic_yield, false); + self.terminating_scopes.insert(hir_id.local_id); + + self.enter_scope(Scope { id: hir_id.local_id, data: ScopeData::CallSite }); + self.enter_scope(Scope { id: hir_id.local_id, data: ScopeData::Arguments }); + + f(self); + + // Restore context we had at the start. + self.expr_and_pat_count = outer_ec; + self.cx = outer_cx; + self.terminating_scopes = outer_ts; + self.pessimistic_yield = outer_pessimistic_yield; + } } impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> { @@ -801,60 +830,40 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> { self.cx.parent ); - // Save all state that is specific to the outer function - // body. These will be restored once down below, once we've - // visited the body. - let outer_ec = mem::replace(&mut self.expr_and_pat_count, 0); - let outer_cx = self.cx; - let outer_ts = mem::take(&mut self.terminating_scopes); - // The 'pessimistic yield' flag is set to true when we are - // processing a `+=` statement and have to make pessimistic - // control flow assumptions. This doesn't apply to nested - // bodies within the `+=` statements. See #69307. - let outer_pessimistic_yield = mem::replace(&mut self.pessimistic_yield, false); - self.terminating_scopes.insert(body.value.hir_id.local_id); + self.enter_body(body.value.hir_id, |this| { + if this.tcx.hir().body_owner_kind(owner_id).is_fn_or_closure() { + // The arguments and `self` are parented to the fn. + this.cx.var_parent = this.cx.parent.take(); + for param in body.params { + this.visit_pat(param.pat); + } - self.enter_scope(Scope { id: body.value.hir_id.local_id, data: ScopeData::CallSite }); - self.enter_scope(Scope { id: body.value.hir_id.local_id, data: ScopeData::Arguments }); - - // The arguments and `self` are parented to the fn. - self.cx.var_parent = self.cx.parent.take(); - for param in body.params { - self.visit_pat(param.pat); - } - - // The body of the every fn is a root scope. - self.cx.parent = self.cx.var_parent; - if self.tcx.hir().body_owner_kind(owner_id).is_fn_or_closure() { - self.visit_expr(body.value) - } else { - // Only functions have an outer terminating (drop) scope, while - // temporaries in constant initializers may be 'static, but only - // according to rvalue lifetime semantics, using the same - // syntactical rules used for let initializers. - // - // e.g., in `let x = &f();`, the temporary holding the result from - // the `f()` call lives for the entirety of the surrounding block. - // - // Similarly, `const X: ... = &f();` would have the result of `f()` - // live for `'static`, implying (if Drop restrictions on constants - // ever get lifted) that the value *could* have a destructor, but - // it'd get leaked instead of the destructor running during the - // evaluation of `X` (if at all allowed by CTFE). - // - // However, `const Y: ... = g(&f());`, like `let y = g(&f());`, - // would *not* let the `f()` temporary escape into an outer scope - // (i.e., `'static`), which means that after `g` returns, it drops, - // and all the associated destruction scope rules apply. - self.cx.var_parent = None; - resolve_local(self, None, Some(body.value)); - } - - // Restore context we had at the start. - self.expr_and_pat_count = outer_ec; - self.cx = outer_cx; - self.terminating_scopes = outer_ts; - self.pessimistic_yield = outer_pessimistic_yield; + // The body of the every fn is a root scope. + this.cx.parent = this.cx.var_parent; + this.visit_expr(body.value) + } else { + // Only functions have an outer terminating (drop) scope, while + // temporaries in constant initializers may be 'static, but only + // according to rvalue lifetime semantics, using the same + // syntactical rules used for let initializers. + // + // e.g., in `let x = &f();`, the temporary holding the result from + // the `f()` call lives for the entirety of the surrounding block. + // + // Similarly, `const X: ... = &f();` would have the result of `f()` + // live for `'static`, implying (if Drop restrictions on constants + // ever get lifted) that the value *could* have a destructor, but + // it'd get leaked instead of the destructor running during the + // evaluation of `X` (if at all allowed by CTFE). + // + // However, `const Y: ... = g(&f());`, like `let y = g(&f());`, + // would *not* let the `f()` temporary escape into an outer scope + // (i.e., `'static`), which means that after `g` returns, it drops, + // and all the associated destruction scope rules apply. + this.cx.var_parent = None; + resolve_local(this, None, Some(body.value)); + } + }) } fn visit_arm(&mut self, a: &'tcx Arm<'tcx>) { diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 75e35e7bf50c..7e7460061484 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1478,7 +1478,7 @@ pub fn suggest_impl_trait<'tcx>( ), ( infcx.tcx.lang_items().future_trait(), - infcx.tcx.get_diagnostic_item(sym::FutureOutput), + infcx.tcx.lang_items().future_output(), format_as_assoc, ), ( diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index abdf85ad707b..9af959681fbf 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -177,10 +177,10 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { } } } - Node::ConstBlock(_) - | Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => { - Some(tcx.typeck_root_def_id(def_id.to_def_id())) - } + Node::Expr(&hir::Expr { + kind: hir::ExprKind::Closure { .. } | hir::ExprKind::ConstBlock { .. }, + .. + }) => Some(tcx.typeck_root_def_id(def_id.to_def_id())), Node::Item(item) => match item.kind { ItemKind::OpaqueTy(&hir::OpaqueTy { origin: @@ -415,7 +415,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { } // provide junk type parameter defs for const blocks. - if let Node::ConstBlock(_) = node { + if let Node::Expr(Expr { kind: ExprKind::ConstBlock(..), .. }) = node { own_params.push(ty::GenericParamDef { index: next_index(), name: Symbol::intern(""), diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index ed942cc50bb4..d497617f6449 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -484,8 +484,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ } Node::AnonConst(_) => anon_const_type_of(tcx, def_id), - - Node::ConstBlock(_) => { + Node::Expr(&Expr { kind: ExprKind::ConstBlock(..), .. }) => { let args = ty::GenericArgs::identity_for_item(tcx, def_id.to_def_id()); args.as_inline_const().ty() } diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 8fe81851f932..65b02a2ec565 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -190,10 +190,6 @@ pub fn check_crate(tcx: TyCtxt<'_>) { } }); - // Freeze definitions as we don't add new ones at this point. This improves performance by - // allowing lock-free access to them. - tcx.untracked().definitions.freeze(); - // FIXME: Remove this when we implement creating `DefId`s // for anon constants during their parents' typeck. // Typeck all body owners in parallel will produce queries @@ -205,6 +201,10 @@ pub fn check_crate(tcx: TyCtxt<'_>) { } }); + // Freeze definitions as we don't add new ones at this point. This improves performance by + // allowing lock-free access to them. + tcx.untracked().definitions.freeze(); + tcx.ensure().check_unused_traits(()); } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 488537e81bec..62abdf0afabf 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -84,7 +84,6 @@ impl<'a> State<'a> { Node::ImplItem(a) => self.print_impl_item(a), Node::Variant(a) => self.print_variant(a), Node::AnonConst(a) => self.print_anon_const(a), - Node::ConstBlock(a) => self.print_inline_const(a), Node::Expr(a) => self.print_expr(a), Node::ExprField(a) => self.print_expr_field(a), Node::Stmt(a) => self.print_stmt(a), @@ -1049,10 +1048,10 @@ impl<'a> State<'a> { self.end() } - fn print_inline_const(&mut self, constant: &hir::ConstBlock) { + fn print_inline_const(&mut self, constant: &hir::Expr<'_>) { self.ibox(INDENT_UNIT); self.word_space("const"); - self.ann.nested(self, Nested::Body(constant.body)); + self.print_expr(constant); self.end() } diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index ebdc558282a9..93726ce2b3eb 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1158,7 +1158,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (a_sig, b_sig) = self.normalize(new.span, (a_sig, b_sig)); let sig = self .at(cause, self.param_env) - .trace(prev_ty, new_ty) .lub(DefineOpaqueTypes::Yes, a_sig, b_sig) .map(|ok| self.register_infer_ok_obligations(ok))?; diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index fade943c5ae3..364f0fec202a 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -32,7 +32,6 @@ use rustc_errors::{ use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefId; -use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; use rustc_hir::{ExprKind, HirId, QPath}; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer as _; @@ -336,7 +335,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } ExprKind::DropTemps(e) => self.check_expr_with_expectation(e, expected), ExprKind::Array(args) => self.check_expr_array(args, expected, expr), - ExprKind::ConstBlock(ref block) => self.check_expr_const_block(block, expected), + ExprKind::ConstBlock(ref block) => self.check_expr_with_expectation(block, expected), ExprKind::Repeat(element, ref count) => { self.check_expr_repeat(element, count, expected, expr) } @@ -1460,24 +1459,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - fn check_expr_const_block( - &self, - block: &'tcx hir::ConstBlock, - expected: Expectation<'tcx>, - ) -> Ty<'tcx> { - let body = self.tcx.hir().body(block.body); - - // Create a new function context. - let def_id = block.def_id; - let fcx = FnCtxt::new(self, self.param_env, def_id); - crate::GatherLocalsVisitor::new(&fcx).visit_body(body); - - let ty = fcx.check_expr_with_expectation(body.value, expected); - fcx.require_type_is_sized(ty, body.value.span, ObligationCauseCode::ConstSized); - fcx.write_ty(block.hir_id, ty); - ty - } - fn check_expr_repeat( &self, element: &'tcx hir::Expr<'tcx>, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index cfd4dd4d1dd0..0d7f59c48715 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1055,6 +1055,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .take_while(|(_, node)| { // look at parents until we find the first body owner node.body_id().is_none() + && !matches!( + node, + Node::Expr(Expr { kind: ExprKind::ConstBlock { .. }, .. }) + ) }) .any(|(parent_id, _)| self.is_loop(parent_id)); diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 466397817dae..4386e68ce867 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -149,10 +149,6 @@ impl<'a, 'tcx> Visitor<'tcx> for InferBorrowKindVisitor<'a, 'tcx> { self.visit_body(body); self.fcx.analyze_closure(expr.hir_id, expr.span, body_id, body, capture_clause); } - hir::ExprKind::ConstBlock(anon_const) => { - let body = self.fcx.tcx.hir().body(anon_const.body); - self.visit_body(body); - } _ => {} } diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index f798deea207a..31caa52d2671 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -3,6 +3,7 @@ // generic parameters. use crate::FnCtxt; +use hir::def::DefKind; use rustc_data_structures::unord::ExtendUnord; use rustc_errors::{ErrorGuaranteed, StashKey}; use rustc_hir as hir; @@ -16,7 +17,7 @@ use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::TypeSuperFoldable; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_span::symbol::sym; +use rustc_span::symbol::{kw, sym}; use rustc_span::Span; use rustc_trait_selection::solve; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; @@ -295,11 +296,11 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { hir::ExprKind::Field(..) | hir::ExprKind::OffsetOf(..) => { self.visit_field_id(e.hir_id); } - hir::ExprKind::ConstBlock(anon_const) => { - self.visit_node_id(e.span, anon_const.hir_id); - - let body = self.tcx().hir().body(anon_const.body); - self.visit_body(body); + hir::ExprKind::ConstBlock(_) => { + let feed = self.tcx().create_def(self.fcx.body_id, kw::Empty, DefKind::InlineConst); + feed.def_span(e.span); + feed.local_def_id_to_hir_id(e.hir_id); + self.typeck_results.inline_consts.insert(e.hir_id.local_id, feed.def_id()); } _ => {} } diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 16057b6ad9dc..17e6d6250ad5 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -48,11 +48,6 @@ pub struct At<'a, 'tcx> { pub param_env: ty::ParamEnv<'tcx>, } -pub struct Trace<'a, 'tcx> { - at: At<'a, 'tcx>, - trace: TypeTrace<'tcx>, -} - impl<'tcx> InferCtxt<'tcx> { #[inline] pub fn at<'a>( @@ -109,9 +104,6 @@ impl<'a, 'tcx> At<'a, 'tcx> { /// call like `foo(x)`, where `foo: fn(i32)`, you might have /// `sup(i32, x)`, since the "expected" type is the type that /// appears in the signature. - /// - /// See [`At::trace`] and [`Trace::sub`] for a version of - /// this method that only requires `T: Relate<'tcx>` pub fn sup( self, define_opaque_types: DefineOpaqueTypes, @@ -121,13 +113,19 @@ impl<'a, 'tcx> At<'a, 'tcx> { where T: ToTrace<'tcx>, { - self.trace(expected, actual).sup(define_opaque_types, expected, actual) + let mut fields = CombineFields::new( + self.infcx, + ToTrace::to_trace(self.cause, true, expected, actual), + self.param_env, + define_opaque_types, + ); + fields + .sup() + .relate(expected, actual) + .map(|_| InferOk { value: (), obligations: fields.obligations }) } /// Makes `expected <: actual`. - /// - /// See [`At::trace`] and [`Trace::sub`] for a version of - /// this method that only requires `T: Relate<'tcx>` pub fn sub( self, define_opaque_types: DefineOpaqueTypes, @@ -137,13 +135,19 @@ impl<'a, 'tcx> At<'a, 'tcx> { where T: ToTrace<'tcx>, { - self.trace(expected, actual).sub(define_opaque_types, expected, actual) + let mut fields = CombineFields::new( + self.infcx, + ToTrace::to_trace(self.cause, true, expected, actual), + self.param_env, + define_opaque_types, + ); + fields + .sub() + .relate(expected, actual) + .map(|_| InferOk { value: (), obligations: fields.obligations }) } - /// Makes `expected <: actual`. - /// - /// See [`At::trace`] and [`Trace::eq`] for a version of - /// this method that only requires `T: Relate<'tcx>` + /// Makes `expected == actual`. pub fn eq( self, define_opaque_types: DefineOpaqueTypes, @@ -153,7 +157,40 @@ impl<'a, 'tcx> At<'a, 'tcx> { where T: ToTrace<'tcx>, { - self.trace(expected, actual).eq(define_opaque_types, expected, actual) + let mut fields = CombineFields::new( + self.infcx, + ToTrace::to_trace(self.cause, true, expected, actual), + self.param_env, + define_opaque_types, + ); + fields + .equate(StructurallyRelateAliases::No) + .relate(expected, actual) + .map(|_| InferOk { value: (), obligations: fields.obligations }) + } + + /// Equates `expected` and `found` while structurally relating aliases. + /// This should only be used inside of the next generation trait solver + /// when relating rigid aliases. + pub fn eq_structurally_relating_aliases( + self, + expected: T, + actual: T, + ) -> InferResult<'tcx, ()> + where + T: ToTrace<'tcx>, + { + assert!(self.infcx.next_trait_solver()); + let mut fields = CombineFields::new( + self.infcx, + ToTrace::to_trace(self.cause, true, expected, actual), + self.param_env, + DefineOpaqueTypes::Yes, + ); + fields + .equate(StructurallyRelateAliases::Yes) + .relate(expected, actual) + .map(|_| InferOk { value: (), obligations: fields.obligations }) } pub fn relate( @@ -185,9 +222,6 @@ impl<'a, 'tcx> At<'a, 'tcx> { /// this can result in an error (e.g., if asked to compute LUB of /// u32 and i32), it is meaningful to call one of them the /// "expected type". - /// - /// See [`At::trace`] and [`Trace::lub`] for a version of - /// this method that only requires `T: Relate<'tcx>` pub fn lub( self, define_opaque_types: DefineOpaqueTypes, @@ -197,15 +231,21 @@ impl<'a, 'tcx> At<'a, 'tcx> { where T: ToTrace<'tcx>, { - self.trace(expected, actual).lub(define_opaque_types, expected, actual) + let mut fields = CombineFields::new( + self.infcx, + ToTrace::to_trace(self.cause, true, expected, actual), + self.param_env, + define_opaque_types, + ); + fields + .lub() + .relate(expected, actual) + .map(|value| InferOk { value, obligations: fields.obligations }) } /// Computes the greatest-lower-bound, or mutual subtype, of two /// values. As with `lub` order doesn't matter, except for error /// cases. - /// - /// See [`At::trace`] and [`Trace::glb`] for a version of - /// this method that only requires `T: Relate<'tcx>` pub fn glb( self, define_opaque_types: DefineOpaqueTypes, @@ -215,105 +255,16 @@ impl<'a, 'tcx> At<'a, 'tcx> { where T: ToTrace<'tcx>, { - self.trace(expected, actual).glb(define_opaque_types, expected, actual) - } - - /// Sets the "trace" values that will be used for - /// error-reporting, but doesn't actually perform any operation - /// yet (this is useful when you want to set the trace using - /// distinct values from those you wish to operate upon). - pub fn trace(self, expected: T, actual: T) -> Trace<'a, 'tcx> - where - T: ToTrace<'tcx>, - { - let trace = ToTrace::to_trace(self.cause, true, expected, actual); - Trace { at: self, trace } - } -} - -impl<'a, 'tcx> Trace<'a, 'tcx> { - /// Makes `a <: b`. - #[instrument(skip(self), level = "debug")] - pub fn sub(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, ()> - where - T: Relate<'tcx>, - { - let Trace { at, trace } = self; - let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types); - fields - .sub() - .relate(a, b) - .map(move |_| InferOk { value: (), obligations: fields.obligations }) - } - - /// Makes `a :> b`. - #[instrument(skip(self), level = "debug")] - pub fn sup(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, ()> - where - T: Relate<'tcx>, - { - let Trace { at, trace } = self; - let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types); - fields - .sup() - .relate(a, b) - .map(move |_| InferOk { value: (), obligations: fields.obligations }) - } - - /// Makes `a == b`. - #[instrument(skip(self), level = "debug")] - pub fn eq(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, ()> - where - T: Relate<'tcx>, - { - let Trace { at, trace } = self; - let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types); - fields - .equate(StructurallyRelateAliases::No) - .relate(a, b) - .map(move |_| InferOk { value: (), obligations: fields.obligations }) - } - - /// Equates `a` and `b` while structurally relating aliases. This should only - /// be used inside of the next generation trait solver when relating rigid aliases. - #[instrument(skip(self), level = "debug")] - pub fn eq_structurally_relating_aliases(self, a: T, b: T) -> InferResult<'tcx, ()> - where - T: Relate<'tcx>, - { - let Trace { at, trace } = self; - debug_assert!(at.infcx.next_trait_solver()); - let mut fields = at.infcx.combine_fields(trace, at.param_env, DefineOpaqueTypes::Yes); - fields - .equate(StructurallyRelateAliases::Yes) - .relate(a, b) - .map(move |_| InferOk { value: (), obligations: fields.obligations }) - } - - #[instrument(skip(self), level = "debug")] - pub fn lub(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, T> - where - T: Relate<'tcx>, - { - let Trace { at, trace } = self; - let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types); - fields - .lub() - .relate(a, b) - .map(move |t| InferOk { value: t, obligations: fields.obligations }) - } - - #[instrument(skip(self), level = "debug")] - pub fn glb(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, T> - where - T: Relate<'tcx>, - { - let Trace { at, trace } = self; - let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types); + let mut fields = CombineFields::new( + self.infcx, + ToTrace::to_trace(self.cause, true, expected, actual), + self.param_env, + define_opaque_types, + ); fields .glb() - .relate(a, b) - .map(move |t| InferOk { value: t, obligations: fields.obligations }) + .relate(expected, actual) + .map(|value| InferOk { value, obligations: fields.obligations }) } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 7ab148e70a13..95fbc1e66cea 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2102,10 +2102,15 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // If a string was expected and the found expression is a character literal, // perhaps the user meant to write `"s"` to specify a string literal. (ty::Ref(_, r, _), ty::Char) if r.is_str() => { - suggestions.push(TypeErrorAdditionalDiags::MeantStrLiteral { - start: span.with_hi(span.lo() + BytePos(1)), - end: span.with_lo(span.hi() - BytePos(1)), - }) + if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) + && code.starts_with("'") + && code.ends_with("'") + { + suggestions.push(TypeErrorAdditionalDiags::MeantStrLiteral { + start: span.with_hi(span.lo() + BytePos(1)), + end: span.with_lo(span.hi() - BytePos(1)), + }); + } } // For code `if Some(..) = expr `, the type mismatch may be expected `bool` but found `()`, // we try to suggest to add the missing `let` for `if let Some(..) = expr` diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 6f603d9b612e..c8bb6cf5f9b4 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -836,21 +836,6 @@ impl<'tcx> InferCtxt<'tcx> { .collect() } - fn combine_fields<'a>( - &'a self, - trace: TypeTrace<'tcx>, - param_env: ty::ParamEnv<'tcx>, - define_opaque_types: DefineOpaqueTypes, - ) -> CombineFields<'a, 'tcx> { - CombineFields { - infcx: self, - trace, - param_env, - obligations: PredicateObligations::new(), - define_opaque_types, - } - } - pub fn can_sub(&self, param_env: ty::ParamEnv<'tcx>, expected: T, actual: T) -> bool where T: at::ToTrace<'tcx>, diff --git a/compiler/rustc_infer/src/infer/relate/combine.rs b/compiler/rustc_infer/src/infer/relate/combine.rs index 7e7d4f43c7cc..6b41e4506846 100644 --- a/compiler/rustc_infer/src/infer/relate/combine.rs +++ b/compiler/rustc_infer/src/infer/relate/combine.rs @@ -42,6 +42,17 @@ pub struct CombineFields<'infcx, 'tcx> { pub define_opaque_types: DefineOpaqueTypes, } +impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { + pub fn new( + infcx: &'infcx InferCtxt<'tcx>, + trace: TypeTrace<'tcx>, + param_env: ty::ParamEnv<'tcx>, + define_opaque_types: DefineOpaqueTypes, + ) -> Self { + Self { infcx, trace, param_env, define_opaque_types, obligations: vec![] } + } +} + impl<'tcx> InferCtxt<'tcx> { pub fn super_combine_tys( &self, diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index c6cf7cf4f3f7..6538995926a5 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -773,6 +773,7 @@ fn test_unstable_options_tracking_hash() { tracked!(emit_thin_lto, false); tracked!(export_executable_symbols, true); tracked!(fewer_names, Some(true)); + tracked!(fixed_x18, true); tracked!(flatten_format_args, false); tracked!(force_unstable_if_unmarked, true); tracked!(fuel, Some(("abc".to_string(), 99))); diff --git a/compiler/rustc_lint/Cargo.toml b/compiler/rustc_lint/Cargo.toml index fa1133e7780f..232d4c18fa48 100644 --- a/compiler/rustc_lint/Cargo.toml +++ b/compiler/rustc_lint/Cargo.toml @@ -13,6 +13,7 @@ rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_hir = { path = "../rustc_hir" } +rustc_hir_pretty = { path = "../rustc_hir_pretty" } rustc_index = { path = "../rustc_index" } rustc_infer = { path = "../rustc_infer" } rustc_macros = { path = "../rustc_macros" } diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index a9304f27fe55..fb71cb601402 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -232,11 +232,9 @@ lint_drop_trait_constraints = lint_dropping_copy_types = calls to `std::mem::drop` with a value that implements `Copy` does nothing .label = argument has type `{$arg_ty}` - .note = use `let _ = ...` to ignore the expression or result lint_dropping_references = calls to `std::mem::drop` with a reference instead of an owned value does nothing .label = argument has type `{$arg_ty}` - .note = use `let _ = ...` to ignore the expression or result lint_duplicate_macro_attribute = duplicated attribute @@ -271,10 +269,9 @@ lint_for_loops_over_fallibles = lint_forgetting_copy_types = calls to `std::mem::forget` with a value that implements `Copy` does nothing .label = argument has type `{$arg_ty}` - .note = use `let _ = ...` to ignore the expression or result + lint_forgetting_references = calls to `std::mem::forget` with a reference instead of an owned value does nothing .label = argument has type `{$arg_ty}` - .note = use `let _ = ...` to ignore the expression or result lint_hidden_glob_reexport = private item shadows public glob re-export .note_glob_reexport = the name `{$name}` in the {$namespace} namespace is supposed to be publicly re-exported here @@ -542,17 +539,21 @@ lint_non_local_definitions_cargo_update = the {$macro_kind} `{$macro_name}` may lint_non_local_definitions_deprecation = this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -lint_non_local_definitions_impl = non-local `impl` definition, they should be avoided as they go against expectation - .help = - move this `impl` block outside the of the current {$body_kind_descr} {$depth -> - [one] `{$body_name}` - *[other] `{$body_name}` and up {$depth} bodies - } - .non_local = an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - .exception = one exception to the rule are anon-const (`const _: () = {"{"} ... {"}"}`) at top-level module and anon-const at the same nesting as the trait or type +lint_non_local_definitions_impl = non-local `impl` definition, `impl` blocks should be written at the same level as their item + .remove_help = remove `{$may_remove_part}` to make the `impl` local + .without_trait = methods and associated constants are still usable outside the current expression, only `impl Local` and `impl dyn Local` can ever be private, and only if the type is nested in the same item as the `impl` + .with_trait = an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` + .bounds = `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + .exception = items in an anonymous const item (`const _: () = {"{"} ... {"}"}`) are treated as in the same scope as the anonymous const's declaration .const_anon = use a const-anon item to suppress this lint -lint_non_local_definitions_macro_rules = non-local `macro_rules!` definition, they should be avoided as they go against expectation +lint_non_local_definitions_impl_move_help = + move the `impl` block outside of this {$body_kind_descr} {$depth -> + [one] `{$body_name}` + *[other] `{$body_name}` and up {$depth} bodies + } + +lint_non_local_definitions_macro_rules = non-local `macro_rules!` definition, `#[macro_export]` macro should be written at top level module .help = remove the `#[macro_export]` or move this `macro_rules!` outside the of the current {$body_kind_descr} {$depth -> [one] `{$body_name}` @@ -561,7 +562,12 @@ lint_non_local_definitions_macro_rules = non-local `macro_rules!` definition, th .help_doctest = remove the `#[macro_export]` or make this doc-test a standalone test with its own `fn main() {"{"} ... {"}"}` .non_local = a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute - .exception = one exception to the rule are anon-const (`const _: () = {"{"} ... {"}"}`) at top-level module + +lint_non_local_definitions_may_move = may need to be moved as well + +lint_non_local_definitions_of_trait_not_local = `{$of_trait_str}` is not local + +lint_non_local_definitions_self_ty_not_local = `{$self_ty_str}` is not local lint_non_snake_case = {$sort} `{$name}` should have a snake case name .rename_or_convert_suggestion = rename the identifier or convert it to a snake case raw identifier @@ -884,6 +890,8 @@ lint_unused_op = unused {$op} that must be used lint_unused_result = unused result of type `{$ty}` +lint_use_let_underscore_ignore_suggestion = use `let _ = ...` to ignore the expression or result + lint_variant_size_differences = enum variant is more than three times larger ({$largest} bytes) than the next largest diff --git a/compiler/rustc_lint/src/drop_forget_useless.rs b/compiler/rustc_lint/src/drop_forget_useless.rs index 60b799f3c746..eea0898d83fa 100644 --- a/compiler/rustc_lint/src/drop_forget_useless.rs +++ b/compiler/rustc_lint/src/drop_forget_useless.rs @@ -1,4 +1,4 @@ -use rustc_hir::{Arm, Expr, ExprKind, Node}; +use rustc_hir::{Arm, Expr, ExprKind, Node, StmtKind}; use rustc_middle::ty; use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::sym; @@ -6,7 +6,7 @@ use rustc_span::sym; use crate::{ lints::{ DropCopyDiag, DropRefDiag, ForgetCopyDiag, ForgetRefDiag, UndroppedManuallyDropsDiag, - UndroppedManuallyDropsSuggestion, + UndroppedManuallyDropsSuggestion, UseLetUnderscoreIgnoreSuggestion, }, LateContext, LateLintPass, LintContext, }; @@ -148,33 +148,59 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetUseless { let arg_ty = cx.typeck_results().expr_ty(arg); let is_copy = arg_ty.is_copy_modulo_regions(cx.tcx, cx.param_env); let drop_is_single_call_in_arm = is_single_call_in_arm(cx, arg, expr); + let let_underscore_ignore_sugg = || { + if let Some((_, node)) = cx.tcx.hir().parent_iter(expr.hir_id).nth(0) + && let Node::Stmt(stmt) = node + && let StmtKind::Semi(e) = stmt.kind + && e.hir_id == expr.hir_id + { + UseLetUnderscoreIgnoreSuggestion::Suggestion { + start_span: expr.span.shrink_to_lo().until(arg.span), + end_span: arg.span.shrink_to_hi().until(expr.span.shrink_to_hi()), + } + } else { + UseLetUnderscoreIgnoreSuggestion::Note + } + }; match fn_name { sym::mem_drop if arg_ty.is_ref() && !drop_is_single_call_in_arm => { cx.emit_span_lint( DROPPING_REFERENCES, expr.span, - DropRefDiag { arg_ty, label: arg.span }, + DropRefDiag { arg_ty, label: arg.span, sugg: let_underscore_ignore_sugg() }, ); } sym::mem_forget if arg_ty.is_ref() => { cx.emit_span_lint( FORGETTING_REFERENCES, expr.span, - ForgetRefDiag { arg_ty, label: arg.span }, + ForgetRefDiag { + arg_ty, + label: arg.span, + sugg: let_underscore_ignore_sugg(), + }, ); } sym::mem_drop if is_copy && !drop_is_single_call_in_arm => { cx.emit_span_lint( DROPPING_COPY_TYPES, expr.span, - DropCopyDiag { arg_ty, label: arg.span }, + DropCopyDiag { + arg_ty, + label: arg.span, + sugg: let_underscore_ignore_sugg(), + }, ); } sym::mem_forget if is_copy => { cx.emit_span_lint( FORGETTING_COPY_TYPES, expr.span, - ForgetCopyDiag { arg_ty, label: arg.span }, + ForgetCopyDiag { + arg_ty, + label: arg.span, + sugg: let_underscore_ignore_sugg(), + }, ); } sym::mem_drop diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 42963a11f71a..84d46ef3b65d 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -6,7 +6,7 @@ use crate::errors::RequestedLevel; use crate::fluent_generated as fluent; use rustc_errors::{ codes::*, Applicability, Diag, DiagArgValue, DiagMessage, DiagStyledString, - ElidedLifetimeInPathSubdiag, EmissionGuarantee, LintDiagnostic, SubdiagMessageOp, + ElidedLifetimeInPathSubdiag, EmissionGuarantee, LintDiagnostic, MultiSpan, SubdiagMessageOp, Subdiagnostic, SuggestionStyle, }; use rustc_hir::{def::Namespace, def_id::DefId}; @@ -656,41 +656,62 @@ pub struct ForLoopsOverFalliblesSuggestion<'a> { pub end_span: Span, } +#[derive(Subdiagnostic)] +pub enum UseLetUnderscoreIgnoreSuggestion { + #[note(lint_use_let_underscore_ignore_suggestion)] + Note, + #[multipart_suggestion( + lint_use_let_underscore_ignore_suggestion, + style = "verbose", + applicability = "maybe-incorrect" + )] + Suggestion { + #[suggestion_part(code = "let _ = ")] + start_span: Span, + #[suggestion_part(code = "")] + end_span: Span, + }, +} + // drop_forget_useless.rs #[derive(LintDiagnostic)] #[diag(lint_dropping_references)] -#[note] pub struct DropRefDiag<'a> { pub arg_ty: Ty<'a>, #[label] pub label: Span, + #[subdiagnostic] + pub sugg: UseLetUnderscoreIgnoreSuggestion, } #[derive(LintDiagnostic)] #[diag(lint_dropping_copy_types)] -#[note] pub struct DropCopyDiag<'a> { pub arg_ty: Ty<'a>, #[label] pub label: Span, + #[subdiagnostic] + pub sugg: UseLetUnderscoreIgnoreSuggestion, } #[derive(LintDiagnostic)] #[diag(lint_forgetting_references)] -#[note] pub struct ForgetRefDiag<'a> { pub arg_ty: Ty<'a>, #[label] pub label: Span, + #[subdiagnostic] + pub sugg: UseLetUnderscoreIgnoreSuggestion, } #[derive(LintDiagnostic)] #[diag(lint_forgetting_copy_types)] -#[note] pub struct ForgetCopyDiag<'a> { pub arg_ty: Ty<'a>, #[label] pub label: Span, + #[subdiagnostic] + pub sugg: UseLetUnderscoreIgnoreSuggestion, } #[derive(LintDiagnostic)] @@ -1329,40 +1350,126 @@ pub struct SuspiciousDoubleRefCloneDiag<'a> { } // non_local_defs.rs -#[derive(LintDiagnostic)] pub enum NonLocalDefinitionsDiag { - #[diag(lint_non_local_definitions_impl)] - #[help] - #[note(lint_non_local)] - #[note(lint_exception)] - #[note(lint_non_local_definitions_deprecation)] Impl { depth: u32, body_kind_descr: &'static str, body_name: String, - #[subdiagnostic] cargo_update: Option, - #[suggestion(lint_const_anon, code = "_", applicability = "machine-applicable")] - const_anon: Option, + const_anon: Option>, + move_to: Option<(Span, Vec)>, + may_remove: Option<(Span, String)>, + has_trait: bool, + self_ty_str: String, + of_trait_str: Option, }, - #[diag(lint_non_local_definitions_macro_rules)] MacroRules { depth: u32, body_kind_descr: &'static str, body_name: String, - #[help] help: Option<()>, - #[help(lint_help_doctest)] doctest_help: Option<()>, - #[note(lint_non_local)] - #[note(lint_exception)] - #[note(lint_non_local_definitions_deprecation)] - notes: (), - #[subdiagnostic] cargo_update: Option, }, } +impl<'a> LintDiagnostic<'a, ()> for NonLocalDefinitionsDiag { + fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) { + match self { + NonLocalDefinitionsDiag::Impl { + depth, + body_kind_descr, + body_name, + cargo_update, + const_anon, + move_to, + may_remove, + has_trait, + self_ty_str, + of_trait_str, + } => { + diag.primary_message(fluent::lint_non_local_definitions_impl); + diag.arg("depth", depth); + diag.arg("body_kind_descr", body_kind_descr); + diag.arg("body_name", body_name); + diag.arg("self_ty_str", self_ty_str); + if let Some(of_trait_str) = of_trait_str { + diag.arg("of_trait_str", of_trait_str); + } + + if has_trait { + diag.note(fluent::lint_bounds); + diag.note(fluent::lint_with_trait); + } else { + diag.note(fluent::lint_without_trait); + } + + if let Some((move_help, may_move)) = move_to { + let mut ms = MultiSpan::from_span(move_help); + for sp in may_move { + ms.push_span_label(sp, fluent::lint_non_local_definitions_may_move); + } + diag.span_help(ms, fluent::lint_non_local_definitions_impl_move_help); + } + + if let Some((span, part)) = may_remove { + diag.arg("may_remove_part", part); + diag.span_suggestion( + span, + fluent::lint_remove_help, + "", + Applicability::MaybeIncorrect, + ); + } + + if let Some(cargo_update) = cargo_update { + diag.subdiagnostic(&diag.dcx, cargo_update); + } + if let Some(const_anon) = const_anon { + diag.note(fluent::lint_exception); + if let Some(const_anon) = const_anon { + diag.span_suggestion( + const_anon, + fluent::lint_const_anon, + "_", + Applicability::MachineApplicable, + ); + } + } + + diag.note(fluent::lint_non_local_definitions_deprecation); + } + NonLocalDefinitionsDiag::MacroRules { + depth, + body_kind_descr, + body_name, + help, + doctest_help, + cargo_update, + } => { + diag.primary_message(fluent::lint_non_local_definitions_macro_rules); + diag.arg("depth", depth); + diag.arg("body_kind_descr", body_kind_descr); + diag.arg("body_name", body_name); + + if let Some(()) = help { + diag.help(fluent::lint_help); + } + if let Some(()) = doctest_help { + diag.help(fluent::lint_help_doctest); + } + + diag.note(fluent::lint_non_local); + diag.note(fluent::lint_non_local_definitions_deprecation); + + if let Some(cargo_update) = cargo_update { + diag.subdiagnostic(&diag.dcx, cargo_update); + } + } + } + } +} + #[derive(Subdiagnostic)] #[note(lint_non_local_definitions_cargo_update)] pub struct NonLocalDefinitionsCargoUpdateNote { diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs index 87ee5f536280..42b03f47a5bc 100644 --- a/compiler/rustc_lint/src/non_local_def.rs +++ b/compiler/rustc_lint/src/non_local_def.rs @@ -1,3 +1,6 @@ +use rustc_errors::MultiSpan; +use rustc_hir::intravisit::{self, Visitor}; +use rustc_hir::HirId; use rustc_hir::{def::DefKind, Body, Item, ItemKind, Node, TyKind}; use rustc_hir::{Path, QPath}; use rustc_infer::infer::InferCtxt; @@ -7,12 +10,13 @@ use rustc_middle::ty::{EarlyBinder, TraitRef, TypeSuperFoldable}; use rustc_session::{declare_lint, impl_lint_pass}; use rustc_span::def_id::{DefId, LOCAL_CRATE}; use rustc_span::Span; -use rustc_span::{sym, symbol::kw, ExpnKind, MacroKind}; +use rustc_span::{sym, symbol::kw, ExpnKind, MacroKind, Symbol}; use rustc_trait_selection::infer::TyCtxtInferExt; use rustc_trait_selection::traits::error_reporting::ambiguity::{ compute_applicable_impls_for_diagnostics, CandidateSource, }; +use crate::fluent_generated as fluent; use crate::lints::{NonLocalDefinitionsCargoUpdateNote, NonLocalDefinitionsDiag}; use crate::{LateContext, LateLintPass, LintContext}; @@ -134,35 +138,8 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { }; // Part 1: Is the Self type local? - let self_ty_has_local_parent = match impl_.self_ty.kind { - TyKind::Path(QPath::Resolved(_, ty_path)) => { - path_has_local_parent(ty_path, cx, parent, parent_parent) - } - TyKind::TraitObject([principle_poly_trait_ref, ..], _, _) => { - path_has_local_parent( - principle_poly_trait_ref.trait_ref.path, - cx, - parent, - parent_parent, - ) - } - TyKind::TraitObject([], _, _) - | TyKind::InferDelegation(_, _) - | TyKind::Slice(_) - | TyKind::Array(_, _) - | TyKind::Ptr(_) - | TyKind::Ref(_, _) - | TyKind::BareFn(_) - | TyKind::Never - | TyKind::Tup(_) - | TyKind::Path(_) - | TyKind::Pat(..) - | TyKind::AnonAdt(_) - | TyKind::OpaqueDef(_, _, _) - | TyKind::Typeof(_) - | TyKind::Infer - | TyKind::Err(_) => false, - }; + let self_ty_has_local_parent = + ty_has_local_parent(&impl_.self_ty.kind, cx, parent, parent_parent); if self_ty_has_local_parent { return; @@ -202,8 +179,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { // Get the span of the parent const item ident (if it's a not a const anon). // // Used to suggest changing the const item to a const anon. - let span_for_const_anon_suggestion = if self.body_depth == 1 - && parent_def_kind == DefKind::Const + let span_for_const_anon_suggestion = if parent_def_kind == DefKind::Const && parent_opt_item_name != Some(kw::Underscore) && let Some(parent) = parent.as_local() && let Node::Item(item) = cx.tcx.hir_node_by_def_id(parent) @@ -215,9 +191,76 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { None }; + let mut collector = PathCollector { paths: Vec::new() }; + collector.visit_ty(&impl_.self_ty); + if let Some(of_trait) = &impl_.of_trait { + collector.visit_trait_ref(of_trait); + } + collector.visit_generics(&impl_.generics); + + let mut may_move: Vec = collector + .paths + .into_iter() + .filter_map(|path| { + if let Some(did) = path.res.opt_def_id() + && did_has_local_parent(did, cx.tcx, parent, parent_parent) + { + Some(cx.tcx.def_span(did)) + } else { + None + } + }) + .collect(); + may_move.sort(); + may_move.dedup(); + + let const_anon = matches!(parent_def_kind, DefKind::Const | DefKind::Static { .. }) + .then_some(span_for_const_anon_suggestion); + + let may_remove = match &impl_.self_ty.kind { + TyKind::Ptr(mut_ty) | TyKind::Ref(_, mut_ty) + if ty_has_local_parent(&mut_ty.ty.kind, cx, parent, parent_parent) => + { + let type_ = + if matches!(impl_.self_ty.kind, TyKind::Ptr(_)) { "*" } else { "&" }; + let part = format!("{}{}", type_, mut_ty.mutbl.prefix_str()); + Some((impl_.self_ty.span.shrink_to_lo().until(mut_ty.ty.span), part)) + } + _ => None, + }; + + let impl_span = item.span.shrink_to_lo().to(impl_.self_ty.span); + let mut ms = MultiSpan::from_span(impl_span); + + let (self_ty_span, self_ty_str) = + self_ty_kind_for_diagnostic(&impl_.self_ty, cx.tcx); + + ms.push_span_label( + self_ty_span, + fluent::lint_non_local_definitions_self_ty_not_local, + ); + let of_trait_str = if let Some(of_trait) = &impl_.of_trait { + ms.push_span_label( + path_span_without_args(&of_trait.path), + fluent::lint_non_local_definitions_of_trait_not_local, + ); + Some(path_name_to_string(&of_trait.path)) + } else { + None + }; + let move_to = if may_move.is_empty() { + ms.push_span_label( + cx.tcx.def_span(parent), + fluent::lint_non_local_definitions_impl_move_help, + ); + None + } else { + Some((cx.tcx.def_span(parent), may_move)) + }; + cx.emit_span_lint( NON_LOCAL_DEFINITIONS, - item.span, + ms, NonLocalDefinitionsDiag::Impl { depth: self.body_depth, body_kind_descr: cx.tcx.def_kind_descr(parent_def_kind, parent), @@ -225,7 +268,12 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { .map(|s| s.to_ident_string()) .unwrap_or_else(|| "".to_string()), cargo_update: cargo_update(), - const_anon: span_for_const_anon_suggestion, + const_anon, + self_ty_str, + of_trait_str, + move_to, + may_remove, + has_trait: impl_.of_trait.is_some(), }, ) } @@ -250,7 +298,6 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { cargo_update: cargo_update(), help: (!is_at_toplevel_doctest).then_some(()), doctest_help: is_at_toplevel_doctest.then_some(()), - notes: (), }, ) } @@ -343,6 +390,54 @@ impl<'a, 'tcx, F: FnMut(DefId) -> bool> TypeFolder> } } +/// Simple hir::Path collector +struct PathCollector<'tcx> { + paths: Vec>, +} + +impl<'tcx> Visitor<'tcx> for PathCollector<'tcx> { + fn visit_path(&mut self, path: &Path<'tcx>, _id: HirId) { + self.paths.push(path.clone()); // need to clone, bc of the restricted lifetime + intravisit::walk_path(self, path) + } +} + +/// Given a `Ty` we check if the (outermost) type is local. +fn ty_has_local_parent( + ty_kind: &TyKind<'_>, + cx: &LateContext<'_>, + impl_parent: DefId, + impl_parent_parent: Option, +) -> bool { + match ty_kind { + TyKind::Path(QPath::Resolved(_, ty_path)) => { + path_has_local_parent(ty_path, cx, impl_parent, impl_parent_parent) + } + TyKind::TraitObject([principle_poly_trait_ref, ..], _, _) => path_has_local_parent( + principle_poly_trait_ref.trait_ref.path, + cx, + impl_parent, + impl_parent_parent, + ), + TyKind::TraitObject([], _, _) + | TyKind::InferDelegation(_, _) + | TyKind::Slice(_) + | TyKind::Array(_, _) + | TyKind::Ptr(_) + | TyKind::Ref(_, _) + | TyKind::BareFn(_) + | TyKind::Never + | TyKind::Tup(_) + | TyKind::Path(_) + | TyKind::Pat(..) + | TyKind::AnonAdt(_) + | TyKind::OpaqueDef(_, _, _) + | TyKind::Typeof(_) + | TyKind::Infer + | TyKind::Err(_) => false, + } +} + /// Given a path and a parent impl def id, this checks if the if parent resolution /// def id correspond to the def id of the parent impl definition. /// @@ -384,3 +479,52 @@ fn did_has_local_parent( false } } + +/// Return for a given `Path` the span until the last args +fn path_span_without_args(path: &Path<'_>) -> Span { + if let Some(args) = &path.segments.last().unwrap().args { + path.span.until(args.span_ext) + } else { + path.span + } +} + +/// Return a "error message-able" ident for the last segment of the `Path` +fn path_name_to_string(path: &Path<'_>) -> String { + path.segments.last().unwrap().ident.name.to_ident_string() +} + +/// Compute the `Span` and visual representation for the `Self` we want to point at; +/// It follows part of the actual logic of non-local, and if possible return the least +/// amount possible for the span and representation. +fn self_ty_kind_for_diagnostic(ty: &rustc_hir::Ty<'_>, tcx: TyCtxt<'_>) -> (Span, String) { + match ty.kind { + TyKind::Path(QPath::Resolved(_, ty_path)) => ( + path_span_without_args(ty_path), + ty_path + .res + .opt_def_id() + .map(|did| tcx.opt_item_name(did)) + .flatten() + .as_ref() + .map(|s| Symbol::as_str(s)) + .unwrap_or("") + .to_string(), + ), + TyKind::TraitObject([principle_poly_trait_ref, ..], _, _) => { + let path = &principle_poly_trait_ref.trait_ref.path; + ( + path_span_without_args(path), + path.res + .opt_def_id() + .map(|did| tcx.opt_item_name(did)) + .flatten() + .as_ref() + .map(|s| Symbol::as_str(s)) + .unwrap_or("") + .to_string(), + ) + } + _ => (ty.span, rustc_hir_pretty::ty_to_string(&tcx, ty)), + } +} diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index b17af47fbcd4..ff8d29197055 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -321,7 +321,7 @@ impl<'hir> Map<'hir> { /// Returns an iterator of the `DefId`s for all body-owners in this /// crate. If you would prefer to iterate over the bodies - /// themselves, you can do `self.hir().krate().body_ids.iter()`. + /// themselves, you can do `self.hir().krate().owners.iter()`. #[inline] pub fn body_owners(self) -> impl Iterator + 'hir { self.tcx.hir_crate_items(()).body_owners.iter().copied() @@ -508,7 +508,17 @@ impl<'hir> Map<'hir> { /// Whether the expression pointed at by `hir_id` belongs to a `const` evaluation context. /// Used exclusively for diagnostics, to avoid suggestion function calls. pub fn is_inside_const_context(self, hir_id: HirId) -> bool { - self.body_const_context(self.enclosing_body_owner(hir_id)).is_some() + for (_, node) in self.parent_iter(hir_id) { + if let Some((def_id, _)) = node.associated_body() { + return self.body_const_context(def_id).is_some(); + } + if let Node::Expr(e) = node { + if let ExprKind::ConstBlock(_) = e.kind { + return true; + } + } + } + false } /// Retrieves the `HirId` for `id`'s enclosing function *if* the `id` block or return is @@ -891,7 +901,6 @@ impl<'hir> Map<'hir> { Node::Variant(variant) => variant.span, Node::Field(field) => field.span, Node::AnonConst(constant) => constant.span, - Node::ConstBlock(constant) => self.body(constant.body).value.span, Node::Expr(expr) => expr.span, Node::ExprField(field) => field.span, Node::Stmt(stmt) => stmt.span, @@ -1161,7 +1170,6 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String { format!("{id} (field `{}` in {})", field.ident, path_str(field.def_id)) } Node::AnonConst(_) => node_str("const"), - Node::ConstBlock(_) => node_str("const"), Node::Expr(_) => node_str("expr"), Node::ExprField(_) => node_str("expr field"), Node::Stmt(_) => node_str("stmt"), @@ -1311,11 +1319,6 @@ impl<'hir> Visitor<'hir> for ItemCollector<'hir> { intravisit::walk_anon_const(self, c) } - fn visit_inline_const(&mut self, c: &'hir ConstBlock) { - self.body_owners.push(c.def_id); - intravisit::walk_inline_const(self, c) - } - fn visit_expr(&mut self, ex: &'hir Expr<'hir>) { if let ExprKind::Closure(closure) = ex.kind { self.body_owners.push(closure.def_id); diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index 791e87735f40..b0f8a047b82f 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -266,19 +266,6 @@ impl AllocRange { // The constructors are all without extra; the extra gets added by a machine hook later. impl Allocation { - /// Creates an allocation from an existing `Bytes` value - this is needed for miri FFI support - pub fn from_raw_bytes(bytes: Bytes, align: Align, mutability: Mutability) -> Self { - let size = Size::from_bytes(bytes.len()); - Self { - bytes, - provenance: ProvenanceMap::new(), - init_mask: InitMask::new(size, true), - align, - mutability, - extra: (), - } - } - /// Creates an allocation initialized by the given bytes pub fn from_bytes<'a>( slice: impl Into>, @@ -342,18 +329,30 @@ impl Allocation { Err(x) => x, } } + + /// Add the extra. + pub fn with_extra(self, extra: Extra) -> Allocation { + Allocation { + bytes: self.bytes, + provenance: self.provenance, + init_mask: self.init_mask, + align: self.align, + mutability: self.mutability, + extra, + } + } } impl Allocation { /// Adjust allocation from the ones in `tcx` to a custom Machine instance - /// with a different `Provenance`, `Extra` and `Byte` type. - pub fn adjust_from_tcx( - self, + /// with a different `Provenance` and `Byte` type. + pub fn adjust_from_tcx( + &self, cx: &impl HasDataLayout, - extra: Extra, mut adjust_ptr: impl FnMut(Pointer) -> Result, Err>, - ) -> Result, Err> { - let mut bytes = self.bytes; + ) -> Result, Err> { + // Copy the data. + let mut bytes = Bytes::from_bytes(Cow::Borrowed(&*self.bytes), self.align); // Adjust provenance of pointers stored in this allocation. let mut new_provenance = Vec::with_capacity(self.provenance.ptrs().len()); let ptr_size = cx.data_layout().pointer_size.bytes_usize(); @@ -369,12 +368,12 @@ impl Allocation { } // Create allocation. Ok(Allocation { - bytes: AllocBytes::from_bytes(Cow::Owned(Vec::from(bytes)), self.align), + bytes, provenance: ProvenanceMap::from_presorted_ptrs(new_provenance), - init_mask: self.init_mask, + init_mask: self.init_mask.clone(), align: self.align, mutability: self.mutability, - extra, + extra: self.extra, }) } } diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 2d4852114332..ebe77a1abfd8 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -1434,6 +1434,13 @@ pub enum UnOp { Not, /// The `-` operator for negation Neg, + /// Get the metadata `M` from a `*const/mut impl Pointee`. + /// + /// For example, this will give a `()` from `*const i32`, a `usize` from + /// `*mut [u8]`, or a pointer to a vtable from a `*const dyn Foo`. + /// + /// Allowed only in [`MirPhase::Runtime`]; earlier it's an intrinsic. + PtrMetadata, } #[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash)] diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index a122cffdb876..126387db1d9c 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -180,7 +180,10 @@ impl<'tcx> Rvalue<'tcx> { let rhs_ty = rhs.ty(local_decls, tcx); op.ty(tcx, lhs_ty, rhs_ty) } - Rvalue::UnaryOp(UnOp::Not | UnOp::Neg, ref operand) => operand.ty(local_decls, tcx), + Rvalue::UnaryOp(op, ref operand) => { + let arg_ty = operand.ty(local_decls, tcx); + op.ty(tcx, arg_ty) + } Rvalue::Discriminant(ref place) => place.ty(local_decls, tcx).ty.discriminant_ty(tcx), Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => { tcx.types.usize @@ -282,6 +285,27 @@ impl<'tcx> BinOp { } } +impl<'tcx> UnOp { + pub fn ty(&self, tcx: TyCtxt<'tcx>, arg_ty: Ty<'tcx>) -> Ty<'tcx> { + match self { + UnOp::Not | UnOp::Neg => arg_ty, + UnOp::PtrMetadata => { + let pointee_ty = arg_ty + .builtin_deref(true) + .unwrap_or_else(|| bug!("PtrMetadata of non-dereferenceable ty {arg_ty:?}")); + if pointee_ty.is_trivially_sized(tcx) { + tcx.types.unit + } else { + let Some(metadata_def_id) = tcx.lang_items().metadata_type() else { + bug!("No metadata_type lang item while looking at {arg_ty:?}") + }; + Ty::new_projection(tcx, metadata_def_id, [pointee_ty]) + } + } + } + } +} + impl BorrowKind { pub fn to_mutbl_lossy(self) -> hir::Mutability { match self { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index c09cb95de883..c2219fba023b 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -218,6 +218,13 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.check_and_mk_args(def_id, args) } + fn intern_canonical_goal_evaluation_step( + self, + step: solve::inspect::CanonicalGoalEvaluationStep>, + ) -> &'tcx solve::inspect::CanonicalGoalEvaluationStep> { + self.arena.alloc(step) + } + fn parent(self, def_id: Self::DefId) -> Self::DefId { self.parent(def_id) } @@ -737,6 +744,7 @@ impl<'tcx> TyCtxtFeed<'tcx, LocalDefId> { 1, ), bodies, + has_inline_consts: false, }))); self.feed_owner_id().hir_attrs(attrs); } diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index efb6cf255462..c730f5117c56 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -121,17 +121,14 @@ impl<'tcx> Predicate<'tcx> { #[inline] pub fn allow_normalization(self) -> bool { match self.kind().skip_binder() { - PredicateKind::Clause(ClauseKind::WellFormed(_)) => false, - // `NormalizesTo` is only used in the new solver, so this shouldn't - // matter. Normalizing `term` would be 'wrong' however, as it changes whether - // `normalizes-to(::Assoc, ::Assoc)` holds. - PredicateKind::NormalizesTo(..) => false, + PredicateKind::Clause(ClauseKind::WellFormed(_)) + | PredicateKind::AliasRelate(..) + | PredicateKind::NormalizesTo(..) => false, PredicateKind::Clause(ClauseKind::Trait(_)) | PredicateKind::Clause(ClauseKind::RegionOutlives(_)) | PredicateKind::Clause(ClauseKind::TypeOutlives(_)) | PredicateKind::Clause(ClauseKind::Projection(_)) | PredicateKind::Clause(ClauseKind::ConstArgHasType(..)) - | PredicateKind::AliasRelate(..) | PredicateKind::ObjectSafe(_) | PredicateKind::Subtype(_) | PredicateKind::Coerce(_) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 3c0f2578284a..83790db99260 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1579,8 +1579,10 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { let formatted_op = match op { UnOp::Not => "!", UnOp::Neg => "-", + UnOp::PtrMetadata => "PtrMetadata", }; let parenthesized = match ct.kind() { + _ if op == UnOp::PtrMetadata => true, ty::ConstKind::Expr(Expr::UnOp(c_op, ..)) => c_op != op, ty::ConstKind::Expr(_) => true, _ => false, diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 24e3e623ff27..69ea9c9843a0 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -217,6 +217,10 @@ pub struct TypeckResults<'tcx> { /// Container types and field indices of `offset_of!` expressions offset_of_data: ItemLocalMap<(Ty<'tcx>, Vec<(VariantIdx, FieldIdx)>)>, + + /// Maps from `HirId`s of const blocks (the `ExprKind::ConstBlock`, not the inner expression's) + /// to the `DefId` of the corresponding inline const. + pub inline_consts: FxIndexMap, } impl<'tcx> TypeckResults<'tcx> { @@ -249,6 +253,7 @@ impl<'tcx> TypeckResults<'tcx> { treat_byte_string_as_slice: Default::default(), closure_size_eval: Default::default(), offset_of_data: Default::default(), + inline_consts: Default::default(), } } diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs index 2ad194313100..b8371cc2bca5 100644 --- a/compiler/rustc_middle/src/ty/vtable.rs +++ b/compiler/rustc_middle/src/ty/vtable.rs @@ -84,10 +84,14 @@ pub(super) fn vtable_allocation_provider<'tcx>( let idx: u64 = u64::try_from(idx).unwrap(); let scalar = match entry { VtblEntry::MetadataDropInPlace => { - let instance = ty::Instance::resolve_drop_in_place(tcx, ty); - let fn_alloc_id = tcx.reserve_and_set_fn_alloc(instance); - let fn_ptr = Pointer::from(fn_alloc_id); - Scalar::from_pointer(fn_ptr, &tcx) + if ty.needs_drop(tcx, ty::ParamEnv::reveal_all()) { + let instance = ty::Instance::resolve_drop_in_place(tcx, ty); + let fn_alloc_id = tcx.reserve_and_set_fn_alloc(instance); + let fn_ptr = Pointer::from(fn_alloc_id); + Scalar::from_pointer(fn_ptr, &tcx) + } else { + Scalar::from_maybe_pointer(Pointer::null(), &tcx) + } } VtblEntry::MetadataSize => Scalar::from_uint(size, ptr_size), VtblEntry::MetadataAlign => Scalar::from_uint(align, ptr_size), diff --git a/compiler/rustc_mir_build/src/build/coverageinfo.rs b/compiler/rustc_mir_build/src/build/coverageinfo.rs index ee9eeb62990d..855dcbbcb346 100644 --- a/compiler/rustc_mir_build/src/build/coverageinfo.rs +++ b/compiler/rustc_mir_build/src/build/coverageinfo.rs @@ -157,6 +157,63 @@ impl BranchInfoBuilder { } impl<'tcx> Builder<'_, 'tcx> { + /// If condition coverage is enabled, inject extra blocks and marker statements + /// that will let us track the value of the condition in `place`. + pub(crate) fn visit_coverage_standalone_condition( + &mut self, + mut expr_id: ExprId, // Expression giving the span of the condition + place: mir::Place<'tcx>, // Already holds the boolean condition value + block: &mut BasicBlock, + ) { + // Bail out if condition coverage is not enabled for this function. + let Some(branch_info) = self.coverage_branch_info.as_mut() else { return }; + if !self.tcx.sess.instrument_coverage_condition() { + return; + }; + + // Remove any wrappers, so that we can inspect the real underlying expression. + while let ExprKind::Use { source: inner } | ExprKind::Scope { value: inner, .. } = + self.thir[expr_id].kind + { + expr_id = inner; + } + // If the expression is a lazy logical op, it will naturally get branch + // coverage as part of its normal lowering, so we can disregard it here. + if let ExprKind::LogicalOp { .. } = self.thir[expr_id].kind { + return; + } + + let source_info = SourceInfo { span: self.thir[expr_id].span, scope: self.source_scope }; + + // Using the boolean value that has already been stored in `place`, set up + // control flow in the shape of a diamond, so that we can place separate + // marker statements in the true and false blocks. The coverage MIR pass + // will use those markers to inject coverage counters as appropriate. + // + // block + // / \ + // true_block false_block + // (marker) (marker) + // \ / + // join_block + + let true_block = self.cfg.start_new_block(); + let false_block = self.cfg.start_new_block(); + self.cfg.terminate( + *block, + source_info, + mir::TerminatorKind::if_(mir::Operand::Copy(place), true_block, false_block), + ); + + branch_info.add_two_way_branch(&mut self.cfg, source_info, true_block, false_block); + + let join_block = self.cfg.start_new_block(); + self.cfg.goto(true_block, source_info, join_block); + self.cfg.goto(false_block, source_info, join_block); + // Any subsequent codegen in the caller should use the new join block. + *block = join_block; + } + /// If branch coverage is enabled, inject marker statements into `then_block` /// and `else_block`, and record their IDs in the table of branch spans. pub(crate) fn visit_coverage_branch_condition( diff --git a/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs b/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs index 9cfb25e663d1..728b63d5b21b 100644 --- a/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs +++ b/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs @@ -217,12 +217,13 @@ impl MCDCInfoBuilder { } _ => { // Do not generate mcdc mappings and statements for decisions with too many conditions. - let rebase_idx = self.branch_spans.len() - decision.conditions_num + 1; + // Therefore, first erase the condition info of the (N-1) previous branch spans. + let rebase_idx = self.branch_spans.len() - (decision.conditions_num - 1); for branch in &mut self.branch_spans[rebase_idx..] { branch.condition_info = None; } - // ConditionInfo of this branch shall also be reset. + // Then, erase this last branch span's info too, for a total of N. condition_info = None; tcx.dcx().emit_warn(MCDCExceedsConditionNumLimit { diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs index 6f8cfc3af447..de748b9c85d1 100644 --- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs @@ -212,6 +212,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { Ok(Rvalue::BinaryOp(BinOp::Offset, Box::new((ptr, offset)))) }, @call(mir_len, args) => Ok(Rvalue::Len(self.parse_place(args[0])?)), + @call(mir_ptr_metadata, args) => Ok(Rvalue::UnaryOp(UnOp::PtrMetadata, self.parse_operand(args[0])?)), @call(mir_copy_for_deref, args) => Ok(Rvalue::CopyForDeref(self.parse_place(args[0])?)), ExprKind::Borrow { borrow_kind, arg } => Ok( Rvalue::Ref(self.tcx.lifetimes.re_erased, *borrow_kind, self.parse_place(*arg)?) diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index 9349133d2dbc..c08a3b6691af 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -183,9 +183,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { const_: Const::from_bool(this.tcx, constant), }, ); - let rhs = unpack!(this.expr_into_dest(destination, continuation, rhs)); + let mut rhs_block = unpack!(this.expr_into_dest(destination, continuation, rhs)); + // Instrument the lowered RHS's value for condition coverage. + // (Does nothing if condition coverage is not enabled.) + this.visit_coverage_standalone_condition(rhs, destination, &mut rhs_block); + let target = this.cfg.start_new_block(); - this.cfg.goto(rhs, source_info, target); + this.cfg.goto(rhs_block, source_info, target); this.cfg.goto(short_circuit, source_info, target); target.unit() } diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 92cd7f75d628..13112f2b12c8 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -568,11 +568,8 @@ fn construct_const<'a, 'tcx>( .. }) => (*span, ty.span), Node::AnonConst(ct) => (ct.span, ct.span), - Node::ConstBlock(_) => { - let span = tcx.def_span(def); - (span, span) - } - _ => span_bug!(tcx.def_span(def), "can't build MIR for {:?}", def), + Node::Expr(&hir::Expr { span, kind: hir::ExprKind::ConstBlock(_), .. }) => (span, span), + node => span_bug!(tcx.def_span(def), "can't build MIR for {def:?}: {node:#?}"), }; let infcx = tcx.infer_ctxt().build(); diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 28f9300b97a8..bd66257e6b68 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -671,9 +671,9 @@ impl<'tcx> Cx<'tcx> { ExprKind::OffsetOf { container, fields } } - hir::ExprKind::ConstBlock(ref anon_const) => { - let ty = self.typeck_results().node_type(anon_const.hir_id); - let did = anon_const.def_id.to_def_id(); + hir::ExprKind::ConstBlock(body) => { + let ty = self.typeck_results().node_type(body.hir_id); + let did = self.typeck_results().inline_consts[&expr.hir_id.local_id].into(); let typeck_root_def_id = tcx.typeck_root_def_id(did); let parent_args = tcx.erase_regions(GenericArgs::identity_for_item(tcx, typeck_root_def_id)); diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index 3c0e2521d88f..bd72ef28cb37 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -13,10 +13,10 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::LangItem; use rustc_hir::HirId; use rustc_hir::Node; -use rustc_middle::bug; use rustc_middle::middle::region; use rustc_middle::thir::*; use rustc_middle::ty::{self, RvalueScopes, TyCtxt}; +use rustc_middle::{bug, span_bug}; use tracing::instrument; pub(crate) fn thir_body( @@ -24,7 +24,22 @@ pub(crate) fn thir_body( owner_def: LocalDefId, ) -> Result<(&Steal>, ExprId), ErrorGuaranteed> { let hir = tcx.hir(); - let body = hir.body(hir.body_owned_by(owner_def)); + let body; + let body = match tcx.def_kind(owner_def) { + // Inline consts do not have bodies of their own, so create one to make the follow-up logic simpler. + DefKind::InlineConst => { + let e = hir.expect_expr(tcx.local_def_id_to_hir_id(owner_def)); + body = hir::Body { + params: &[], + value: match e.kind { + hir::ExprKind::ConstBlock(body) => body, + _ => span_bug!(e.span, "InlineConst was not a ConstBlock: {e:#?}"), + }, + }; + &body + } + _ => hir.body(hir.body_owned_by(owner_def)), + }; let mut cx = Cx::new(tcx, owner_def); if let Some(reported) = cx.typeck_results.tainted_by_errors { return Err(reported); @@ -165,7 +180,7 @@ impl<'tcx> Cx<'tcx> { &'a mut self, owner_id: HirId, fn_decl: &'tcx hir::FnDecl<'tcx>, - body: &'tcx hir::Body<'tcx>, + body: &hir::Body<'tcx>, ) -> impl Iterator> + 'a { let fn_sig = self.typeck_results.liberated_fn_sigs()[owner_id]; diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 7408c679f00b..33401cad631a 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -637,15 +637,13 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { /// Converts inline const patterns. fn lower_inline_const( &mut self, - block: &'tcx hir::ConstBlock, + expr: &'tcx hir::Expr<'tcx>, id: hir::HirId, span: Span, ) -> PatKind<'tcx> { let tcx = self.tcx; - let def_id = block.def_id; - let body_id = block.body; - let expr = &tcx.hir().body(body_id).value; - let ty = tcx.typeck(def_id).node_type(block.hir_id); + let def_id = self.typeck_results.inline_consts[&id.local_id]; + let ty = tcx.typeck(def_id).node_type(expr.hir_id); // Special case inline consts that are just literals. This is solely // a performance optimization, as we could also just go through the regular diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs index 5e70b300f338..a54332b6f257 100644 --- a/compiler/rustc_mir_transform/src/instsimplify.rs +++ b/compiler/rustc_mir_transform/src/instsimplify.rs @@ -219,10 +219,8 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> { for (i, field) in variant.fields.iter_enumerated() { let field_ty = field.ty(self.tcx, args); if field_ty == *cast_ty { - let place = place.project_deeper( - &[ProjectionElem::Field(i, *cast_ty)], - self.tcx, - ); + let place = place + .project_deeper(&[ProjectionElem::Field(i, *cast_ty)], self.tcx); let operand = if operand.is_move() { Operand::Move(place) } else { diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index e4670633914e..93ae105150cc 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -211,7 +211,7 @@ fn remap_mir_for_const_eval_select<'tcx>( } fn is_mir_available(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { - tcx.mir_keys(()).contains(&def_id) + tcx.hir().maybe_body_owned_by(def_id).is_some() } /// Finds the full set of `DefId`s within the current crate that have @@ -222,6 +222,15 @@ fn mir_keys(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet { // All body-owners have MIR associated with them. set.extend(tcx.hir().body_owners()); + // Inline consts' bodies are created in + // typeck instead of during ast lowering, like all other bodies so far. + for def_id in tcx.hir().body_owners() { + // Incremental performance optimization: only load typeck results for things that actually have inline consts + if tcx.hir_owner_nodes(tcx.hir().body_owned_by(def_id).hir_id.owner).has_inline_consts { + set.extend(tcx.typeck(def_id).inline_consts.values()) + } + } + // Additionally, tuple struct/variant constructors have MIR, but // they don't have a BodyId, so we need to build them separately. struct GatherCtors<'a> { diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs index 221301b2ceb0..3ffc447217d7 100644 --- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs +++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs @@ -316,6 +316,23 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics { terminator.kind = TerminatorKind::Goto { target }; } + sym::ptr_metadata => { + let Ok([ptr]) = <[_; 1]>::try_from(std::mem::take(args)) else { + span_bug!( + terminator.source_info.span, + "Wrong number of arguments for ptr_metadata intrinsic", + ); + }; + let target = target.unwrap(); + block.statements.push(Statement { + source_info: terminator.source_info, + kind: StatementKind::Assign(Box::new(( + *destination, + Rvalue::UnaryOp(UnOp::PtrMetadata, ptr.node), + ))), + }); + terminator.kind = TerminatorKind::Goto { target }; + } _ => {} } } diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index e37f90ae7f40..7ec59cc983f5 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -464,7 +464,7 @@ impl<'tcx> Validator<'_, 'tcx> { Rvalue::UnaryOp(op, operand) => { match op { // These operations can never fail. - UnOp::Neg | UnOp::Not => {} + UnOp::Neg | UnOp::Not | UnOp::PtrMetadata => {} } self.validate_operand(operand)?; diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index 6df32169eecb..851e16559580 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -691,7 +691,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { location, format!( "You can't project to field {f:?} of `DynMetadata` because \ - layout is weird and thinks it doesn't have fields." + layout is weird and thinks it doesn't have fields." ), ); } @@ -1109,6 +1109,16 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ty::Int(..) | ty::Uint(..) | ty::Bool ); } + UnOp::PtrMetadata => { + if !matches!(self.mir_phase, MirPhase::Runtime(_)) { + // It would probably be fine to support this in earlier phases, + // but at the time of writing it's only ever introduced from intrinsic lowering, + // so earlier things can just `bug!` on it. + self.fail(location, "PtrMetadata should be in runtime MIR only"); + } + + check_kinds!(a, "Cannot PtrMetadata non-pointer type {:?}", ty::RawPtr(..)); + } } } Rvalue::ShallowInitBox(operand, _) => { diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index c2183258eef1..bab8b6c06ebe 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -25,8 +25,8 @@ use rustc_ast::tokenstream::{AttributesData, DelimSpacing, DelimSpan, Spacing}; use rustc_ast::tokenstream::{TokenStream, TokenTree, TokenTreeCursor}; use rustc_ast::util::case::Case; use rustc_ast::{ - self as ast, AnonConst, AttrArgs, AttrArgsEq, AttrId, ByRef, Const, CoroutineKind, DelimArgs, - Expr, ExprKind, Extern, HasAttrs, HasTokens, Mutability, Recovered, Safety, StrLit, Visibility, + self as ast, AttrArgs, AttrArgsEq, AttrId, ByRef, Const, CoroutineKind, DelimArgs, Expr, + ExprKind, Extern, HasAttrs, HasTokens, Mutability, Recovered, Safety, StrLit, Visibility, VisibilityKind, DUMMY_NODE_ID, }; use rustc_ast_pretty::pprust; @@ -1260,12 +1260,9 @@ impl<'a> Parser<'a> { } self.eat_keyword(kw::Const); let (attrs, blk) = self.parse_inner_attrs_and_block()?; - let anon_const = AnonConst { - id: DUMMY_NODE_ID, - value: self.mk_expr(blk.span, ExprKind::Block(blk, None)), - }; - let blk_span = anon_const.value.span; - Ok(self.mk_expr_with_attrs(span.to(blk_span), ExprKind::ConstBlock(anon_const), attrs)) + let expr = self.mk_expr(blk.span, ExprKind::Block(blk, None)); + let blk_span = expr.span; + Ok(self.mk_expr_with_attrs(span.to(blk_span), ExprKind::ConstBlock(expr), attrs)) } /// Parses mutability (`mut` or nothing). diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index eb29a65cb293..fa2c8f69c71d 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -196,11 +196,6 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> { self.recurse_into(kind, None, |this| intravisit::walk_anon_const(this, anon)); } - fn visit_inline_const(&mut self, block: &'tcx hir::ConstBlock) { - let kind = Some(hir::ConstContext::Const { inline: true }); - self.recurse_into(kind, None, |this| intravisit::walk_inline_const(this, block)); - } - fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) { let owner = self.tcx.hir().body_owner_def_id(body.id()); let kind = self.tcx.hir().body_const_context(owner); @@ -228,6 +223,11 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> { self.const_check_violated(expr, e.span); } } + hir::ExprKind::ConstBlock(expr) => { + let kind = Some(hir::ConstContext::Const { inline: true }); + self.recurse_into(kind, None, |this| intravisit::walk_expr(this, expr)); + return; + } _ => {} } diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index ddc50e2b811a..0049afff528c 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -587,6 +587,16 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { hir::ExprKind::OffsetOf(..) => { self.handle_offset_of(expr); } + hir::ExprKind::ConstBlock(expr) => { + // When inline const blocks are used in pattern position, paths + // referenced by it should be considered as used. + let in_pat = mem::replace(&mut self.in_pat, false); + + intravisit::walk_expr(self, expr); + + self.in_pat = in_pat; + return; + } _ => (), } @@ -648,17 +658,6 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { self.in_pat = in_pat; } - - fn visit_inline_const(&mut self, c: &'tcx hir::ConstBlock) { - // When inline const blocks are used in pattern position, paths - // referenced by it should be considered as used. - let in_pat = mem::replace(&mut self.in_pat, false); - - self.live_symbols.insert(c.def_id); - intravisit::walk_inline_const(self, c); - - self.in_pat = in_pat; - } } fn has_allow_dead_code_or_lang_attr( diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index b0a753604e2e..1f966be26ff4 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -147,6 +147,11 @@ fn check_liveness(tcx: TyCtxt<'_>, def_id: LocalDefId) { return; } + // Don't run for inline consts, they are collected together with their parent + if let DefKind::InlineConst = tcx.def_kind(def_id) { + return; + } + // Don't run unused pass for #[naked] if tcx.has_attr(def_id.to_def_id(), sym::naked) { return; @@ -1144,12 +1149,13 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } hir::ExprKind::Lit(..) - | hir::ExprKind::ConstBlock(..) | hir::ExprKind::Err(_) | hir::ExprKind::Path(hir::QPath::TypeRelative(..)) | hir::ExprKind::Path(hir::QPath::LangItem(..)) | hir::ExprKind::OffsetOf(..) => succ, + hir::ExprKind::ConstBlock(expr) => self.propagate_through_expr(expr, succ), + // Note that labels have been resolved, so we don't need to look // at the label ident hir::ExprKind::Block(ref blk, _) => self.propagate_through_block(blk, succ), diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs index 2587a18b8c89..737310e5c04a 100644 --- a/compiler/rustc_passes/src/loops.rs +++ b/compiler/rustc_passes/src/loops.rs @@ -93,10 +93,6 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { self.with_context(Constant, |v| intravisit::walk_anon_const(v, c)); } - fn visit_inline_const(&mut self, c: &'hir hir::ConstBlock) { - self.with_context(Constant, |v| intravisit::walk_inline_const(v, c)); - } - fn visit_fn( &mut self, fk: hir::intravisit::FnKind<'hir>, @@ -289,6 +285,9 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { self.cx_stack.len() - 1, ) } + hir::ExprKind::ConstBlock(expr) => { + self.with_context(Constant, |v| intravisit::walk_expr(v, expr)); + } _ => intravisit::walk_expr(self, e), } } diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index bd0622428569..cad10571afe6 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -325,16 +325,6 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { ExprKind::Gen(_, _, _) => { self.create_def(expr.id, kw::Empty, DefKind::Closure, expr.span) } - ExprKind::ConstBlock(ref constant) => { - let def = self.create_def( - constant.id, - kw::Empty, - DefKind::InlineConst, - constant.value.span, - ); - self.with_parent(def, |this| visit::walk_anon_const(this, constant)); - return; - } _ => self.parent_def, }; diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 51b87c5a9b03..6bbde26db344 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -537,6 +537,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let determined_imports = mem::take(&mut self.determined_imports); let indeterminate_imports = mem::take(&mut self.indeterminate_imports); + let mut glob_error = false; for (is_indeterminate, import) in determined_imports .iter() .map(|i| (false, i)) @@ -548,6 +549,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { self.import_dummy_binding(*import, is_indeterminate); if let Some(err) = unresolved_import_error { + glob_error |= import.is_glob(); + if let ImportKind::Single { source, ref source_bindings, .. } = import.kind { if source.name == kw::SelfLower { // Silence `unresolved import` error if E0429 is already emitted @@ -563,7 +566,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { { // In the case of a new import line, throw a diagnostic message // for the previous line. - self.throw_unresolved_import_error(errors); + self.throw_unresolved_import_error(errors, glob_error); errors = vec![]; } if seen_spans.insert(err.span) { @@ -574,7 +577,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } if !errors.is_empty() { - self.throw_unresolved_import_error(errors); + self.throw_unresolved_import_error(errors, glob_error); return; } @@ -600,9 +603,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } - if !errors.is_empty() { - self.throw_unresolved_import_error(errors); - } + self.throw_unresolved_import_error(errors, glob_error); } pub(crate) fn check_hidden_glob_reexports( @@ -672,7 +673,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } - fn throw_unresolved_import_error(&mut self, errors: Vec<(Import<'_>, UnresolvedImportError)>) { + fn throw_unresolved_import_error( + &mut self, + errors: Vec<(Import<'_>, UnresolvedImportError)>, + glob_error: bool, + ) { if errors.is_empty() { return; } @@ -751,7 +756,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } - diag.emit(); + let guar = diag.emit(); + if glob_error { + self.glob_error = Some(guar); + } } /// Attempts to resolve the given import, returning: diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 63d0d6c260db..bcdd6716cc37 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -4033,9 +4033,12 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { } #[inline] - /// If we're actually rustdoc then avoid giving a name resolution error for `cfg()` items. + /// If we're actually rustdoc then avoid giving a name resolution error for `cfg()` items or + // an invalid `use foo::*;` was found, which can cause unbounded ammounts of "item not found" + // errors. We silence them all. fn should_report_errs(&self) -> bool { !(self.r.tcx.sess.opts.actually_rustdoc && self.in_func_body) + && !self.r.glob_error.is_some() } // Resolve in alternative namespaces if resolution in the primary namespace fails. @@ -4502,8 +4505,10 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { self.visit_expr(elem); self.resolve_anon_const(ct, AnonConstKind::ConstArg(IsRepeatExpr::Yes)); } - ExprKind::ConstBlock(ref ct) => { - self.resolve_anon_const(ct, AnonConstKind::InlineConst); + ExprKind::ConstBlock(ref expr) => { + self.resolve_anon_const_manual(false, AnonConstKind::InlineConst, |this| { + this.visit_expr(expr) + }); } ExprKind::Index(ref elem, ref idx, _) => { self.resolve_expr(elem, Some(expr)); diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index f4c5ad8f6721..9557b0f5ebc0 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -32,7 +32,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::{FreezeReadGuard, Lrc}; -use rustc_errors::{Applicability, Diag, ErrCode}; +use rustc_errors::{Applicability, Diag, ErrCode, ErrorGuaranteed}; use rustc_expand::base::{DeriveResolution, SyntaxExtension, SyntaxExtensionKind}; use rustc_feature::BUILTIN_ATTRIBUTES; use rustc_hir::def::Namespace::{self, *}; @@ -1048,6 +1048,7 @@ pub struct Resolver<'a, 'tcx> { /// Maps glob imports to the names of items actually imported. glob_map: FxHashMap>, + glob_error: Option, visibilities_for_hashing: Vec<(LocalDefId, ty::Visibility)>, used_imports: FxHashSet, maybe_unused_trait_imports: FxIndexSet, @@ -1417,6 +1418,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ast_transform_scopes: FxHashMap::default(), glob_map: Default::default(), + glob_error: None, visibilities_for_hashing: Default::default(), used_imports: FxHashSet::default(), maybe_unused_trait_imports: Default::default(), diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index c90da966e708..a622f1b577df 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -159,7 +159,23 @@ pub enum CoverageLevel { Block, /// Also instrument branch points (includes block coverage). Branch, - /// Instrument for MC/DC. Mostly a superset of branch coverage, but might + /// Same as branch coverage, but also adds branch instrumentation for + /// certain boolean expressions that are not directly used for branching. + /// + /// For example, in the following code, `b` does not directly participate + /// in a branch, but condition coverage will instrument it as its own + /// artificial branch: + /// ``` + /// # let (a, b) = (false, true); + /// let x = a && b; + /// // ^ last operand + /// ``` + /// + /// This level is mainly intended to be a stepping-stone towards full MC/DC + /// instrumentation, so it might be removed in the future when MC/DC is + /// sufficiently complete, or if it is making MC/DC changes difficult. + Condition, + /// Instrument for MC/DC. Mostly a superset of condition coverage, but might /// differ in some corner cases. Mcdc, } @@ -773,6 +789,7 @@ pub enum PrintKind { TargetLibdir, CrateName, Cfg, + CheckCfg, CallingConventions, TargetList, TargetCPUs, @@ -1443,7 +1460,7 @@ pub fn rustc_short_optgroups() -> Vec { "", "print", "Compiler information to print on stdout", - "[crate-name|file-names|sysroot|target-libdir|cfg|calling-conventions|\ + "[crate-name|file-names|sysroot|target-libdir|cfg|check-cfg|calling-conventions|\ target-list|target-cpus|target-features|relocation-models|code-models|\ tls-models|target-spec-json|all-target-specs-json|native-static-libs|\ stack-protector-strategies|link-args|deployment-target]", @@ -1859,6 +1876,7 @@ fn collect_print_requests( ("all-target-specs-json", PrintKind::AllTargetSpecs), ("calling-conventions", PrintKind::CallingConventions), ("cfg", PrintKind::Cfg), + ("check-cfg", PrintKind::CheckCfg), ("code-models", PrintKind::CodeModels), ("crate-name", PrintKind::CrateName), ("deployment-target", PrintKind::DeploymentTarget), @@ -1908,6 +1926,16 @@ fn collect_print_requests( ); } } + Some((_, PrintKind::CheckCfg)) => { + if unstable_opts.unstable_options { + PrintKind::CheckCfg + } else { + early_dcx.early_fatal( + "the `-Z unstable-options` flag must also be passed to \ + enable the check-cfg print option", + ); + } + } Some(&(_, print_kind)) => print_kind, None => { let prints = diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 6309fcdd2db3..fd4a3a9e6ceb 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -395,7 +395,7 @@ mod desc { pub const parse_optimization_fuel: &str = "crate=integer"; pub const parse_dump_mono_stats: &str = "`markdown` (default) or `json`"; pub const parse_instrument_coverage: &str = parse_bool; - pub const parse_coverage_options: &str = "`block` | `branch` | `mcdc`"; + pub const parse_coverage_options: &str = "`block` | `branch` | `condition` | `mcdc`"; pub const parse_instrument_xray: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), or a comma separated list of settings: `always` or `never` (mutually exclusive), `ignore-loops`, `instruction-threshold=N`, `skip-entry`, `skip-exit`"; pub const parse_unpretty: &str = "`string` or `string=string`"; pub const parse_treat_err_as_bug: &str = "either no value or a non-negative number"; @@ -961,6 +961,7 @@ mod parse { match option { "block" => slot.level = CoverageLevel::Block, "branch" => slot.level = CoverageLevel::Branch, + "condition" => slot.level = CoverageLevel::Condition, "mcdc" => slot.level = CoverageLevel::Mcdc, _ => return false, } @@ -1678,6 +1679,8 @@ options! { fewer_names: Option = (None, parse_opt_bool, [TRACKED], "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) \ (default: no)"), + fixed_x18: bool = (false, parse_bool, [TRACKED], + "make the x18 register reserved on AArch64 (default: no)"), flatten_format_args: bool = (true, parse_bool, [TRACKED], "flatten nested format_args!() and literals into a simplified format_args!() call \ (default: yes)"), diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index a5cf136db6a6..87bbfcf07c84 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -353,6 +353,11 @@ impl Session { && self.opts.unstable_opts.coverage_options.level >= CoverageLevel::Branch } + pub fn instrument_coverage_condition(&self) -> bool { + self.instrument_coverage() + && self.opts.unstable_opts.coverage_options.level >= CoverageLevel::Condition + } + pub fn instrument_coverage_mcdc(&self) -> bool { self.instrument_coverage() && self.opts.unstable_opts.coverage_options.level >= CoverageLevel::Mcdc diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs index 6b73c1ebd1ca..6ec710f97d16 100644 --- a/compiler/rustc_smir/src/rustc_internal/internal.rs +++ b/compiler/rustc_smir/src/rustc_internal/internal.rs @@ -10,7 +10,7 @@ use rustc_span::Symbol; use stable_mir::abi::Layout; use stable_mir::mir::alloc::AllocId; use stable_mir::mir::mono::{Instance, MonoItem, StaticDef}; -use stable_mir::mir::{BinOp, Mutability, Place, ProjectionElem, Safety}; +use stable_mir::mir::{BinOp, Mutability, Place, ProjectionElem, Safety, UnOp}; use stable_mir::ty::{ Abi, AdtDef, Binder, BoundRegionKind, BoundTyKind, BoundVariableKind, ClosureKind, Const, DynKind, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FloatTy, FnSig, @@ -582,6 +582,18 @@ impl RustcInternal for BinOp { } } +impl RustcInternal for UnOp { + type T<'tcx> = rustc_middle::mir::UnOp; + + fn internal<'tcx>(&self, _tables: &mut Tables<'_>, _tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { + match self { + UnOp::Not => rustc_middle::mir::UnOp::Not, + UnOp::Neg => rustc_middle::mir::UnOp::Neg, + UnOp::PtrMetadata => rustc_middle::mir::UnOp::PtrMetadata, + } + } +} + impl RustcInternal for &T where T: RustcInternal, diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index 7afe46f2cbe1..fa7b2a30ba6c 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -19,7 +19,7 @@ use stable_mir::abi::{FnAbi, Layout, LayoutShape}; use stable_mir::compiler_interface::Context; use stable_mir::mir::alloc::GlobalAlloc; use stable_mir::mir::mono::{InstanceDef, StaticDef}; -use stable_mir::mir::{BinOp, Body, Place}; +use stable_mir::mir::{BinOp, Body, Place, UnOp}; use stable_mir::target::{MachineInfo, MachineSize}; use stable_mir::ty::{ AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, ForeignDef, @@ -700,6 +700,14 @@ impl<'tcx> Context for TablesWrapper<'tcx> { let ty = bin_op.internal(&mut *tables, tcx).ty(tcx, rhs_internal, lhs_internal); ty.stable(&mut *tables) } + + fn unop_ty(&self, un_op: UnOp, arg: Ty) -> Ty { + let mut tables = self.0.borrow_mut(); + let tcx = tables.tcx; + let arg_internal = arg.internal(&mut *tables, tcx); + let ty = un_op.internal(&mut *tables, tcx).ty(tcx, arg_internal); + ty.stable(&mut *tables) + } } pub struct TablesWrapper<'tcx>(pub RefCell>); diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs index d89caabab3e1..a1a5c09ef0af 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs @@ -526,6 +526,7 @@ impl<'tcx> Stable<'tcx> for mir::UnOp { match self { UnOp::Not => stable_mir::mir::UnOp::Not, UnOp::Neg => stable_mir::mir::UnOp::Neg, + UnOp::PtrMetadata => stable_mir::mir::UnOp::PtrMetadata, } } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index ace4dff46aa0..25ecb9a31c6a 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -210,7 +210,6 @@ symbols! { FsPermissions, FusedIterator, Future, - FutureOutput, GlobalAlloc, Hash, HashMap, @@ -439,8 +438,10 @@ symbols! { async_fn, async_fn_in_trait, async_fn_kind_helper, + async_fn_kind_upvars, async_fn_mut, async_fn_once, + async_fn_once_output, async_fn_track_caller, async_fn_traits, async_for_loop, @@ -498,6 +499,8 @@ symbols! { call, call_mut, call_once, + call_once_future, + call_ref_future, caller_location, capture_disjoint_fields, catch_unwind, @@ -911,6 +914,7 @@ symbols! { fundamental, fused_iterator, future, + future_output, future_trait, gdb_script_file, ge, @@ -1179,6 +1183,7 @@ symbols! { mir_make_place, mir_move, mir_offset, + mir_ptr_metadata, mir_retag, mir_return, mir_return_to, @@ -1433,6 +1438,7 @@ symbols! { ptr_guaranteed_cmp, ptr_is_null, ptr_mask, + ptr_metadata, ptr_null, ptr_null_mut, ptr_offset_from, diff --git a/compiler/rustc_target/src/abi/call/nvptx64.rs b/compiler/rustc_target/src/abi/call/nvptx64.rs index f85fa2419f0f..c6b6f66e6be8 100644 --- a/compiler/rustc_target/src/abi/call/nvptx64.rs +++ b/compiler/rustc_target/src/abi/call/nvptx64.rs @@ -11,11 +11,10 @@ fn classify_ret(ret: &mut ArgAbi<'_, Ty>) { } fn classify_arg(arg: &mut ArgAbi<'_, Ty>) { - if arg.layout.is_aggregate() && arg.layout.size.bits() > 64 { - arg.make_indirect(); - } else { - // FIXME: this is wrong! Need to decide which ABI we really want here. - arg.make_direct_deprecated(); + if arg.layout.is_aggregate() { + arg.make_indirect_byval(None); + } else if arg.layout.size.bits() < 32 { + arg.extend_integer_width_to(32); } } diff --git a/compiler/rustc_trait_selection/src/solve/alias_relate.rs b/compiler/rustc_trait_selection/src/solve/alias_relate.rs index 43e61de955af..4d7e2fc2cefa 100644 --- a/compiler/rustc_trait_selection/src/solve/alias_relate.rs +++ b/compiler/rustc_trait_selection/src/solve/alias_relate.rs @@ -26,8 +26,9 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { &mut self, goal: Goal<'tcx, (ty::Term<'tcx>, ty::Term<'tcx>, ty::AliasRelationDirection)>, ) -> QueryResult<'tcx> { - let tcx = self.tcx(); + let tcx = self.interner(); let Goal { param_env, predicate: (lhs, rhs, direction) } = goal; + debug_assert!(lhs.to_alias_term().is_some() || rhs.to_alias_term().is_some()); // Structurally normalize the lhs. let lhs = if let Some(alias) = lhs.to_alias_term() { diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 115244106928..aae6fa9f635b 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -83,7 +83,7 @@ pub(super) trait GoalKind<'tcx>: assumption: ty::Clause<'tcx>, ) -> Result, NoSolution> { Self::probe_and_match_goal_against_assumption(ecx, source, goal, assumption, |ecx| { - let tcx = ecx.tcx(); + let tcx = ecx.interner(); let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else { bug!("expected object type in `probe_and_consider_object_bound_candidate`"); }; @@ -288,8 +288,10 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { return self.forced_ambiguity(MaybeCause::Ambiguity).into_iter().collect(); } - let goal: Goal<'tcx, G> = - goal.with(self.tcx(), goal.predicate.with_self_ty(self.tcx(), normalized_self_ty)); + let goal: Goal<'tcx, G> = goal.with( + self.interner(), + goal.predicate.with_self_ty(self.interner(), normalized_self_ty), + ); // Vars that show up in the rest of the goal substs may have been constrained by // normalizing the self type as well, since type variables are not uniquified. let goal = self.resolve_vars_if_possible(goal); @@ -339,7 +341,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { goal: Goal<'tcx, G>, candidates: &mut Vec>, ) { - let tcx = self.tcx(); + let tcx = self.interner(); let self_ty = goal.predicate.self_ty(); let trait_impls = tcx.trait_impls_of(goal.predicate.trait_def_id(tcx)); let mut consider_impls_for_simplified_type = |simp| { @@ -455,7 +457,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { goal: Goal<'tcx, G>, candidates: &mut Vec>, ) { - let tcx = self.tcx(); + let tcx = self.interner(); let trait_impls = tcx.trait_impls_of(goal.predicate.trait_def_id(tcx)); for &impl_def_id in trait_impls.blanket_impls() { // For every `default impl`, there's always a non-default `impl` @@ -478,7 +480,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { goal: Goal<'tcx, G>, candidates: &mut Vec>, ) { - let tcx = self.tcx(); + let tcx = self.interner(); let lang_items = tcx.lang_items(); let trait_def_id = goal.predicate.trait_def_id(tcx); @@ -505,9 +507,9 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { G::consider_builtin_pointer_like_candidate(self, goal) } else if lang_items.fn_ptr_trait() == Some(trait_def_id) { G::consider_builtin_fn_ptr_trait_candidate(self, goal) - } else if let Some(kind) = self.tcx().fn_trait_kind_from_def_id(trait_def_id) { + } else if let Some(kind) = self.interner().fn_trait_kind_from_def_id(trait_def_id) { G::consider_builtin_fn_trait_candidates(self, goal, kind) - } else if let Some(kind) = self.tcx().async_fn_trait_kind_from_def_id(trait_def_id) { + } else if let Some(kind) = self.interner().async_fn_trait_kind_from_def_id(trait_def_id) { G::consider_builtin_async_fn_trait_candidates(self, goal, kind) } else if lang_items.async_fn_kind_helper() == Some(trait_def_id) { G::consider_builtin_async_fn_kind_helper_candidate(self, goal) @@ -634,7 +636,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) => (kind, alias_ty), ty::Alias(ty::Inherent | ty::Weak, _) => { - self.tcx().sess.dcx().span_delayed_bug( + self.interner().sess.dcx().span_delayed_bug( DUMMY_SP, format!("could not normalize {self_ty}, it is not WF"), ); @@ -643,7 +645,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { }; for assumption in - self.tcx().item_bounds(alias_ty.def_id).instantiate(self.tcx(), alias_ty.args) + self.interner().item_bounds(alias_ty.def_id).instantiate(self.interner(), alias_ty.args) { candidates.extend(G::probe_and_consider_implied_clause( self, @@ -673,7 +675,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { goal: Goal<'tcx, G>, candidates: &mut Vec>, ) { - let tcx = self.tcx(); + let tcx = self.interner(); if !tcx.trait_def(goal.predicate.trait_def_id(tcx)).implement_via_object { return; } @@ -764,7 +766,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { goal: Goal<'tcx, G>, candidates: &mut Vec>, ) { - let tcx = self.tcx(); + let tcx = self.interner(); candidates.extend(self.probe_trait_candidate(CandidateSource::CoherenceUnknowable).enter( |ecx| { @@ -793,7 +795,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { goal: Goal<'tcx, G>, candidates: &mut Vec>, ) { - let tcx = self.tcx(); + let tcx = self.interner(); let trait_goal: Goal<'tcx, ty::TraitPredicate<'tcx>> = goal.with(tcx, goal.predicate.trait_ref(tcx)); diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index 6f68875e6f63..08796ef3109e 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -9,7 +9,6 @@ use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::bug; use rustc_middle::traits::solve::Goal; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, Upcast}; -use rustc_span::sym; use crate::solve::EvalCtxt; @@ -22,7 +21,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>( ecx: &EvalCtxt<'_, InferCtxt<'tcx>>, ty: Ty<'tcx>, ) -> Result>>, NoSolution> { - let tcx = ecx.tcx(); + let tcx = ecx.interner(); match *ty.kind() { ty::Uint(_) | ty::Int(_) @@ -75,7 +74,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>( } ty::CoroutineWitness(def_id, args) => Ok(ecx - .tcx() + .interner() .bound_coroutine_hidden_types(def_id) .map(|bty| bty.instantiate(tcx, args)) .collect()), @@ -151,8 +150,8 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>( // "best effort" optimization and `sized_constraint` may return `Some`, even // if the ADT is sized for all possible args. ty::Adt(def, args) => { - if let Some(sized_crit) = def.sized_constraint(ecx.tcx()) { - Ok(vec![ty::Binder::dummy(sized_crit.instantiate(ecx.tcx(), args))]) + if let Some(sized_crit) = def.sized_constraint(ecx.interner()) { + Ok(vec![ty::Binder::dummy(sized_crit.instantiate(ecx.interner(), args))]) } else { Ok(vec![]) } @@ -210,10 +209,10 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( // only when `coroutine_clone` is enabled and the coroutine is movable // impl Copy/Clone for Coroutine where T: Copy/Clone forall T in (upvars, witnesses) - ty::Coroutine(def_id, args) => match ecx.tcx().coroutine_movability(def_id) { + ty::Coroutine(def_id, args) => match ecx.interner().coroutine_movability(def_id) { Movability::Static => Err(NoSolution), Movability::Movable => { - if ecx.tcx().features().coroutine_clone { + if ecx.interner().features().coroutine_clone { let coroutine = args.as_coroutine(); Ok(vec![ ty::Binder::dummy(coroutine.tupled_upvars_ty()), @@ -227,9 +226,9 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( // impl Copy/Clone for CoroutineWitness where T: Copy/Clone forall T in coroutine_hidden_types ty::CoroutineWitness(def_id, args) => Ok(ecx - .tcx() + .interner() .bound_coroutine_hidden_types(def_id) - .map(|bty| bty.instantiate(ecx.tcx(), args)) + .map(|bty| bty.instantiate(ecx.interner(), args)) .collect()), } } @@ -454,12 +453,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc .rebind(ty::TraitRef::new(tcx, future_trait_def_id, [sig.output()])) .upcast(tcx), ]; - let future_output_def_id = tcx - .associated_items(future_trait_def_id) - .filter_by_name_unhygienic(sym::Output) - .next() - .unwrap() - .def_id; + let future_output_def_id = tcx.require_lang_item(LangItem::FutureOutput, None); let future_output_ty = Ty::new_projection(tcx, future_output_def_id, [sig.output()]); Ok(( bound_sig.rebind(AsyncCallableRelevantTypes { @@ -510,12 +504,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc ); } - let future_output_def_id = tcx - .associated_items(future_trait_def_id) - .filter_by_name_unhygienic(sym::Output) - .next() - .unwrap() - .def_id; + let future_output_def_id = tcx.require_lang_item(LangItem::FutureOutput, None); let future_output_ty = Ty::new_projection(tcx, future_output_def_id, [sig.output()]); Ok(( bound_sig.rebind(AsyncCallableRelevantTypes { @@ -592,13 +581,7 @@ fn coroutine_closure_to_ambiguous_coroutine<'tcx>( args: ty::CoroutineClosureArgs<'tcx>, sig: ty::CoroutineClosureSignature<'tcx>, ) -> Ty<'tcx> { - let async_fn_kind_trait_def_id = tcx.require_lang_item(LangItem::AsyncFnKindHelper, None); - let upvars_projection_def_id = tcx - .associated_items(async_fn_kind_trait_def_id) - .filter_by_name_unhygienic(sym::Upvars) - .next() - .unwrap() - .def_id; + let upvars_projection_def_id = tcx.require_lang_item(LangItem::AsyncFnKindUpvars, None); let tupled_upvars_ty = Ty::new_projection( tcx, upvars_projection_def_id, @@ -666,7 +649,7 @@ pub(in crate::solve) fn predicates_for_object_candidate<'tcx>( trait_ref: ty::TraitRef<'tcx>, object_bound: &'tcx ty::List>, ) -> Vec>> { - let tcx = ecx.tcx(); + let tcx = ecx.interner(); let mut requirements = vec![]; requirements.extend( tcx.super_predicates_of(trait_ref.def_id).instantiate(tcx, trait_ref.args).predicates, @@ -722,7 +705,7 @@ struct ReplaceProjectionWith<'a, 'tcx> { impl<'tcx> TypeFolder> for ReplaceProjectionWith<'_, 'tcx> { fn interner(&self) -> TyCtxt<'tcx> { - self.ecx.tcx() + self.ecx.interner() } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { @@ -739,7 +722,7 @@ impl<'tcx> TypeFolder> for ReplaceProjectionWith<'_, 'tcx> { .eq_and_get_goals( self.param_env, alias_ty, - proj.projection_term.expect_ty(self.ecx.tcx()), + proj.projection_term.expect_ty(self.ecx.interner()), ) .expect("expected to be able to unify goal projection with dyn's projection"), ); diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs index f6ec65490845..690c1797f239 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs @@ -16,7 +16,6 @@ use crate::solve::{ use rustc_data_structures::fx::FxHashSet; use rustc_index::IndexVec; use rustc_infer::infer::canonical::query_response::make_query_region_constraints; -use rustc_infer::infer::canonical::CanonicalVarValues; use rustc_infer::infer::canonical::{CanonicalExt, QueryRegionConstraints}; use rustc_infer::infer::RegionVariableOrigin; use rustc_infer::infer::{InferCtxt, InferOk}; @@ -32,22 +31,24 @@ use rustc_middle::ty::{self, BoundVar, GenericArgKind, Ty, TyCtxt, TypeFoldable} use rustc_next_trait_solver::canonicalizer::{CanonicalizeMode, Canonicalizer}; use rustc_next_trait_solver::resolve::EagerResolver; use rustc_span::{Span, DUMMY_SP}; +use rustc_type_ir::CanonicalVarValues; +use rustc_type_ir::{InferCtxtLike, Interner}; use std::assert_matches::assert_matches; use std::iter; use std::ops::Deref; trait ResponseT<'tcx> { - fn var_values(&self) -> CanonicalVarValues<'tcx>; + fn var_values(&self) -> CanonicalVarValues>; } impl<'tcx> ResponseT<'tcx> for Response> { - fn var_values(&self) -> CanonicalVarValues<'tcx> { + fn var_values(&self) -> CanonicalVarValues> { self.var_values } } impl<'tcx, T> ResponseT<'tcx> for inspect::State, T> { - fn var_values(&self) -> CanonicalVarValues<'tcx> { + fn var_values(&self) -> CanonicalVarValues> { self.var_values } } @@ -71,7 +72,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { QueryInput { goal, predefined_opaques_in_body: self - .tcx() + .interner() .mk_predefined_opaques_in_body(PredefinedOpaquesData { opaque_types }), }, ); @@ -144,7 +145,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { Response { var_values, certainty, - external_constraints: self.tcx().mk_external_constraints(external_constraints), + external_constraints: self.interner().mk_external_constraints(external_constraints), }, ); @@ -160,7 +161,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { maybe_cause: MaybeCause, ) -> CanonicalResponse<'tcx> { response_no_constraints_raw( - self.tcx(), + self.interner(), self.max_input_universe, self.variables, Certainty::Maybe(maybe_cause), @@ -194,7 +195,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { let region_obligations = self.infcx.inner.borrow().region_obligations().to_owned(); let mut region_constraints = self.infcx.with_region_constraints(|region_constraints| { make_query_region_constraints( - self.tcx(), + self.interner(), region_obligations.iter().map(|r_o| { (r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category()) }), @@ -239,7 +240,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { ); let Response { var_values, external_constraints, certainty } = - response.instantiate(self.tcx(), &instantiation); + response.instantiate(self.interner(), &instantiation); Self::unify_query_var_values(self.infcx, param_env, &original_values, var_values); @@ -260,7 +261,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { infcx: &InferCtxt<'tcx>, original_values: &[ty::GenericArg<'tcx>], response: &Canonical<'tcx, T>, - ) -> CanonicalVarValues<'tcx> { + ) -> CanonicalVarValues> { // FIXME: Longterm canonical queries should deal with all placeholders // created inside of the query directly instead of returning them to the // caller. @@ -354,7 +355,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, original_values: &[ty::GenericArg<'tcx>], - var_values: CanonicalVarValues<'tcx>, + var_values: CanonicalVarValues>, ) { assert_eq!(original_values.len(), var_values.len()); @@ -362,7 +363,6 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { for (&orig, response) in iter::zip(original_values, var_values.var_values) { let InferOk { value: (), obligations } = infcx .at(&cause, param_env) - .trace(orig, response) .eq_structurally_relating_aliases(orig, response) .unwrap(); assert!(obligations.is_empty()); @@ -393,13 +393,18 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { /// evaluating a goal. The `var_values` not only include the bound variables /// of the query input, but also contain all unconstrained inference vars /// created while evaluating this goal. -pub(in crate::solve) fn make_canonical_state<'tcx, T: TypeFoldable>>( - infcx: &InferCtxt<'tcx>, - var_values: &[ty::GenericArg<'tcx>], +pub(in crate::solve) fn make_canonical_state( + infcx: &Infcx, + var_values: &[I::GenericArg], max_input_universe: ty::UniverseIndex, data: T, -) -> inspect::CanonicalState, T> { - let var_values = CanonicalVarValues { var_values: infcx.tcx.mk_args(var_values) }; +) -> inspect::CanonicalState +where + Infcx: InferCtxtLike, + I: Interner, + T: TypeFoldable, +{ + let var_values = CanonicalVarValues { var_values: infcx.interner().mk_args(var_values) }; let state = inspect::State { var_values, data }; let state = state.fold_with(&mut EagerResolver::new(infcx)); Canonicalizer::canonicalize( diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs index ce408ddea378..b18b59d9a752 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs @@ -13,11 +13,14 @@ use rustc_middle::traits::solve::{ inspect, CanonicalInput, CanonicalResponse, Certainty, PredefinedOpaquesData, QueryResult, }; use rustc_middle::traits::specialization_graph; +use rustc_middle::ty::AliasRelationDirection; +use rustc_middle::ty::TypeFolder; use rustc_middle::ty::{ self, InferCtxtLike, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, }; use rustc_span::DUMMY_SP; +use rustc_type_ir::fold::TypeSuperFoldable; use rustc_type_ir::{self as ir, CanonicalVarValues, Interner}; use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; use std::ops::ControlFlow; @@ -95,7 +98,7 @@ pub struct EvalCtxt< // evaluation code. tainted: Result<(), NoSolution>, - pub(super) inspect: ProofTreeBuilder, + pub(super) inspect: ProofTreeBuilder, } #[derive(derivative::Derivative)] @@ -215,7 +218,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { tcx: TyCtxt<'tcx>, search_graph: &'a mut search_graph::SearchGraph>, canonical_input: CanonicalInput<'tcx>, - canonical_goal_evaluation: &mut ProofTreeBuilder>, + canonical_goal_evaluation: &mut ProofTreeBuilder>, f: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>, Goal<'tcx, ty::Predicate<'tcx>>) -> R, ) -> R { let intercrate = match search_graph.solver_mode() { @@ -277,7 +280,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { tcx: TyCtxt<'tcx>, search_graph: &'a mut search_graph::SearchGraph>, canonical_input: CanonicalInput<'tcx>, - goal_evaluation: &mut ProofTreeBuilder>, + goal_evaluation: &mut ProofTreeBuilder>, ) -> QueryResult<'tcx> { let mut canonical_goal_evaluation = goal_evaluation.new_canonical_goal_evaluation(canonical_input); @@ -344,7 +347,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { let mut goal_evaluation = self.inspect.new_goal_evaluation(goal, &orig_values, goal_evaluation_kind); let canonical_response = EvalCtxt::evaluate_canonical_goal( - self.tcx(), + self.interner(), self.search_graph, canonical_goal, &mut goal_evaluation, @@ -447,7 +450,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { } } else { self.infcx.enter_forall(kind, |kind| { - let goal = goal.with(self.tcx(), ty::Binder::dummy(kind)); + let goal = goal.with(self.interner(), ty::Binder::dummy(kind)); self.add_goal(GoalSource::InstantiateHigherRanked, goal); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) @@ -455,13 +458,23 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { } #[instrument(level = "trace", skip(self))] - pub(super) fn add_normalizes_to_goal(&mut self, goal: Goal<'tcx, ty::NormalizesTo<'tcx>>) { + pub(super) fn add_normalizes_to_goal(&mut self, mut goal: Goal<'tcx, ty::NormalizesTo<'tcx>>) { + goal.predicate = goal + .predicate + .fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env }); self.inspect.add_normalizes_to_goal(self.infcx, self.max_input_universe, goal); self.nested_goals.normalizes_to_goals.push(goal); } #[instrument(level = "debug", skip(self))] - pub(super) fn add_goal(&mut self, source: GoalSource, goal: Goal<'tcx, ty::Predicate<'tcx>>) { + pub(super) fn add_goal( + &mut self, + source: GoalSource, + mut goal: Goal<'tcx, ty::Predicate<'tcx>>, + ) { + goal.predicate = goal + .predicate + .fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env }); self.inspect.add_goal(self.infcx, self.max_input_universe, source, goal); self.nested_goals.goals.push((source, goal)); } @@ -498,7 +511,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { /// /// Goals for the next step get directly added to the nested goals of the `EvalCtxt`. fn evaluate_added_goals_step(&mut self) -> Result, NoSolution> { - let tcx = self.tcx(); + let tcx = self.interner(); let mut goals = core::mem::take(&mut self.nested_goals); // If this loop did not result in any progress, what's our final certainty. @@ -584,11 +597,13 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { } } -impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { - pub(super) fn tcx(&self) -> TyCtxt<'tcx> { - self.infcx.tcx +impl, I: Interner> EvalCtxt<'_, Infcx> { + pub(super) fn interner(&self) -> I { + self.infcx.interner() } +} +impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { pub(super) fn next_ty_infer(&mut self) -> Ty<'tcx> { let ty = self.infcx.next_ty_var(DUMMY_SP); self.inspect.add_var_value(ty); @@ -746,7 +761,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { // NOTE: this check is purely an optimization, the structural eq would // always fail if the term is not an inference variable. if term.is_infer() { - let tcx = self.tcx(); + let tcx = self.interner(); // We need to relate `alias` to `term` treating only the outermost // constructor as rigid, relating any contained generic arguments as // normal. We do this by first structurally equating the `term` @@ -761,7 +776,6 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { let InferOk { value: (), obligations } = self .infcx .at(&ObligationCause::dummy(), param_env) - .trace(term, ctor_term) .eq_structurally_relating_aliases(term, ctor_term)?; debug_assert!(obligations.is_empty()); self.relate(param_env, alias, variance, rigid_ctor) @@ -781,11 +795,8 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { rhs: T, ) -> Result<(), NoSolution> { let cause = ObligationCause::dummy(); - let InferOk { value: (), obligations } = self - .infcx - .at(&cause, param_env) - .trace(lhs, rhs) - .eq_structurally_relating_aliases(lhs, rhs)?; + let InferOk { value: (), obligations } = + self.infcx.at(&cause, param_env).eq_structurally_relating_aliases(lhs, rhs)?; assert!(obligations.is_empty()); Ok(()) } @@ -1041,10 +1052,10 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { ) -> Option> { use rustc_middle::mir::interpret::ErrorHandled; match self.infcx.const_eval_resolve(param_env, unevaluated, DUMMY_SP) { - Ok(Some(val)) => Some(ty::Const::new_value(self.tcx(), val, ty)), + Ok(Some(val)) => Some(ty::Const::new_value(self.interner(), val, ty)), Ok(None) | Err(ErrorHandled::TooGeneric(_)) => None, Err(ErrorHandled::Reported(e, _)) => { - Some(ty::Const::new_error(self.tcx(), e.into(), ty)) + Some(ty::Const::new_error(self.interner(), e.into(), ty)) } } } @@ -1057,7 +1068,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { principal: ty::PolyTraitRef<'tcx>, mut supertrait_visitor: impl FnMut(&mut Self, ty::PolyTraitRef<'tcx>, usize, Option), ) { - let tcx = self.tcx(); + let tcx = self.interner(); let mut offset = 0; prepare_vtable_segments::<()>(tcx, principal, |segment| { match segment { @@ -1084,3 +1095,63 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { }); } } + +/// Eagerly replace aliases with inference variables, emitting `AliasRelate` +/// goals, used when adding goals to the `EvalCtxt`. We compute the +/// `AliasRelate` goals before evaluating the actual goal to get all the +/// constraints we can. +/// +/// This is a performance optimization to more eagerly detect cycles during trait +/// solving. See tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.rs. +struct ReplaceAliasWithInfer<'me, 'a, 'tcx> { + ecx: &'me mut EvalCtxt<'a, InferCtxt<'tcx>>, + param_env: ty::ParamEnv<'tcx>, +} + +impl<'tcx> TypeFolder> for ReplaceAliasWithInfer<'_, '_, 'tcx> { + fn interner(&self) -> TyCtxt<'tcx> { + self.ecx.interner() + } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + match *ty.kind() { + ty::Alias(..) if !ty.has_escaping_bound_vars() => { + let infer_ty = self.ecx.next_ty_infer(); + let normalizes_to = ty::PredicateKind::AliasRelate( + ty.into(), + infer_ty.into(), + AliasRelationDirection::Equate, + ); + self.ecx.add_goal( + GoalSource::Misc, + Goal::new(self.interner(), self.param_env, normalizes_to), + ); + infer_ty + } + _ => ty.super_fold_with(self), + } + } + + fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { + match ct.kind() { + ty::ConstKind::Unevaluated(..) if !ct.has_escaping_bound_vars() => { + let infer_ct = self.ecx.next_const_infer(ct.ty()); + let normalizes_to = ty::PredicateKind::AliasRelate( + ct.into(), + infer_ct.into(), + AliasRelationDirection::Equate, + ); + self.ecx.add_goal( + GoalSource::Misc, + Goal::new(self.interner(), self.param_env, normalizes_to), + ); + infer_ct + } + _ => ct.super_fold_with(self), + } + } + + fn fold_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { + if predicate.allow_normalization() { predicate.super_fold_with(self) } else { predicate } + } +} diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index 447357f8b3f6..1f27978e5a62 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -89,10 +89,8 @@ impl<'tcx> NormalizesToTermHack<'tcx> { pub struct InspectCandidate<'a, 'tcx> { goal: &'a InspectGoal<'a, 'tcx>, kind: inspect::ProbeKind>, - nested_goals: - Vec<(GoalSource, inspect::CanonicalState, Goal<'tcx, ty::Predicate<'tcx>>>)>, + steps: Vec<&'a inspect::ProbeStep>>, final_state: inspect::CanonicalState, ()>, - impl_args: Option, ty::GenericArgsRef<'tcx>>>, result: QueryResult<'tcx>, shallow_certainty: Certainty, } @@ -148,7 +146,7 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { #[instrument( level = "debug", skip_all, - fields(goal = ?self.goal.goal, nested_goals = ?self.nested_goals) + fields(goal = ?self.goal.goal, steps = ?self.steps) )] pub fn instantiate_nested_goals_and_opt_impl_args( &self, @@ -157,22 +155,34 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { let infcx = self.goal.infcx; let param_env = self.goal.goal.param_env; let mut orig_values = self.goal.orig_values.to_vec(); - let instantiated_goals: Vec<_> = self - .nested_goals - .iter() - .map(|(source, goal)| { - ( - *source, + + let mut instantiated_goals = vec![]; + let mut opt_impl_args = None; + for step in &self.steps { + match **step { + inspect::ProbeStep::AddGoal(source, goal) => instantiated_goals.push(( + source, canonical::instantiate_canonical_state( infcx, span, param_env, &mut orig_values, - *goal, + goal, ), - ) - }) - .collect(); + )), + inspect::ProbeStep::RecordImplArgs { impl_args } => { + opt_impl_args = Some(canonical::instantiate_canonical_state( + infcx, + span, + param_env, + &mut orig_values, + impl_args, + )); + } + inspect::ProbeStep::MakeCanonicalResponse { .. } + | inspect::ProbeStep::NestedProbe(_) => unreachable!(), + } + } let () = canonical::instantiate_canonical_state( infcx, @@ -182,17 +192,6 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { self.final_state, ); - let impl_args = self.impl_args.map(|impl_args| { - canonical::instantiate_canonical_state( - infcx, - span, - param_env, - &mut orig_values, - impl_args, - ) - .fold_with(&mut EagerResolver::new(infcx)) - }); - if let Some(term_hack) = self.goal.normalizes_to_term_hack { // FIXME: We ignore the expected term of `NormalizesTo` goals // when computing the result of its candidates. This is @@ -200,6 +199,9 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { let _ = term_hack.constrain(infcx, span, param_env); } + let opt_impl_args = + opt_impl_args.map(|impl_args| impl_args.fold_with(&mut EagerResolver::new(infcx))); + let goals = instantiated_goals .into_iter() .map(|(source, goal)| match goal.predicate.kind().no_bound_vars() { @@ -249,7 +251,7 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { }) .collect(); - (goals, impl_args) + (goals, opt_impl_args) } /// Visit all nested goals of this candidate, rolling back @@ -279,17 +281,18 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { fn candidates_recur( &'a self, candidates: &mut Vec>, - nested_goals: &mut Vec<( - GoalSource, - inspect::CanonicalState, Goal<'tcx, ty::Predicate<'tcx>>>, - )>, - probe: &inspect::Probe>, + steps: &mut Vec<&'a inspect::ProbeStep>>, + probe: &'a inspect::Probe>, ) { let mut shallow_certainty = None; - let mut impl_args = None; for step in &probe.steps { match *step { - inspect::ProbeStep::AddGoal(source, goal) => nested_goals.push((source, goal)), + inspect::ProbeStep::AddGoal(..) | inspect::ProbeStep::RecordImplArgs { .. } => { + steps.push(step) + } + inspect::ProbeStep::MakeCanonicalResponse { shallow_certainty: c } => { + assert_eq!(shallow_certainty.replace(c), None); + } inspect::ProbeStep::NestedProbe(ref probe) => { match probe.kind { // These never assemble candidates for the goal we're trying to solve. @@ -305,18 +308,12 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { // Nested probes have to prove goals added in their parent // but do not leak them, so we truncate the added goals // afterwards. - let num_goals = nested_goals.len(); - self.candidates_recur(candidates, nested_goals, probe); - nested_goals.truncate(num_goals); + let num_steps = steps.len(); + self.candidates_recur(candidates, steps, probe); + steps.truncate(num_steps); } } } - inspect::ProbeStep::MakeCanonicalResponse { shallow_certainty: c } => { - assert_eq!(shallow_certainty.replace(c), None); - } - inspect::ProbeStep::RecordImplArgs { impl_args: i } => { - assert_eq!(impl_args.replace(i), None); - } } } @@ -338,11 +335,10 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { candidates.push(InspectCandidate { goal: self, kind: probe.kind, - nested_goals: nested_goals.clone(), + steps: steps.clone(), final_state: probe.final_state, - result, shallow_certainty, - impl_args, + result, }); } } diff --git a/compiler/rustc_trait_selection/src/solve/inspect/build.rs b/compiler/rustc_trait_selection/src/solve/inspect/build.rs index 3c6333626483..84c04900ae48 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/build.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/build.rs @@ -3,18 +3,16 @@ //! This code is *a bit* of a mess and can hopefully be //! mostly ignored. For a general overview of how it works, //! see the comment on [ProofTreeBuilder]. +use std::marker::PhantomData; use std::mem; use crate::solve::eval_ctxt::canonical; use crate::solve::{self, inspect, GenerateProofTree}; -use rustc_infer::infer::InferCtxt; use rustc_middle::bug; -use rustc_middle::infer::canonical::CanonicalVarValues; -use rustc_middle::ty::{self, TyCtxt}; use rustc_next_trait_solver::solve::{ CanonicalInput, Certainty, Goal, GoalSource, QueryInput, QueryResult, }; -use rustc_type_ir::Interner; +use rustc_type_ir::{self as ty, InferCtxtLike, Interner}; /// The core data structure when building proof trees. /// @@ -36,7 +34,11 @@ use rustc_type_ir::Interner; /// trees. At the end of trait solving `ProofTreeBuilder::finalize` /// is called to recursively convert the whole structure to a /// finished proof tree. -pub(in crate::solve) struct ProofTreeBuilder { +pub(in crate::solve) struct ProofTreeBuilder< + Infcx: InferCtxtLike, + I: Interner = ::Interner, +> { + _infcx: PhantomData, state: Option>>, } @@ -229,36 +231,36 @@ impl WipProbeStep { } } -// FIXME: Genericize this impl. -impl<'tcx> ProofTreeBuilder> { - fn new(state: impl Into>>) -> ProofTreeBuilder> { - ProofTreeBuilder { state: Some(Box::new(state.into())) } +impl, I: Interner> ProofTreeBuilder { + fn new(state: impl Into>) -> ProofTreeBuilder { + ProofTreeBuilder { state: Some(Box::new(state.into())), _infcx: PhantomData } } - fn opt_nested>>>( - &self, - state: impl FnOnce() -> Option, - ) -> Self { + fn opt_nested>>(&self, state: impl FnOnce() -> Option) -> Self { ProofTreeBuilder { state: self.state.as_ref().and_then(|_| Some(state()?.into())).map(Box::new), + _infcx: PhantomData, } } - fn nested>>>(&self, state: impl FnOnce() -> T) -> Self { - ProofTreeBuilder { state: self.state.as_ref().map(|_| Box::new(state().into())) } + fn nested>>(&self, state: impl FnOnce() -> T) -> Self { + ProofTreeBuilder { + state: self.state.as_ref().map(|_| Box::new(state().into())), + _infcx: PhantomData, + } } - fn as_mut(&mut self) -> Option<&mut DebugSolver>> { + fn as_mut(&mut self) -> Option<&mut DebugSolver> { self.state.as_deref_mut() } - pub fn take_and_enter_probe(&mut self) -> ProofTreeBuilder> { - let mut nested = ProofTreeBuilder { state: self.state.take() }; + pub fn take_and_enter_probe(&mut self) -> ProofTreeBuilder { + let mut nested = ProofTreeBuilder { state: self.state.take(), _infcx: PhantomData }; nested.enter_probe(); nested } - pub fn finalize(self) -> Option>> { + pub fn finalize(self) -> Option> { match *self.state? { DebugSolver::GoalEvaluation(wip_goal_evaluation) => { Some(wip_goal_evaluation.finalize()) @@ -267,21 +269,19 @@ impl<'tcx> ProofTreeBuilder> { } } - pub fn new_maybe_root( - generate_proof_tree: GenerateProofTree, - ) -> ProofTreeBuilder> { + pub fn new_maybe_root(generate_proof_tree: GenerateProofTree) -> ProofTreeBuilder { match generate_proof_tree { GenerateProofTree::No => ProofTreeBuilder::new_noop(), GenerateProofTree::Yes => ProofTreeBuilder::new_root(), } } - pub fn new_root() -> ProofTreeBuilder> { + pub fn new_root() -> ProofTreeBuilder { ProofTreeBuilder::new(DebugSolver::Root) } - pub fn new_noop() -> ProofTreeBuilder> { - ProofTreeBuilder { state: None } + pub fn new_noop() -> ProofTreeBuilder { + ProofTreeBuilder { state: None, _infcx: PhantomData } } pub fn is_noop(&self) -> bool { @@ -290,10 +290,10 @@ impl<'tcx> ProofTreeBuilder> { pub(in crate::solve) fn new_goal_evaluation( &mut self, - goal: Goal, ty::Predicate<'tcx>>, - orig_values: &[ty::GenericArg<'tcx>], + goal: Goal, + orig_values: &[I::GenericArg], kind: solve::GoalEvaluationKind, - ) -> ProofTreeBuilder> { + ) -> ProofTreeBuilder { self.opt_nested(|| match kind { solve::GoalEvaluationKind::Root => Some(WipGoalEvaluation { uncanonicalized_goal: goal, @@ -306,8 +306,8 @@ impl<'tcx> ProofTreeBuilder> { pub fn new_canonical_goal_evaluation( &mut self, - goal: CanonicalInput>, - ) -> ProofTreeBuilder> { + goal: CanonicalInput, + ) -> ProofTreeBuilder { self.nested(|| WipCanonicalGoalEvaluation { goal, kind: None, @@ -318,12 +318,13 @@ impl<'tcx> ProofTreeBuilder> { pub fn finalize_canonical_goal_evaluation( &mut self, - tcx: TyCtxt<'tcx>, - ) -> Option<&'tcx inspect::CanonicalGoalEvaluationStep>> { + tcx: I, + ) -> Option { self.as_mut().map(|this| match this { DebugSolver::CanonicalGoalEvaluation(evaluation) => { let final_revision = mem::take(&mut evaluation.final_revision).unwrap(); - let final_revision = &*tcx.arena.alloc(final_revision.finalize()); + let final_revision = + tcx.intern_canonical_goal_evaluation_step(final_revision.finalize()); let kind = WipCanonicalGoalEvaluationKind::Interned { final_revision }; assert_eq!(evaluation.kind.replace(kind), None); final_revision @@ -334,7 +335,7 @@ impl<'tcx> ProofTreeBuilder> { pub fn canonical_goal_evaluation( &mut self, - canonical_goal_evaluation: ProofTreeBuilder>, + canonical_goal_evaluation: ProofTreeBuilder, ) { if let Some(this) = self.as_mut() { match (this, *canonical_goal_evaluation.state.unwrap()) { @@ -350,10 +351,7 @@ impl<'tcx> ProofTreeBuilder> { } } - pub fn canonical_goal_evaluation_kind( - &mut self, - kind: WipCanonicalGoalEvaluationKind>, - ) { + pub fn canonical_goal_evaluation_kind(&mut self, kind: WipCanonicalGoalEvaluationKind) { if let Some(this) = self.as_mut() { match this { DebugSolver::CanonicalGoalEvaluation(canonical_goal_evaluation) => { @@ -364,7 +362,7 @@ impl<'tcx> ProofTreeBuilder> { } } - pub fn goal_evaluation(&mut self, goal_evaluation: ProofTreeBuilder>) { + pub fn goal_evaluation(&mut self, goal_evaluation: ProofTreeBuilder) { if let Some(this) = self.as_mut() { match this { DebugSolver::Root => *this = *goal_evaluation.state.unwrap(), @@ -378,9 +376,9 @@ impl<'tcx> ProofTreeBuilder> { pub fn new_goal_evaluation_step( &mut self, - var_values: CanonicalVarValues<'tcx>, - instantiated_goal: QueryInput, ty::Predicate<'tcx>>, - ) -> ProofTreeBuilder> { + var_values: ty::CanonicalVarValues, + instantiated_goal: QueryInput, + ) -> ProofTreeBuilder { self.nested(|| WipCanonicalGoalEvaluationStep { var_values: var_values.var_values.to_vec(), instantiated_goal, @@ -394,7 +392,7 @@ impl<'tcx> ProofTreeBuilder> { }) } - pub fn goal_evaluation_step(&mut self, goal_evaluation_step: ProofTreeBuilder>) { + pub fn goal_evaluation_step(&mut self, goal_evaluation_step: ProofTreeBuilder) { if let Some(this) = self.as_mut() { match (this, *goal_evaluation_step.state.unwrap()) { ( @@ -408,7 +406,7 @@ impl<'tcx> ProofTreeBuilder> { } } - pub fn add_var_value>>(&mut self, arg: T) { + pub fn add_var_value>(&mut self, arg: T) { match self.as_mut() { None => {} Some(DebugSolver::CanonicalGoalEvaluationStep(state)) => { @@ -435,7 +433,7 @@ impl<'tcx> ProofTreeBuilder> { } } - pub fn probe_kind(&mut self, probe_kind: inspect::ProbeKind>) { + pub fn probe_kind(&mut self, probe_kind: inspect::ProbeKind) { match self.as_mut() { None => {} Some(DebugSolver::CanonicalGoalEvaluationStep(state)) => { @@ -446,11 +444,7 @@ impl<'tcx> ProofTreeBuilder> { } } - pub fn probe_final_state( - &mut self, - infcx: &InferCtxt<'tcx>, - max_input_universe: ty::UniverseIndex, - ) { + pub fn probe_final_state(&mut self, infcx: &Infcx, max_input_universe: ty::UniverseIndex) { match self.as_mut() { None => {} Some(DebugSolver::CanonicalGoalEvaluationStep(state)) => { @@ -469,24 +463,24 @@ impl<'tcx> ProofTreeBuilder> { pub fn add_normalizes_to_goal( &mut self, - infcx: &InferCtxt<'tcx>, + infcx: &Infcx, max_input_universe: ty::UniverseIndex, - goal: Goal, ty::NormalizesTo<'tcx>>, + goal: Goal>, ) { self.add_goal( infcx, max_input_universe, GoalSource::Misc, - goal.with(infcx.tcx, goal.predicate), + goal.with(infcx.interner(), goal.predicate), ); } pub fn add_goal( &mut self, - infcx: &InferCtxt<'tcx>, + infcx: &Infcx, max_input_universe: ty::UniverseIndex, source: GoalSource, - goal: Goal, ty::Predicate<'tcx>>, + goal: Goal, ) { match self.as_mut() { None => {} @@ -505,9 +499,9 @@ impl<'tcx> ProofTreeBuilder> { pub(crate) fn record_impl_args( &mut self, - infcx: &InferCtxt<'tcx>, + infcx: &Infcx, max_input_universe: ty::UniverseIndex, - impl_args: ty::GenericArgsRef<'tcx>, + impl_args: I::GenericArgs, ) { match self.as_mut() { Some(DebugSolver::CanonicalGoalEvaluationStep(state)) => { @@ -540,7 +534,7 @@ impl<'tcx> ProofTreeBuilder> { } } - pub fn finish_probe(mut self) -> ProofTreeBuilder> { + pub fn finish_probe(mut self) -> ProofTreeBuilder { match self.as_mut() { None => {} Some(DebugSolver::CanonicalGoalEvaluationStep(state)) => { @@ -555,7 +549,7 @@ impl<'tcx> ProofTreeBuilder> { self } - pub fn query_result(&mut self, result: QueryResult>) { + pub fn query_result(&mut self, result: QueryResult) { if let Some(this) = self.as_mut() { match this { DebugSolver::CanonicalGoalEvaluation(canonical_goal_evaluation) => { diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 60722d3618f9..a432090f78cd 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -133,7 +133,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { } fn compute_object_safe_goal(&mut self, trait_def_id: DefId) -> QueryResult<'tcx> { - if self.tcx().check_is_object_safe(trait_def_id) { + if self.interner().check_is_object_safe(trait_def_id) { self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } else { Err(NoSolution) @@ -274,7 +274,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { if let ty::Alias(..) = ty.kind() { let normalized_ty = self.next_ty_infer(); let alias_relate_goal = Goal::new( - self.tcx(), + self.interner(), param_env, ty::PredicateKind::AliasRelate( ty.into(), diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/anon_const.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/anon_const.rs index c9621e705e57..362c4072278d 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/anon_const.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/anon_const.rs @@ -12,7 +12,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { if let Some(normalized_const) = self.try_const_eval_resolve( goal.param_env, ty::UnevaluatedConst::new(goal.predicate.alias.def_id, goal.predicate.alias.args), - self.tcx() + self.interner() .type_of(goal.predicate.alias.def_id) .no_bound_vars() .expect("const ty should not rely on other generics"), diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs index 2146a2c2f081..41b2b9cd4d26 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs @@ -15,7 +15,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { &mut self, goal: Goal<'tcx, ty::NormalizesTo<'tcx>>, ) -> QueryResult<'tcx> { - let tcx = self.tcx(); + let tcx = self.interner(); let inherent = goal.predicate.alias.expect_ty(tcx); let impl_def_id = tcx.parent(inherent.def_id); diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs index 7ef8373663ba..f9e164e1f3f9 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs @@ -54,7 +54,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { &mut self, goal: Goal<'tcx, NormalizesTo<'tcx>>, ) -> QueryResult<'tcx> { - match goal.predicate.alias.kind(self.tcx()) { + match goal.predicate.alias.kind(self.interner()) { ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst => { let candidates = self.assemble_and_evaluate_candidates(goal); self.merge_candidates(candidates) @@ -107,7 +107,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { ) -> Result, NoSolution> { if let Some(projection_pred) = assumption.as_projection_clause() { if projection_pred.projection_def_id() == goal.predicate.def_id() { - let tcx = ecx.tcx(); + let tcx = ecx.interner(); ecx.probe_trait_candidate(source).enter(|ecx| { let assumption_projection_pred = ecx.instantiate_binder_with_infer(projection_pred); @@ -142,7 +142,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { goal: Goal<'tcx, NormalizesTo<'tcx>>, impl_def_id: DefId, ) -> Result, NoSolution> { - let tcx = ecx.tcx(); + let tcx = ecx.interner(); let goal_trait_ref = goal.predicate.alias.trait_ref(tcx); let impl_trait_header = tcx.impl_trait_header(impl_def_id).unwrap(); @@ -290,8 +290,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, ) -> Result, NoSolution> { - ecx.tcx().dcx().span_delayed_bug( - ecx.tcx().def_span(goal.predicate.def_id()), + ecx.interner().dcx().span_delayed_bug( + ecx.interner().def_span(goal.predicate.def_id()), "associated types not allowed on auto traits", ); Err(NoSolution) @@ -337,7 +337,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { goal: Goal<'tcx, Self>, goal_kind: ty::ClosureKind, ) -> Result, NoSolution> { - let tcx = ecx.tcx(); + let tcx = ecx.interner(); let tupled_inputs_and_output = match structural_traits::extract_tupled_inputs_and_output_from_callable( tcx, @@ -380,7 +380,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { goal: Goal<'tcx, Self>, goal_kind: ty::ClosureKind, ) -> Result, NoSolution> { - let tcx = ecx.tcx(); + let tcx = ecx.interner(); let env_region = match goal_kind { ty::ClosureKind::Fn | ty::ClosureKind::FnMut => goal.predicate.alias.args.region_at(2), @@ -407,16 +407,20 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { output_coroutine_ty, coroutine_return_ty, }| { - let (projection_term, term) = match tcx.item_name(goal.predicate.def_id()) { - sym::CallOnceFuture => ( + let lang_items = tcx.lang_items(); + let (projection_term, term) = if Some(goal.predicate.def_id()) + == lang_items.call_once_future() + { + ( ty::AliasTerm::new( tcx, goal.predicate.def_id(), [goal.predicate.self_ty(), tupled_inputs_ty], ), output_coroutine_ty.into(), - ), - sym::CallRefFuture => ( + ) + } else if Some(goal.predicate.def_id()) == lang_items.call_ref_future() { + ( ty::AliasTerm::new( tcx, goal.predicate.def_id(), @@ -427,8 +431,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { ], ), output_coroutine_ty.into(), - ), - sym::Output => ( + ) + } else if Some(goal.predicate.def_id()) == lang_items.async_fn_once_output() { + ( ty::AliasTerm::new( tcx, goal.predicate.def_id(), @@ -438,8 +443,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { ], ), coroutine_return_ty.into(), - ), - name => bug!("no such associated type: {name}"), + ) + } else { + bug!("no such associated type in `AsyncFn*`: {:?}", goal.predicate.def_id()) }; ty::ProjectionPredicate { projection_term, term } }, @@ -493,7 +499,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { } let upvars_ty = ty::CoroutineClosureSignature::tupled_upvars_by_closure_kind( - ecx.tcx(), + ecx.interner(), goal_kind, tupled_inputs_ty.expect_ty(), tupled_upvars_ty.expect_ty(), @@ -518,7 +524,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, ) -> Result, NoSolution> { - let tcx = ecx.tcx(); + let tcx = ecx.interner(); let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None); assert_eq!(metadata_def_id, goal.predicate.def_id()); ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { @@ -606,7 +612,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { }; // Coroutines are not futures unless they come from `async` desugaring - let tcx = ecx.tcx(); + let tcx = ecx.interner(); if !tcx.coroutine_is_async(def_id) { return Err(NoSolution); } @@ -618,7 +624,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), goal, ty::ProjectionPredicate { - projection_term: ty::AliasTerm::new(ecx.tcx(), goal.predicate.def_id(), [self_ty]), + projection_term: ty::AliasTerm::new( + ecx.interner(), + goal.predicate.def_id(), + [self_ty], + ), term, } .upcast(tcx), @@ -638,7 +648,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { }; // Coroutines are not Iterators unless they come from `gen` desugaring - let tcx = ecx.tcx(); + let tcx = ecx.interner(); if !tcx.coroutine_is_gen(def_id) { return Err(NoSolution); } @@ -650,7 +660,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), goal, ty::ProjectionPredicate { - projection_term: ty::AliasTerm::new(ecx.tcx(), goal.predicate.def_id(), [self_ty]), + projection_term: ty::AliasTerm::new( + ecx.interner(), + goal.predicate.def_id(), + [self_ty], + ), term, } .upcast(tcx), @@ -677,7 +691,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { }; // Coroutines are not AsyncIterators unless they come from `gen` desugaring - let tcx = ecx.tcx(); + let tcx = ecx.interner(); if !tcx.coroutine_is_async_gen(def_id) { return Err(NoSolution); } @@ -713,7 +727,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { }; // `async`-desugared coroutines do not implement the coroutine trait - let tcx = ecx.tcx(); + let tcx = ecx.interner(); if !tcx.is_general_coroutine(def_id) { return Err(NoSolution); } @@ -735,7 +749,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { goal, ty::ProjectionPredicate { projection_term: ty::AliasTerm::new( - ecx.tcx(), + ecx.interner(), goal.predicate.def_id(), [self_ty, coroutine.resume_ty()], ), @@ -784,7 +798,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { | ty::Slice(_) | ty::Dynamic(_, _, _) | ty::Tuple(_) - | ty::Error(_) => self_ty.discriminant_ty(ecx.tcx()), + | ty::Error(_) => self_ty.discriminant_ty(ecx.interner()), // We do not call `Ty::discriminant_ty` on alias, param, or placeholder // types, which return `::Discriminant` @@ -831,7 +845,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { | ty::Str | ty::Slice(_) | ty::Tuple(_) - | ty::Error(_) => self_ty.async_destructor_ty(ecx.tcx(), goal.param_env), + | ty::Error(_) => self_ty.async_destructor_ty(ecx.interner(), goal.param_env), // We do not call `Ty::async_destructor_ty` on alias, param, or placeholder // types, which return `::AsyncDestructor` @@ -887,8 +901,9 @@ fn fetch_eligible_assoc_item_def<'tcx>( trait_assoc_def_id: DefId, impl_def_id: DefId, ) -> Result, NoSolution> { - let node_item = specialization_graph::assoc_def(ecx.tcx(), impl_def_id, trait_assoc_def_id) - .map_err(|ErrorGuaranteed { .. }| NoSolution)?; + let node_item = + specialization_graph::assoc_def(ecx.interner(), impl_def_id, trait_assoc_def_id) + .map_err(|ErrorGuaranteed { .. }| NoSolution)?; let eligible = if node_item.is_final() { // Non-specializable items are always projectable. diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs index 3b83d347276f..67ec2f3be481 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs @@ -15,7 +15,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { &mut self, goal: Goal<'tcx, ty::NormalizesTo<'tcx>>, ) -> QueryResult<'tcx> { - let tcx = self.tcx(); + let tcx = self.interner(); let opaque_ty = goal.predicate.alias; let expected = goal.predicate.term.ty().expect("no such thing as an opaque const"); @@ -31,7 +31,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { return Err(NoSolution); } // FIXME: This may have issues when the args contain aliases... - match self.tcx().uses_unique_placeholders_ignoring_regions(opaque_ty.args) { + match self.interner().uses_unique_placeholders_ignoring_regions(opaque_ty.args) { Err(NotUniqueParam::NotParam(param)) if param.is_non_region_infer() => { return self.evaluate_added_goals_and_make_canonical_response( Certainty::AMBIGUOUS, diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/weak_types.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/weak_types.rs index 109a9e9671f0..5442b9ccffc8 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/weak_types.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/weak_types.rs @@ -14,7 +14,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { &mut self, goal: Goal<'tcx, ty::NormalizesTo<'tcx>>, ) -> QueryResult<'tcx> { - let tcx = self.tcx(); + let tcx = self.interner(); let weak_ty = goal.predicate.alias; // Check where clauses diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 8fa78e49dc6e..cae73cc2d073 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -11,7 +11,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { &mut self, goal: Goal<'tcx, ProjectionPredicate<'tcx>>, ) -> QueryResult<'tcx> { - let tcx = self.tcx(); + let tcx = self.interner(); let projection_term = goal.predicate.projection_term.to_term(tcx); let goal = goal.with( tcx, diff --git a/compiler/rustc_trait_selection/src/solve/search_graph.rs b/compiler/rustc_trait_selection/src/solve/search_graph.rs index 6be623b6044f..f1b8bf4676ee 100644 --- a/compiler/rustc_trait_selection/src/solve/search_graph.rs +++ b/compiler/rustc_trait_selection/src/solve/search_graph.rs @@ -3,6 +3,7 @@ use std::mem; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_index::Idx; use rustc_index::IndexVec; +use rustc_infer::infer::InferCtxt; use rustc_middle::dep_graph::dep_kinds; use rustc_middle::traits::solve::CacheData; use rustc_middle::traits::solve::EvaluationCache; @@ -261,10 +262,10 @@ impl<'tcx> SearchGraph> { &mut self, tcx: TyCtxt<'tcx>, input: CanonicalInput>, - inspect: &mut ProofTreeBuilder>, + inspect: &mut ProofTreeBuilder>, mut prove_goal: impl FnMut( &mut Self, - &mut ProofTreeBuilder>, + &mut ProofTreeBuilder>, ) -> QueryResult>, ) -> QueryResult> { self.check_invariants(); @@ -426,7 +427,7 @@ impl<'tcx> SearchGraph> { tcx: TyCtxt<'tcx>, input: CanonicalInput>, available_depth: Limit, - inspect: &mut ProofTreeBuilder>, + inspect: &mut ProofTreeBuilder>, ) -> Option>> { let CacheData { result, proof_tree, additional_depth, encountered_overflow } = self .global_cache(tcx) @@ -473,11 +474,11 @@ impl<'tcx> SearchGraph> { &mut self, tcx: TyCtxt<'tcx>, input: CanonicalInput>, - inspect: &mut ProofTreeBuilder>, + inspect: &mut ProofTreeBuilder>, prove_goal: &mut F, ) -> StepResult> where - F: FnMut(&mut Self, &mut ProofTreeBuilder>) -> QueryResult>, + F: FnMut(&mut Self, &mut ProofTreeBuilder>) -> QueryResult>, { let result = prove_goal(self, inspect); let stack_entry = self.pop_stack(); diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index e59eef22f411..67dd3fa85fa1 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -42,7 +42,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { goal: Goal<'tcx, TraitPredicate<'tcx>>, impl_def_id: DefId, ) -> Result, NoSolution> { - let tcx = ecx.tcx(); + let tcx = ecx.interner(); let impl_trait_header = tcx.impl_trait_header(impl_def_id).unwrap(); let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::ForLookup }; @@ -181,7 +181,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { return Err(NoSolution); } - let tcx = ecx.tcx(); + let tcx = ecx.interner(); ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { let nested_obligations = tcx @@ -235,7 +235,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } // The regions of a type don't affect the size of the type - let tcx = ecx.tcx(); + let tcx = ecx.interner(); // We should erase regions from both the param-env and type, since both // may have infer regions. Specifically, after canonicalizing and instantiating, // early bound regions turn into region vars in both the new and old solver. @@ -296,7 +296,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { return Err(NoSolution); } - let tcx = ecx.tcx(); + let tcx = ecx.interner(); let tupled_inputs_and_output = match structural_traits::extract_tupled_inputs_and_output_from_callable( tcx, @@ -337,7 +337,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { return Err(NoSolution); } - let tcx = ecx.tcx(); + let tcx = ecx.interner(); let (tupled_inputs_and_output_and_coroutine, nested_preds) = structural_traits::extract_tupled_inputs_and_output_from_async_callable( tcx, @@ -447,7 +447,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { }; // Coroutines are not futures unless they come from `async` desugaring - let tcx = ecx.tcx(); + let tcx = ecx.interner(); if !tcx.coroutine_is_async(def_id) { return Err(NoSolution); } @@ -473,7 +473,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { }; // Coroutines are not iterators unless they come from `gen` desugaring - let tcx = ecx.tcx(); + let tcx = ecx.interner(); if !tcx.coroutine_is_gen(def_id) { return Err(NoSolution); } @@ -499,7 +499,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { }; // Coroutines are not iterators unless they come from `gen` desugaring - let tcx = ecx.tcx(); + let tcx = ecx.interner(); if !tcx.coroutine_is_gen(def_id) { return Err(NoSolution); } @@ -523,7 +523,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { }; // Coroutines are not iterators unless they come from `gen` desugaring - let tcx = ecx.tcx(); + let tcx = ecx.interner(); if !tcx.coroutine_is_async_gen(def_id) { return Err(NoSolution); } @@ -550,7 +550,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { }; // `async`-desugared coroutines do not implement the coroutine trait - let tcx = ecx.tcx(); + let tcx = ecx.interner(); if !tcx.is_general_coroutine(def_id) { return Err(NoSolution); } @@ -625,10 +625,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { // Erase regions because we compute layouts in `rustc_transmute`, // which will ICE for region vars. - let args = ecx.tcx().erase_regions(goal.predicate.trait_ref.args); + let args = ecx.interner().erase_regions(goal.predicate.trait_ref.args); let Some(assume) = - rustc_transmute::Assume::from_const(ecx.tcx(), goal.param_env, args.const_at(2)) + rustc_transmute::Assume::from_const(ecx.interner(), goal.param_env, args.const_at(2)) else { return Err(NoSolution); }; @@ -675,7 +675,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { return vec![]; }; - let goal = goal.with(ecx.tcx(), (a_ty, b_ty)); + let goal = goal.with(ecx.interner(), (a_ty, b_ty)); match (a_ty.kind(), b_ty.kind()) { (ty::Infer(ty::TyVar(..)), ..) => bug!("unexpected infer {a_ty:?} {b_ty:?}"), @@ -741,7 +741,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { b_data: &'tcx ty::List>, b_region: ty::Region<'tcx>, ) -> Vec> { - let tcx = self.tcx(); + let tcx = self.interner(); let Goal { predicate: (a_ty, _b_ty), .. } = goal; let mut responses = vec![]; @@ -787,7 +787,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { b_data: &'tcx ty::List>, b_region: ty::Region<'tcx>, ) -> Result, NoSolution> { - let tcx = self.tcx(); + let tcx = self.interner(); let Goal { predicate: (a_ty, _), .. } = goal; // Can only unsize to an object-safe trait. @@ -837,8 +837,8 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { let a_auto_traits: FxIndexSet = a_data .auto_traits() .chain(a_data.principal_def_id().into_iter().flat_map(|principal_def_id| { - supertrait_def_ids(self.tcx(), principal_def_id) - .filter(|def_id| self.tcx().trait_is_auto(*def_id)) + supertrait_def_ids(self.interner(), principal_def_id) + .filter(|def_id| self.interner().trait_is_auto(*def_id)) })) .collect(); @@ -907,7 +907,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { ecx.add_goal( GoalSource::ImplWhereBound, Goal::new( - ecx.tcx(), + ecx.interner(), param_env, ty::Binder::dummy(ty::OutlivesPredicate(a_region, b_region)), ), @@ -956,7 +956,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { a_args: ty::GenericArgsRef<'tcx>, b_args: ty::GenericArgsRef<'tcx>, ) -> Result, NoSolution> { - let tcx = self.tcx(); + let tcx = self.interner(); let Goal { predicate: (_a_ty, b_ty), .. } = goal; let unsizing_params = tcx.unsizing_params_for_adt(def.did()); @@ -1017,7 +1017,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { a_tys: &'tcx ty::List>, b_tys: &'tcx ty::List>, ) -> Result, NoSolution> { - let tcx = self.tcx(); + let tcx = self.interner(); let Goal { predicate: (_a_ty, b_ty), .. } = goal; let (&a_last_ty, a_rest_tys) = a_tys.split_last().unwrap(); @@ -1077,9 +1077,9 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { // takes precedence over the structural auto trait candidate being // assembled. ty::Coroutine(def_id, _) - if Some(goal.predicate.def_id()) == self.tcx().lang_items().unpin_trait() => + if Some(goal.predicate.def_id()) == self.interner().lang_items().unpin_trait() => { - match self.tcx().coroutine_movability(def_id) { + match self.interner().coroutine_movability(def_id) { Movability::Static => Some(Err(NoSolution)), Movability::Movable => Some( self.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { @@ -1124,7 +1124,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { | ty::Tuple(_) | ty::Adt(_, _) => { let mut disqualifying_impl = None; - self.tcx().for_each_relevant_impl( + self.interner().for_each_relevant_impl( goal.predicate.def_id(), goal.predicate.self_ty(), |impl_def_id| { @@ -1164,7 +1164,10 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { .into_iter() .map(|ty| { ecx.enter_forall(ty, |ty| { - goal.with(ecx.tcx(), goal.predicate.with_self_ty(ecx.tcx(), ty)) + goal.with( + ecx.interner(), + goal.predicate.with_self_ty(ecx.interner(), ty), + ) }) }) .collect::>(), diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 07fcf109fdaa..629f6f394af3 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -566,10 +566,13 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { { if let Ok(new_obligations) = infcx .at(&obligation.cause, obligation.param_env) - .trace(c1, c2) // Can define opaque types as this is only reachable with // `generic_const_exprs` - .eq(DefineOpaqueTypes::Yes, a.args, b.args) + .eq( + DefineOpaqueTypes::Yes, + ty::AliasTerm::from(a), + ty::AliasTerm::from(b), + ) { return ProcessResult::Changed(mk_pending( new_obligations.into_obligations(), diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 87c8b1cda504..b6557e6c4eb3 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1680,14 +1680,8 @@ fn confirm_closure_candidate<'cx, 'tcx>( args.coroutine_captures_by_ref_ty(), ) } else { - let async_fn_kind_trait_def_id = - tcx.require_lang_item(LangItem::AsyncFnKindHelper, None); - let upvars_projection_def_id = tcx - .associated_items(async_fn_kind_trait_def_id) - .filter_by_name_unhygienic(sym::Upvars) - .next() - .unwrap() - .def_id; + let upvars_projection_def_id = + tcx.require_lang_item(LangItem::AsyncFnKindUpvars, None); let tupled_upvars_ty = Ty::new_projection( tcx, upvars_projection_def_id, @@ -1816,14 +1810,8 @@ fn confirm_async_closure_candidate<'cx, 'tcx>( args.coroutine_captures_by_ref_ty(), ) } else { - let async_fn_kind_trait_def_id = - tcx.require_lang_item(LangItem::AsyncFnKindHelper, None); - let upvars_projection_def_id = tcx - .associated_items(async_fn_kind_trait_def_id) - .filter_by_name_unhygienic(sym::Upvars) - .next() - .unwrap() - .def_id; + let upvars_projection_def_id = + tcx.require_lang_item(LangItem::AsyncFnKindUpvars, None); // When we don't know the closure kind (and therefore also the closure's upvars, // which are computed at the same time), we must delay the computation of the // generator's upvars. We do this using the `AsyncFnKindHelper`, which as a trait @@ -1880,13 +1868,7 @@ fn confirm_async_closure_candidate<'cx, 'tcx>( let term = match item_name { sym::CallOnceFuture | sym::CallRefFuture => sig.output(), sym::Output => { - let future_trait_def_id = tcx.require_lang_item(LangItem::Future, None); - let future_output_def_id = tcx - .associated_items(future_trait_def_id) - .filter_by_name_unhygienic(sym::Output) - .next() - .unwrap() - .def_id; + let future_output_def_id = tcx.require_lang_item(LangItem::FutureOutput, None); Ty::new_projection(tcx, future_output_def_id, [sig.output()]) } name => bug!("no such associated type: {name}"), @@ -1919,13 +1901,7 @@ fn confirm_async_closure_candidate<'cx, 'tcx>( let term = match item_name { sym::CallOnceFuture | sym::CallRefFuture => sig.output(), sym::Output => { - let future_trait_def_id = tcx.require_lang_item(LangItem::Future, None); - let future_output_def_id = tcx - .associated_items(future_trait_def_id) - .filter_by_name_unhygienic(sym::Output) - .next() - .unwrap() - .def_id; + let future_output_def_id = tcx.require_lang_item(LangItem::FutureOutput, None); Ty::new_projection(tcx, future_output_def_id, [sig.output()]) } name => bug!("no such associated type: {name}"), diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 696b1c151153..7aec4e1987ed 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -910,10 +910,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if let Ok(InferOk { obligations, value: () }) = self .infcx .at(&obligation.cause, obligation.param_env) - .trace(c1, c2) // Can define opaque types as this is only reachable with // `generic_const_exprs` - .eq(DefineOpaqueTypes::Yes, a.args, b.args) + .eq( + DefineOpaqueTypes::Yes, + ty::AliasTerm::from(a), + ty::AliasTerm::from(b), + ) { return self.evaluate_predicates_recursively( previous_stack, diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 6f513f24948a..c5ea85c90dc5 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -520,7 +520,8 @@ fn fn_abi_sanity_check<'tcx>( assert!( matches!(&*cx.tcx.sess.target.arch, "wasm32" | "wasm64") || matches!(spec_abi, SpecAbi::PtxKernel | SpecAbi::Unadjusted), - r#"`PassMode::Direct` for aggregates only allowed for "unadjusted" and "ptx-kernel" functions and on wasm\nProblematic type: {:#?}"#, + "`PassMode::Direct` for aggregates only allowed for \"unadjusted\" and \"ptx-kernel\" functions and on wasm\n\ + Problematic type: {:#?}", arg.layout, ); } diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index 58447f6d6a31..e9112d232cbd 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -94,7 +94,7 @@ fn check_binop(op: mir::BinOp) -> bool { fn check_unop(op: mir::UnOp) -> bool { use mir::UnOp::*; match op { - Not | Neg => true, + Not | Neg | PtrMetadata => true, } } diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index e7e893f27daa..7b1dfecfee2e 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -132,7 +132,14 @@ pub trait GenericArgs>: } pub trait Predicate>: - Copy + Debug + Hash + Eq + TypeSuperVisitable + TypeSuperFoldable + Flags + Copy + + Debug + + Hash + + Eq + + TypeSuperVisitable + + TypeSuperFoldable + + Flags + + UpcastFrom> { fn is_coinductive(self, interner: I) -> bool; } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index e49db171a534..2a228c973d34 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -3,6 +3,7 @@ use std::fmt::Debug; use std::hash::Hash; use std::ops::Deref; +use crate::fold::TypeFoldable; use crate::inherent::*; use crate::ir_print::IrPrint; use crate::solve::inspect::CanonicalGoalEvaluationStep; @@ -90,7 +91,7 @@ pub trait Interner: type PlaceholderRegion: PlaceholderLike; // Predicates - type ParamEnv: Copy + Debug + Hash + Eq; + type ParamEnv: Copy + Debug + Hash + Eq + TypeFoldable; type Predicate: Predicate; type Clause: Clause; type Clauses: Copy + Debug + Hash + Eq + TypeSuperVisitable + Flags; @@ -114,15 +115,18 @@ pub trait Interner: ) -> (ty::TraitRef, Self::OwnItemArgs); fn mk_args(self, args: &[Self::GenericArg]) -> Self::GenericArgs; - fn mk_args_from_iter(self, args: impl Iterator) -> Self::GenericArgs; - fn check_and_mk_args( self, def_id: Self::DefId, args: impl IntoIterator>, ) -> Self::GenericArgs; + fn intern_canonical_goal_evaluation_step( + self, + step: CanonicalGoalEvaluationStep, + ) -> Self::CanonicalGoalEvaluationStepRef; + fn parent(self, def_id: Self::DefId) -> Self::DefId; fn recursion_limit(self) -> usize; diff --git a/compiler/stable_mir/src/compiler_interface.rs b/compiler/stable_mir/src/compiler_interface.rs index 4dd64228bbad..858ce5301d84 100644 --- a/compiler/stable_mir/src/compiler_interface.rs +++ b/compiler/stable_mir/src/compiler_interface.rs @@ -8,7 +8,7 @@ use std::cell::Cell; use crate::abi::{FnAbi, Layout, LayoutShape}; use crate::mir::alloc::{AllocId, GlobalAlloc}; use crate::mir::mono::{Instance, InstanceDef, StaticDef}; -use crate::mir::{BinOp, Body, Place}; +use crate::mir::{BinOp, Body, Place, UnOp}; use crate::target::MachineInfo; use crate::ty::{ AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, ForeignDef, @@ -226,6 +226,9 @@ pub trait Context { /// Get the resulting type of binary operation. fn binop_ty(&self, bin_op: BinOp, rhs: Ty, lhs: Ty) -> Ty; + + /// Get the resulting type of unary operation. + fn unop_ty(&self, un_op: UnOp, arg: Ty) -> Ty; } // A thread local variable that stores a pointer to the tables mapping between TyCtxt diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index a1432acf93cb..4c779ae96a81 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -346,6 +346,15 @@ impl BinOp { pub enum UnOp { Not, Neg, + PtrMetadata, +} + +impl UnOp { + /// Return the type of this operation for the given input Ty. + /// This function does not perform type checking, and it currently doesn't handle SIMD. + pub fn ty(&self, arg_ty: Ty) -> Ty { + with(|ctx| ctx.unop_ty(*self, arg_ty)) + } } #[derive(Clone, Debug, Eq, PartialEq)] @@ -580,7 +589,10 @@ impl Rvalue { let ty = op.ty(lhs_ty, rhs_ty); Ok(Ty::new_tuple(&[ty, Ty::bool_ty()])) } - Rvalue::UnaryOp(UnOp::Not | UnOp::Neg, operand) => operand.ty(locals), + Rvalue::UnaryOp(op, operand) => { + let arg_ty = operand.ty(locals)?; + Ok(op.ty(arg_ty)) + } Rvalue::Discriminant(place) => { let place_ty = place.ty(locals)?; place_ty diff --git a/library/core/src/cell/lazy.rs b/library/core/src/cell/lazy.rs index 47eab6fd0163..80b85b954462 100644 --- a/library/core/src/cell/lazy.rs +++ b/library/core/src/cell/lazy.rs @@ -78,7 +78,7 @@ impl T> LazyCell { /// assert_eq!(&*lazy, "HELLO, WORLD!"); /// assert_eq!(LazyCell::into_inner(lazy).ok(), Some("HELLO, WORLD!".to_string())); /// ``` - #[unstable(feature = "lazy_cell_consume", issue = "109736")] + #[unstable(feature = "lazy_cell_consume", issue = "125623")] pub fn into_inner(this: Self) -> Result { match this.state.into_inner() { State::Init(data) => Ok(data), diff --git a/library/core/src/future/future.rs b/library/core/src/future/future.rs index f965afc8a593..86963b548b9c 100644 --- a/library/core/src/future/future.rs +++ b/library/core/src/future/future.rs @@ -35,7 +35,7 @@ use crate::task::{Context, Poll}; pub trait Future { /// The type of value produced on completion. #[stable(feature = "futures_api", since = "1.36.0")] - #[rustc_diagnostic_item = "FutureOutput"] + #[cfg_attr(not(bootstrap), lang = "future_output")] type Output; /// Attempt to resolve the future to a final value, registering diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 5a2a4c5ae6eb..89e0b6709951 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -2821,6 +2821,21 @@ impl AggregateRawPtr<*mut T> for *mut P { type Metadata =

::Metadata; } +/// Lowers in MIR to `Rvalue::UnaryOp` with `UnOp::PtrMetadata`. +/// +/// This is used to implement functions like `ptr::metadata`. +#[rustc_nounwind] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[cfg(not(bootstrap))] +pub const fn ptr_metadata + ?Sized, M>(_ptr: *const P) -> M { + // To implement a fallback we'd have to assume the layout of the pointer, + // but the whole point of this intrinsic is that we shouldn't do that. + unreachable!() +} + // Some functions are defined here because they accidentally got made // available in this module on stable. See . // (`transmute` also falls into this category, but it cannot be wrapped due to the diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs index 02665b2676cc..fa5bb28adff9 100644 --- a/library/core/src/intrinsics/mir.rs +++ b/library/core/src/intrinsics/mir.rs @@ -360,6 +360,10 @@ define!("mir_assume", fn Assume(operand: bool)); define!("mir_deinit", fn Deinit(place: T)); define!("mir_checked", fn Checked(binop: T) -> (T, bool)); define!("mir_len", fn Len(place: T) -> usize); +define!( + "mir_ptr_metadata", + fn PtrMetadata(place: *const P) ->

::Metadata +); define!("mir_copy_for_deref", fn CopyForDeref(place: T) -> T); define!("mir_retag", fn Retag(place: T)); define!("mir_move", fn Move(place: T) -> T); diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 86078c8377bd..89642d6226a2 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -174,7 +174,6 @@ #![feature(duration_consts_float)] #![feature(internal_impls_macro)] #![feature(ip)] -#![feature(ip_bits)] #![feature(is_ascii_octdigit)] #![feature(isqrt)] #![feature(link_cfg)] diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs index 959c3289affb..e008215ebe96 100644 --- a/library/core/src/net/ip_addr.rs +++ b/library/core/src/net/ip_addr.rs @@ -460,12 +460,11 @@ impl Ipv4Addr { /// # Examples /// /// ``` - /// #![feature(ip_bits)] /// use std::net::Ipv4Addr; /// /// assert_eq!(Ipv4Addr::BITS, 32); /// ``` - #[unstable(feature = "ip_bits", issue = "113744")] + #[stable(feature = "ip_bits", since = "CURRENT_RUSTC_VERSION")] pub const BITS: u32 = 32; /// Converts an IPv4 address into a `u32` representation using native byte order. @@ -479,7 +478,6 @@ impl Ipv4Addr { /// # Examples /// /// ``` - /// #![feature(ip_bits)] /// use std::net::Ipv4Addr; /// /// let addr = Ipv4Addr::new(0x12, 0x34, 0x56, 0x78); @@ -487,7 +485,6 @@ impl Ipv4Addr { /// ``` /// /// ``` - /// #![feature(ip_bits)] /// use std::net::Ipv4Addr; /// /// let addr = Ipv4Addr::new(0x12, 0x34, 0x56, 0x78); @@ -495,8 +492,8 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(0x12, 0x34, 0x56, 0x00), Ipv4Addr::from_bits(addr_bits)); /// /// ``` - #[rustc_const_unstable(feature = "ip_bits", issue = "113744")] - #[unstable(feature = "ip_bits", issue = "113744")] + #[rustc_const_stable(feature = "ip_bits", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "ip_bits", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline] pub const fn to_bits(self) -> u32 { @@ -510,14 +507,13 @@ impl Ipv4Addr { /// # Examples /// /// ``` - /// #![feature(ip_bits)] /// use std::net::Ipv4Addr; /// /// let addr = Ipv4Addr::from(0x12345678); /// assert_eq!(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78), addr); /// ``` - #[rustc_const_unstable(feature = "ip_bits", issue = "113744")] - #[unstable(feature = "ip_bits", issue = "113744")] + #[rustc_const_stable(feature = "ip_bits", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "ip_bits", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline] pub const fn from_bits(bits: u32) -> Ipv4Addr { @@ -1238,12 +1234,11 @@ impl Ipv6Addr { /// # Examples /// /// ``` - /// #![feature(ip_bits)] /// use std::net::Ipv6Addr; /// /// assert_eq!(Ipv6Addr::BITS, 128); /// ``` - #[unstable(feature = "ip_bits", issue = "113744")] + #[stable(feature = "ip_bits", since = "CURRENT_RUSTC_VERSION")] pub const BITS: u32 = 128; /// Converts an IPv6 address into a `u128` representation using native byte order. @@ -1257,7 +1252,6 @@ impl Ipv6Addr { /// # Examples /// /// ``` - /// #![feature(ip_bits)] /// use std::net::Ipv6Addr; /// /// let addr = Ipv6Addr::new( @@ -1268,7 +1262,6 @@ impl Ipv6Addr { /// ``` /// /// ``` - /// #![feature(ip_bits)] /// use std::net::Ipv6Addr; /// /// let addr = Ipv6Addr::new( @@ -1284,8 +1277,8 @@ impl Ipv6Addr { /// Ipv6Addr::from_bits(addr_bits)); /// /// ``` - #[rustc_const_unstable(feature = "ip_bits", issue = "113744")] - #[unstable(feature = "ip_bits", issue = "113744")] + #[rustc_const_stable(feature = "ip_bits", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "ip_bits", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline] pub const fn to_bits(self) -> u128 { @@ -1299,7 +1292,6 @@ impl Ipv6Addr { /// # Examples /// /// ``` - /// #![feature(ip_bits)] /// use std::net::Ipv6Addr; /// /// let addr = Ipv6Addr::from(0x102030405060708090A0B0C0D0E0F00D_u128); @@ -1310,8 +1302,8 @@ impl Ipv6Addr { /// ), /// addr); /// ``` - #[rustc_const_unstable(feature = "ip_bits", issue = "113744")] - #[unstable(feature = "ip_bits", issue = "113744")] + #[rustc_const_stable(feature = "ip_bits", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "ip_bits", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline] pub const fn from_bits(bits: u128) -> Ipv6Addr { diff --git a/library/core/src/ops/async_function.rs b/library/core/src/ops/async_function.rs index 18bcee5a1c7e..f4e9d1a63ac6 100644 --- a/library/core/src/ops/async_function.rs +++ b/library/core/src/ops/async_function.rs @@ -26,6 +26,7 @@ pub trait AsyncFn: AsyncFnMut { pub trait AsyncFnMut: AsyncFnOnce { /// Future returned by [`AsyncFnMut::async_call_mut`] and [`AsyncFn::async_call`]. #[unstable(feature = "async_fn_traits", issue = "none")] + #[cfg_attr(not(bootstrap), lang = "call_ref_future")] type CallRefFuture<'a>: Future where Self: 'a; @@ -46,10 +47,12 @@ pub trait AsyncFnMut: AsyncFnOnce { pub trait AsyncFnOnce { /// Future returned by [`AsyncFnOnce::async_call_once`]. #[unstable(feature = "async_fn_traits", issue = "none")] + #[cfg_attr(not(bootstrap), lang = "call_once_future")] type CallOnceFuture: Future; /// Output type of the called closure's future. #[unstable(feature = "async_fn_traits", issue = "none")] + #[cfg_attr(not(bootstrap), lang = "async_fn_once_output")] type Output; /// Call the [`AsyncFnOnce`], returning a future which may move out of the called closure. @@ -143,6 +146,7 @@ mod internal_implementation_detail { // `for<'env> fn() -> (&'env T, ...)`. This allows us to represent the binder // of the closure's self-capture, and these upvar types will be instantiated with // the `'closure_env` region provided to the associated type. + #[cfg_attr(not(bootstrap), lang = "async_fn_kind_upvars")] type Upvars<'closure_env, Inputs, Upvars, BorrowedUpvarsAsFnPtr>; } } diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs index e501970b580d..78fe0c5add50 100644 --- a/library/core/src/ptr/metadata.rs +++ b/library/core/src/ptr/metadata.rs @@ -3,6 +3,8 @@ use crate::fmt; use crate::hash::{Hash, Hasher}; use crate::intrinsics::aggregate_raw_ptr; +#[cfg(not(bootstrap))] +use crate::intrinsics::ptr_metadata; use crate::marker::Freeze; /// Provides the pointer metadata type of any pointed-to type. @@ -94,10 +96,17 @@ pub trait Thin = Pointee; #[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")] #[inline] pub const fn metadata(ptr: *const T) -> ::Metadata { - // SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T - // and PtrComponents have the same memory layouts. Only std can make this - // guarantee. - unsafe { PtrRepr { const_ptr: ptr }.components.metadata } + #[cfg(bootstrap)] + { + // SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T + // and PtrComponents have the same memory layouts. Only std can make this + // guarantee. + unsafe { PtrRepr { const_ptr: ptr }.components.metadata } + } + #[cfg(not(bootstrap))] + { + ptr_metadata(ptr) + } } /// Forms a (possibly-wide) raw pointer from a data pointer and metadata. @@ -111,7 +120,7 @@ pub const fn metadata(ptr: *const T) -> ::Metadata { #[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")] #[inline] pub const fn from_raw_parts( - data_pointer: *const (), + data_pointer: *const impl Thin, metadata: ::Metadata, ) -> *const T { aggregate_raw_ptr(data_pointer, metadata) @@ -125,13 +134,14 @@ pub const fn from_raw_parts( #[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")] #[inline] pub const fn from_raw_parts_mut( - data_pointer: *mut (), + data_pointer: *mut impl Thin, metadata: ::Metadata, ) -> *mut T { aggregate_raw_ptr(data_pointer, metadata) } #[repr(C)] +#[cfg(bootstrap)] union PtrRepr { const_ptr: *const T, mut_ptr: *mut T, @@ -139,15 +149,18 @@ union PtrRepr { } #[repr(C)] +#[cfg(bootstrap)] struct PtrComponents { data_pointer: *const (), metadata: ::Metadata, } // Manual impl needed to avoid `T: Copy` bound. +#[cfg(bootstrap)] impl Copy for PtrComponents {} // Manual impl needed to avoid `T: Clone` bound. +#[cfg(bootstrap)] impl Clone for PtrComponents { fn clone(&self) -> Self { *self @@ -209,18 +222,14 @@ impl DynMetadata { // Consider a reference like `&(i32, dyn Send)`: the vtable will only store the size of the // `Send` part! // SAFETY: DynMetadata always contains a valid vtable pointer - return unsafe { - crate::intrinsics::vtable_size(self.vtable_ptr() as *const ()) - }; + return unsafe { crate::intrinsics::vtable_size(self.vtable_ptr() as *const ()) }; } /// Returns the alignment of the type associated with this vtable. #[inline] pub fn align_of(self) -> usize { // SAFETY: DynMetadata always contains a valid vtable pointer - return unsafe { - crate::intrinsics::vtable_align(self.vtable_ptr() as *const ()) - }; + return unsafe { crate::intrinsics::vtable_align(self.vtable_ptr() as *const ()) }; } /// Returns the size and alignment together as a `Layout` diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index d2bbdc84d4dd..4213a9dedfe4 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -565,7 +565,7 @@ pub unsafe fn drop_in_place(to_drop: *mut T) { #[rustc_allow_const_fn_unstable(ptr_metadata)] #[rustc_diagnostic_item = "ptr_null"] pub const fn null() -> *const T { - from_raw_parts(without_provenance(0), ()) + from_raw_parts(without_provenance::<()>(0), ()) } /// Creates a null mutable raw pointer. @@ -591,7 +591,7 @@ pub const fn null() -> *const T { #[rustc_allow_const_fn_unstable(ptr_metadata)] #[rustc_diagnostic_item = "ptr_null_mut"] pub const fn null_mut() -> *mut T { - from_raw_parts_mut(without_provenance_mut(0), ()) + from_raw_parts_mut(without_provenance_mut::<()>(0), ()) } /// Creates a pointer with the given address and no provenance. @@ -835,7 +835,7 @@ pub const fn from_mut(r: &mut T) -> *mut T { #[rustc_allow_const_fn_unstable(ptr_metadata)] #[rustc_diagnostic_item = "ptr_slice_from_raw_parts"] pub const fn slice_from_raw_parts(data: *const T, len: usize) -> *const [T] { - intrinsics::aggregate_raw_ptr(data, len) + from_raw_parts(data, len) } /// Forms a raw mutable slice from a pointer and a length. @@ -881,7 +881,7 @@ pub const fn slice_from_raw_parts(data: *const T, len: usize) -> *const [T] { #[rustc_const_unstable(feature = "const_slice_from_raw_parts_mut", issue = "67456")] #[rustc_diagnostic_item = "ptr_slice_from_raw_parts_mut"] pub const fn slice_from_raw_parts_mut(data: *mut T, len: usize) -> *mut [T] { - intrinsics::aggregate_raw_ptr(data, len) + from_raw_parts_mut(data, len) } /// Swaps the values at two mutable locations of the same type, without diff --git a/library/core/src/str/converts.rs b/library/core/src/str/converts.rs index b6ffb0a608d0..397759bd5cae 100644 --- a/library/core/src/str/converts.rs +++ b/library/core/src/str/converts.rs @@ -222,7 +222,7 @@ pub const unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str { #[rustc_const_unstable(feature = "str_from_raw_parts", issue = "119206")] pub const unsafe fn from_raw_parts<'a>(ptr: *const u8, len: usize) -> &'a str { // SAFETY: the caller must uphold the safety contract for `from_raw_parts`. - unsafe { &*ptr::from_raw_parts(ptr.cast(), len) } + unsafe { &*ptr::from_raw_parts(ptr, len) } } /// Creates an `&mut str` from a pointer and a length. @@ -241,5 +241,5 @@ pub const unsafe fn from_raw_parts<'a>(ptr: *const u8, len: usize) -> &'a str { #[rustc_const_unstable(feature = "const_str_from_raw_parts_mut", issue = "119206")] pub const unsafe fn from_raw_parts_mut<'a>(ptr: *mut u8, len: usize) -> &'a mut str { // SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`. - unsafe { &mut *ptr::from_raw_parts_mut(ptr.cast(), len) } + unsafe { &mut *ptr::from_raw_parts_mut(ptr, len) } } diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs index e388800f400d..cc7339163076 100644 --- a/library/core/tests/mem.rs +++ b/library/core/tests/mem.rs @@ -83,12 +83,12 @@ fn align_of_val_raw_packed() { f: [u32], } let storage = [0u8; 4]; - let b: *const B = ptr::from_raw_parts(storage.as_ptr().cast(), 1); + let b: *const B = ptr::from_raw_parts(storage.as_ptr(), 1); assert_eq!(unsafe { align_of_val_raw(b) }, 1); const ALIGN_OF_VAL_RAW: usize = { let storage = [0u8; 4]; - let b: *const B = ptr::from_raw_parts(storage.as_ptr().cast(), 1); + let b: *const B = ptr::from_raw_parts(storage.as_ptr(), 1); unsafe { align_of_val_raw(b) } }; assert_eq!(ALIGN_OF_VAL_RAW, 1); diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs index 7b55c2bf8a81..e3830165eda6 100644 --- a/library/core/tests/ptr.rs +++ b/library/core/tests/ptr.rs @@ -965,7 +965,7 @@ fn thin_box() { fn value_ptr(&self) -> *const T { let (_, offset) = self.layout(); let data_ptr = unsafe { self.ptr.cast::().as_ptr().add(offset) }; - ptr::from_raw_parts(data_ptr.cast(), self.meta()) + ptr::from_raw_parts(data_ptr, self.meta()) } fn value_mut_ptr(&mut self) -> *mut T { @@ -973,7 +973,7 @@ fn thin_box() { // FIXME: can this line be shared with the same in `value_ptr()` // without upsetting Stacked Borrows? let data_ptr = unsafe { self.ptr.cast::().as_ptr().add(offset) }; - from_raw_parts_mut(data_ptr.cast(), self.meta()) + from_raw_parts_mut(data_ptr, self.meta()) } } @@ -1171,3 +1171,15 @@ fn test_ptr_from_raw_parts_in_const() { assert_eq!(EMPTY_SLICE_PTR.addr(), 123); assert_eq!(EMPTY_SLICE_PTR.len(), 456); } + +#[test] +fn test_ptr_metadata_in_const() { + use std::fmt::Debug; + + const ARRAY_META: () = std::ptr::metadata::<[u16; 3]>(&[1, 2, 3]); + const SLICE_META: usize = std::ptr::metadata::<[u16]>(&[1, 2, 3]); + const DYN_META: DynMetadata = std::ptr::metadata::(&[0_u8; 42]); + assert_eq!(ARRAY_META, ()); + assert_eq!(SLICE_META, 3); + assert_eq!(DYN_META.size_of(), 42); +} diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index dfa05671ab0f..62a268facb63 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -1431,7 +1431,7 @@ fn metadata_access_times() { assert_eq!(check!(a.modified()), check!(a.modified())); assert_eq!(check!(b.accessed()), check!(b.modified())); - if cfg!(target_os = "macos") || cfg!(target_os = "windows") { + if cfg!(target_vendor = "apple") || cfg!(target_os = "windows") { check!(a.created()); check!(b.created()); } diff --git a/library/std/src/sync/lazy_lock.rs b/library/std/src/sync/lazy_lock.rs index 16d5dc30552f..d3bb3bfdff92 100644 --- a/library/std/src/sync/lazy_lock.rs +++ b/library/std/src/sync/lazy_lock.rs @@ -126,7 +126,7 @@ impl T> LazyLock { /// assert_eq!(&*lazy, "HELLO, WORLD!"); /// assert_eq!(LazyLock::into_inner(lazy).ok(), Some("HELLO, WORLD!".to_string())); /// ``` - #[unstable(feature = "lazy_cell_consume", issue = "109736")] + #[unstable(feature = "lazy_cell_consume", issue = "125623")] pub fn into_inner(mut this: Self) -> Result { let state = this.once.state(); match state { diff --git a/library/std/src/sys/pal/unix/stack_overflow.rs b/library/std/src/sys/pal/unix/stack_overflow.rs index 26c49257ad00..2e5bd85327a1 100644 --- a/library/std/src/sys/pal/unix/stack_overflow.rs +++ b/library/std/src/sys/pal/unix/stack_overflow.rs @@ -491,6 +491,14 @@ mod imp { } } +// This is intentionally not enabled on iOS/tvOS/watchOS/visionOS, as it uses +// several symbols that might lead to rejections from the App Store, namely +// `sigaction`, `sigaltstack`, `sysctlbyname`, `mmap`, `munmap` and `mprotect`. +// +// This might be overly cautious, though it is also what Swift does (and they +// usually have fewer qualms about forwards compatibility, since the runtime +// is shipped with the OS): +// #[cfg(not(any( target_os = "linux", target_os = "freebsd", diff --git a/rustfmt.toml b/rustfmt.toml index ef56059feb1c..b78e96d5872f 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -3,25 +3,18 @@ version = "Two" use_small_heuristics = "Max" merge_derives = false -# by default we ignore everything in the repository -# tidy only checks files which are not ignored, each entry follows gitignore style +# Files to ignore. Each entry uses gitignore syntax, but `!` prefixes aren't allowed. ignore = [ "/build/", "/*-build/", "/build-*/", "/vendor/", - # tests for now are not formatted, as they are sometimes pretty-printing constrained - # (and generally rustfmt can move around comments in UI-testing incompatible ways) - "/tests/*", + # Tests for now are not formatted, as they are sometimes pretty-printing constrained + # (and generally rustfmt can move around comments in UI-testing incompatible ways). + "/tests/", - # but we still want to format rmake.rs files in tests/run-make/ so we need to do this - # dance to avoid the parent directory from being excluded - "!/tests/run-make/", - "/tests/run-make/*/*.rs", - "!/tests/run-make/*/rmake.rs", - - # do not format submodules + # Do not format submodules. # FIXME: sync submodule list with tidy/bootstrap/etc # tidy/src/walk.rs:filter_dirs "library/backtrace", @@ -43,7 +36,7 @@ ignore = [ "src/tools/rustc-perf", "src/tools/rustfmt", - # these are ignored by a standard cargo fmt run + # These are ignored by a standard cargo fmt run. "compiler/rustc_codegen_cranelift/scripts", "compiler/rustc_codegen_cranelift/example/gen_block_iterate.rs", # uses edition 2024 ] diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index 38c48bd9570d..30b3edfd3aed 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -1028,6 +1028,14 @@ tool_doc!( is_library = true, crates = ["bootstrap"] ); +tool_doc!( + RunMakeSupport, + "run_make_support", + "src/tools/run-make-support", + rustc_tool = false, + is_library = true, + crates = ["run_make_support"] +); #[derive(Ord, PartialOrd, Debug, Clone, Hash, PartialEq, Eq)] pub struct ErrorIndex { diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs index d9dc34c01370..601e4e55e094 100644 --- a/src/bootstrap/src/core/build_steps/format.rs +++ b/src/bootstrap/src/core/build_steps/format.rs @@ -9,11 +9,12 @@ use std::collections::VecDeque; use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; use std::sync::mpsc::SyncSender; +use std::sync::Mutex; fn rustfmt(src: &Path, rustfmt: &Path, paths: &[PathBuf], check: bool) -> impl FnMut(bool) -> bool { let mut cmd = Command::new(rustfmt); - // avoid the submodule config paths from coming into play, - // we only allow a single global config for the workspace for now + // Avoid the submodule config paths from coming into play. We only allow a single global config + // for the workspace for now. cmd.arg("--config-path").arg(&src.canonicalize().unwrap()); cmd.arg("--edition").arg("2021"); cmd.arg("--unstable-features"); @@ -24,20 +25,23 @@ fn rustfmt(src: &Path, rustfmt: &Path, paths: &[PathBuf], check: bool) -> impl F cmd.args(paths); let cmd_debug = format!("{cmd:?}"); let mut cmd = cmd.spawn().expect("running rustfmt"); - // poor man's async: return a closure that'll wait for rustfmt's completion + // Poor man's async: return a closure that might wait for rustfmt's completion (depending on + // the value of the `block` argument). move |block: bool| -> bool { - if !block { + let status = if !block { match cmd.try_wait() { - Ok(Some(_)) => {} - _ => return false, + Ok(Some(status)) => Ok(status), + Ok(None) => return false, + Err(err) => Err(err), } - } - let status = cmd.wait().unwrap(); - if !status.success() { + } else { + cmd.wait() + }; + if !status.unwrap().success() { eprintln!( - "Running `{}` failed.\nIf you're running `tidy`, \ - try again with `--bless`. Or, if you just want to format \ - code, run `./x.py fmt` instead.", + "fmt error: Running `{}` failed.\nIf you're running `tidy`, \ + try again with `--bless`. Or, if you just want to format \ + code, run `./x.py fmt` instead.", cmd_debug, ); crate::exit!(1); @@ -72,7 +76,7 @@ fn verify_rustfmt_version(build: &Builder<'_>) -> bool { !program_out_of_date(&stamp_file, &version) } -/// Updates the last rustfmt version used +/// Updates the last rustfmt version used. fn update_rustfmt_version(build: &Builder<'_>) { let Some((version, stamp_file)) = get_rustfmt_version(build) else { return; @@ -97,28 +101,61 @@ struct RustfmtConfig { ignore: Vec, } -pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) { +// Prints output describing a collection of paths, with lines such as "formatted modified file +// foo/bar/baz" or "skipped 20 untracked files". +fn print_paths(verb: &str, adjective: Option<&str>, paths: &[String]) { + let len = paths.len(); + let adjective = + if let Some(adjective) = adjective { format!("{adjective} ") } else { String::new() }; + if len <= 10 { + for path in paths { + println!("fmt: {verb} {adjective}file {path}"); + } + } else { + println!("fmt: {verb} {len} {adjective}files"); + } +} + +pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) { + if !paths.is_empty() { + eprintln!("fmt error: path arguments are not accepted"); + crate::exit!(1); + }; if build.config.dry_run() { return; } + + // By default, we only check modified files locally to speed up runtime. Exceptions are if + // `--all` is specified or we are in CI. We check all files in CI to avoid bugs in + // `get_modified_rs_files` letting regressions slip through; we also care about CI time less + // since this is still very fast compared to building the compiler. + let all = all || CiEnv::is_ci(); + let mut builder = ignore::types::TypesBuilder::new(); builder.add_defaults(); builder.select("rust"); let matcher = builder.build().unwrap(); let rustfmt_config = build.src.join("rustfmt.toml"); if !rustfmt_config.exists() { - eprintln!("Not running formatting checks; rustfmt.toml does not exist."); - eprintln!("This may happen in distributed tarballs."); + eprintln!("fmt error: Not running formatting checks; rustfmt.toml does not exist."); + eprintln!("fmt error: This may happen in distributed tarballs."); return; } let rustfmt_config = t!(std::fs::read_to_string(&rustfmt_config)); let rustfmt_config: RustfmtConfig = t!(toml::from_str(&rustfmt_config)); - let mut fmt_override = ignore::overrides::OverrideBuilder::new(&build.src); + let mut override_builder = ignore::overrides::OverrideBuilder::new(&build.src); for ignore in rustfmt_config.ignore { - if let Some(ignore) = ignore.strip_prefix('!') { - fmt_override.add(ignore).expect(ignore); + if ignore.starts_with('!') { + // A `!`-prefixed entry could be added as a whitelisted entry in `override_builder`, + // i.e. strip the `!` prefix. But as soon as whitelisted entries are added, an + // `OverrideBuilder` will only traverse those whitelisted entries, and won't traverse + // any files that aren't explicitly mentioned. No bueno! Maybe there's a way to combine + // explicit whitelisted entries and traversal of unmentioned files, but for now just + // forbid such entries. + eprintln!("fmt error: `!`-prefixed entries are not supported in rustfmt.toml, sorry"); + crate::exit!(1); } else { - fmt_override.add(&format!("!{ignore}")).expect(&ignore); + override_builder.add(&format!("!{ignore}")).expect(&ignore); } } let git_available = match Command::new("git") @@ -131,6 +168,7 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) { Err(_) => false, }; + let mut adjective = None; if git_available { let in_working_tree = match build .config @@ -154,142 +192,74 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) { .arg("-z") .arg("--untracked-files=normal"), ); - let untracked_paths = untracked_paths_output.split_terminator('\0').filter_map( - |entry| entry.strip_prefix("?? "), // returns None if the prefix doesn't match - ); - let mut untracked_count = 0; + let untracked_paths: Vec<_> = untracked_paths_output + .split_terminator('\0') + .filter_map( + |entry| entry.strip_prefix("?? "), // returns None if the prefix doesn't match + ) + .map(|x| x.to_string()) + .collect(); + print_paths("skipped", Some("untracked"), &untracked_paths); + for untracked_path in untracked_paths { - println!("skip untracked path {untracked_path} during rustfmt invocations"); // The leading `/` makes it an exact match against the // repository root, rather than a glob. Without that, if you // have `foo.rs` in the repository root it will also match // against anything like `compiler/rustc_foo/src/foo.rs`, // preventing the latter from being formatted. - untracked_count += 1; - fmt_override.add(&format!("!/{untracked_path}")).expect(untracked_path); + override_builder.add(&format!("!/{untracked_path}")).expect(&untracked_path); } - // Only check modified files locally to speed up runtime. - // We still check all files in CI to avoid bugs in `get_modified_rs_files` letting regressions slip through; - // we also care about CI time less since this is still very fast compared to building the compiler. - if !CiEnv::is_ci() && paths.is_empty() { + if !all { + adjective = Some("modified"); match get_modified_rs_files(build) { Ok(Some(files)) => { - if files.len() <= 10 { - for file in &files { - println!("formatting modified file {file}"); - } - } else { - let pluralized = |count| if count > 1 { "files" } else { "file" }; - let untracked_msg = if untracked_count == 0 { - "".to_string() - } else { - format!( - ", skipped {} untracked {}", - untracked_count, - pluralized(untracked_count), - ) - }; - println!( - "formatting {} modified {}{}", - files.len(), - pluralized(files.len()), - untracked_msg - ); - } for file in files { - fmt_override.add(&format!("/{file}")).expect(&file); + override_builder.add(&format!("/{file}")).expect(&file); } } Ok(None) => {} Err(err) => { - println!( - "WARN: Something went wrong when running git commands:\n{err}\n\ - Falling back to formatting all files." - ); + eprintln!("fmt warning: Something went wrong running git commands:"); + eprintln!("fmt warning: {err}"); + eprintln!("fmt warning: Falling back to formatting all files."); } } } } else { - println!("Not in git tree. Skipping git-aware format checks"); + eprintln!("fmt: warning: Not in git tree. Skipping git-aware format checks"); } } else { - println!("Could not find usable git. Skipping git-aware format checks"); + eprintln!("fmt: warning: Could not find usable git. Skipping git-aware format checks"); } - let fmt_override = fmt_override.build().unwrap(); + let override_ = override_builder.build().unwrap(); // `override` is a reserved keyword let rustfmt_path = build.initial_rustfmt().unwrap_or_else(|| { - eprintln!("./x.py fmt is not supported on this channel"); + eprintln!("fmt error: `x fmt` is not supported on this channel"); crate::exit!(1); }); assert!(rustfmt_path.exists(), "{}", rustfmt_path.display()); let src = build.src.clone(); let (tx, rx): (SyncSender, _) = std::sync::mpsc::sync_channel(128); - let walker = match paths.first() { - Some(first) => { - let find_shortcut_candidates = |p: &PathBuf| { - let mut candidates = Vec::new(); - for entry in - WalkBuilder::new(src.clone()).max_depth(Some(3)).build().map_while(Result::ok) - { - if let Some(dir_name) = p.file_name() { - if entry.path().is_dir() && entry.file_name() == dir_name { - candidates.push(entry.into_path()); - } - } - } - candidates - }; + let walker = WalkBuilder::new(src.clone()).types(matcher).overrides(override_).build_parallel(); - // Only try to look for shortcut candidates for single component paths like - // `std` and not for e.g. relative paths like `../library/std`. - let should_look_for_shortcut_dir = |p: &PathBuf| p.components().count() == 1; - - let mut walker = if should_look_for_shortcut_dir(first) { - if let [single_candidate] = &find_shortcut_candidates(first)[..] { - WalkBuilder::new(single_candidate) - } else { - WalkBuilder::new(first) - } - } else { - WalkBuilder::new(src.join(first)) - }; - - for path in &paths[1..] { - if should_look_for_shortcut_dir(path) { - if let [single_candidate] = &find_shortcut_candidates(path)[..] { - walker.add(single_candidate); - } else { - walker.add(path); - } - } else { - walker.add(src.join(path)); - } - } - - walker - } - None => WalkBuilder::new(src.clone()), - } - .types(matcher) - .overrides(fmt_override) - .build_parallel(); - - // there is a lot of blocking involved in spawning a child process and reading files to format. - // spawn more processes than available concurrency to keep the CPU busy + // There is a lot of blocking involved in spawning a child process and reading files to format. + // Spawn more processes than available concurrency to keep the CPU busy. let max_processes = build.jobs() as usize * 2; - // spawn child processes on a separate thread so we can batch entries we have received from ignore + // Spawn child processes on a separate thread so we can batch entries we have received from + // ignore. let thread = std::thread::spawn(move || { let mut children = VecDeque::new(); while let Ok(path) = rx.recv() { - // try getting more paths from the channel to amortize the overhead of spawning processes + // Try getting more paths from the channel to amortize the overhead of spawning + // processes. let paths: Vec<_> = rx.try_iter().take(63).chain(std::iter::once(path)).collect(); let child = rustfmt(&src, &rustfmt_path, paths.as_slice(), check); children.push_back(child); - // poll completion before waiting + // Poll completion before waiting. for i in (0..children.len()).rev() { if children[i](false) { children.swap_remove_back(i); @@ -298,27 +268,44 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) { } if children.len() >= max_processes { - // await oldest child + // Await oldest child. children.pop_front().unwrap()(true); } } - // await remaining children + // Await remaining children. for mut child in children { child(true); } }); + let formatted_paths = Mutex::new(Vec::new()); + let formatted_paths_ref = &formatted_paths; walker.run(|| { let tx = tx.clone(); Box::new(move |entry| { + let cwd = std::env::current_dir(); let entry = t!(entry); if entry.file_type().map_or(false, |t| t.is_file()) { + formatted_paths_ref.lock().unwrap().push({ + // `into_path` produces an absolute path. Try to strip `cwd` to get a shorter + // relative path. + let mut path = entry.clone().into_path(); + if let Ok(cwd) = cwd { + if let Ok(path2) = path.strip_prefix(cwd) { + path = path2.to_path_buf(); + } + } + path.display().to_string() + }); t!(tx.send(entry.into_path())); } ignore::WalkState::Continue }) }); + let mut paths = formatted_paths.into_inner().unwrap(); + paths.sort(); + print_paths(if check { "checked" } else { "formatted" }, adjective, &paths); drop(tx); diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 360bd3840d45..215886863624 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -1140,7 +1140,13 @@ HELP: to skip test's attempt to check tidiness, pass `--skip src/tools/tidy` to ); crate::exit!(1); } - crate::core::build_steps::format::format(builder, !builder.config.cmd.bless(), &[]); + let all = false; + crate::core::build_steps::format::format( + builder, + !builder.config.cmd.bless(), + all, + &[], + ); } builder.info("tidy check"); diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index 045cde56f411..b3d8465cda98 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -888,6 +888,7 @@ impl<'a> Builder<'a> { doc::Tidy, doc::Bootstrap, doc::Releases, + doc::RunMakeSupport, ), Kind::Dist => describe!( dist::Docs, diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs index f4ed7e76fba1..83def0c6df0c 100644 --- a/src/bootstrap/src/core/config/flags.rs +++ b/src/bootstrap/src/core/config/flags.rs @@ -284,8 +284,8 @@ pub enum Subcommand { name = "fmt", long_about = "\n Arguments: - This subcommand optionally accepts a `--check` flag which succeeds if formatting is correct and - fails if it is not. For example: + This subcommand optionally accepts a `--check` flag which succeeds if + formatting is correct and fails if it is not. For example: ./x.py fmt ./x.py fmt --check" )] @@ -294,6 +294,10 @@ pub enum Subcommand { /// check formatting instead of applying #[arg(long)] check: bool, + + /// apply to all appropriate files, not just those that have been modified + #[arg(long)] + all: bool, }, #[command(aliases = ["d"], long_about = "\n Arguments: diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 52c94465cd33..8312885915c5 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -660,10 +660,11 @@ impl Build { // hardcoded subcommands match &self.config.cmd { - Subcommand::Format { check } => { + Subcommand::Format { check, all } => { return core::build_steps::format::format( &builder::Builder::new(self), *check, + *all, &self.config.paths, ); } diff --git a/src/bootstrap/src/utils/dylib.rs b/src/bootstrap/src/utils/dylib.rs index b6e7aec1756b..90bcff59a647 100644 --- a/src/bootstrap/src/utils/dylib.rs +++ b/src/bootstrap/src/utils/dylib.rs @@ -5,7 +5,7 @@ pub fn dylib_path_var() -> &'static str { if cfg!(target_os = "windows") { "PATH" - } else if cfg!(target_os = "macos") { + } else if cfg!(target_vendor = "apple") { "DYLD_LIBRARY_PATH" } else if cfg!(target_os = "haiku") { "LIBRARY_PATH" diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile index 538962802c96..275acb47c33a 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile @@ -45,10 +45,6 @@ RUN sh /scripts/sccache.sh ENV NO_DOWNLOAD_CI_LLVM 1 ENV EXTERNAL_LLVM 1 -# This is not the latest LLVM version, so some components required by tests may -# be missing. -ENV IS_NOT_LATEST_LLVM 1 - # Using llvm-link-shared due to libffi issues -- see #34486 ENV RUST_CONFIGURE_ARGS \ --build=x86_64-unknown-linux-gnu \ diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 174aaeec6b50..d43258622486 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -384,7 +384,6 @@ auto: # We are intentionally allowing an old toolchain on this builder (and that's # incompatible with LLVM downloads today). NO_DOWNLOAD_CI_LLVM: 1 - CUSTOM_MINGW: 1 <<: *job-windows-8c - image: x86_64-mingw @@ -396,7 +395,6 @@ auto: # We are intentionally allowing an old toolchain on this builder (and that's # incompatible with LLVM downloads today). NO_DOWNLOAD_CI_LLVM: 1 - CUSTOM_MINGW: 1 <<: *job-windows-8c - image: dist-x86_64-msvc @@ -445,7 +443,6 @@ auto: # incompatible with LLVM downloads today). NO_DOWNLOAD_CI_LLVM: 1 SCRIPT: python x.py dist bootstrap --include-default-paths - CUSTOM_MINGW: 1 DIST_REQUIRE_ALL_TOOLS: 1 <<: *job-windows-8c @@ -459,7 +456,6 @@ auto: # We are intentionally allowing an old toolchain on this builder (and that's # incompatible with LLVM downloads today). NO_DOWNLOAD_CI_LLVM: 1 - CUSTOM_MINGW: 1 DIST_REQUIRE_ALL_TOOLS: 1 <<: *job-windows-8c diff --git a/src/ci/run.sh b/src/ci/run.sh index 3ad04c73d3da..2e36b7e5962e 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -89,6 +89,8 @@ RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --dist-compression-formats=xz" # (to avoid spending a lot of time cloning llvm) if [ "$EXTERNAL_LLVM" = "" ]; then RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set build.optimized-compiler-builtins" + # Likewise, only demand we test all LLVM components if we know we built LLVM with them + export COMPILETEST_NEEDS_ALL_LLVM_COMPONENTS=1 elif [ "$DEPLOY$DEPLOY_ALT" = "1" ]; then echo "error: dist builds should always use optimized compiler-rt!" >&2 exit 1 @@ -169,12 +171,6 @@ else fi fi -# Unless we're using an older version of LLVM, check that all LLVM components -# used by tests are available. -if [ "$IS_NOT_LATEST_LLVM" = "" ]; then - export COMPILETEST_NEEDS_ALL_LLVM_COMPONENTS=1 -fi - if [ "$ENABLE_GCC_CODEGEN" = "1" ]; then # If `ENABLE_GCC_CODEGEN` is set and not empty, we add the `--enable-new-symbol-mangling` # argument to `RUST_CONFIGURE_ARGS` and set the `GCC_EXEC_PREFIX` environment variable. diff --git a/src/ci/scripts/install-mingw.sh b/src/ci/scripts/install-mingw.sh index 45541b8b6934..31aa3785bc36 100755 --- a/src/ci/scripts/install-mingw.sh +++ b/src/ci/scripts/install-mingw.sh @@ -1,8 +1,5 @@ #!/bin/bash -# If we need to download a custom MinGW, do so here and set the path -# appropriately. -# -# Otherwise install MinGW through `pacman` +# For mingw builds use a vendored mingw. set -euo pipefail IFS=$'\n\t' @@ -16,19 +13,16 @@ if isWindows && isKnownToBeMingwBuild; then case "${CI_JOB_NAME}" in *i686*) bits=32 - arch=i686 mingw_archive="${MINGW_ARCHIVE_32}" ;; *x86_64*) bits=64 - arch=x86_64 mingw_archive="${MINGW_ARCHIVE_64}" ;; *aarch64*) # aarch64 is a cross-compiled target. Use the x86_64 # mingw, since that's the host architecture. bits=64 - arch=x86_64 mingw_archive="${MINGW_ARCHIVE_64}" ;; *) @@ -38,13 +32,9 @@ if isWindows && isKnownToBeMingwBuild; then ;; esac - if [[ "${CUSTOM_MINGW:-0}" == 0 ]]; then - pacman -S --noconfirm --needed mingw-w64-$arch-toolchain - else - mingw_dir="mingw${bits}" + mingw_dir="mingw${bits}" - curl -o mingw.7z "${MIRRORS_BASE}/${mingw_archive}" - 7z x -y mingw.7z > /dev/null - ciCommandAddPath "$(pwd)/${mingw_dir}/bin" - fi + curl -o mingw.7z "${MIRRORS_BASE}/${mingw_archive}" + 7z x -y mingw.7z > /dev/null + ciCommandAddPath "$(pwd)/${mingw_dir}/bin" fi diff --git a/src/ci/scripts/install-msys2.sh b/src/ci/scripts/install-msys2.sh deleted file mode 100755 index 968b1e572e43..000000000000 --- a/src/ci/scripts/install-msys2.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash -# Clean up and prepare the MSYS2 installation. -# MSYS2 is used by the MinGW toolchain for assembling things. - -set -euo pipefail -IFS=$'\n\t' - -source "$(cd "$(dirname "$0")" && pwd)/../shared.sh" -if isWindows; then - # Detect the native Python version installed on the agent. On GitHub - # Actions, the C:\hostedtoolcache\windows\Python directory contains a - # subdirectory for each installed Python version. - # - # The -V flag of the sort command sorts the input by version number. - native_python_version="$(ls /c/hostedtoolcache/windows/Python | sort -Vr | head -n 1)" - - # Make sure we use the native python interpreter instead of some msys equivalent - # one way or another. The msys interpreters seem to have weird path conversions - # baked in which break LLVM's build system one way or another, so let's use the - # native version which keeps everything as native as possible. - python_home="/c/hostedtoolcache/windows/Python/${native_python_version}/x64" - if ! [[ -f "${python_home}/python3.exe" ]]; then - cp "${python_home}/python.exe" "${python_home}/python3.exe" - fi - ciCommandAddPath "C:\\hostedtoolcache\\windows\\Python\\${native_python_version}\\x64" - ciCommandAddPath "C:\\hostedtoolcache\\windows\\Python\\${native_python_version}\\x64\\Scripts" -fi diff --git a/src/doc/rustc/src/target-tier-policy.md b/src/doc/rustc/src/target-tier-policy.md index 48b58f6f06ad..e9cf2a0d1ae5 100644 --- a/src/doc/rustc/src/target-tier-policy.md +++ b/src/doc/rustc/src/target-tier-policy.md @@ -247,7 +247,8 @@ approved by the appropriate team for that shared code before acceptance. target may not have; use conditional compilation or runtime detection, as appropriate, to let each target run code supported by that target. - Tier 3 targets must be able to produce assembly using at least one of - rustc's supported backends from any host target. + rustc's supported backends from any host target. (Having support in a fork + of the backend is not sufficient, it must be upstream.) If a tier 3 target stops meeting these requirements, or the target maintainers no longer have interest or time, or the target shows no signs of activity and diff --git a/src/doc/unstable-book/src/compiler-flags/coverage-options.md b/src/doc/unstable-book/src/compiler-flags/coverage-options.md index 212788335502..87a9a00b3c0f 100644 --- a/src/doc/unstable-book/src/compiler-flags/coverage-options.md +++ b/src/doc/unstable-book/src/compiler-flags/coverage-options.md @@ -5,13 +5,16 @@ This option controls details of the coverage instrumentation performed by Multiple options can be passed, separated by commas. Valid options are: -- `block`, `branch`, `mcdc`: +- `block`, `branch`, `condition`, `mcdc`: Sets the level of coverage instrumentation. Setting the level will override any previously-specified level. - `block` (default): Blocks in the control-flow graph will be instrumented for coverage. - `branch`: In addition to block coverage, also enables branch coverage instrumentation. + - `condition`: + In addition to branch coverage, also instruments some boolean expressions + as branches, even if they are not directly used as branch conditions. - `mcdc`: - In addition to block and branch coverage, also enables MC/DC instrumentation. + In addition to condition coverage, also enables MC/DC instrumentation. (Branch coverage instrumentation may differ in some cases.) diff --git a/src/doc/unstable-book/src/compiler-flags/fixed-x18.md b/src/doc/unstable-book/src/compiler-flags/fixed-x18.md new file mode 100644 index 000000000000..8c8bff5fa296 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/fixed-x18.md @@ -0,0 +1,32 @@ +# `fixed-x18` + +This option prevents the compiler from using the x18 register. It is only +supported on aarch64. + +From the [ABI spec][arm-abi]: + +> X18 is the platform register and is reserved for the use of platform ABIs. +> This is an additional temporary register on platforms that don't assign a +> special meaning to it. + +This flag only has an effect when the x18 register would otherwise be considered +a temporary register. When the flag is applied, x18 is always a reserved +register. + +This flag is intended for use with the shadow call stack sanitizer. Generally, +when that sanitizer is enabled, the x18 register is used to store a pointer to +the shadow stack. Enabling this flag prevents the compiler from overwriting the +shadow stack pointer with temporary data, which is necessary for the sanitizer +to work correctly. + +Currently, the `-Zsanitizer=shadow-call-stack` flag is only supported on +platforms that always treat x18 as a reserved register, and the `-Zfixed-x18` +flag is not required to use the sanitizer on such platforms. However, the +sanitizer may be supported on targets where this is not the case in the future. + +It is undefined behavior for `-Zsanitizer=shadow-call-stack` code to call into +code where x18 is a temporary register. On the other hand, when you are *not* +using the shadow call stack sanitizer, compilation units compiled with and +without the `-Zfixed-x18` flag are compatible with each other. + +[arm-abi]: https://developer.arm.com/documentation/den0024/a/The-ABI-for-ARM-64-bit-Architecture/Register-use-in-the-AArch64-Procedure-Call-Standard/Parameters-in-general-purpose-registers diff --git a/src/doc/unstable-book/src/compiler-flags/print-check-cfg.md b/src/doc/unstable-book/src/compiler-flags/print-check-cfg.md new file mode 100644 index 000000000000..e55165b53740 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/print-check-cfg.md @@ -0,0 +1,25 @@ +# `print=check-cfg` + +The tracking issue for this feature is: [#XXXXXX](https://github.com/rust-lang/rust/issues/XXXXXX). + +------------------------ + +This option of the `--print` flag print the list of expected cfgs. + +This is related to the `--check-cfg` flag which allows specifying arbitrary expected +names and values. + +This print option works similarly to `--print=cfg` (modulo check-cfg specifics): + - *check_cfg syntax*: *output of --print=check-cfg* + - `cfg(windows)`: `windows` + - `cfg(feature, values("foo", "bar"))`: `feature="foo"` and `feature="bar"` + - `cfg(feature, values(none(), ""))`: `feature` and `feature=""` + - `cfg(feature, values(any()))`: `feature=any()` + - `cfg(any())`: `any()` + - *nothing*: `any()=any()` + +To be used like this: + +```bash +rustc --print=check-cfg -Zunstable-options lib.rs +``` diff --git a/src/etc/completions/x.py.fish b/src/etc/completions/x.py.fish index 40a25f13fcbd..7343f3147eed 100644 --- a/src/etc/completions/x.py.fish +++ b/src/etc/completions/x.py.fish @@ -216,6 +216,7 @@ complete -c x.py -n "__fish_seen_subcommand_from fmt" -l llvm-profile-use -d 'us complete -c x.py -n "__fish_seen_subcommand_from fmt" -l reproducible-artifact -d 'Additional reproducible artifacts that should be added to the reproducible artifacts archive' -r complete -c x.py -n "__fish_seen_subcommand_from fmt" -l set -d 'override options in config.toml' -r -f complete -c x.py -n "__fish_seen_subcommand_from fmt" -l check -d 'check formatting instead of applying' +complete -c x.py -n "__fish_seen_subcommand_from fmt" -l all -d 'apply to all appropriate files, not just those that have been modified' complete -c x.py -n "__fish_seen_subcommand_from fmt" -s v -l verbose -d 'use verbose output (-vv for very verbose)' complete -c x.py -n "__fish_seen_subcommand_from fmt" -s i -l incremental -d 'use incremental compilation' complete -c x.py -n "__fish_seen_subcommand_from fmt" -l include-default-paths -d 'include default paths in addition to the provided ones' diff --git a/src/etc/completions/x.py.ps1 b/src/etc/completions/x.py.ps1 index f3d1d372c733..d9adb1778f2f 100644 --- a/src/etc/completions/x.py.ps1 +++ b/src/etc/completions/x.py.ps1 @@ -275,6 +275,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--reproducible-artifact', 'reproducible-artifact', [CompletionResultType]::ParameterName, 'Additional reproducible artifacts that should be added to the reproducible artifacts archive') [CompletionResult]::new('--set', 'set', [CompletionResultType]::ParameterName, 'override options in config.toml') [CompletionResult]::new('--check', 'check', [CompletionResultType]::ParameterName, 'check formatting instead of applying') + [CompletionResult]::new('--all', 'all', [CompletionResultType]::ParameterName, 'apply to all appropriate files, not just those that have been modified') [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('-i', 'i', [CompletionResultType]::ParameterName, 'use incremental compilation') diff --git a/src/etc/completions/x.py.sh b/src/etc/completions/x.py.sh index 82cacb52ffee..6cb9e95c8c10 100644 --- a/src/etc/completions/x.py.sh +++ b/src/etc/completions/x.py.sh @@ -1077,7 +1077,7 @@ _x.py() { return 0 ;; x.py__fmt) - opts="-v -i -j -h --check --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --check --all --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/src/etc/completions/x.py.zsh b/src/etc/completions/x.py.zsh index 12e96dbd40a3..24ddd1c4b7cc 100644 --- a/src/etc/completions/x.py.zsh +++ b/src/etc/completions/x.py.zsh @@ -271,6 +271,7 @@ _arguments "${_arguments_options[@]}" \ '*--reproducible-artifact=[Additional reproducible artifacts that should be added to the reproducible artifacts archive]:REPRODUCIBLE_ARTIFACT: ' \ '*--set=[override options in config.toml]:section.option=value:( )' \ '--check[check formatting instead of applying]' \ +'--all[apply to all appropriate files, not just those that have been modified]' \ '*-v[use verbose output (-vv for very verbose)]' \ '*--verbose[use verbose output (-vv for very verbose)]' \ '-i[use incremental compilation]' \ diff --git a/src/tools/cargo b/src/tools/cargo index a8d72c675ee5..431db31d0dbe 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit a8d72c675ee52dd57f0d8f2bae6655913c15b2fb +Subproject commit 431db31d0dbeda320caf8ef8535ea48eb3093407 diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs index 9c8dd37d53dc..3b32e4396b9f 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs @@ -278,7 +278,7 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx> ty = sized_ty; continue; } - if def.repr().inhibit_struct_field_reordering_opt() { + if def.repr().inhibit_struct_field_reordering() { ReducedTy::OrderedFields(Some(sized_ty)) } else { ReducedTy::UnorderedFields(ty) diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index 253ae3aca689..f5d3967d130d 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -6,7 +6,7 @@ use crate::{clip, is_direct_expn_of, sext, unsext}; use rustc_ast::ast::{self, LitFloatType, LitKind}; use rustc_data_structures::sync::Lrc; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{BinOp, BinOpKind, Block, ConstBlock, Expr, ExprKind, HirId, Item, ItemKind, Node, QPath, UnOp}; +use rustc_hir::{BinOp, BinOpKind, Block, Expr, ExprKind, HirId, Item, ItemKind, Node, QPath, UnOp}; use rustc_lexer::tokenize; use rustc_lint::LateContext; use rustc_middle::mir::interpret::{alloc_range, Scalar}; @@ -412,7 +412,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { /// Simple constant folding: Insert an expression, get a constant or none. pub fn expr(&mut self, e: &Expr<'_>) -> Option> { match e.kind { - ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.lcx.tcx.hir().body(body).value), + ExprKind::ConstBlock(e) | ExprKind::DropTemps(e) => self.expr(e), ExprKind::Path(ref qpath) => { self.fetch_path_and_apply(qpath, e.hir_id, self.typeck_results.expr_ty(e), |this, result| { @@ -491,7 +491,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { /// leaves the local crate. pub fn expr_is_empty(&mut self, e: &Expr<'_>) -> Option { match e.kind { - ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr_is_empty(self.lcx.tcx.hir().body(body).value), + ExprKind::ConstBlock(e) | ExprKind::DropTemps(e) => self.expr_is_empty(e), ExprKind::Path(ref qpath) => { if !self diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 9f285621e0c9..cc5ccd4053a2 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -295,7 +295,7 @@ impl HirEqInterExpr<'_, '_, '_> { self.eq_expr(lx, rx) && self.eq_ty(lt, rt) }, (&ExprKind::Closure(_l), &ExprKind::Closure(_r)) => false, - (&ExprKind::ConstBlock(lb), &ExprKind::ConstBlock(rb)) => self.eq_body(lb.body, rb.body), + (&ExprKind::ConstBlock(lb), &ExprKind::ConstBlock(rb)) => self.eq_expr(lb, rb), (&ExprKind::Continue(li), &ExprKind::Continue(ri)) => { both(&li.label, &ri.label, |l, r| l.ident.name == r.ident.name) }, @@ -770,7 +770,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_expr(self.cx.tcx.hir().body(body).value); }, ExprKind::ConstBlock(ref l_id) => { - self.hash_body(l_id.body); + self.hash_expr(l_id); }, ExprKind::DropTemps(e) | ExprKind::Yield(e, _) => { self.hash_expr(e); diff --git a/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr b/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr index 8039c0bfa248..df14ff396f6c 100644 --- a/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr +++ b/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr @@ -1,11 +1,35 @@ +error: arithmetic operation that can potentially result in unexpected side-effects + --> tests/ui/arithmetic_side_effects.rs:188:36 + | +LL | let _ = const { let mut n = 1; n += 1; n }; + | ^^^^^^ + | + = note: `-D clippy::arithmetic-side-effects` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::arithmetic_side_effects)]` + +error: arithmetic operation that can potentially result in unexpected side-effects + --> tests/ui/arithmetic_side_effects.rs:191:40 + | +LL | let _ = const { let mut n = 1; n = n + 1; n }; + | ^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> tests/ui/arithmetic_side_effects.rs:194:40 + | +LL | let _ = const { let mut n = 1; n = 1 + n; n }; + | ^^^^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> tests/ui/arithmetic_side_effects.rs:200:59 + | +LL | let _ = const { let mut n = 1; n = -1; n = -(-1); n = -n; n }; + | ^^ + error: arithmetic operation that can potentially result in unexpected side-effects --> tests/ui/arithmetic_side_effects.rs:304:5 | LL | _n += 1; | ^^^^^^^ - | - = note: `-D clippy::arithmetic-side-effects` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::arithmetic_side_effects)]` error: arithmetic operation that can potentially result in unexpected side-effects --> tests/ui/arithmetic_side_effects.rs:305:5 @@ -727,5 +751,5 @@ error: arithmetic operation that can potentially result in unexpected side-effec LL | one.sub_assign(1); | ^^^^^^^^^^^^^^^^^ -error: aborting due to 121 previous errors +error: aborting due to 125 previous errors diff --git a/src/tools/clippy/tests/ui/tabs_in_doc_comments.stderr b/src/tools/clippy/tests/ui/tabs_in_doc_comments.stderr index aef6c3914526..23d5dcd3a8da 100644 --- a/src/tools/clippy/tests/ui/tabs_in_doc_comments.stderr +++ b/src/tools/clippy/tests/ui/tabs_in_doc_comments.stderr @@ -1,35 +1,11 @@ -error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:6:5 - | -LL | /// - first one - | ^^^^ help: consider using four spaces per tab - | - = note: `-D clippy::tabs-in-doc-comments` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::tabs_in_doc_comments)]` - -error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:6:13 - | -LL | /// - first one - | ^^^^^^^^ help: consider using four spaces per tab - -error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:7:5 - | -LL | /// - second one - | ^^^^ help: consider using four spaces per tab - -error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:7:14 - | -LL | /// - second one - | ^^^^ help: consider using four spaces per tab - error: using tabs in doc comments is not recommended --> tests/ui/tabs_in_doc_comments.rs:10:9 | LL | /// - First String: | ^^^^ help: consider using four spaces per tab + | + = note: `-D clippy::tabs-in-doc-comments` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::tabs_in_doc_comments)]` error: using tabs in doc comments is not recommended --> tests/ui/tabs_in_doc_comments.rs:11:9 @@ -49,5 +25,29 @@ error: using tabs in doc comments is not recommended LL | /// - needs to be inside here | ^^^^^^^^ help: consider using four spaces per tab +error: using tabs in doc comments is not recommended + --> tests/ui/tabs_in_doc_comments.rs:6:5 + | +LL | /// - first one + | ^^^^ help: consider using four spaces per tab + +error: using tabs in doc comments is not recommended + --> tests/ui/tabs_in_doc_comments.rs:6:13 + | +LL | /// - first one + | ^^^^^^^^ help: consider using four spaces per tab + +error: using tabs in doc comments is not recommended + --> tests/ui/tabs_in_doc_comments.rs:7:5 + | +LL | /// - second one + | ^^^^ help: consider using four spaces per tab + +error: using tabs in doc comments is not recommended + --> tests/ui/tabs_in_doc_comments.rs:7:14 + | +LL | /// - second one + | ^^^^ help: consider using four spaces per tab + error: aborting due to 8 previous errors diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index c7c807d3e684..dc5818201b6d 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -747,6 +747,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "ignore-aarch64", "ignore-aarch64-unknown-linux-gnu", "ignore-android", + "ignore-apple", "ignore-arm", "ignore-avr", "ignore-beta", @@ -829,7 +830,6 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "ignore-x32", "ignore-x86", "ignore-x86_64", - "ignore-x86_64-apple-darwin", "ignore-x86_64-unknown-linux-gnu", "incremental", "known-bug", @@ -876,6 +876,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "only-32bit", "only-64bit", "only-aarch64", + "only-apple", "only-arm", "only-avr", "only-beta", diff --git a/src/tools/compiletest/src/header/cfg.rs b/src/tools/compiletest/src/header/cfg.rs index df8c80470502..510043e3bfd8 100644 --- a/src/tools/compiletest/src/header/cfg.rs +++ b/src/tools/compiletest/src/header/cfg.rs @@ -159,6 +159,12 @@ pub(super) fn parse_cfg_name_directive<'a>( message: "when the architecture is part of the Thumb family" } + condition! { + name: "apple", + condition: config.target.contains("apple"), + message: "when the target vendor is Apple" + } + // Technically the locally built compiler uses the "dev" channel rather than the "nightly" // channel, even though most people don't know or won't care about it. To avoid confusion, we // treat the "dev" channel as the "nightly" channel when processing the directive. diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 02c9d384ab7e..910a829fbea1 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -9,7 +9,7 @@ use crate::common::{Codegen, CodegenUnits, DebugInfo, Debugger, Rustdoc}; use crate::common::{CompareMode, FailMode, PassMode}; use crate::common::{Config, TestPaths}; use crate::common::{CoverageMap, CoverageRun, Pretty, RunPassValgrind}; -use crate::common::{UI_COVERAGE, UI_COVERAGE_MAP, UI_RUN_STDERR, UI_RUN_STDOUT}; +use crate::common::{UI_RUN_STDERR, UI_RUN_STDOUT}; use crate::compute_diff::{write_diff, write_filtered_diff}; use crate::errors::{self, Error, ErrorKind}; use crate::header::TestProps; @@ -41,6 +41,7 @@ use tracing::*; use crate::extract_gdb_version; use crate::is_android_gdb_target; +mod coverage; mod debugger; use debugger::DebuggerCommands; @@ -53,6 +54,7 @@ macro_rules! static_regex { RE.get_or_init(|| ::regex::Regex::new($re).unwrap()) }}; } +use static_regex; const FAKE_SRC_BASE: &str = "fake-test-src-base"; @@ -98,7 +100,7 @@ fn get_lib_name(lib: &str, aux_type: AuxType) -> Option { AuxType::Lib => Some(format!("lib{}.rlib", lib)), AuxType::Dylib => Some(if cfg!(windows) { format!("{}.dll", lib) - } else if cfg!(target_os = "macos") { + } else if cfg!(target_vendor = "apple") { format!("lib{}.dylib", lib) } else { format!("lib{}.so", lib) @@ -267,8 +269,8 @@ impl<'test> TestCx<'test> { MirOpt => self.run_mir_opt_test(), Assembly => self.run_assembly_test(), JsDocTest => self.run_js_doc_test(), - CoverageMap => self.run_coverage_map_test(), - CoverageRun => self.run_coverage_run_test(), + CoverageMap => self.run_coverage_map_test(), // see self::coverage + CoverageRun => self.run_coverage_run_test(), // see self::coverage Crashes => self.run_crash_test(), } } @@ -504,224 +506,6 @@ impl<'test> TestCx<'test> { } } - fn run_coverage_map_test(&self) { - let Some(coverage_dump_path) = &self.config.coverage_dump_path else { - self.fatal("missing --coverage-dump"); - }; - - let (proc_res, llvm_ir_path) = self.compile_test_and_save_ir(); - if !proc_res.status.success() { - self.fatal_proc_rec("compilation failed!", &proc_res); - } - drop(proc_res); - - let mut dump_command = Command::new(coverage_dump_path); - dump_command.arg(llvm_ir_path); - let proc_res = self.run_command_to_procres(&mut dump_command); - if !proc_res.status.success() { - self.fatal_proc_rec("coverage-dump failed!", &proc_res); - } - - let kind = UI_COVERAGE_MAP; - - let expected_coverage_dump = self.load_expected_output(kind); - let actual_coverage_dump = self.normalize_output(&proc_res.stdout, &[]); - - let coverage_dump_errors = - self.compare_output(kind, &actual_coverage_dump, &expected_coverage_dump); - - if coverage_dump_errors > 0 { - self.fatal_proc_rec( - &format!("{coverage_dump_errors} errors occurred comparing coverage output."), - &proc_res, - ); - } - } - - fn run_coverage_run_test(&self) { - let should_run = self.run_if_enabled(); - let proc_res = self.compile_test(should_run, Emit::None); - - if !proc_res.status.success() { - self.fatal_proc_rec("compilation failed!", &proc_res); - } - drop(proc_res); - - if let WillExecute::Disabled = should_run { - return; - } - - let profraw_path = self.output_base_dir().join("default.profraw"); - let profdata_path = self.output_base_dir().join("default.profdata"); - - // Delete any existing profraw/profdata files to rule out unintended - // interference between repeated test runs. - if profraw_path.exists() { - std::fs::remove_file(&profraw_path).unwrap(); - } - if profdata_path.exists() { - std::fs::remove_file(&profdata_path).unwrap(); - } - - let proc_res = self.exec_compiled_test_general( - &[("LLVM_PROFILE_FILE", &profraw_path.to_str().unwrap())], - false, - ); - if self.props.failure_status.is_some() { - self.check_correct_failure_status(&proc_res); - } else if !proc_res.status.success() { - self.fatal_proc_rec("test run failed!", &proc_res); - } - drop(proc_res); - - let mut profraw_paths = vec![profraw_path]; - let mut bin_paths = vec![self.make_exe_name()]; - - if self.config.suite == "coverage-run-rustdoc" { - self.run_doctests_for_coverage(&mut profraw_paths, &mut bin_paths); - } - - // Run `llvm-profdata merge` to index the raw coverage output. - let proc_res = self.run_llvm_tool("llvm-profdata", |cmd| { - cmd.args(["merge", "--sparse", "--output"]); - cmd.arg(&profdata_path); - cmd.args(&profraw_paths); - }); - if !proc_res.status.success() { - self.fatal_proc_rec("llvm-profdata merge failed!", &proc_res); - } - drop(proc_res); - - // Run `llvm-cov show` to produce a coverage report in text format. - let proc_res = self.run_llvm_tool("llvm-cov", |cmd| { - cmd.args(["show", "--format=text", "--show-line-counts-or-regions"]); - - cmd.arg("--Xdemangler"); - cmd.arg(self.config.rust_demangler_path.as_ref().unwrap()); - - cmd.arg("--instr-profile"); - cmd.arg(&profdata_path); - - for bin in &bin_paths { - cmd.arg("--object"); - cmd.arg(bin); - } - - cmd.args(&self.props.llvm_cov_flags); - }); - if !proc_res.status.success() { - self.fatal_proc_rec("llvm-cov show failed!", &proc_res); - } - - let kind = UI_COVERAGE; - - let expected_coverage = self.load_expected_output(kind); - let normalized_actual_coverage = - self.normalize_coverage_output(&proc_res.stdout).unwrap_or_else(|err| { - self.fatal_proc_rec(&err, &proc_res); - }); - - let coverage_errors = - self.compare_output(kind, &normalized_actual_coverage, &expected_coverage); - - if coverage_errors > 0 { - self.fatal_proc_rec( - &format!("{} errors occurred comparing coverage output.", coverage_errors), - &proc_res, - ); - } - } - - /// Run any doctests embedded in this test file, and add any resulting - /// `.profraw` files and doctest executables to the given vectors. - fn run_doctests_for_coverage( - &self, - profraw_paths: &mut Vec, - bin_paths: &mut Vec, - ) { - // Put .profraw files and doctest executables in dedicated directories, - // to make it easier to glob them all later. - let profraws_dir = self.output_base_dir().join("doc_profraws"); - let bins_dir = self.output_base_dir().join("doc_bins"); - - // Remove existing directories to prevent cross-run interference. - if profraws_dir.try_exists().unwrap() { - std::fs::remove_dir_all(&profraws_dir).unwrap(); - } - if bins_dir.try_exists().unwrap() { - std::fs::remove_dir_all(&bins_dir).unwrap(); - } - - let mut rustdoc_cmd = - Command::new(self.config.rustdoc_path.as_ref().expect("--rustdoc-path not passed")); - - // In general there will be multiple doctest binaries running, so we - // tell the profiler runtime to write their coverage data into separate - // profraw files. - rustdoc_cmd.env("LLVM_PROFILE_FILE", profraws_dir.join("%p-%m.profraw")); - - rustdoc_cmd.args(["--test", "-Cinstrument-coverage"]); - - // Without this, the doctests complain about not being able to find - // their enclosing file's crate for some reason. - rustdoc_cmd.args(["--crate-name", "workaround_for_79771"]); - - // Persist the doctest binaries so that `llvm-cov show` can read their - // embedded coverage mappings later. - rustdoc_cmd.arg("-Zunstable-options"); - rustdoc_cmd.arg("--persist-doctests"); - rustdoc_cmd.arg(&bins_dir); - - rustdoc_cmd.arg("-L"); - rustdoc_cmd.arg(self.aux_output_dir_name()); - - rustdoc_cmd.arg(&self.testpaths.file); - - let proc_res = self.compose_and_run_compiler(rustdoc_cmd, None); - if !proc_res.status.success() { - self.fatal_proc_rec("rustdoc --test failed!", &proc_res) - } - - fn glob_iter(path: impl AsRef) -> impl Iterator { - let path_str = path.as_ref().to_str().unwrap(); - let iter = glob(path_str).unwrap(); - iter.map(Result::unwrap) - } - - // Find all profraw files in the profraw directory. - for p in glob_iter(profraws_dir.join("*.profraw")) { - profraw_paths.push(p); - } - // Find all executables in the `--persist-doctests` directory, while - // avoiding other file types (e.g. `.pdb` on Windows). This doesn't - // need to be perfect, as long as it can handle the files actually - // produced by `rustdoc --test`. - for p in glob_iter(bins_dir.join("**/*")) { - let is_bin = p.is_file() - && match p.extension() { - None => true, - Some(ext) => ext == OsStr::new("exe"), - }; - if is_bin { - bin_paths.push(p); - } - } - } - - fn run_llvm_tool(&self, name: &str, configure_cmd_fn: impl FnOnce(&mut Command)) -> ProcRes { - let tool_path = self - .config - .llvm_bin_dir - .as_ref() - .expect("this test expects the LLVM bin dir to be available") - .join(name); - - let mut cmd = Command::new(tool_path); - configure_cmd_fn(&mut cmd); - - self.run_command_to_procres(&mut cmd) - } - fn run_command_to_procres(&self, cmd: &mut Command) -> ProcRes { let output = cmd.output().unwrap_or_else(|e| panic!("failed to exec `{cmd:?}`: {e:?}")); @@ -737,143 +521,6 @@ impl<'test> TestCx<'test> { proc_res } - fn normalize_coverage_output(&self, coverage: &str) -> Result { - let normalized = self.normalize_output(coverage, &[]); - let normalized = Self::anonymize_coverage_line_numbers(&normalized); - - let mut lines = normalized.lines().collect::>(); - - Self::sort_coverage_file_sections(&mut lines)?; - Self::sort_coverage_subviews(&mut lines)?; - - let joined_lines = lines.iter().flat_map(|line| [line, "\n"]).collect::(); - Ok(joined_lines) - } - - /// Replace line numbers in coverage reports with the placeholder `LL`, - /// so that the tests are less sensitive to lines being added/removed. - fn anonymize_coverage_line_numbers(coverage: &str) -> String { - // The coverage reporter prints line numbers at the start of a line. - // They are truncated or left-padded to occupy exactly 5 columns. - // (`LineNumberColumnWidth` in `SourceCoverageViewText.cpp`.) - // A pipe character `|` appears immediately after the final digit. - // - // Line numbers that appear inside expansion/instantiation subviews - // have an additional prefix of ` |` for each nesting level. - // - // Branch views also include the relevant line number, so we want to - // redact those too. (These line numbers don't have padding.) - // - // Note: The pattern `(?m:^)` matches the start of a line. - - // ` 1|` => ` LL|` - // ` 10|` => ` LL|` - // ` 100|` => ` LL|` - // ` | 1000|` => ` | LL|` - // ` | | 1000|` => ` | | LL|` - let coverage = static_regex!(r"(?m:^)(?(?: \|)*) *[0-9]+\|") - .replace_all(&coverage, "${prefix} LL|"); - - // ` | Branch (1:` => ` | Branch (LL:` - // ` | | Branch (10:` => ` | | Branch (LL:` - let coverage = static_regex!(r"(?m:^)(?(?: \|)+ Branch \()[0-9]+:") - .replace_all(&coverage, "${prefix}LL:"); - - // ` |---> MC/DC Decision Region (1:30) to (2:` => ` |---> MC/DC Decision Region (LL:30) to (LL:` - let coverage = - static_regex!(r"(?m:^)(?(?: \|)+---> MC/DC Decision Region \()[0-9]+:(?[0-9]+\) to \()[0-9]+:") - .replace_all(&coverage, "${prefix}LL:${middle}LL:"); - - // ` | Condition C1 --> (1:` => ` | Condition C1 --> (LL:` - let coverage = - static_regex!(r"(?m:^)(?(?: \|)+ Condition C[0-9]+ --> \()[0-9]+:") - .replace_all(&coverage, "${prefix}LL:"); - - coverage.into_owned() - } - - /// Coverage reports can describe multiple source files, separated by - /// blank lines. The order of these files is unpredictable (since it - /// depends on implementation details), so we need to sort the file - /// sections into a consistent order before comparing against a snapshot. - fn sort_coverage_file_sections(coverage_lines: &mut Vec<&str>) -> Result<(), String> { - // Group the lines into file sections, separated by blank lines. - let mut sections = coverage_lines.split(|line| line.is_empty()).collect::>(); - - // The last section should be empty, representing an extra trailing blank line. - if !sections.last().is_some_and(|last| last.is_empty()) { - return Err("coverage report should end with an extra blank line".to_owned()); - } - - // Sort the file sections (not including the final empty "section"). - let except_last = sections.len() - 1; - (&mut sections[..except_last]).sort(); - - // Join the file sections back into a flat list of lines, with - // sections separated by blank lines. - let joined = sections.join(&[""] as &[_]); - assert_eq!(joined.len(), coverage_lines.len()); - *coverage_lines = joined; - - Ok(()) - } - - fn sort_coverage_subviews(coverage_lines: &mut Vec<&str>) -> Result<(), String> { - let mut output_lines = Vec::new(); - - // We accumulate a list of zero or more "subviews", where each - // subview is a list of one or more lines. - let mut subviews: Vec> = Vec::new(); - - fn flush<'a>(subviews: &mut Vec>, output_lines: &mut Vec<&'a str>) { - if subviews.is_empty() { - return; - } - - // Take and clear the list of accumulated subviews. - let mut subviews = std::mem::take(subviews); - - // The last "subview" should be just a boundary line on its own, - // so exclude it when sorting the other subviews. - let except_last = subviews.len() - 1; - (&mut subviews[..except_last]).sort(); - - for view in subviews { - for line in view { - output_lines.push(line); - } - } - } - - for (line, line_num) in coverage_lines.iter().zip(1..) { - if line.starts_with(" ------------------") { - // This is a subview boundary line, so start a new subview. - subviews.push(vec![line]); - } else if line.starts_with(" |") { - // Add this line to the current subview. - subviews - .last_mut() - .ok_or(format!( - "unexpected subview line outside of a subview on line {line_num}" - ))? - .push(line); - } else { - // This line is not part of a subview, so sort and print any - // accumulated subviews, and then print the line as-is. - flush(&mut subviews, &mut output_lines); - output_lines.push(line); - } - } - - flush(&mut subviews, &mut output_lines); - assert!(subviews.is_empty()); - - assert_eq!(output_lines.len(), coverage_lines.len()); - *coverage_lines = output_lines; - - Ok(()) - } - fn run_pretty_test(&self) { if self.props.pp_exact.is_some() { logv(self.config, "testing for exact pretty-printing".to_owned()); diff --git a/src/tools/compiletest/src/runtest/coverage.rs b/src/tools/compiletest/src/runtest/coverage.rs new file mode 100644 index 000000000000..dad3fb301333 --- /dev/null +++ b/src/tools/compiletest/src/runtest/coverage.rs @@ -0,0 +1,367 @@ +//! Code specific to the coverage test suites. + +use std::ffi::OsStr; +use std::path::{Path, PathBuf}; +use std::process::Command; + +use glob::glob; + +use crate::common::{UI_COVERAGE, UI_COVERAGE_MAP}; +use crate::runtest::{static_regex, Emit, ProcRes, TestCx, WillExecute}; + +impl<'test> TestCx<'test> { + pub(crate) fn run_coverage_map_test(&self) { + let Some(coverage_dump_path) = &self.config.coverage_dump_path else { + self.fatal("missing --coverage-dump"); + }; + + let (proc_res, llvm_ir_path) = self.compile_test_and_save_ir(); + if !proc_res.status.success() { + self.fatal_proc_rec("compilation failed!", &proc_res); + } + drop(proc_res); + + let mut dump_command = Command::new(coverage_dump_path); + dump_command.arg(llvm_ir_path); + let proc_res = self.run_command_to_procres(&mut dump_command); + if !proc_res.status.success() { + self.fatal_proc_rec("coverage-dump failed!", &proc_res); + } + + let kind = UI_COVERAGE_MAP; + + let expected_coverage_dump = self.load_expected_output(kind); + let actual_coverage_dump = self.normalize_output(&proc_res.stdout, &[]); + + let coverage_dump_errors = + self.compare_output(kind, &actual_coverage_dump, &expected_coverage_dump); + + if coverage_dump_errors > 0 { + self.fatal_proc_rec( + &format!("{coverage_dump_errors} errors occurred comparing coverage output."), + &proc_res, + ); + } + } + + pub(crate) fn run_coverage_run_test(&self) { + let should_run = self.run_if_enabled(); + let proc_res = self.compile_test(should_run, Emit::None); + + if !proc_res.status.success() { + self.fatal_proc_rec("compilation failed!", &proc_res); + } + drop(proc_res); + + if let WillExecute::Disabled = should_run { + return; + } + + let profraw_path = self.output_base_dir().join("default.profraw"); + let profdata_path = self.output_base_dir().join("default.profdata"); + + // Delete any existing profraw/profdata files to rule out unintended + // interference between repeated test runs. + if profraw_path.exists() { + std::fs::remove_file(&profraw_path).unwrap(); + } + if profdata_path.exists() { + std::fs::remove_file(&profdata_path).unwrap(); + } + + let proc_res = self.exec_compiled_test_general( + &[("LLVM_PROFILE_FILE", &profraw_path.to_str().unwrap())], + false, + ); + if self.props.failure_status.is_some() { + self.check_correct_failure_status(&proc_res); + } else if !proc_res.status.success() { + self.fatal_proc_rec("test run failed!", &proc_res); + } + drop(proc_res); + + let mut profraw_paths = vec![profraw_path]; + let mut bin_paths = vec![self.make_exe_name()]; + + if self.config.suite == "coverage-run-rustdoc" { + self.run_doctests_for_coverage(&mut profraw_paths, &mut bin_paths); + } + + // Run `llvm-profdata merge` to index the raw coverage output. + let proc_res = self.run_llvm_tool("llvm-profdata", |cmd| { + cmd.args(["merge", "--sparse", "--output"]); + cmd.arg(&profdata_path); + cmd.args(&profraw_paths); + }); + if !proc_res.status.success() { + self.fatal_proc_rec("llvm-profdata merge failed!", &proc_res); + } + drop(proc_res); + + // Run `llvm-cov show` to produce a coverage report in text format. + let proc_res = self.run_llvm_tool("llvm-cov", |cmd| { + cmd.args(["show", "--format=text", "--show-line-counts-or-regions"]); + + cmd.arg("--Xdemangler"); + cmd.arg(self.config.rust_demangler_path.as_ref().unwrap()); + + cmd.arg("--instr-profile"); + cmd.arg(&profdata_path); + + for bin in &bin_paths { + cmd.arg("--object"); + cmd.arg(bin); + } + + cmd.args(&self.props.llvm_cov_flags); + }); + if !proc_res.status.success() { + self.fatal_proc_rec("llvm-cov show failed!", &proc_res); + } + + let kind = UI_COVERAGE; + + let expected_coverage = self.load_expected_output(kind); + let normalized_actual_coverage = + self.normalize_coverage_output(&proc_res.stdout).unwrap_or_else(|err| { + self.fatal_proc_rec(&err, &proc_res); + }); + + let coverage_errors = + self.compare_output(kind, &normalized_actual_coverage, &expected_coverage); + + if coverage_errors > 0 { + self.fatal_proc_rec( + &format!("{} errors occurred comparing coverage output.", coverage_errors), + &proc_res, + ); + } + } + + /// Run any doctests embedded in this test file, and add any resulting + /// `.profraw` files and doctest executables to the given vectors. + fn run_doctests_for_coverage( + &self, + profraw_paths: &mut Vec, + bin_paths: &mut Vec, + ) { + // Put .profraw files and doctest executables in dedicated directories, + // to make it easier to glob them all later. + let profraws_dir = self.output_base_dir().join("doc_profraws"); + let bins_dir = self.output_base_dir().join("doc_bins"); + + // Remove existing directories to prevent cross-run interference. + if profraws_dir.try_exists().unwrap() { + std::fs::remove_dir_all(&profraws_dir).unwrap(); + } + if bins_dir.try_exists().unwrap() { + std::fs::remove_dir_all(&bins_dir).unwrap(); + } + + let mut rustdoc_cmd = + Command::new(self.config.rustdoc_path.as_ref().expect("--rustdoc-path not passed")); + + // In general there will be multiple doctest binaries running, so we + // tell the profiler runtime to write their coverage data into separate + // profraw files. + rustdoc_cmd.env("LLVM_PROFILE_FILE", profraws_dir.join("%p-%m.profraw")); + + rustdoc_cmd.args(["--test", "-Cinstrument-coverage"]); + + // Without this, the doctests complain about not being able to find + // their enclosing file's crate for some reason. + rustdoc_cmd.args(["--crate-name", "workaround_for_79771"]); + + // Persist the doctest binaries so that `llvm-cov show` can read their + // embedded coverage mappings later. + rustdoc_cmd.arg("-Zunstable-options"); + rustdoc_cmd.arg("--persist-doctests"); + rustdoc_cmd.arg(&bins_dir); + + rustdoc_cmd.arg("-L"); + rustdoc_cmd.arg(self.aux_output_dir_name()); + + rustdoc_cmd.arg(&self.testpaths.file); + + let proc_res = self.compose_and_run_compiler(rustdoc_cmd, None); + if !proc_res.status.success() { + self.fatal_proc_rec("rustdoc --test failed!", &proc_res) + } + + fn glob_iter(path: impl AsRef) -> impl Iterator { + let path_str = path.as_ref().to_str().unwrap(); + let iter = glob(path_str).unwrap(); + iter.map(Result::unwrap) + } + + // Find all profraw files in the profraw directory. + for p in glob_iter(profraws_dir.join("*.profraw")) { + profraw_paths.push(p); + } + // Find all executables in the `--persist-doctests` directory, while + // avoiding other file types (e.g. `.pdb` on Windows). This doesn't + // need to be perfect, as long as it can handle the files actually + // produced by `rustdoc --test`. + for p in glob_iter(bins_dir.join("**/*")) { + let is_bin = p.is_file() + && match p.extension() { + None => true, + Some(ext) => ext == OsStr::new("exe"), + }; + if is_bin { + bin_paths.push(p); + } + } + } + + fn run_llvm_tool(&self, name: &str, configure_cmd_fn: impl FnOnce(&mut Command)) -> ProcRes { + let tool_path = self + .config + .llvm_bin_dir + .as_ref() + .expect("this test expects the LLVM bin dir to be available") + .join(name); + + let mut cmd = Command::new(tool_path); + configure_cmd_fn(&mut cmd); + + self.run_command_to_procres(&mut cmd) + } + + fn normalize_coverage_output(&self, coverage: &str) -> Result { + let normalized = self.normalize_output(coverage, &[]); + let normalized = Self::anonymize_coverage_line_numbers(&normalized); + + let mut lines = normalized.lines().collect::>(); + + Self::sort_coverage_file_sections(&mut lines)?; + Self::sort_coverage_subviews(&mut lines)?; + + let joined_lines = lines.iter().flat_map(|line| [line, "\n"]).collect::(); + Ok(joined_lines) + } + + /// Replace line numbers in coverage reports with the placeholder `LL`, + /// so that the tests are less sensitive to lines being added/removed. + fn anonymize_coverage_line_numbers(coverage: &str) -> String { + // The coverage reporter prints line numbers at the start of a line. + // They are truncated or left-padded to occupy exactly 5 columns. + // (`LineNumberColumnWidth` in `SourceCoverageViewText.cpp`.) + // A pipe character `|` appears immediately after the final digit. + // + // Line numbers that appear inside expansion/instantiation subviews + // have an additional prefix of ` |` for each nesting level. + // + // Branch views also include the relevant line number, so we want to + // redact those too. (These line numbers don't have padding.) + // + // Note: The pattern `(?m:^)` matches the start of a line. + + // ` 1|` => ` LL|` + // ` 10|` => ` LL|` + // ` 100|` => ` LL|` + // ` | 1000|` => ` | LL|` + // ` | | 1000|` => ` | | LL|` + let coverage = static_regex!(r"(?m:^)(?(?: \|)*) *[0-9]+\|") + .replace_all(&coverage, "${prefix} LL|"); + + // ` | Branch (1:` => ` | Branch (LL:` + // ` | | Branch (10:` => ` | | Branch (LL:` + let coverage = static_regex!(r"(?m:^)(?(?: \|)+ Branch \()[0-9]+:") + .replace_all(&coverage, "${prefix}LL:"); + + // ` |---> MC/DC Decision Region (1:30) to (2:` => ` |---> MC/DC Decision Region (LL:30) to (LL:` + let coverage = + static_regex!(r"(?m:^)(?(?: \|)+---> MC/DC Decision Region \()[0-9]+:(?[0-9]+\) to \()[0-9]+:") + .replace_all(&coverage, "${prefix}LL:${middle}LL:"); + + // ` | Condition C1 --> (1:` => ` | Condition C1 --> (LL:` + let coverage = + static_regex!(r"(?m:^)(?(?: \|)+ Condition C[0-9]+ --> \()[0-9]+:") + .replace_all(&coverage, "${prefix}LL:"); + + coverage.into_owned() + } + + /// Coverage reports can describe multiple source files, separated by + /// blank lines. The order of these files is unpredictable (since it + /// depends on implementation details), so we need to sort the file + /// sections into a consistent order before comparing against a snapshot. + fn sort_coverage_file_sections(coverage_lines: &mut Vec<&str>) -> Result<(), String> { + // Group the lines into file sections, separated by blank lines. + let mut sections = coverage_lines.split(|line| line.is_empty()).collect::>(); + + // The last section should be empty, representing an extra trailing blank line. + if !sections.last().is_some_and(|last| last.is_empty()) { + return Err("coverage report should end with an extra blank line".to_owned()); + } + + // Sort the file sections (not including the final empty "section"). + let except_last = sections.len() - 1; + (&mut sections[..except_last]).sort(); + + // Join the file sections back into a flat list of lines, with + // sections separated by blank lines. + let joined = sections.join(&[""] as &[_]); + assert_eq!(joined.len(), coverage_lines.len()); + *coverage_lines = joined; + + Ok(()) + } + + fn sort_coverage_subviews(coverage_lines: &mut Vec<&str>) -> Result<(), String> { + let mut output_lines = Vec::new(); + + // We accumulate a list of zero or more "subviews", where each + // subview is a list of one or more lines. + let mut subviews: Vec> = Vec::new(); + + fn flush<'a>(subviews: &mut Vec>, output_lines: &mut Vec<&'a str>) { + if subviews.is_empty() { + return; + } + + // Take and clear the list of accumulated subviews. + let mut subviews = std::mem::take(subviews); + + // The last "subview" should be just a boundary line on its own, + // so exclude it when sorting the other subviews. + let except_last = subviews.len() - 1; + (&mut subviews[..except_last]).sort(); + + for view in subviews { + for line in view { + output_lines.push(line); + } + } + } + + for (line, line_num) in coverage_lines.iter().zip(1..) { + if line.starts_with(" ------------------") { + // This is a subview boundary line, so start a new subview. + subviews.push(vec![line]); + } else if line.starts_with(" |") { + // Add this line to the current subview. + subviews + .last_mut() + .ok_or(format!( + "unexpected subview line outside of a subview on line {line_num}" + ))? + .push(line); + } else { + // This line is not part of a subview, so sort and print any + // accumulated subviews, and then print the line as-is. + flush(&mut subviews, &mut output_lines); + output_lines.push(line); + } + } + + flush(&mut subviews, &mut output_lines); + assert!(subviews.is_empty()); + + assert_eq!(output_lines.len(), coverage_lines.len()); + *coverage_lines = output_lines; + + Ok(()) + } +} diff --git a/src/tools/compiletest/src/runtest/tests.rs b/src/tools/compiletest/src/runtest/tests.rs index 817b56109a50..fb3dd326a4c8 100644 --- a/src/tools/compiletest/src/runtest/tests.rs +++ b/src/tools/compiletest/src/runtest/tests.rs @@ -48,71 +48,3 @@ fn normalize_platform_differences() { r#"println!("test\ntest")"#, ); } - -/// Test for anonymizing line numbers in coverage reports, especially for -/// MC/DC regions. -/// -/// FIXME(#123409): This test can be removed when we have examples of MC/DC -/// coverage in the actual coverage test suite. -#[test] -fn anonymize_coverage_line_numbers() { - let anon = |coverage| TestCx::anonymize_coverage_line_numbers(coverage); - - let input = r#" - 7| 2|fn mcdc_check_neither(a: bool, b: bool) { - 8| 2| if a && b { - ^0 - ------------------ - |---> MC/DC Decision Region (8:8) to (8:14) - | - | Number of Conditions: 2 - | Condition C1 --> (8:8) - | Condition C2 --> (8:13) - | - | Executed MC/DC Test Vectors: - | - | C1, C2 Result - | 1 { F, - = F } - | - | C1-Pair: not covered - | C2-Pair: not covered - | MC/DC Coverage for Decision: 0.00% - | - ------------------ - 9| 0| say("a and b"); - 10| 2| } else { - 11| 2| say("not both"); - 12| 2| } - 13| 2|} -"#; - - let expected = r#" - LL| 2|fn mcdc_check_neither(a: bool, b: bool) { - LL| 2| if a && b { - ^0 - ------------------ - |---> MC/DC Decision Region (LL:8) to (LL:14) - | - | Number of Conditions: 2 - | Condition C1 --> (LL:8) - | Condition C2 --> (LL:13) - | - | Executed MC/DC Test Vectors: - | - | C1, C2 Result - | 1 { F, - = F } - | - | C1-Pair: not covered - | C2-Pair: not covered - | MC/DC Coverage for Decision: 0.00% - | - ------------------ - LL| 0| say("a and b"); - LL| 2| } else { - LL| 2| say("not both"); - LL| 2| } - LL| 2|} -"#; - - assert_eq!(anon(input), expected); -} diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index 8f9425eb0716..09a7f0395cfb 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs @@ -57,7 +57,7 @@ impl PathBufExt for PathBuf { pub fn dylib_env_var() -> &'static str { if cfg!(windows) { "PATH" - } else if cfg!(target_os = "macos") { + } else if cfg!(target_vendor = "apple") { "DYLD_LIBRARY_PATH" } else if cfg!(target_os = "haiku") { "LIBRARY_PATH" diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs index da3aafb54e66..07d41772ba4d 100644 --- a/src/tools/miri/src/concurrency/thread.rs +++ b/src/tools/miri/src/concurrency/thread.rs @@ -861,14 +861,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if tcx.is_foreign_item(def_id) { throw_unsup_format!("foreign thread-local statics are not supported"); } - let allocation = this.ctfe_query(|tcx| tcx.eval_static_initializer(def_id))?; - let mut allocation = allocation.inner().clone(); + let alloc = this.ctfe_query(|tcx| tcx.eval_static_initializer(def_id))?; + // We make a full copy of this allocation. + let mut alloc = alloc.inner().adjust_from_tcx(&this.tcx, |ptr| this.global_root_pointer(ptr))?; // This allocation will be deallocated when the thread dies, so it is not in read-only memory. - allocation.mutability = Mutability::Mut; + alloc.mutability = Mutability::Mut; // Create a fresh allocation with this content. - let new_alloc = this.allocate_raw_ptr(allocation, MiriMemoryKind::Tls.into())?; - this.machine.threads.set_thread_local_alloc(def_id, new_alloc); - Ok(new_alloc) + let ptr = this.allocate_raw_ptr(alloc, MiriMemoryKind::Tls.into())?; + this.machine.threads.set_thread_local_alloc(def_id, ptr); + Ok(ptr) } } diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 70f326af8aef..0d91279f9f4c 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -1,7 +1,6 @@ //! Global machine state as well as implementation of the interpreter engine //! `Machine` trait. -use std::borrow::Cow; use std::cell::RefCell; use std::collections::hash_map::Entry; use std::fmt; @@ -1082,40 +1081,33 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { } } - fn adjust_allocation<'b>( + fn init_alloc_extra( ecx: &MiriInterpCx<'tcx>, id: AllocId, - alloc: Cow<'b, Allocation>, - kind: Option, - ) -> InterpResult<'tcx, Cow<'b, Allocation>> - { - let kind = kind.expect("we set our STATIC_KIND so this cannot be None"); + kind: MemoryKind, + size: Size, + align: Align, + ) -> InterpResult<'tcx, Self::AllocExtra> { if ecx.machine.tracked_alloc_ids.contains(&id) { - ecx.emit_diagnostic(NonHaltingDiagnostic::CreatedAlloc( - id, - alloc.size(), - alloc.align, - kind, - )); + ecx.emit_diagnostic(NonHaltingDiagnostic::CreatedAlloc(id, size, align, kind)); } - let alloc = alloc.into_owned(); let borrow_tracker = ecx .machine .borrow_tracker .as_ref() - .map(|bt| bt.borrow_mut().new_allocation(id, alloc.size(), kind, &ecx.machine)); + .map(|bt| bt.borrow_mut().new_allocation(id, size, kind, &ecx.machine)); - let race_alloc = ecx.machine.data_race.as_ref().map(|data_race| { + let data_race = ecx.machine.data_race.as_ref().map(|data_race| { data_race::AllocState::new_allocation( data_race, &ecx.machine.threads, - alloc.size(), + size, kind, ecx.machine.current_span(), ) }); - let buffer_alloc = ecx.machine.weak_memory.then(weak_memory::AllocState::new_allocation); + let weak_memory = ecx.machine.weak_memory.then(weak_memory::AllocState::new_allocation); // If an allocation is leaked, we want to report a backtrace to indicate where it was // allocated. We don't need to record a backtrace for allocations which are allowed to @@ -1126,17 +1118,6 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { Some(ecx.generate_stacktrace()) }; - let alloc: Allocation = alloc.adjust_from_tcx( - &ecx.tcx, - AllocExtra { - borrow_tracker, - data_race: race_alloc, - weak_memory: buffer_alloc, - backtrace, - }, - |ptr| ecx.global_root_pointer(ptr), - )?; - if matches!(kind, MemoryKind::Machine(kind) if kind.should_save_allocation_span()) { ecx.machine .allocation_spans @@ -1144,7 +1125,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { .insert(id, (ecx.machine.current_span(), None)); } - Ok(Cow::Owned(alloc)) + Ok(AllocExtra { borrow_tracker, data_race, weak_memory, backtrace }) } fn adjust_alloc_root_pointer( @@ -1347,7 +1328,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { } #[inline(always)] - fn init_frame_extra( + fn init_frame( ecx: &mut InterpCx<'tcx, Self>, frame: Frame<'tcx, Provenance>, ) -> InterpResult<'tcx, Frame<'tcx, Provenance, FrameExtra<'tcx>>> { diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.rs b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.rs new file mode 100644 index 000000000000..ff23f1e729e8 --- /dev/null +++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.rs @@ -0,0 +1,22 @@ +//@compile-flags: -Zmiri-disable-validation +#![feature(core_intrinsics, custom_mir)] +use std::intrinsics::mir::*; + +// This disables validation and uses custom MIR hit exactly the UB in the intrinsic, +// rather than getting UB from the typed load or parameter passing. + +#[custom_mir(dialect = "runtime")] +pub unsafe fn deref_meta(p: *const *const [i32]) -> usize { + mir!({ + RET = PtrMetadata(*p); //~ ERROR: Undefined Behavior: using uninitialized data + Return() + }) +} + +fn main() { + let mut p = std::mem::MaybeUninit::<*const [i32]>::uninit(); + unsafe { + (*p.as_mut_ptr().cast::<[usize; 2]>())[1] = 4; + let _meta = deref_meta(p.as_ptr().cast()); + } +} diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.stderr new file mode 100644 index 000000000000..61e1541d1ee4 --- /dev/null +++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory + --> $DIR/ptr_metadata_uninit_slice_data.rs:LL:CC + | +LL | RET = PtrMetadata(*p); + | ^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `deref_meta` at $DIR/ptr_metadata_uninit_slice_data.rs:LL:CC +note: inside `main` + --> $DIR/ptr_metadata_uninit_slice_data.rs:LL:CC + | +LL | let _meta = deref_meta(p.as_ptr().cast()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs new file mode 100644 index 000000000000..65f74c0acdd6 --- /dev/null +++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs @@ -0,0 +1,22 @@ +//@compile-flags: -Zmiri-disable-validation +#![feature(core_intrinsics, custom_mir)] +use std::intrinsics::mir::*; + +// This disables validation and uses custom MIR hit exactly the UB in the intrinsic, +// rather than getting UB from the typed load or parameter passing. + +#[custom_mir(dialect = "runtime")] +pub unsafe fn deref_meta(p: *const *const [i32]) -> usize { + mir!({ + RET = PtrMetadata(*p); //~ ERROR: Undefined Behavior: using uninitialized data + Return() + }) +} + +fn main() { + let mut p = std::mem::MaybeUninit::<*const [i32]>::uninit(); + unsafe { + (*p.as_mut_ptr().cast::<[*const i32; 2]>())[0] = 4 as *const i32; + let _meta = deref_meta(p.as_ptr().cast()); + } +} diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr new file mode 100644 index 000000000000..de559263a326 --- /dev/null +++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr @@ -0,0 +1,35 @@ +warning: integer-to-pointer cast + --> $DIR/ptr_metadata_uninit_slice_len.rs:LL:CC + | +LL | (*p.as_mut_ptr().cast::<[*const i32; 2]>())[0] = 4 as *const i32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast + | + = help: This program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`, + = help: which means that Miri might miss pointer bugs in this program. + = help: See https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation. + = help: To ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead. + = help: You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `with_exposed_provenance` semantics. + = help: Alternatively, the `-Zmiri-permissive-provenance` flag disables this warning. + = note: BACKTRACE: + = note: inside `main` at $DIR/ptr_metadata_uninit_slice_len.rs:LL:CC + +error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory + --> $DIR/ptr_metadata_uninit_slice_len.rs:LL:CC + | +LL | RET = PtrMetadata(*p); + | ^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `deref_meta` at $DIR/ptr_metadata_uninit_slice_len.rs:LL:CC +note: inside `main` + --> $DIR/ptr_metadata_uninit_slice_len.rs:LL:CC + | +LL | let _meta = deref_meta(p.as_ptr().cast()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error; 1 warning emitted + diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.rs b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.rs new file mode 100644 index 000000000000..ad2e9fc800eb --- /dev/null +++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.rs @@ -0,0 +1,23 @@ +//@compile-flags: -Zmiri-disable-validation +#![feature(core_intrinsics, custom_mir)] +use std::intrinsics::mir::*; + +// This disables validation and uses custom MIR hit exactly the UB in the intrinsic, +// rather than getting UB from the typed load or parameter passing. + +#[custom_mir(dialect = "runtime")] +pub unsafe fn deref_meta(p: *const *const i32) -> () { + mir!({ + RET = PtrMetadata(*p); //~ ERROR: Undefined Behavior: using uninitialized data + Return() + }) +} + +fn main() { + // Even though the meta is the trivially-valid `()`, this is still UB + + let p = std::mem::MaybeUninit::<*const i32>::uninit(); + unsafe { + let _meta = deref_meta(p.as_ptr()); + } +} diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.stderr new file mode 100644 index 000000000000..3ab2643afa72 --- /dev/null +++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory + --> $DIR/ptr_metadata_uninit_thin.rs:LL:CC + | +LL | RET = PtrMetadata(*p); + | ^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `deref_meta` at $DIR/ptr_metadata_uninit_thin.rs:LL:CC +note: inside `main` + --> $DIR/ptr_metadata_uninit_thin.rs:LL:CC + | +LL | let _meta = deref_meta(p.as_ptr()); + | ^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/reading_half_a_pointer.rs b/src/tools/miri/tests/fail/reading_half_a_pointer.rs index 7dd98eab7852..feac30b83c30 100644 --- a/src/tools/miri/tests/fail/reading_half_a_pointer.rs +++ b/src/tools/miri/tests/fail/reading_half_a_pointer.rs @@ -1,7 +1,7 @@ #![allow(dead_code)] // We use packed structs to get around alignment restrictions -#[repr(packed)] +#[repr(C, packed)] struct Data { pad: u8, ptr: &'static i32, diff --git a/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment2.rs b/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment2.rs index 8459c64ed2d3..06dd97deedae 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment2.rs +++ b/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment2.rs @@ -7,7 +7,7 @@ pub struct Aligned { _pad: [u8; 11], packed: Packed, } -#[repr(packed)] +#[repr(C, packed)] #[derive(Default, Copy, Clone)] pub struct Packed { _pad: [u8; 5], diff --git a/src/tools/miri/tests/pass/intrinsics/intrinsics.rs b/src/tools/miri/tests/pass/intrinsics/intrinsics.rs index 0dda5aadce20..89289a25d50a 100644 --- a/src/tools/miri/tests/pass/intrinsics/intrinsics.rs +++ b/src/tools/miri/tests/pass/intrinsics/intrinsics.rs @@ -1,5 +1,5 @@ //@compile-flags: -Zmiri-permissive-provenance -#![feature(core_intrinsics, layout_for_ptr)] +#![feature(core_intrinsics, layout_for_ptr, ptr_metadata)] //! Tests for various intrinsics that do not fit anywhere else. use std::intrinsics; @@ -57,4 +57,10 @@ fn main() { // Make sure that even if the discriminant is stored together with data, the intrinsic returns // only the discriminant, nothing about the data. assert_eq!(discriminant(&Some(false)), discriminant(&Some(true))); + + let () = intrinsics::ptr_metadata(&[1, 2, 3]); + let len = intrinsics::ptr_metadata(&[1, 2, 3][..]); + assert_eq!(len, 3); + let dyn_meta = intrinsics::ptr_metadata(&[1, 2, 3] as &dyn std::fmt::Debug); + assert_eq!(dyn_meta.size_of(), 12); } diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index d96c8b891278..0cf64db6ac9c 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -135,7 +135,13 @@ pub fn dynamic_lib_name(name: &str) -> String { /// Construct a path to a rust library (rlib) under `$TMPDIR` given the library name. This will return a /// path with `$TMPDIR` joined with the library name. pub fn rust_lib(name: &str) -> PathBuf { - tmp_dir().join(format!("lib{name}.rlib")) + tmp_dir().join(rust_lib_name(name)) +} + +/// Generate the name a rust library (rlib) would have. If you want the complete path, use +/// [`rust_lib`] instead. +pub fn rust_lib_name(name: &str) -> String { + format!("lib{name}.rlib") } /// Construct the binary name based on platform. @@ -268,6 +274,17 @@ pub fn recursive_diff(dir1: impl AsRef, dir2: impl AsRef) { } } +/// Check that `haystack` does not contain `needle`. Panic otherwise. +pub fn assert_not_contains(haystack: &str, needle: &str) { + if haystack.contains(needle) { + eprintln!("=== HAYSTACK ==="); + eprintln!("{}", haystack); + eprintln!("=== NEEDLE ==="); + eprintln!("{}", needle); + panic!("needle was unexpectedly found in haystack"); + } +} + /// Implement common helpers for command wrappers. This assumes that the command wrapper is a struct /// containing a `cmd: Command` field and a `output` function. The provided helpers are: /// @@ -351,7 +368,7 @@ macro_rules! impl_common_helpers { self } - /// Inspect what the underlying [`Command`][::std::process::Command] is up to the + /// Inspect what the underlying [`Command`] is up to the /// current construction. pub fn inspect(&mut self, inspector: I) -> &mut Self where diff --git a/src/tools/run-make-support/src/rustc.rs b/src/tools/run-make-support/src/rustc.rs index 1c83b630861c..8b0252b8f04c 100644 --- a/src/tools/run-make-support/src/rustc.rs +++ b/src/tools/run-make-support/src/rustc.rs @@ -203,9 +203,15 @@ impl Rustc { self } - /// Get the [`Output`][::std::process::Output] of the finished process. + /// Specify the linker + pub fn linker(&mut self, linker: &str) -> &mut Self { + self.cmd.arg(format!("-Clinker={linker}")); + self + } + + /// Get the [`Output`] of the finished process. #[track_caller] - pub fn command_output(&mut self) -> ::std::process::Output { + pub fn command_output(&mut self) -> Output { // let's make sure we piped all the input and outputs self.cmd.stdin(Stdio::piped()); self.cmd.stdout(Stdio::piped()); diff --git a/src/tools/run-make-support/src/rustdoc.rs b/src/tools/run-make-support/src/rustdoc.rs index 9c77f1ca4624..61d7448a6bfe 100644 --- a/src/tools/run-make-support/src/rustdoc.rs +++ b/src/tools/run-make-support/src/rustdoc.rs @@ -94,7 +94,7 @@ impl Rustdoc { self } - /// Get the [`Output`][::std::process::Output] of the finished process. + /// Get the [`Output`] of the finished process. #[track_caller] pub fn command_output(&mut self) -> ::std::process::Output { // let's make sure we piped all the input and outputs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 2329b8b44dea..009200aca15d 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -1,6 +1,5 @@ run-make/allocator-shim-circular-deps/Makefile run-make/allow-non-lint-warnings-cmdline/Makefile -run-make/allow-warnings-cmdline-stability/Makefile run-make/archive-duplicate-names/Makefile run-make/atomic-lock-free/Makefile run-make/bare-outfile/Makefile @@ -22,9 +21,7 @@ run-make/compiler-lookup-paths-2/Makefile run-make/compiler-lookup-paths/Makefile run-make/compiler-rt-works-on-mingw/Makefile run-make/compressed-debuginfo/Makefile -run-make/const-prop-lint/Makefile run-make/const_fn_mir/Makefile -run-make/crate-data-smoke/Makefile run-make/crate-hash-rustc-version/Makefile run-make/crate-name-priority/Makefile run-make/cross-lang-lto-clang/Makefile @@ -73,7 +70,6 @@ run-make/forced-unwind-terminate-pof/Makefile run-make/foreign-double-unwind/Makefile run-make/foreign-exceptions/Makefile run-make/foreign-rust-exceptions/Makefile -run-make/fpic/Makefile run-make/glibc-staticlib-args/Makefile run-make/inaccessible-temp-dir/Makefile run-make/include_bytes_deps/Makefile @@ -104,7 +100,6 @@ run-make/issue-33329/Makefile run-make/issue-35164/Makefile run-make/issue-36710/Makefile run-make/issue-37839/Makefile -run-make/issue-37893/Makefile run-make/issue-40535/Makefile run-make/issue-47384/Makefile run-make/issue-47551/Makefile @@ -117,7 +112,6 @@ run-make/issue-83112-incr-test-moved-file/Makefile run-make/issue-84395-lto-embed-bitcode/Makefile run-make/issue-85019-moved-src-dir/Makefile run-make/issue-85401-static-mir/Makefile -run-make/issue-85441/Makefile run-make/issue-88756-default-output/Makefile run-make/issue-97463-abi-param-passing/Makefile run-make/jobserver-error/Makefile @@ -145,7 +139,6 @@ run-make/lto-linkage-used-attr/Makefile run-make/lto-no-link-whole-rlib/Makefile run-make/lto-readonly-lib/Makefile run-make/lto-smoke-c/Makefile -run-make/lto-smoke/Makefile run-make/macos-deployment-target/Makefile run-make/macos-fat-archive/Makefile run-make/manual-crate-name/Makefile @@ -157,7 +150,6 @@ run-make/min-global-align/Makefile run-make/mingw-export-call-convention/Makefile run-make/mismatching-target-triples/Makefile run-make/missing-crate-dependency/Makefile -run-make/mixing-deps/Makefile run-make/mixing-formats/Makefile run-make/mixing-libs/Makefile run-make/msvc-opt-minsize/Makefile @@ -238,8 +230,6 @@ run-make/share-generics-dylib/Makefile run-make/short-ice/Makefile run-make/silly-file-names/Makefile run-make/simd-ffi/Makefile -run-make/simple-dylib/Makefile -run-make/simple-rlib/Makefile run-make/split-debuginfo/Makefile run-make/stable-symbol-names/Makefile run-make/static-dylib-by-default/Makefile @@ -276,8 +266,4 @@ run-make/volatile-intrinsics/Makefile run-make/wasm-exceptions-nostd/Makefile run-make/wasm-override-linker/Makefile run-make/weird-output-filenames/Makefile -run-make/windows-binary-no-external-deps/Makefile -run-make/windows-safeseh/Makefile -run-make/windows-spawn/Makefile -run-make/windows-subsystem/Makefile run-make/x86_64-fortanix-unknown-sgx-lvi/Makefile diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 881b4f84173c..398a6fd0fbaa 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -2122,7 +2122,6 @@ ui/issues/issue-33687.rs ui/issues/issue-33770.rs ui/issues/issue-3389.rs ui/issues/issue-33941.rs -ui/issues/issue-33992.rs ui/issues/issue-34047.rs ui/issues/issue-34074.rs ui/issues/issue-34209.rs diff --git a/src/tools/tidy/src/target_specific_tests.rs b/src/tools/tidy/src/target_specific_tests.rs index 5a402f3cc601..6fd2148ef678 100644 --- a/src/tools/tidy/src/target_specific_tests.rs +++ b/src/tools/tidy/src/target_specific_tests.rs @@ -15,6 +15,7 @@ const KNOWN_LLVM_COMPONENTS: &[&str] = &[ "arm", "avr", "bpf", + "csky", "hexagon", "loongarch", "m68k", diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 055d620361fb..cce0fb2c1a25 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -15,7 +15,7 @@ use std::path::{Path, PathBuf}; const ENTRY_LIMIT: u32 = 900; // FIXME: The following limits should be reduced eventually. -const ISSUES_ENTRY_LIMIT: u32 = 1676; +const ISSUES_ENTRY_LIMIT: u32 = 1674; const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ "rs", // test source files diff --git a/tests/assembly/nvptx-c-abi-arg-v7.rs b/tests/assembly/nvptx-c-abi-arg-v7.rs new file mode 100644 index 000000000000..99f90ea526e1 --- /dev/null +++ b/tests/assembly/nvptx-c-abi-arg-v7.rs @@ -0,0 +1,206 @@ +//@ assembly-output: ptx-linker +//@ compile-flags: --crate-type cdylib -C target-cpu=sm_86 -Z unstable-options -Clinker-flavor=llbc +//@ only-nvptx64 + +// The PTX ABI stability is tied to major versions of the PTX ISA +// These tests assume major version 7 + +// CHECK: .version 7 + +#![feature(abi_ptx, lang_items, no_core)] +#![no_core] + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +#[repr(C)] +pub struct SingleU8 { + f: u8, +} + +#[repr(C)] +pub struct DoubleU8 { + f: u8, + g: u8, +} + +#[repr(C)] +pub struct TripleU8 { + f: u8, + g: u8, + h: u8, +} + +#[repr(C)] +pub struct TripleU16 { + f: u16, + g: u16, + h: u16, +} +#[repr(C)] +pub struct TripleU32 { + f: u32, + g: u32, + h: u32, +} +#[repr(C)] +pub struct TripleU64 { + f: u64, + g: u64, + h: u64, +} + +#[repr(C)] +pub struct DoubleFloat { + f: f32, + g: f32, +} + +#[repr(C)] +pub struct TripleFloat { + f: f32, + g: f32, + h: f32, +} + +#[repr(C)] +pub struct TripleDouble { + f: f64, + g: f64, + h: f64, +} + +#[repr(C)] +pub struct ManyIntegers { + f: u8, + g: u16, + h: u32, + i: u64, +} + +#[repr(C)] +pub struct ManyNumerics { + f: u8, + g: u16, + h: u32, + i: u64, + j: f32, + k: f64, +} + +// CHECK: .visible .func f_u8_arg( +// CHECK: .param .b32 f_u8_arg_param_0 +#[no_mangle] +pub unsafe extern "C" fn f_u8_arg(_a: u8) {} + +// CHECK: .visible .func f_u16_arg( +// CHECK: .param .b32 f_u16_arg_param_0 +#[no_mangle] +pub unsafe extern "C" fn f_u16_arg(_a: u16) {} + +// CHECK: .visible .func f_u32_arg( +// CHECK: .param .b32 f_u32_arg_param_0 +#[no_mangle] +pub unsafe extern "C" fn f_u32_arg(_a: u32) {} + +// CHECK: .visible .func f_u64_arg( +// CHECK: .param .b64 f_u64_arg_param_0 +#[no_mangle] +pub unsafe extern "C" fn f_u64_arg(_a: u64) {} + +// CHECK: .visible .func f_u128_arg( +// CHECK: .param .align 16 .b8 f_u128_arg_param_0[16] +#[no_mangle] +pub unsafe extern "C" fn f_u128_arg(_a: u128) {} + +// CHECK: .visible .func f_i8_arg( +// CHECK: .param .b32 f_i8_arg_param_0 +#[no_mangle] +pub unsafe extern "C" fn f_i8_arg(_a: i8) {} + +// CHECK: .visible .func f_i16_arg( +// CHECK: .param .b32 f_i16_arg_param_0 +#[no_mangle] +pub unsafe extern "C" fn f_i16_arg(_a: i16) {} + +// CHECK: .visible .func f_i32_arg( +// CHECK: .param .b32 f_i32_arg_param_0 +#[no_mangle] +pub unsafe extern "C" fn f_i32_arg(_a: i32) {} + +// CHECK: .visible .func f_i64_arg( +// CHECK: .param .b64 f_i64_arg_param_0 +#[no_mangle] +pub unsafe extern "C" fn f_i64_arg(_a: i64) {} + +// CHECK: .visible .func f_i128_arg( +// CHECK: .param .align 16 .b8 f_i128_arg_param_0[16] +#[no_mangle] +pub unsafe extern "C" fn f_i128_arg(_a: i128) {} + +// CHECK: .visible .func f_f32_arg( +// CHECK: .param .b32 f_f32_arg_param_0 +#[no_mangle] +pub unsafe extern "C" fn f_f32_arg(_a: f32) {} + +// CHECK: .visible .func f_f64_arg( +// CHECK: .param .b64 f_f64_arg_param_0 +#[no_mangle] +pub unsafe extern "C" fn f_f64_arg(_a: f64) {} + +// CHECK: .visible .func f_single_u8_arg( +// CHECK: .param .align 1 .b8 f_single_u8_arg_param_0[1] +#[no_mangle] +pub unsafe extern "C" fn f_single_u8_arg(_a: SingleU8) {} + +// CHECK: .visible .func f_double_u8_arg( +// CHECK: .param .align 1 .b8 f_double_u8_arg_param_0[2] +#[no_mangle] +pub unsafe extern "C" fn f_double_u8_arg(_a: DoubleU8) {} + +// CHECK: .visible .func f_triple_u8_arg( +// CHECK: .param .align 1 .b8 f_triple_u8_arg_param_0[3] +#[no_mangle] +pub unsafe extern "C" fn f_triple_u8_arg(_a: TripleU8) {} + +// CHECK: .visible .func f_triple_u16_arg( +// CHECK: .param .align 2 .b8 f_triple_u16_arg_param_0[6] +#[no_mangle] +pub unsafe extern "C" fn f_triple_u16_arg(_a: TripleU16) {} + +// CHECK: .visible .func f_triple_u32_arg( +// CHECK: .param .align 4 .b8 f_triple_u32_arg_param_0[12] +#[no_mangle] +pub unsafe extern "C" fn f_triple_u32_arg(_a: TripleU32) {} + +// CHECK: .visible .func f_triple_u64_arg( +// CHECK: .param .align 8 .b8 f_triple_u64_arg_param_0[24] +#[no_mangle] +pub unsafe extern "C" fn f_triple_u64_arg(_a: TripleU64) {} + +// CHECK: .visible .func f_many_integers_arg( +// CHECK: .param .align 8 .b8 f_many_integers_arg_param_0[16] +#[no_mangle] +pub unsafe extern "C" fn f_many_integers_arg(_a: ManyIntegers) {} + +// CHECK: .visible .func f_double_float_arg( +// CHECK: .param .align 4 .b8 f_double_float_arg_param_0[8] +#[no_mangle] +pub unsafe extern "C" fn f_double_float_arg(_a: DoubleFloat) {} + +// CHECK: .visible .func f_triple_float_arg( +// CHECK: .param .align 4 .b8 f_triple_float_arg_param_0[12] +#[no_mangle] +pub unsafe extern "C" fn f_triple_float_arg(_a: TripleFloat) {} + +// CHECK: .visible .func f_triple_double_arg( +// CHECK: .param .align 8 .b8 f_triple_double_arg_param_0[24] +#[no_mangle] +pub unsafe extern "C" fn f_triple_double_arg(_a: TripleDouble) {} + +// CHECK: .visible .func f_many_numerics_arg( +// CHECK: .param .align 8 .b8 f_many_numerics_arg_param_0[32] +#[no_mangle] +pub unsafe extern "C" fn f_many_numerics_arg(_a: ManyNumerics) {} diff --git a/tests/assembly/nvptx-c-abi-ret-v7.rs b/tests/assembly/nvptx-c-abi-ret-v7.rs new file mode 100644 index 000000000000..0c1594a5f200 --- /dev/null +++ b/tests/assembly/nvptx-c-abi-ret-v7.rs @@ -0,0 +1,230 @@ +//@ assembly-output: ptx-linker +//@ compile-flags: --crate-type cdylib -C target-cpu=sm_86 -Z unstable-options -Clinker-flavor=llbc +//@ only-nvptx64 +//@ ignore-nvptx64 + +// The PTX ABI stability is tied to major versions of the PTX ISA +// These tests assume major version 7 + +// CHECK: .version 7 + +#![feature(abi_ptx, lang_items, no_core)] +#![no_core] + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +#[repr(C)] +pub struct SingleU8 { + f: u8, +} + +#[repr(C)] +pub struct DoubleU8 { + f: u8, + g: u8, +} + +#[repr(C)] +pub struct TripleU8 { + f: u8, + g: u8, + h: u8, +} + +#[repr(C)] +pub struct TripleU16 { + f: u16, + g: u16, + h: u16, +} +#[repr(C)] +pub struct TripleU32 { + f: u32, + g: u32, + h: u32, +} +#[repr(C)] +pub struct TripleU64 { + f: u64, + g: u64, + h: u64, +} + +#[repr(C)] +pub struct DoubleFloat { + f: f32, + g: f32, +} + +#[repr(C)] +pub struct TripleFloat { + f: f32, + g: f32, + h: f32, +} + +#[repr(C)] +pub struct TripleDouble { + f: f64, + g: f64, + h: f64, +} + +#[repr(C)] +pub struct ManyIntegers { + f: u8, + g: u16, + h: u32, + i: u64, +} + +#[repr(C)] +pub struct ManyNumerics { + f: u8, + g: u16, + h: u32, + i: u64, + j: f32, + k: f64, +} + +// CHECK: .visible .func (.param .b32 func_retval0) f_u8_ret( +#[no_mangle] +pub unsafe extern "C" fn f_u8_ret() -> u8 { + 0 +} + +// CHECK: .visible .func (.param .b32 func_retval0) f_u16_ret( +#[no_mangle] +pub unsafe extern "C" fn f_u16_ret() -> u16 { + 1 +} + +// CHECK: .visible .func (.param .b32 func_retval0) f_u32_ret( +#[no_mangle] +pub unsafe extern "C" fn f_u32_ret() -> u32 { + 2 +} + +// CHECK: .visible .func (.param .b64 func_retval0) f_u64_ret( +#[no_mangle] +pub unsafe extern "C" fn f_u64_ret() -> u64 { + 3 +} + +// CHECK: .visible .func (.param .align 16 .b8 func_retval0[16]) f_u128_ret( +#[no_mangle] +pub unsafe extern "C" fn f_u128_ret() -> u128 { + 4 +} + +// CHECK: .visible .func (.param .b32 func_retval0) f_i8_ret( +#[no_mangle] +pub unsafe extern "C" fn f_i8_ret() -> i8 { + 5 +} + +// CHECK: .visible .func (.param .b32 func_retval0) f_i16_ret( +#[no_mangle] +pub unsafe extern "C" fn f_i16_ret() -> i16 { + 6 +} + +// CHECK: .visible .func (.param .b32 func_retval0) f_i32_ret( +#[no_mangle] +pub unsafe extern "C" fn f_i32_ret() -> i32 { + 7 +} + +// CHECK: .visible .func (.param .b64 func_retval0) f_i64_ret( +#[no_mangle] +pub unsafe extern "C" fn f_i64_ret() -> i64 { + 8 +} + +// CHECK: .visible .func (.param .align 16 .b8 func_retval0[16]) f_i128_ret( +#[no_mangle] +pub unsafe extern "C" fn f_i128_ret() -> i128 { + 9 +} + +// CHECK: .visible .func (.param .b32 func_retval0) f_f32_ret( +#[no_mangle] +pub unsafe extern "C" fn f_f32_ret() -> f32 { + 10.0 +} + +// CHECK: .visible .func (.param .b64 func_retval0) f_f64_ret( +#[no_mangle] +pub unsafe extern "C" fn f_f64_ret() -> f64 { + 11.0 +} + +// CHECK: .visible .func (.param .align 1 .b8 func_retval0[1]) f_single_u8_ret( +#[no_mangle] +pub unsafe extern "C" fn f_single_u8_ret() -> SingleU8 { + SingleU8 { f: 12 } +} + +// CHECK: .visible .func (.param .align 1 .b8 func_retval0[2]) f_double_u8_ret( +#[no_mangle] +pub unsafe extern "C" fn f_double_u8_ret() -> DoubleU8 { + DoubleU8 { f: 13, g: 14 } +} + +// CHECK: .visible .func (.param .align 1 .b8 func_retval0[3]) f_triple_u8_ret( +#[no_mangle] +pub unsafe extern "C" fn f_triple_u8_ret() -> TripleU8 { + TripleU8 { f: 15, g: 16, h: 17 } +} + +// CHECK: .visible .func (.param .align 2 .b8 func_retval0[6]) f_triple_u16_ret( +#[no_mangle] +pub unsafe extern "C" fn f_triple_u16_ret() -> TripleU16 { + TripleU16 { f: 18, g: 19, h: 20 } +} + +// CHECK: .visible .func (.param .align 4 .b8 func_retval0[12]) f_triple_u32_ret( +#[no_mangle] +pub unsafe extern "C" fn f_triple_u32_ret() -> TripleU32 { + TripleU32 { f: 20, g: 21, h: 22 } +} + +// CHECK: .visible .func (.param .align 8 .b8 func_retval0[24]) f_triple_u64_ret( +#[no_mangle] +pub unsafe extern "C" fn f_triple_u64_ret() -> TripleU64 { + TripleU64 { f: 23, g: 24, h: 25 } +} + +// CHECK: .visible .func (.param .align 8 .b8 func_retval0[16]) f_many_integers_ret( +#[no_mangle] +pub unsafe extern "C" fn f_many_integers_ret() -> ManyIntegers { + ManyIntegers { f: 26, g: 27, h: 28, i: 29 } +} + +// CHECK: .visible .func (.param .align 4 .b8 func_retval0[8]) f_double_float_ret( +#[no_mangle] +pub unsafe extern "C" fn f_double_float_ret() -> DoubleFloat { + DoubleFloat { f: 29.0, g: 30.0 } +} + +// CHECK: .visible .func (.param .align 4 .b8 func_retval0[12]) f_triple_float_ret( +#[no_mangle] +pub unsafe extern "C" fn f_triple_float_ret() -> TripleFloat { + TripleFloat { f: 31.0, g: 32.0, h: 33.0 } +} + +// CHECK: .visible .func (.param .align 8 .b8 func_retval0[24]) f_triple_double_ret( +#[no_mangle] +pub unsafe extern "C" fn f_triple_double_ret() -> TripleDouble { + TripleDouble { f: 34.0, g: 35.0, h: 36.0 } +} + +// CHECK: .visible .func (.param .align 8 .b8 func_retval0[32]) f_many_numerics_ret( +#[no_mangle] +pub unsafe extern "C" fn f_many_numerics_ret() -> ManyNumerics { + ManyNumerics { f: 37, g: 38, h: 39, i: 40, j: 41.0, k: 43.0 } +} diff --git a/tests/assembly/stack-protector/stack-protector-heuristics-effect.rs b/tests/assembly/stack-protector/stack-protector-heuristics-effect.rs index 8e32d170244a..1f15f1a318a6 100644 --- a/tests/assembly/stack-protector/stack-protector-heuristics-effect.rs +++ b/tests/assembly/stack-protector/stack-protector-heuristics-effect.rs @@ -1,6 +1,6 @@ //@ revisions: all strong basic none missing //@ assembly-output: emit-asm -//@ ignore-macos slightly different policy on stack protection of arrays +//@ ignore-apple slightly different policy on stack protection of arrays //@ ignore-msvc stack check code uses different function names //@ ignore-nvptx64 stack protector is not supported //@ ignore-wasm32-bare @@ -17,12 +17,9 @@ // See comments on https://github.com/rust-lang/rust/issues/114903. #![crate_type = "lib"] - #![allow(incomplete_features)] - #![feature(unsized_locals, unsized_fn_params)] - // CHECK-LABEL: emptyfn: #[no_mangle] pub fn emptyfn() { diff --git a/tests/assembly/x86_64-array-pair-load-store-merge.rs b/tests/assembly/x86_64-array-pair-load-store-merge.rs index 9cf54ae14a16..849f34e72e51 100644 --- a/tests/assembly/x86_64-array-pair-load-store-merge.rs +++ b/tests/assembly/x86_64-array-pair-load-store-merge.rs @@ -2,7 +2,7 @@ //@ compile-flags: --crate-type=lib -O -C llvm-args=-x86-asm-syntax=intel //@ only-x86_64 //@ ignore-sgx -//@ ignore-macos (manipulates rsp too) +//@ ignore-apple (manipulates rsp too) // Depending on various codegen choices, this might end up copying // a `<2 x i8>`, an `i16`, or two `i8`s. diff --git a/tests/assembly/x86_64-function-return.rs b/tests/assembly/x86_64-function-return.rs index 64eb05062cbc..7cfdf5bce0c1 100644 --- a/tests/assembly/x86_64-function-return.rs +++ b/tests/assembly/x86_64-function-return.rs @@ -9,7 +9,7 @@ //@ [keep-thunk-extern] compile-flags: -Zfunction-return=keep -Zfunction-return=thunk-extern //@ [thunk-extern-keep] compile-flags: -Zfunction-return=thunk-extern -Zfunction-return=keep //@ only-x86_64 -//@ ignore-x86_64-apple-darwin Symbol is called `___x86_return_thunk` (Darwin's extra underscore) +//@ ignore-apple Symbol is called `___x86_return_thunk` (Darwin's extra underscore) //@ ignore-sgx Tests incompatible with LVI mitigations #![crate_type = "lib"] diff --git a/tests/codegen-units/partitioning/vtable-through-const.rs b/tests/codegen-units/partitioning/vtable-through-const.rs index ca4d3822b549..f91c0c0bfdbf 100644 --- a/tests/codegen-units/partitioning/vtable-through-const.rs +++ b/tests/codegen-units/partitioning/vtable-through-const.rs @@ -9,19 +9,25 @@ #![feature(start)] mod mod1 { + struct NeedsDrop; + + impl Drop for NeedsDrop { + fn drop(&mut self) {} + } + pub trait Trait1 { fn do_something(&self) {} fn do_something_else(&self) {} } - impl Trait1 for u32 {} + impl Trait1 for NeedsDrop {} pub trait Trait1Gen { fn do_something(&self, x: T) -> T; fn do_something_else(&self, x: T) -> T; } - impl Trait1Gen for u32 { + impl Trait1Gen for NeedsDrop { fn do_something(&self, x: T) -> T { x } fn do_something_else(&self, x: T) -> T { x } } @@ -30,8 +36,8 @@ mod mod1 { fn id(x: T) -> T { x } // These are referenced, so they produce mono-items (see start()) - pub const TRAIT1_REF: &'static Trait1 = &0u32 as &Trait1; - pub const TRAIT1_GEN_REF: &'static Trait1Gen = &0u32 as &Trait1Gen; + pub const TRAIT1_REF: &'static Trait1 = &NeedsDrop as &Trait1; + pub const TRAIT1_GEN_REF: &'static Trait1Gen = &NeedsDrop as &Trait1Gen; pub const ID_CHAR: fn(char) -> char = id::; @@ -41,47 +47,48 @@ mod mod1 { fn do_something_else(&self) {} } - //~ MONO_ITEM fn ::do_something @@ vtable_through_const-mod1.volatile[Internal] - //~ MONO_ITEM fn ::do_something_else @@ vtable_through_const-mod1.volatile[Internal] - impl Trait2 for u32 {} + //~ MONO_ITEM fn ::do_something @@ vtable_through_const-mod1.volatile[Internal] + //~ MONO_ITEM fn ::do_something_else @@ vtable_through_const-mod1.volatile[Internal] + impl Trait2 for NeedsDrop {} pub trait Trait2Gen { fn do_something(&self, x: T) -> T; fn do_something_else(&self, x: T) -> T; } - impl Trait2Gen for u32 { + impl Trait2Gen for NeedsDrop { fn do_something(&self, x: T) -> T { x } fn do_something_else(&self, x: T) -> T { x } } // These are not referenced, so they do not produce mono-items - pub const TRAIT2_REF: &'static Trait2 = &0u32 as &Trait2; - pub const TRAIT2_GEN_REF: &'static Trait2Gen = &0u32 as &Trait2Gen; + pub const TRAIT2_REF: &'static Trait2 = &NeedsDrop as &Trait2; + pub const TRAIT2_GEN_REF: &'static Trait2Gen = &NeedsDrop as &Trait2Gen; pub const ID_I64: fn(i64) -> i64 = id::; } //~ MONO_ITEM fn start #[start] fn start(_: isize, _: *const *const u8) -> isize { - //~ MONO_ITEM fn std::ptr::drop_in_place:: - shim(None) @@ vtable_through_const[Internal] + //~ MONO_ITEM fn ::drop @@ vtable_through_const-fallback.cgu[Internal] + //~ MONO_ITEM fn std::ptr::drop_in_place:: - shim(Some(mod1::NeedsDrop)) @@ vtable_through_const-fallback.cgu[External] // Since Trait1::do_something() is instantiated via its default implementation, // it is considered a generic and is instantiated here only because it is // referenced in this module. - //~ MONO_ITEM fn ::do_something_else @@ vtable_through_const-mod1.volatile[External] + //~ MONO_ITEM fn ::do_something_else @@ vtable_through_const-mod1.volatile[External] // Although it is never used, Trait1::do_something_else() has to be - // instantiated locally here too, otherwise the <&u32 as &Trait1> vtable + // instantiated locally here too, otherwise the <&NeedsDrop as &Trait1> vtable // could not be fully constructed. - //~ MONO_ITEM fn ::do_something @@ vtable_through_const-mod1.volatile[External] + //~ MONO_ITEM fn ::do_something @@ vtable_through_const-mod1.volatile[External] mod1::TRAIT1_REF.do_something(); // Same as above - //~ MONO_ITEM fn >::do_something @@ vtable_through_const-mod1.volatile[External] - //~ MONO_ITEM fn >::do_something_else @@ vtable_through_const-mod1.volatile[External] - //~ MONO_ITEM fn >::do_something @@ vtable_through_const-mod1.volatile[Internal] - //~ MONO_ITEM fn >::do_something_else @@ vtable_through_const-mod1.volatile[Internal] + //~ MONO_ITEM fn >::do_something @@ vtable_through_const-mod1.volatile[External] + //~ MONO_ITEM fn >::do_something_else @@ vtable_through_const-mod1.volatile[External] + //~ MONO_ITEM fn >::do_something @@ vtable_through_const-mod1.volatile[Internal] + //~ MONO_ITEM fn >::do_something_else @@ vtable_through_const-mod1.volatile[Internal] mod1::TRAIT1_GEN_REF.do_something(0u8); //~ MONO_ITEM fn mod1::id:: @@ vtable_through_const-mod1.volatile[External] diff --git a/tests/codegen/fixed-x18.rs b/tests/codegen/fixed-x18.rs new file mode 100644 index 000000000000..4997a39a7263 --- /dev/null +++ b/tests/codegen/fixed-x18.rs @@ -0,0 +1,22 @@ +// Test that the `reserve-x18` target feature is (not) emitted when +// the `-Zfixed-x18` flag is (not) set. + +//@ revisions: unset set +//@ needs-llvm-components: aarch64 +//@ compile-flags: --target aarch64-unknown-none +//@ [set] compile-flags: -Zfixed-x18 + +#![crate_type = "lib"] +#![feature(no_core, lang_items)] +#![no_core] + +#[lang = "sized"] +trait Sized {} + +#[no_mangle] +pub fn foo() { + // CHECK: @foo() unnamed_addr #0 + + // unset-NOT: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+reserve-x18{{.*}} } + // set: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+reserve-x18{{.*}} } +} diff --git a/tests/codegen/gdb_debug_script_load.rs b/tests/codegen/gdb_debug_script_load.rs index f15defeaca8b..30d518c0bcb8 100644 --- a/tests/codegen/gdb_debug_script_load.rs +++ b/tests/codegen/gdb_debug_script_load.rs @@ -1,6 +1,6 @@ // //@ ignore-windows -//@ ignore-macos +//@ ignore-apple //@ ignore-wasm //@ ignore-emscripten diff --git a/tests/codegen/instrument-coverage/testprog.rs b/tests/codegen/instrument-coverage/testprog.rs index b352cbdb7557..acc4f35d9054 100644 --- a/tests/codegen/instrument-coverage/testprog.rs +++ b/tests/codegen/instrument-coverage/testprog.rs @@ -11,7 +11,7 @@ //@ [LINUX] filecheck-flags: -DINSTR_PROF_COVFUN=__llvm_covfun //@ [LINUX] filecheck-flags: '-DCOMDAT_IF_SUPPORTED=, comdat' -//@ [DARWIN] only-macos +//@ [DARWIN] only-apple //@ [DARWIN] filecheck-flags: -DINSTR_PROF_DATA=__DATA,__llvm_prf_data,regular,live_support //@ [DARWIN] filecheck-flags: -DINSTR_PROF_NAME=__DATA,__llvm_prf_names //@ [DARWIN] filecheck-flags: -DINSTR_PROF_CNTS=__DATA,__llvm_prf_cnts @@ -49,7 +49,7 @@ where pub fn wrap_with(inner: T, should_wrap: bool, wrapper: F) where - F: FnOnce(&T) + F: FnOnce(&T), { if should_wrap { wrapper(&inner) diff --git a/tests/codegen/intrinsics/ptr_metadata.rs b/tests/codegen/intrinsics/ptr_metadata.rs new file mode 100644 index 000000000000..f4bf5a1f5f17 --- /dev/null +++ b/tests/codegen/intrinsics/ptr_metadata.rs @@ -0,0 +1,36 @@ +//@ compile-flags: -O -C no-prepopulate-passes -Z inline-mir +//@ only-64bit (so I don't need to worry about usize) + +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +use std::intrinsics::ptr_metadata; + +// CHECK-LABEL: @thin_metadata( +#[no_mangle] +pub fn thin_metadata(p: *const ()) { + // CHECK: start + // CHECK-NEXT: ret void + ptr_metadata(p) +} + +// CHECK-LABEL: @slice_metadata( +#[no_mangle] +pub fn slice_metadata(p: *const [u8]) -> usize { + // CHECK: start + // CHECK-NEXT: ret i64 %p.1 + ptr_metadata(p) +} + +// CHECK-LABEL: @dyn_byte_offset( +#[no_mangle] +pub unsafe fn dyn_byte_offset( + p: *const dyn std::fmt::Debug, + n: usize, +) -> *const dyn std::fmt::Debug { + // CHECK: %[[Q:.+]] = getelementptr inbounds i8, ptr %p.0, i64 %n + // CHECK: %[[TEMP1:.+]] = insertvalue { ptr, ptr } poison, ptr %[[Q]], 0 + // CHECK: %[[TEMP2:.+]] = insertvalue { ptr, ptr } %[[TEMP1]], ptr %p.1, 1 + // CHECK: ret { ptr, ptr } %[[TEMP2]] + p.byte_add(n) +} diff --git a/tests/codegen/issues/issue-44056-macos-tls-align.rs b/tests/codegen/issues/issue-44056-macos-tls-align.rs index c99f0b73038b..972b8490d18f 100644 --- a/tests/codegen/issues/issue-44056-macos-tls-align.rs +++ b/tests/codegen/issues/issue-44056-macos-tls-align.rs @@ -1,5 +1,5 @@ // -//@ only-macos +//@ only-apple //@ compile-flags: -O #![crate_type = "rlib"] diff --git a/tests/codegen/mainsubprogram.rs b/tests/codegen/mainsubprogram.rs index c1933b2b3904..12b24c90229e 100644 --- a/tests/codegen/mainsubprogram.rs +++ b/tests/codegen/mainsubprogram.rs @@ -2,7 +2,7 @@ // before 4.0, formerly backported to the Rust LLVM fork. //@ ignore-windows -//@ ignore-macos +//@ ignore-apple //@ ignore-wasi //@ compile-flags: -g -C no-prepopulate-passes @@ -10,5 +10,4 @@ // CHECK-LABEL: @main // CHECK: {{.*}}DISubprogram{{.*}}name: "main",{{.*}}DI{{(SP)?}}FlagMainSubprogram{{.*}} -pub fn main() { -} +pub fn main() {} diff --git a/tests/codegen/mainsubprogramstart.rs b/tests/codegen/mainsubprogramstart.rs index 84d680b9bff9..20741791db5c 100644 --- a/tests/codegen/mainsubprogramstart.rs +++ b/tests/codegen/mainsubprogramstart.rs @@ -1,5 +1,5 @@ //@ ignore-windows -//@ ignore-macos +//@ ignore-apple //@ ignore-wasi wasi codegens the main symbol differently //@ compile-flags: -g -C no-prepopulate-passes diff --git a/tests/codegen/pgo-counter-bias.rs b/tests/codegen/pgo-counter-bias.rs index 1263eaf206f7..87d31073d5ae 100644 --- a/tests/codegen/pgo-counter-bias.rs +++ b/tests/codegen/pgo-counter-bias.rs @@ -1,6 +1,6 @@ // Test that __llvm_profile_counter_bias does not get internalized by lto. -//@ ignore-macos -runtime-counter-relocation not honored on Mach-O +//@ ignore-apple -runtime-counter-relocation not honored on Mach-O //@ compile-flags: -Cprofile-generate -Cllvm-args=-runtime-counter-relocation -Clto=fat //@ needs-profiler-support //@ no-prefer-dynamic diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs index 6c3d991af9f1..4e5ad8ad4a93 100644 --- a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs +++ b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs @@ -4,7 +4,7 @@ //@ needs-sanitizer-cfi //@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static -#![crate_type="lib"] +#![crate_type = "lib"] #![feature(type_alias_impl_trait)] extern crate core; @@ -14,14 +14,15 @@ pub type Type2 = impl Send; pub type Type3 = impl Send; pub type Type4 = impl Send; -pub fn foo() where +pub fn foo() +where Type1: 'static, Type2: 'static, Type3: 'static, Type4: 'static, { // Type in extern path - extern { + extern "C" { fn bar(); } let _: Type1 = bar; @@ -35,43 +36,44 @@ pub fn foo() where // Type in const path const { pub struct Foo; - fn bar() -> Type3 { Foo } + fn bar() -> Type3 { + Foo + } }; - // Type in impl path struct Foo; impl Foo { - fn bar(&self) { } + fn bar(&self) {} } let _: Type4 = ::bar; } // Force arguments to be passed by using a reference. Otherwise, they may end up PassMode::Ignore -pub fn foo1(_: &Type1) { } +pub fn foo1(_: &Type1) {} // CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo2(_: &Type1, _: &Type1) { } +pub fn foo2(_: &Type1, _: &Type1) {} // CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo3(_: &Type1, _: &Type1, _: &Type1) { } +pub fn foo3(_: &Type1, _: &Type1, _: &Type1) {} // CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo4(_: &Type2) { } +pub fn foo4(_: &Type2) {} // CHECK: define{{.*}}4foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo5(_: &Type2, _: &Type2) { } +pub fn foo5(_: &Type2, _: &Type2) {} // CHECK: define{{.*}}4foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo6(_: &Type2, _: &Type2, _: &Type2) { } +pub fn foo6(_: &Type2, _: &Type2, _: &Type2) {} // CHECK: define{{.*}}4foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo7(_: &Type3) { } +pub fn foo7(_: &Type3) {} // CHECK: define{{.*}}4foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo8(_: &Type3, _: &Type3) { } +pub fn foo8(_: &Type3, _: &Type3) {} // CHECK: define{{.*}}4foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo9(_: &Type3, _: &Type3, _: &Type3) { } +pub fn foo9(_: &Type3, _: &Type3, _: &Type3) {} // CHECK: define{{.*}}4foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo10(_: &Type4) { } +pub fn foo10(_: &Type4) {} // CHECK: define{{.*}}5foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo11(_: &Type4, _: &Type4) { } +pub fn foo11(_: &Type4, _: &Type4) {} // CHECK: define{{.*}}5foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo12(_: &Type4, _: &Type4, _: &Type4) { } +pub fn foo12(_: &Type4, _: &Type4, _: &Type4) {} // CHECK: define{{.*}}5foo12{{.*}}!type ![[TYPE12:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} // CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo10{{[{}][{}]}}extern{{[}][}]}}3barEE"} @@ -80,9 +82,9 @@ pub fn foo12(_: &Type4, _: &Type4, _: &Type4) { } // CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooEE"} // CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooES0_E"} // CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooES0_S0_E"} -// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooEE"} -// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooES0_E"} -// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooES0_S0_E"} +// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo3FooEE"} +// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo3FooES0_E"} +// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo3FooES0_S0_E"} // CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barEE"} // CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barES0_E"} // CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barES0_S0_E"} diff --git a/tests/codegen/vtable-loads.rs b/tests/codegen/vtable-loads.rs new file mode 100644 index 000000000000..1dd6ca51063b --- /dev/null +++ b/tests/codegen/vtable-loads.rs @@ -0,0 +1,16 @@ +//@ compile-flags: -O + +#![crate_type = "lib"] + +// CHECK-LABEL: @loop_skips_vtable_load +#[no_mangle] +pub fn loop_skips_vtable_load(x: &dyn Fn()) { + // CHECK: load ptr, ptr %0{{.*}}, !invariant.load + // CHECK-NEXT: tail call void %1 + // CHECK-NOT: load ptr + x(); + for _ in 0..100 { + // CHECK: tail call void %1 + x(); + } +} diff --git a/tests/coverage/auxiliary/used_crate.rs b/tests/coverage/auxiliary/used_crate.rs index 72d479c74a68..c0556a5bb4cd 100644 --- a/tests/coverage/auxiliary/used_crate.rs +++ b/tests/coverage/auxiliary/used_crate.rs @@ -17,23 +17,23 @@ pub fn used_function() { } pub fn used_only_from_bin_crate_generic_function(arg: T) { - println!("used_only_from_bin_crate_generic_function with {:?}", arg); + println!("used_only_from_bin_crate_generic_function with {arg:?}"); } // Expect for above function: `Unexecuted instantiation` (see below) pub fn used_only_from_this_lib_crate_generic_function(arg: T) { - println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); + println!("used_only_from_this_lib_crate_generic_function with {arg:?}"); } pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { - println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + println!("used_from_bin_crate_and_lib_crate_generic_function with {arg:?}"); } pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { - println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {arg:?}"); } pub fn unused_generic_function(arg: T) { - println!("unused_generic_function with {:?}", arg); + println!("unused_generic_function with {arg:?}"); } pub fn unused_function() { diff --git a/tests/coverage/auxiliary/used_inline_crate.rs b/tests/coverage/auxiliary/used_inline_crate.rs index d5fe7478aa41..165d5c1e3096 100644 --- a/tests/coverage/auxiliary/used_inline_crate.rs +++ b/tests/coverage/auxiliary/used_inline_crate.rs @@ -31,28 +31,28 @@ pub fn used_inline_function() { #[inline(always)] pub fn used_only_from_bin_crate_generic_function(arg: T) { - println!("used_only_from_bin_crate_generic_function with {:?}", arg); + println!("used_only_from_bin_crate_generic_function with {arg:?}"); } // Expect for above function: `Unexecuted instantiation` (see notes in `used_crate.rs`) #[inline(always)] pub fn used_only_from_this_lib_crate_generic_function(arg: T) { - println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); + println!("used_only_from_this_lib_crate_generic_function with {arg:?}"); } #[inline(always)] pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { - println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + println!("used_from_bin_crate_and_lib_crate_generic_function with {arg:?}"); } #[inline(always)] pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { - println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {arg:?}"); } #[inline(always)] pub fn unused_generic_function(arg: T) { - println!("unused_generic_function with {:?}", arg); + println!("unused_generic_function with {arg:?}"); } #[inline(always)] diff --git a/tests/coverage/condition/conditions.cov-map b/tests/coverage/condition/conditions.cov-map new file mode 100644 index 000000000000..74726e269fc6 --- /dev/null +++ b/tests/coverage/condition/conditions.cov-map @@ -0,0 +1,152 @@ +Function name: conditions::assign_3_and_or +Raw bytes (69): 0x[01, 01, 07, 07, 11, 09, 0d, 01, 05, 05, 09, 16, 1a, 05, 09, 01, 05, 09, 01, 1c, 01, 00, 2f, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 1a, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 20, 09, 16, 00, 12, 00, 13, 13, 00, 17, 00, 18, 20, 0d, 11, 00, 17, 00, 18, 03, 01, 05, 01, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 7 +- expression 0 operands: lhs = Expression(1, Add), rhs = Counter(4) +- expression 1 operands: lhs = Counter(2), rhs = Counter(3) +- expression 2 operands: lhs = Counter(0), rhs = Counter(1) +- expression 3 operands: lhs = Counter(1), rhs = Counter(2) +- expression 4 operands: lhs = Expression(5, Sub), rhs = Expression(6, Sub) +- expression 5 operands: lhs = Counter(1), rhs = Counter(2) +- expression 6 operands: lhs = Counter(0), rhs = Counter(1) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 28, 1) to (start + 0, 47) +- Code(Expression(0, Add)) at (prev + 1, 9) to (start + 0, 10) + = ((c2 + c3) + c4) +- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) +- Branch { true: Counter(1), false: Expression(6, Sub) } at (prev + 0, 13) to (start + 0, 14) + true = c1 + false = (c0 - c1) +- Code(Counter(1)) at (prev + 0, 18) to (start + 0, 19) +- Branch { true: Counter(2), false: Expression(5, Sub) } at (prev + 0, 18) to (start + 0, 19) + true = c2 + false = (c1 - c2) +- Code(Expression(4, Add)) at (prev + 0, 23) to (start + 0, 24) + = ((c1 - c2) + (c0 - c1)) +- Branch { true: Counter(3), false: Counter(4) } at (prev + 0, 23) to (start + 0, 24) + true = c3 + false = c4 +- Code(Expression(0, Add)) at (prev + 1, 5) to (start + 1, 2) + = ((c2 + c3) + c4) + +Function name: conditions::assign_3_or_and +Raw bytes (73): 0x[01, 01, 09, 05, 07, 0b, 11, 09, 0d, 01, 05, 01, 05, 22, 11, 01, 05, 22, 11, 01, 05, 09, 01, 17, 01, 00, 2f, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 22, 00, 0d, 00, 0e, 22, 00, 12, 00, 13, 20, 1e, 11, 00, 12, 00, 13, 1e, 00, 17, 00, 18, 20, 09, 0d, 00, 17, 00, 18, 03, 01, 05, 01, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 9 +- expression 0 operands: lhs = Counter(1), rhs = Expression(1, Add) +- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(4) +- expression 2 operands: lhs = Counter(2), rhs = Counter(3) +- expression 3 operands: lhs = Counter(0), rhs = Counter(1) +- expression 4 operands: lhs = Counter(0), rhs = Counter(1) +- expression 5 operands: lhs = Expression(8, Sub), rhs = Counter(4) +- expression 6 operands: lhs = Counter(0), rhs = Counter(1) +- expression 7 operands: lhs = Expression(8, Sub), rhs = Counter(4) +- expression 8 operands: lhs = Counter(0), rhs = Counter(1) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 23, 1) to (start + 0, 47) +- Code(Expression(0, Add)) at (prev + 1, 9) to (start + 0, 10) + = (c1 + ((c2 + c3) + c4)) +- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) +- Branch { true: Counter(1), false: Expression(8, Sub) } at (prev + 0, 13) to (start + 0, 14) + true = c1 + false = (c0 - c1) +- Code(Expression(8, Sub)) at (prev + 0, 18) to (start + 0, 19) + = (c0 - c1) +- Branch { true: Expression(7, Sub), false: Counter(4) } at (prev + 0, 18) to (start + 0, 19) + true = ((c0 - c1) - c4) + false = c4 +- Code(Expression(7, Sub)) at (prev + 0, 23) to (start + 0, 24) + = ((c0 - c1) - c4) +- Branch { true: Counter(2), false: Counter(3) } at (prev + 0, 23) to (start + 0, 24) + true = c2 + false = c3 +- Code(Expression(0, Add)) at (prev + 1, 5) to (start + 1, 2) + = (c1 + ((c2 + c3) + c4)) + +Function name: conditions::assign_and +Raw bytes (51): 0x[01, 01, 04, 07, 0e, 09, 0d, 01, 05, 01, 05, 07, 01, 0d, 01, 00, 21, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 0e, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 20, 09, 0d, 00, 12, 00, 13, 03, 01, 05, 01, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 4 +- expression 0 operands: lhs = Expression(1, Add), rhs = Expression(3, Sub) +- expression 1 operands: lhs = Counter(2), rhs = Counter(3) +- expression 2 operands: lhs = Counter(0), rhs = Counter(1) +- expression 3 operands: lhs = Counter(0), rhs = Counter(1) +Number of file 0 mappings: 7 +- Code(Counter(0)) at (prev + 13, 1) to (start + 0, 33) +- Code(Expression(0, Add)) at (prev + 1, 9) to (start + 0, 10) + = ((c2 + c3) + (c0 - c1)) +- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) +- Branch { true: Counter(1), false: Expression(3, Sub) } at (prev + 0, 13) to (start + 0, 14) + true = c1 + false = (c0 - c1) +- Code(Counter(1)) at (prev + 0, 18) to (start + 0, 19) +- Branch { true: Counter(2), false: Counter(3) } at (prev + 0, 18) to (start + 0, 19) + true = c2 + false = c3 +- Code(Expression(0, Add)) at (prev + 1, 5) to (start + 1, 2) + = ((c2 + c3) + (c0 - c1)) + +Function name: conditions::assign_or +Raw bytes (51): 0x[01, 01, 04, 07, 0d, 05, 09, 01, 05, 01, 05, 07, 01, 12, 01, 00, 20, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 0e, 00, 0d, 00, 0e, 0e, 00, 12, 00, 13, 20, 09, 0d, 00, 12, 00, 13, 03, 01, 05, 01, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 4 +- expression 0 operands: lhs = Expression(1, Add), rhs = Counter(3) +- expression 1 operands: lhs = Counter(1), rhs = Counter(2) +- expression 2 operands: lhs = Counter(0), rhs = Counter(1) +- expression 3 operands: lhs = Counter(0), rhs = Counter(1) +Number of file 0 mappings: 7 +- Code(Counter(0)) at (prev + 18, 1) to (start + 0, 32) +- Code(Expression(0, Add)) at (prev + 1, 9) to (start + 0, 10) + = ((c1 + c2) + c3) +- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) +- Branch { true: Counter(1), false: Expression(3, Sub) } at (prev + 0, 13) to (start + 0, 14) + true = c1 + false = (c0 - c1) +- Code(Expression(3, Sub)) at (prev + 0, 18) to (start + 0, 19) + = (c0 - c1) +- Branch { true: Counter(2), false: Counter(3) } at (prev + 0, 18) to (start + 0, 19) + true = c2 + false = c3 +- Code(Expression(0, Add)) at (prev + 1, 5) to (start + 1, 2) + = ((c1 + c2) + c3) + +Function name: conditions::foo +Raw bytes (9): 0x[01, 01, 00, 01, 01, 21, 01, 02, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 33, 1) to (start + 2, 2) + +Function name: conditions::func_call +Raw bytes (39): 0x[01, 01, 03, 01, 05, 0b, 02, 09, 0d, 05, 01, 25, 01, 01, 0a, 20, 05, 02, 01, 09, 00, 0a, 05, 00, 0e, 00, 0f, 20, 09, 0d, 00, 0e, 00, 0f, 07, 01, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 3 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Expression(2, Add), rhs = Expression(0, Sub) +- expression 2 operands: lhs = Counter(2), rhs = Counter(3) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 37, 1) to (start + 1, 10) +- Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 1, 9) to (start + 0, 10) + true = c1 + false = (c0 - c1) +- Code(Counter(1)) at (prev + 0, 14) to (start + 0, 15) +- Branch { true: Counter(2), false: Counter(3) } at (prev + 0, 14) to (start + 0, 15) + true = c2 + false = c3 +- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2) + = ((c2 + c3) + (c0 - c1)) + +Function name: conditions::simple_assign +Raw bytes (9): 0x[01, 01, 00, 01, 01, 08, 01, 03, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 8, 1) to (start + 3, 2) + diff --git a/tests/coverage/condition/conditions.coverage b/tests/coverage/condition/conditions.coverage new file mode 100644 index 000000000000..3215b391d622 --- /dev/null +++ b/tests/coverage/condition/conditions.coverage @@ -0,0 +1,95 @@ + LL| |#![feature(coverage_attribute)] + LL| |//@ edition: 2021 + LL| |//@ compile-flags: -Zcoverage-options=condition + LL| |//@ llvm-cov-flags: --show-branches=count + LL| | + LL| |use core::hint::black_box; + LL| | + LL| 2|fn simple_assign(a: bool) { + LL| 2| let x = a; + LL| 2| black_box(x); + LL| 2|} + LL| | + LL| 3|fn assign_and(a: bool, b: bool) { + LL| 3| let x = a && b; + ^2 + ------------------ + | Branch (LL:13): [True: 2, False: 1] + | Branch (LL:18): [True: 1, False: 1] + ------------------ + LL| 3| black_box(x); + LL| 3|} + LL| | + LL| 3|fn assign_or(a: bool, b: bool) { + LL| 3| let x = a || b; + ^1 + ------------------ + | Branch (LL:13): [True: 2, False: 1] + | Branch (LL:18): [True: 0, False: 1] + ------------------ + LL| 3| black_box(x); + LL| 3|} + LL| | + LL| 4|fn assign_3_or_and(a: bool, b: bool, c: bool) { + LL| 4| let x = a || b && c; + ^2 ^1 + ------------------ + | Branch (LL:13): [True: 2, False: 2] + | Branch (LL:18): [True: 1, False: 1] + | Branch (LL:23): [True: 1, False: 0] + ------------------ + LL| 4| black_box(x); + LL| 4|} + LL| | + LL| 4|fn assign_3_and_or(a: bool, b: bool, c: bool) { + LL| 4| let x = a && b || c; + ^2 ^3 + ------------------ + | Branch (LL:13): [True: 2, False: 2] + | Branch (LL:18): [True: 1, False: 1] + | Branch (LL:23): [True: 2, False: 1] + ------------------ + LL| 4| black_box(x); + LL| 4|} + LL| | + LL| 3|fn foo(a: bool) -> bool { + LL| 3| black_box(a) + LL| 3|} + LL| | + LL| 3|fn func_call(a: bool, b: bool) { + LL| 3| foo(a && b); + ^2 + ------------------ + | Branch (LL:9): [True: 2, False: 1] + | Branch (LL:14): [True: 1, False: 1] + ------------------ + LL| 3|} + LL| | + LL| |#[coverage(off)] + LL| |fn main() { + LL| | simple_assign(true); + LL| | simple_assign(false); + LL| | + LL| | assign_and(true, false); + LL| | assign_and(true, true); + LL| | assign_and(false, false); + LL| | + LL| | assign_or(true, false); + LL| | assign_or(true, true); + LL| | assign_or(false, false); + LL| | + LL| | assign_3_or_and(true, false, false); + LL| | assign_3_or_and(true, true, false); + LL| | assign_3_or_and(false, false, true); + LL| | assign_3_or_and(false, true, true); + LL| | + LL| | assign_3_and_or(true, false, false); + LL| | assign_3_and_or(true, true, false); + LL| | assign_3_and_or(false, false, true); + LL| | assign_3_and_or(false, true, true); + LL| | + LL| | func_call(true, false); + LL| | func_call(true, true); + LL| | func_call(false, false); + LL| |} + diff --git a/tests/coverage/condition/conditions.rs b/tests/coverage/condition/conditions.rs new file mode 100644 index 000000000000..3d658dc93e0c --- /dev/null +++ b/tests/coverage/condition/conditions.rs @@ -0,0 +1,67 @@ +#![feature(coverage_attribute)] +//@ edition: 2021 +//@ compile-flags: -Zcoverage-options=condition +//@ llvm-cov-flags: --show-branches=count + +use core::hint::black_box; + +fn simple_assign(a: bool) { + let x = a; + black_box(x); +} + +fn assign_and(a: bool, b: bool) { + let x = a && b; + black_box(x); +} + +fn assign_or(a: bool, b: bool) { + let x = a || b; + black_box(x); +} + +fn assign_3_or_and(a: bool, b: bool, c: bool) { + let x = a || b && c; + black_box(x); +} + +fn assign_3_and_or(a: bool, b: bool, c: bool) { + let x = a && b || c; + black_box(x); +} + +fn foo(a: bool) -> bool { + black_box(a) +} + +fn func_call(a: bool, b: bool) { + foo(a && b); +} + +#[coverage(off)] +fn main() { + simple_assign(true); + simple_assign(false); + + assign_and(true, false); + assign_and(true, true); + assign_and(false, false); + + assign_or(true, false); + assign_or(true, true); + assign_or(false, false); + + assign_3_or_and(true, false, false); + assign_3_or_and(true, true, false); + assign_3_or_and(false, false, true); + assign_3_or_and(false, true, true); + + assign_3_and_or(true, false, false); + assign_3_and_or(true, true, false); + assign_3_and_or(false, false, true); + assign_3_and_or(false, true, true); + + func_call(true, false); + func_call(true, true); + func_call(false, false); +} diff --git a/tests/coverage/coroutine.cov-map b/tests/coverage/coroutine.cov-map index 6ead788b82f9..6ff5ed74a96d 100644 --- a/tests/coverage/coroutine.cov-map +++ b/tests/coverage/coroutine.cov-map @@ -12,7 +12,7 @@ Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2) Function name: coroutine::main -Raw bytes (65): 0x[01, 01, 08, 07, 0d, 05, 09, 11, 15, 1e, 19, 11, 15, 15, 19, 1e, 19, 11, 15, 09, 01, 13, 01, 02, 16, 01, 07, 0b, 00, 2e, 11, 01, 2b, 00, 2d, 03, 01, 0e, 00, 35, 11, 02, 0b, 00, 2e, 1e, 01, 22, 00, 27, 1a, 00, 2c, 00, 2e, 17, 01, 0e, 00, 35, 1a, 02, 01, 00, 02] +Raw bytes (65): 0x[01, 01, 08, 07, 0d, 05, 09, 11, 15, 1e, 19, 11, 15, 15, 19, 1e, 19, 11, 15, 09, 01, 13, 01, 02, 16, 01, 08, 0b, 00, 2e, 11, 01, 2b, 00, 2d, 03, 01, 0e, 00, 35, 11, 02, 0b, 00, 2e, 1e, 01, 22, 00, 27, 1a, 00, 2c, 00, 2e, 17, 01, 0e, 00, 35, 1a, 02, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 8 @@ -26,7 +26,7 @@ Number of expressions: 8 - expression 7 operands: lhs = Counter(4), rhs = Counter(5) Number of file 0 mappings: 9 - Code(Counter(0)) at (prev + 19, 1) to (start + 2, 22) -- Code(Counter(0)) at (prev + 7, 11) to (start + 0, 46) +- Code(Counter(0)) at (prev + 8, 11) to (start + 0, 46) - Code(Counter(4)) at (prev + 1, 43) to (start + 0, 45) - Code(Expression(0, Add)) at (prev + 1, 14) to (start + 0, 53) = ((c1 + c2) + c3) @@ -41,11 +41,11 @@ Number of file 0 mappings: 9 = ((c4 - c5) - c6) Function name: coroutine::main::{closure#0} -Raw bytes (14): 0x[01, 01, 00, 02, 01, 15, 29, 01, 1f, 05, 02, 10, 01, 06] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 16, 08, 01, 1f, 05, 02, 10, 01, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 21, 41) to (start + 1, 31) +- Code(Counter(0)) at (prev + 22, 8) to (start + 1, 31) - Code(Counter(1)) at (prev + 2, 16) to (start + 1, 6) diff --git a/tests/coverage/coroutine.coverage b/tests/coverage/coroutine.coverage index 68b52d198316..611470c57738 100644 --- a/tests/coverage/coroutine.coverage +++ b/tests/coverage/coroutine.coverage @@ -10,15 +10,16 @@ LL| |// to handle this condition, and still report dead block coverage. LL| 1|fn get_u32(val: bool) -> Result { LL| 1| if val { - LL| 1| Ok(1) + LL| 1| Ok(1) // LL| | } else { - LL| 0| Err(String::from("some error")) + LL| 0| Err(String::from("some error")) // LL| | } LL| 1|} LL| | LL| 1|fn main() { LL| 1| let is_true = std::env::args().len() == 1; - LL| 1| let mut coroutine = #[coroutine] || { + LL| 1| let mut coroutine = #[coroutine] + LL| 1| || { LL| 1| yield get_u32(is_true); LL| 1| return "foo"; LL| 1| }; diff --git a/tests/coverage/coroutine.rs b/tests/coverage/coroutine.rs index 7f72e0d8bd42..bd149764b373 100644 --- a/tests/coverage/coroutine.rs +++ b/tests/coverage/coroutine.rs @@ -10,15 +10,16 @@ use std::pin::Pin; // to handle this condition, and still report dead block coverage. fn get_u32(val: bool) -> Result { if val { - Ok(1) + Ok(1) // } else { - Err(String::from("some error")) + Err(String::from("some error")) // } } fn main() { let is_true = std::env::args().len() == 1; - let mut coroutine = #[coroutine] || { + let mut coroutine = #[coroutine] + || { yield get_u32(is_true); return "foo"; }; diff --git a/tests/coverage/inline-dead.coverage b/tests/coverage/inline-dead.coverage index a2d24fd2f6a6..c12668ce89a2 100644 --- a/tests/coverage/inline-dead.coverage +++ b/tests/coverage/inline-dead.coverage @@ -14,7 +14,7 @@ LL| |#[inline] LL| 1|fn live() -> u32 { LL| 1| if B { - LL| 0| dead() + LL| 0| dead() // LL| | } else { LL| 1| 0 LL| | } diff --git a/tests/coverage/inline-dead.rs b/tests/coverage/inline-dead.rs index 327e68c60bb7..4eb397a43fc1 100644 --- a/tests/coverage/inline-dead.rs +++ b/tests/coverage/inline-dead.rs @@ -13,7 +13,7 @@ fn main() { #[inline] fn live() -> u32 { if B { - dead() + dead() // } else { 0 } diff --git a/tests/coverage/inner_items.coverage b/tests/coverage/inner_items.coverage index 65493bcd9db4..152f3da1a221 100644 --- a/tests/coverage/inner_items.coverage +++ b/tests/coverage/inner_items.coverage @@ -52,7 +52,7 @@ ^0 LL| | LL| 1| let mut val = InStruct { - LL| 1| in_struct_field: 101, + LL| 1| in_struct_field: 101, // LL| 1| }; LL| 1| LL| 1| val.default_trait_func(); diff --git a/tests/coverage/inner_items.rs b/tests/coverage/inner_items.rs index bcb62b3031cd..4d513e612f06 100644 --- a/tests/coverage/inner_items.rs +++ b/tests/coverage/inner_items.rs @@ -50,7 +50,7 @@ fn main() { } let mut val = InStruct { - in_struct_field: 101, + in_struct_field: 101, // }; val.default_trait_func(); diff --git a/tests/coverage/let_else_loop.cov-map b/tests/coverage/let_else_loop.cov-map index b0cee3005220..13d0d08adb11 100644 --- a/tests/coverage/let_else_loop.cov-map +++ b/tests/coverage/let_else_loop.cov-map @@ -1,12 +1,12 @@ Function name: let_else_loop::_if (unused) -Raw bytes (19): 0x[01, 01, 00, 03, 00, 16, 01, 01, 0c, 00, 02, 09, 00, 10, 00, 02, 09, 00, 10] +Raw bytes (19): 0x[01, 01, 00, 03, 00, 16, 01, 01, 0c, 00, 01, 0f, 00, 16, 00, 00, 20, 00, 27] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 3 - Code(Zero) at (prev + 22, 1) to (start + 1, 12) -- Code(Zero) at (prev + 2, 9) to (start + 0, 16) -- Code(Zero) at (prev + 2, 9) to (start + 0, 16) +- Code(Zero) at (prev + 1, 15) to (start + 0, 22) +- Code(Zero) at (prev + 0, 32) to (start + 0, 39) Function name: let_else_loop::_loop_either_way (unused) Raw bytes (19): 0x[01, 01, 00, 03, 00, 0f, 01, 01, 14, 00, 01, 1c, 00, 23, 00, 01, 05, 00, 0c] diff --git a/tests/coverage/let_else_loop.coverage b/tests/coverage/let_else_loop.coverage index d193c8ca1b51..bd13f6e56501 100644 --- a/tests/coverage/let_else_loop.coverage +++ b/tests/coverage/let_else_loop.coverage @@ -21,11 +21,7 @@ LL| |// Variant using regular `if` instead of let-else. LL| |// This doesn't trigger the original ICE, but might help detect regressions. LL| 0|fn _if(cond: bool) { - LL| 0| if cond { - LL| 0| loop {} - LL| | } else { - LL| 0| loop {} - LL| | } + LL| 0| if cond { loop {} } else { loop {} } LL| |} LL| | LL| |#[coverage(off)] diff --git a/tests/coverage/let_else_loop.rs b/tests/coverage/let_else_loop.rs index 12e0aeabcab9..8217c0d072a6 100644 --- a/tests/coverage/let_else_loop.rs +++ b/tests/coverage/let_else_loop.rs @@ -20,11 +20,7 @@ fn _loop_either_way(cond: bool) { // Variant using regular `if` instead of let-else. // This doesn't trigger the original ICE, but might help detect regressions. fn _if(cond: bool) { - if cond { - loop {} - } else { - loop {} - } + if cond { loop {} } else { loop {} } } #[coverage(off)] diff --git a/tests/coverage/mcdc/condition-limit.cov-map b/tests/coverage/mcdc/condition-limit.cov-map new file mode 100644 index 000000000000..b4447a33691a --- /dev/null +++ b/tests/coverage/mcdc/condition-limit.cov-map @@ -0,0 +1,162 @@ +Function name: condition_limit::bad +Raw bytes (204): 0x[01, 01, 2c, 01, 05, 05, 1d, 05, 1d, 7a, 19, 05, 1d, 7a, 19, 05, 1d, 76, 15, 7a, 19, 05, 1d, 76, 15, 7a, 19, 05, 1d, 72, 11, 76, 15, 7a, 19, 05, 1d, 72, 11, 76, 15, 7a, 19, 05, 1d, 6e, 0d, 72, 11, 76, 15, 7a, 19, 05, 1d, 6e, 0d, 72, 11, 76, 15, 7a, 19, 05, 1d, 9f, 01, 02, a3, 01, 1d, a7, 01, 19, ab, 01, 15, af, 01, 11, 09, 0d, 21, 9b, 01, 9f, 01, 02, a3, 01, 1d, a7, 01, 19, ab, 01, 15, af, 01, 11, 09, 0d, 11, 01, 14, 01, 03, 09, 20, 05, 02, 03, 08, 00, 09, 05, 00, 0d, 00, 0e, 20, 7a, 1d, 00, 0d, 00, 0e, 7a, 00, 12, 00, 13, 20, 76, 19, 00, 12, 00, 13, 76, 00, 17, 00, 18, 20, 72, 15, 00, 17, 00, 18, 72, 00, 1c, 00, 1d, 20, 6e, 11, 00, 1c, 00, 1d, 6e, 00, 21, 00, 22, 20, 6a, 0d, 00, 21, 00, 22, 6a, 00, 26, 00, 27, 20, 21, 09, 00, 26, 00, 27, 21, 00, 28, 02, 06, 9b, 01, 02, 06, 00, 07, 97, 01, 01, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 44 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Counter(7) +- expression 2 operands: lhs = Counter(1), rhs = Counter(7) +- expression 3 operands: lhs = Expression(30, Sub), rhs = Counter(6) +- expression 4 operands: lhs = Counter(1), rhs = Counter(7) +- expression 5 operands: lhs = Expression(30, Sub), rhs = Counter(6) +- expression 6 operands: lhs = Counter(1), rhs = Counter(7) +- expression 7 operands: lhs = Expression(29, Sub), rhs = Counter(5) +- expression 8 operands: lhs = Expression(30, Sub), rhs = Counter(6) +- expression 9 operands: lhs = Counter(1), rhs = Counter(7) +- expression 10 operands: lhs = Expression(29, Sub), rhs = Counter(5) +- expression 11 operands: lhs = Expression(30, Sub), rhs = Counter(6) +- expression 12 operands: lhs = Counter(1), rhs = Counter(7) +- expression 13 operands: lhs = Expression(28, Sub), rhs = Counter(4) +- expression 14 operands: lhs = Expression(29, Sub), rhs = Counter(5) +- expression 15 operands: lhs = Expression(30, Sub), rhs = Counter(6) +- expression 16 operands: lhs = Counter(1), rhs = Counter(7) +- expression 17 operands: lhs = Expression(28, Sub), rhs = Counter(4) +- expression 18 operands: lhs = Expression(29, Sub), rhs = Counter(5) +- expression 19 operands: lhs = Expression(30, Sub), rhs = Counter(6) +- expression 20 operands: lhs = Counter(1), rhs = Counter(7) +- expression 21 operands: lhs = Expression(27, Sub), rhs = Counter(3) +- expression 22 operands: lhs = Expression(28, Sub), rhs = Counter(4) +- expression 23 operands: lhs = Expression(29, Sub), rhs = Counter(5) +- expression 24 operands: lhs = Expression(30, Sub), rhs = Counter(6) +- expression 25 operands: lhs = Counter(1), rhs = Counter(7) +- expression 26 operands: lhs = Expression(27, Sub), rhs = Counter(3) +- expression 27 operands: lhs = Expression(28, Sub), rhs = Counter(4) +- expression 28 operands: lhs = Expression(29, Sub), rhs = Counter(5) +- expression 29 operands: lhs = Expression(30, Sub), rhs = Counter(6) +- expression 30 operands: lhs = Counter(1), rhs = Counter(7) +- expression 31 operands: lhs = Expression(39, Add), rhs = Expression(0, Sub) +- expression 32 operands: lhs = Expression(40, Add), rhs = Counter(7) +- expression 33 operands: lhs = Expression(41, Add), rhs = Counter(6) +- expression 34 operands: lhs = Expression(42, Add), rhs = Counter(5) +- expression 35 operands: lhs = Expression(43, Add), rhs = Counter(4) +- expression 36 operands: lhs = Counter(2), rhs = Counter(3) +- expression 37 operands: lhs = Counter(8), rhs = Expression(38, Add) +- expression 38 operands: lhs = Expression(39, Add), rhs = Expression(0, Sub) +- expression 39 operands: lhs = Expression(40, Add), rhs = Counter(7) +- expression 40 operands: lhs = Expression(41, Add), rhs = Counter(6) +- expression 41 operands: lhs = Expression(42, Add), rhs = Counter(5) +- expression 42 operands: lhs = Expression(43, Add), rhs = Counter(4) +- expression 43 operands: lhs = Counter(2), rhs = Counter(3) +Number of file 0 mappings: 17 +- Code(Counter(0)) at (prev + 20, 1) to (start + 3, 9) +- Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 3, 8) to (start + 0, 9) + true = c1 + false = (c0 - c1) +- Code(Counter(1)) at (prev + 0, 13) to (start + 0, 14) +- Branch { true: Expression(30, Sub), false: Counter(7) } at (prev + 0, 13) to (start + 0, 14) + true = (c1 - c7) + false = c7 +- Code(Expression(30, Sub)) at (prev + 0, 18) to (start + 0, 19) + = (c1 - c7) +- Branch { true: Expression(29, Sub), false: Counter(6) } at (prev + 0, 18) to (start + 0, 19) + true = ((c1 - c7) - c6) + false = c6 +- Code(Expression(29, Sub)) at (prev + 0, 23) to (start + 0, 24) + = ((c1 - c7) - c6) +- Branch { true: Expression(28, Sub), false: Counter(5) } at (prev + 0, 23) to (start + 0, 24) + true = (((c1 - c7) - c6) - c5) + false = c5 +- Code(Expression(28, Sub)) at (prev + 0, 28) to (start + 0, 29) + = (((c1 - c7) - c6) - c5) +- Branch { true: Expression(27, Sub), false: Counter(4) } at (prev + 0, 28) to (start + 0, 29) + true = ((((c1 - c7) - c6) - c5) - c4) + false = c4 +- Code(Expression(27, Sub)) at (prev + 0, 33) to (start + 0, 34) + = ((((c1 - c7) - c6) - c5) - c4) +- Branch { true: Expression(26, Sub), false: Counter(3) } at (prev + 0, 33) to (start + 0, 34) + true = (((((c1 - c7) - c6) - c5) - c4) - c3) + false = c3 +- Code(Expression(26, Sub)) at (prev + 0, 38) to (start + 0, 39) + = (((((c1 - c7) - c6) - c5) - c4) - c3) +- Branch { true: Counter(8), false: Counter(2) } at (prev + 0, 38) to (start + 0, 39) + true = c8 + false = c2 +- Code(Counter(8)) at (prev + 0, 40) to (start + 2, 6) +- Code(Expression(38, Add)) at (prev + 2, 6) to (start + 0, 7) + = ((((((c2 + c3) + c4) + c5) + c6) + c7) + (c0 - c1)) +- Code(Expression(37, Add)) at (prev + 1, 1) to (start + 0, 2) + = (c8 + ((((((c2 + c3) + c4) + c5) + c6) + c7) + (c0 - c1))) + +Function name: condition_limit::good +Raw bytes (180): 0x[01, 01, 20, 01, 05, 05, 19, 05, 19, 52, 15, 05, 19, 52, 15, 05, 19, 4e, 11, 52, 15, 05, 19, 4e, 11, 52, 15, 05, 19, 4a, 0d, 4e, 11, 52, 15, 05, 19, 4a, 0d, 4e, 11, 52, 15, 05, 19, 73, 02, 77, 19, 7b, 15, 7f, 11, 09, 0d, 1d, 6f, 73, 02, 77, 19, 7b, 15, 7f, 11, 09, 0d, 10, 01, 0c, 01, 03, 09, 28, 00, 06, 03, 08, 00, 22, 30, 05, 02, 01, 06, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 52, 19, 06, 05, 00, 00, 0d, 00, 0e, 52, 00, 12, 00, 13, 30, 4e, 15, 05, 04, 00, 00, 12, 00, 13, 4e, 00, 17, 00, 18, 30, 4a, 11, 04, 03, 00, 00, 17, 00, 18, 4a, 00, 1c, 00, 1d, 30, 46, 0d, 03, 02, 00, 00, 1c, 00, 1d, 46, 00, 21, 00, 22, 30, 1d, 09, 02, 00, 00, 00, 21, 00, 22, 1d, 00, 23, 02, 06, 6f, 02, 06, 00, 07, 6b, 01, 01, 00, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 32 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Counter(6) +- expression 2 operands: lhs = Counter(1), rhs = Counter(6) +- expression 3 operands: lhs = Expression(20, Sub), rhs = Counter(5) +- expression 4 operands: lhs = Counter(1), rhs = Counter(6) +- expression 5 operands: lhs = Expression(20, Sub), rhs = Counter(5) +- expression 6 operands: lhs = Counter(1), rhs = Counter(6) +- expression 7 operands: lhs = Expression(19, Sub), rhs = Counter(4) +- expression 8 operands: lhs = Expression(20, Sub), rhs = Counter(5) +- expression 9 operands: lhs = Counter(1), rhs = Counter(6) +- expression 10 operands: lhs = Expression(19, Sub), rhs = Counter(4) +- expression 11 operands: lhs = Expression(20, Sub), rhs = Counter(5) +- expression 12 operands: lhs = Counter(1), rhs = Counter(6) +- expression 13 operands: lhs = Expression(18, Sub), rhs = Counter(3) +- expression 14 operands: lhs = Expression(19, Sub), rhs = Counter(4) +- expression 15 operands: lhs = Expression(20, Sub), rhs = Counter(5) +- expression 16 operands: lhs = Counter(1), rhs = Counter(6) +- expression 17 operands: lhs = Expression(18, Sub), rhs = Counter(3) +- expression 18 operands: lhs = Expression(19, Sub), rhs = Counter(4) +- expression 19 operands: lhs = Expression(20, Sub), rhs = Counter(5) +- expression 20 operands: lhs = Counter(1), rhs = Counter(6) +- expression 21 operands: lhs = Expression(28, Add), rhs = Expression(0, Sub) +- expression 22 operands: lhs = Expression(29, Add), rhs = Counter(6) +- expression 23 operands: lhs = Expression(30, Add), rhs = Counter(5) +- expression 24 operands: lhs = Expression(31, Add), rhs = Counter(4) +- expression 25 operands: lhs = Counter(2), rhs = Counter(3) +- expression 26 operands: lhs = Counter(7), rhs = Expression(27, Add) +- expression 27 operands: lhs = Expression(28, Add), rhs = Expression(0, Sub) +- expression 28 operands: lhs = Expression(29, Add), rhs = Counter(6) +- expression 29 operands: lhs = Expression(30, Add), rhs = Counter(5) +- expression 30 operands: lhs = Expression(31, Add), rhs = Counter(4) +- expression 31 operands: lhs = Counter(2), rhs = Counter(3) +Number of file 0 mappings: 16 +- Code(Counter(0)) at (prev + 12, 1) to (start + 3, 9) +- MCDCDecision { bitmap_idx: 0, conditions_num: 6 } at (prev + 3, 8) to (start + 0, 34) +- MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 6, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9) + true = c1 + false = (c0 - c1) +- Code(Counter(1)) at (prev + 0, 13) to (start + 0, 14) +- MCDCBranch { true: Expression(20, Sub), false: Counter(6), condition_id: 6, true_next_id: 5, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14) + true = (c1 - c6) + false = c6 +- Code(Expression(20, Sub)) at (prev + 0, 18) to (start + 0, 19) + = (c1 - c6) +- MCDCBranch { true: Expression(19, Sub), false: Counter(5), condition_id: 5, true_next_id: 4, false_next_id: 0 } at (prev + 0, 18) to (start + 0, 19) + true = ((c1 - c6) - c5) + false = c5 +- Code(Expression(19, Sub)) at (prev + 0, 23) to (start + 0, 24) + = ((c1 - c6) - c5) +- MCDCBranch { true: Expression(18, Sub), false: Counter(4), condition_id: 4, true_next_id: 3, false_next_id: 0 } at (prev + 0, 23) to (start + 0, 24) + true = (((c1 - c6) - c5) - c4) + false = c4 +- Code(Expression(18, Sub)) at (prev + 0, 28) to (start + 0, 29) + = (((c1 - c6) - c5) - c4) +- MCDCBranch { true: Expression(17, Sub), false: Counter(3), condition_id: 3, true_next_id: 2, false_next_id: 0 } at (prev + 0, 28) to (start + 0, 29) + true = ((((c1 - c6) - c5) - c4) - c3) + false = c3 +- Code(Expression(17, Sub)) at (prev + 0, 33) to (start + 0, 34) + = ((((c1 - c6) - c5) - c4) - c3) +- MCDCBranch { true: Counter(7), false: Counter(2), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 33) to (start + 0, 34) + true = c7 + false = c2 +- Code(Counter(7)) at (prev + 0, 35) to (start + 2, 6) +- Code(Expression(27, Add)) at (prev + 2, 6) to (start + 0, 7) + = (((((c2 + c3) + c4) + c5) + c6) + (c0 - c1)) +- Code(Expression(26, Add)) at (prev + 1, 1) to (start + 0, 2) + = (c7 + (((((c2 + c3) + c4) + c5) + c6) + (c0 - c1))) + diff --git a/tests/coverage/mcdc/condition-limit.coverage b/tests/coverage/mcdc/condition-limit.coverage new file mode 100644 index 000000000000..4eb87432fab4 --- /dev/null +++ b/tests/coverage/mcdc/condition-limit.coverage @@ -0,0 +1,76 @@ + LL| |#![feature(coverage_attribute)] + LL| |//@ edition: 2021 + LL| |//@ min-llvm-version: 18 + LL| |//@ compile-flags: -Zcoverage-options=mcdc + LL| |//@ llvm-cov-flags: --show-branches=count --show-mcdc + LL| | + LL| |// Check that MC/DC instrumentation can gracefully handle conditions that + LL| |// exceed LLVM's limit of 6 conditions per decision. + LL| |// + LL| |// (The limit is enforced in `compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs`.) + LL| | + LL| 1|fn good() { + LL| 1| // With only 6 conditions, perform full MC/DC instrumentation. + LL| 1| let [a, b, c, d, e, f] = <[bool; 6]>::default(); + LL| 1| if a && b && c && d && e && f { + ^0 ^0 ^0 ^0 ^0 + ------------------ + | Branch (LL:8): [True: 0, False: 1] + | Branch (LL:13): [True: 0, False: 0] + | Branch (LL:18): [True: 0, False: 0] + | Branch (LL:23): [True: 0, False: 0] + | Branch (LL:28): [True: 0, False: 0] + | Branch (LL:33): [True: 0, False: 0] + ------------------ + |---> MC/DC Decision Region (LL:8) to (LL:34) + | + | Number of Conditions: 6 + | Condition C1 --> (LL:8) + | Condition C2 --> (LL:13) + | Condition C3 --> (LL:18) + | Condition C4 --> (LL:23) + | Condition C5 --> (LL:28) + | Condition C6 --> (LL:33) + | + | Executed MC/DC Test Vectors: + | + | C1, C2, C3, C4, C5, C6 Result + | 1 { F, -, -, -, -, - = F } + | + | C1-Pair: not covered + | C2-Pair: not covered + | C3-Pair: not covered + | C4-Pair: not covered + | C5-Pair: not covered + | C6-Pair: not covered + | MC/DC Coverage for Decision: 0.00% + | + ------------------ + LL| 0| core::hint::black_box("hello"); + LL| 1| } + LL| 1|} + LL| | + LL| 1|fn bad() { + LL| 1| // With 7 conditions, fall back to branch instrumentation only. + LL| 1| let [a, b, c, d, e, f, g] = <[bool; 7]>::default(); + LL| 1| if a && b && c && d && e && f && g { + ^0 ^0 ^0 ^0 ^0 ^0 + ------------------ + | Branch (LL:8): [True: 0, False: 1] + | Branch (LL:13): [True: 0, False: 0] + | Branch (LL:18): [True: 0, False: 0] + | Branch (LL:23): [True: 0, False: 0] + | Branch (LL:28): [True: 0, False: 0] + | Branch (LL:33): [True: 0, False: 0] + | Branch (LL:38): [True: 0, False: 0] + ------------------ + LL| 0| core::hint::black_box("hello"); + LL| 1| } + LL| 1|} + LL| | + LL| |#[coverage(off)] + LL| |fn main() { + LL| | good(); + LL| | bad(); + LL| |} + diff --git a/tests/coverage/mcdc/condition-limit.rs b/tests/coverage/mcdc/condition-limit.rs new file mode 100644 index 000000000000..571c600ebd09 --- /dev/null +++ b/tests/coverage/mcdc/condition-limit.rs @@ -0,0 +1,32 @@ +#![feature(coverage_attribute)] +//@ edition: 2021 +//@ min-llvm-version: 18 +//@ compile-flags: -Zcoverage-options=mcdc +//@ llvm-cov-flags: --show-branches=count --show-mcdc + +// Check that MC/DC instrumentation can gracefully handle conditions that +// exceed LLVM's limit of 6 conditions per decision. +// +// (The limit is enforced in `compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs`.) + +fn good() { + // With only 6 conditions, perform full MC/DC instrumentation. + let [a, b, c, d, e, f] = <[bool; 6]>::default(); + if a && b && c && d && e && f { + core::hint::black_box("hello"); + } +} + +fn bad() { + // With 7 conditions, fall back to branch instrumentation only. + let [a, b, c, d, e, f, g] = <[bool; 7]>::default(); + if a && b && c && d && e && f && g { + core::hint::black_box("hello"); + } +} + +#[coverage(off)] +fn main() { + good(); + bad(); +} diff --git a/tests/coverage/partial_eq.cov-map b/tests/coverage/partial_eq.cov-map index 80670fbfa5a7..6c39ac0e378b 100644 --- a/tests/coverage/partial_eq.cov-map +++ b/tests/coverage/partial_eq.cov-map @@ -1,16 +1,16 @@ Function name: ::new -Raw bytes (9): 0x[01, 01, 00, 01, 01, 0c, 05, 06, 06] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 0c, 05, 02, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 12, 5) to (start + 6, 6) +- Code(Counter(0)) at (prev + 12, 5) to (start + 2, 6) Function name: partial_eq::main -Raw bytes (9): 0x[01, 01, 00, 01, 01, 15, 01, 0a, 02] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 11, 01, 0a, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 21, 1) to (start + 10, 2) +- Code(Counter(0)) at (prev + 17, 1) to (start + 10, 2) diff --git a/tests/coverage/partial_eq.coverage b/tests/coverage/partial_eq.coverage index 9de1c933570c..dc5b82b3c5f1 100644 --- a/tests/coverage/partial_eq.coverage +++ b/tests/coverage/partial_eq.coverage @@ -10,11 +10,7 @@ LL| | LL| |impl Version { LL| 2| pub fn new(major: usize, minor: usize, patch: usize) -> Self { - LL| 2| Self { - LL| 2| major, - LL| 2| minor, - LL| 2| patch, - LL| 2| } + LL| 2| Self { major, minor, patch } LL| 2| } LL| |} LL| | @@ -26,7 +22,7 @@ LL| 1| "{:?} < {:?} = {}", LL| 1| version_3_2_1, LL| 1| version_3_3_0, - LL| 1| version_3_2_1 < version_3_3_0 + LL| 1| version_3_2_1 < version_3_3_0, // LL| 1| ); LL| 1|} LL| | diff --git a/tests/coverage/partial_eq.rs b/tests/coverage/partial_eq.rs index 825e266f111f..081502d4a9d6 100644 --- a/tests/coverage/partial_eq.rs +++ b/tests/coverage/partial_eq.rs @@ -10,11 +10,7 @@ pub struct Version { impl Version { pub fn new(major: usize, minor: usize, patch: usize) -> Self { - Self { - major, - minor, - patch, - } + Self { major, minor, patch } } } @@ -26,7 +22,7 @@ fn main() { "{:?} < {:?} = {}", version_3_2_1, version_3_3_0, - version_3_2_1 < version_3_3_0 + version_3_2_1 < version_3_3_0, // ); } diff --git a/tests/coverage/try_error_result.cov-map b/tests/coverage/try_error_result.cov-map index 49e6c7ceefca..9c18827d8e68 100644 --- a/tests/coverage/try_error_result.cov-map +++ b/tests/coverage/try_error_result.cov-map @@ -25,26 +25,26 @@ Number of file 0 mappings: 4 - Code(Counter(0)) at (prev + 2, 5) to (start + 0, 6) Function name: try_error_result::call -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 04, 01, 01, 14, 05, 02, 09, 00, 10, 02, 02, 09, 00, 0f, 01, 02, 01, 00, 02] +Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 05, 01, 01, 14, 05, 02, 09, 00, 10, 02, 02, 09, 00, 0f, 01, 02, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 4, 1) to (start + 1, 20) +- Code(Counter(0)) at (prev + 5, 1) to (start + 1, 20) - Code(Counter(1)) at (prev + 2, 9) to (start + 0, 16) - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 15) = (c0 - c1) - Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2) Function name: try_error_result::main -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 73, 01, 02, 0c, 05, 03, 05, 00, 06, 02, 02, 05, 00, 0b, 01, 01, 01, 00, 02] +Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 71, 01, 02, 0c, 05, 03, 05, 00, 06, 02, 02, 05, 00, 0b, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 115, 1) to (start + 2, 12) +- Code(Counter(0)) at (prev + 113, 1) to (start + 2, 12) - Code(Counter(1)) at (prev + 3, 5) to (start + 0, 6) - Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 11) = (c0 - c1) @@ -81,7 +81,7 @@ Number of file 0 mappings: 11 = (((c4 + Zero) + Zero) + c3) Function name: try_error_result::test2 -Raw bytes (280): 0x[01, 01, 24, 01, 07, 00, 09, 03, 0d, 41, 00, 1e, 00, 41, 00, 1e, 00, 41, 00, 4a, 00, 4e, 00, 52, 41, 03, 0d, 52, 41, 03, 0d, 4e, 00, 52, 41, 03, 0d, 4a, 00, 4e, 00, 52, 41, 03, 0d, 66, 00, 45, 00, 45, 00, 66, 00, 45, 00, 7a, 00, 4d, 00, 4d, 00, 7a, 00, 4d, 00, 83, 01, 0d, 87, 01, 00, 00, 8b, 01, 8f, 01, 00, 19, 00, 28, 01, 3e, 01, 03, 17, 03, 08, 09, 00, 0e, 52, 02, 09, 04, 1a, 41, 06, 0d, 00, 2f, 00, 00, 2f, 00, 30, 1e, 00, 31, 03, 35, 00, 04, 11, 00, 12, 1a, 02, 11, 04, 12, 00, 05, 11, 00, 14, 1a, 00, 17, 00, 41, 19, 00, 41, 00, 42, 00, 00, 43, 00, 5f, 00, 00, 5f, 00, 60, 00, 01, 0d, 00, 20, 00, 01, 11, 00, 14, 00, 00, 17, 00, 41, 00, 00, 41, 00, 42, 00, 00, 43, 00, 60, 00, 00, 60, 00, 61, 00, 01, 0d, 00, 20, 46, 04, 11, 00, 14, 4e, 00, 17, 00, 42, 00, 00, 42, 00, 43, 4a, 00, 44, 00, 61, 00, 00, 61, 00, 62, 46, 01, 0d, 00, 20, 62, 01, 11, 00, 14, 45, 00, 17, 01, 36, 00, 01, 36, 00, 37, 66, 01, 12, 00, 2f, 00, 00, 2f, 00, 30, 62, 01, 0d, 00, 20, 76, 01, 11, 00, 14, 4d, 00, 17, 01, 36, 00, 02, 11, 00, 12, 7a, 01, 12, 00, 2f, 00, 01, 11, 00, 12, 76, 02, 0d, 00, 20, 0d, 03, 05, 00, 0b, 7f, 01, 01, 00, 02] +Raw bytes (280): 0x[01, 01, 24, 01, 07, 00, 09, 03, 0d, 41, 00, 1e, 00, 41, 00, 1e, 00, 41, 00, 4a, 00, 4e, 00, 52, 41, 03, 0d, 52, 41, 03, 0d, 4e, 00, 52, 41, 03, 0d, 4a, 00, 4e, 00, 52, 41, 03, 0d, 66, 00, 45, 00, 45, 00, 66, 00, 45, 00, 7a, 00, 4d, 00, 4d, 00, 7a, 00, 4d, 00, 83, 01, 0d, 87, 01, 00, 00, 8b, 01, 8f, 01, 00, 19, 00, 28, 01, 3d, 01, 03, 17, 03, 08, 09, 00, 0e, 52, 02, 09, 04, 1a, 41, 06, 0d, 00, 2f, 00, 00, 2f, 00, 30, 1e, 00, 31, 03, 35, 00, 04, 11, 00, 12, 1a, 02, 11, 04, 12, 00, 05, 11, 00, 14, 1a, 00, 17, 00, 41, 19, 00, 41, 00, 42, 00, 00, 43, 00, 5f, 00, 00, 5f, 00, 60, 00, 01, 0d, 00, 20, 00, 01, 11, 00, 14, 00, 00, 17, 00, 41, 00, 00, 41, 00, 42, 00, 00, 43, 00, 60, 00, 00, 60, 00, 61, 00, 01, 0d, 00, 20, 46, 04, 11, 00, 14, 4e, 00, 17, 00, 42, 00, 00, 42, 00, 43, 4a, 00, 44, 00, 61, 00, 00, 61, 00, 62, 46, 01, 0d, 00, 20, 62, 01, 11, 00, 14, 45, 00, 17, 01, 36, 00, 01, 36, 00, 37, 66, 01, 12, 00, 2f, 00, 00, 2f, 00, 30, 62, 01, 0d, 00, 20, 76, 01, 11, 00, 14, 4d, 00, 17, 01, 36, 00, 02, 11, 00, 12, 7a, 01, 12, 00, 2f, 00, 01, 11, 00, 12, 76, 02, 0d, 00, 20, 0d, 03, 05, 00, 0b, 7f, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 36 @@ -122,7 +122,7 @@ Number of expressions: 36 - expression 34 operands: lhs = Expression(35, Add), rhs = Zero - expression 35 operands: lhs = Counter(6), rhs = Zero Number of file 0 mappings: 40 -- Code(Counter(0)) at (prev + 62, 1) to (start + 3, 23) +- Code(Counter(0)) at (prev + 61, 1) to (start + 3, 23) - Code(Expression(0, Add)) at (prev + 8, 9) to (start + 0, 14) = (c0 + (Zero + c2)) - Code(Expression(20, Sub)) at (prev + 2, 9) to (start + 4, 26) diff --git a/tests/coverage/try_error_result.coverage b/tests/coverage/try_error_result.coverage index 6fbe8b8db13f..7100248f7df8 100644 --- a/tests/coverage/try_error_result.coverage +++ b/tests/coverage/try_error_result.coverage @@ -1,4 +1,5 @@ LL| |#![allow(unused_assignments)] + LL| |#![cfg_attr(rustfmt, rustfmt::skip)] LL| |//@ failure-status: 1 LL| | LL| 6|fn call(return_error: bool) -> Result<(), ()> { @@ -9,7 +10,6 @@ LL| | } LL| 6|} LL| | - LL| |#[rustfmt::skip] LL| 1|fn test1() -> Result<(), ()> { LL| 1| let mut LL| 1| countdown = 10 @@ -59,7 +59,6 @@ LL| 17| } LL| |} LL| | - LL| |#[rustfmt::skip] LL| 1|fn test2() -> Result<(), ()> { LL| 1| let thing1 = Thing1{}; LL| 1| let mut @@ -117,7 +116,6 @@ LL| 0| Ok(()) LL| 1|} LL| | - LL| |#[rustfmt::skip] LL| 1|fn main() -> Result<(), ()> { LL| 1| test1().expect_err("test1 should fail"); LL| 1| test2() diff --git a/tests/coverage/try_error_result.rs b/tests/coverage/try_error_result.rs index f36283c34c8b..1fd176c353d9 100644 --- a/tests/coverage/try_error_result.rs +++ b/tests/coverage/try_error_result.rs @@ -1,4 +1,5 @@ #![allow(unused_assignments)] +#![cfg_attr(rustfmt, rustfmt::skip)] //@ failure-status: 1 fn call(return_error: bool) -> Result<(), ()> { @@ -9,7 +10,6 @@ fn call(return_error: bool) -> Result<(), ()> { } } -#[rustfmt::skip] fn test1() -> Result<(), ()> { let mut countdown = 10 @@ -58,7 +58,6 @@ impl Thing2 { } } -#[rustfmt::skip] fn test2() -> Result<(), ()> { let thing1 = Thing1{}; let mut @@ -111,7 +110,6 @@ fn test2() -> Result<(), ()> { Ok(()) } -#[rustfmt::skip] fn main() -> Result<(), ()> { test1().expect_err("test1 should fail"); test2() diff --git a/tests/coverage/uses_crate.coverage b/tests/coverage/uses_crate.coverage index a6a570a08502..d001eeffd863 100644 --- a/tests/coverage/uses_crate.coverage +++ b/tests/coverage/uses_crate.coverage @@ -19,69 +19,69 @@ $DIR/auxiliary/used_crate.rs: LL| 1|} LL| | LL| 2|pub fn used_only_from_bin_crate_generic_function(arg: T) { - LL| 2| println!("used_only_from_bin_crate_generic_function with {:?}", arg); + LL| 2| println!("used_only_from_bin_crate_generic_function with {arg:?}"); LL| 2|} ------------------ | Unexecuted instantiation: used_crate::used_only_from_bin_crate_generic_function::<_> ------------------ | used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec>: | LL| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { - | LL| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); + | LL| 1| println!("used_only_from_bin_crate_generic_function with {arg:?}"); | LL| 1|} ------------------ | used_crate::used_only_from_bin_crate_generic_function::<&str>: | LL| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { - | LL| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); + | LL| 1| println!("used_only_from_bin_crate_generic_function with {arg:?}"); | LL| 1|} ------------------ LL| |// Expect for above function: `Unexecuted instantiation` (see below) LL| 2|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { - LL| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); + LL| 2| println!("used_only_from_this_lib_crate_generic_function with {arg:?}"); LL| 2|} ------------------ | used_crate::used_only_from_this_lib_crate_generic_function::<&str>: | LL| 1|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { - | LL| 1| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); + | LL| 1| println!("used_only_from_this_lib_crate_generic_function with {arg:?}"); | LL| 1|} ------------------ | used_crate::used_only_from_this_lib_crate_generic_function::>: | LL| 1|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { - | LL| 1| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); + | LL| 1| println!("used_only_from_this_lib_crate_generic_function with {arg:?}"); | LL| 1|} ------------------ LL| | LL| 2|pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { - LL| 2| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + LL| 2| println!("used_from_bin_crate_and_lib_crate_generic_function with {arg:?}"); LL| 2|} ------------------ | used_crate::used_from_bin_crate_and_lib_crate_generic_function::<&str>: | LL| 1|pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { - | LL| 1| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + | LL| 1| println!("used_from_bin_crate_and_lib_crate_generic_function with {arg:?}"); | LL| 1|} ------------------ | used_crate::used_from_bin_crate_and_lib_crate_generic_function::>: | LL| 1|pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { - | LL| 1| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + | LL| 1| println!("used_from_bin_crate_and_lib_crate_generic_function with {arg:?}"); | LL| 1|} ------------------ LL| | LL| 2|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { - LL| 2| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + LL| 2| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {arg:?}"); LL| 2|} ------------------ | used_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function::<&str>: | LL| 1|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { - | LL| 1| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + | LL| 1| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {arg:?}"); | LL| 1|} ------------------ | used_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function::<&str>: | LL| 1|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { - | LL| 1| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + | LL| 1| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {arg:?}"); | LL| 1|} ------------------ LL| | LL| 0|pub fn unused_generic_function(arg: T) { - LL| 0| println!("unused_generic_function with {:?}", arg); + LL| 0| println!("unused_generic_function with {arg:?}"); LL| 0|} LL| | LL| 0|pub fn unused_function() { diff --git a/tests/coverage/uses_inline_crate.coverage b/tests/coverage/uses_inline_crate.coverage index 0c9735990c7e..832a5a6a62b4 100644 --- a/tests/coverage/uses_inline_crate.coverage +++ b/tests/coverage/uses_inline_crate.coverage @@ -34,74 +34,74 @@ $DIR/auxiliary/used_inline_crate.rs: LL| | LL| |#[inline(always)] LL| 2|pub fn used_only_from_bin_crate_generic_function(arg: T) { - LL| 2| println!("used_only_from_bin_crate_generic_function with {:?}", arg); + LL| 2| println!("used_only_from_bin_crate_generic_function with {arg:?}"); LL| 2|} ------------------ | Unexecuted instantiation: used_inline_crate::used_only_from_bin_crate_generic_function::<_> ------------------ | used_inline_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec>: | LL| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { - | LL| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); + | LL| 1| println!("used_only_from_bin_crate_generic_function with {arg:?}"); | LL| 1|} ------------------ | used_inline_crate::used_only_from_bin_crate_generic_function::<&str>: | LL| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { - | LL| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); + | LL| 1| println!("used_only_from_bin_crate_generic_function with {arg:?}"); | LL| 1|} ------------------ LL| |// Expect for above function: `Unexecuted instantiation` (see notes in `used_crate.rs`) LL| | LL| |#[inline(always)] LL| 4|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { - LL| 4| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); + LL| 4| println!("used_only_from_this_lib_crate_generic_function with {arg:?}"); LL| 4|} ------------------ | used_inline_crate::used_only_from_this_lib_crate_generic_function::<&str>: | LL| 2|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { - | LL| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); + | LL| 2| println!("used_only_from_this_lib_crate_generic_function with {arg:?}"); | LL| 2|} ------------------ | used_inline_crate::used_only_from_this_lib_crate_generic_function::>: | LL| 2|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { - | LL| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); + | LL| 2| println!("used_only_from_this_lib_crate_generic_function with {arg:?}"); | LL| 2|} ------------------ LL| | LL| |#[inline(always)] LL| 3|pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { - LL| 3| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + LL| 3| println!("used_from_bin_crate_and_lib_crate_generic_function with {arg:?}"); LL| 3|} ------------------ | used_inline_crate::used_from_bin_crate_and_lib_crate_generic_function::<&str>: | LL| 2|pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { - | LL| 2| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + | LL| 2| println!("used_from_bin_crate_and_lib_crate_generic_function with {arg:?}"); | LL| 2|} ------------------ | used_inline_crate::used_from_bin_crate_and_lib_crate_generic_function::>: | LL| 1|pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { - | LL| 1| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + | LL| 1| println!("used_from_bin_crate_and_lib_crate_generic_function with {arg:?}"); | LL| 1|} ------------------ LL| | LL| |#[inline(always)] LL| 3|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { - LL| 3| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + LL| 3| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {arg:?}"); LL| 3|} ------------------ | used_inline_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function::<&str>: | LL| 1|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { - | LL| 1| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + | LL| 1| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {arg:?}"); | LL| 1|} ------------------ | used_inline_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function::<&str>: | LL| 2|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { - | LL| 2| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + | LL| 2| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {arg:?}"); | LL| 2|} ------------------ LL| | LL| |#[inline(always)] LL| 0|pub fn unused_generic_function(arg: T) { - LL| 0| println!("unused_generic_function with {:?}", arg); + LL| 0| println!("unused_generic_function with {arg:?}"); LL| 0|} LL| | LL| |#[inline(always)] diff --git a/tests/coverage/yield.cov-map b/tests/coverage/yield.cov-map index 0347aaaa3676..a273c688e248 100644 --- a/tests/coverage/yield.cov-map +++ b/tests/coverage/yield.cov-map @@ -1,5 +1,5 @@ Function name: yield::main -Raw bytes (106): 0x[01, 01, 0b, 05, 00, 0d, 11, 22, 15, 0d, 11, 11, 15, 22, 15, 0d, 11, 22, 15, 0d, 11, 19, 1d, 25, 29, 10, 01, 07, 01, 01, 16, 01, 06, 0b, 00, 2e, 0d, 01, 27, 00, 29, 03, 01, 0e, 00, 34, 0d, 02, 0b, 00, 2e, 22, 01, 22, 00, 27, 1e, 00, 2c, 00, 2e, 13, 01, 0e, 00, 34, 1e, 03, 09, 00, 16, 1e, 07, 0b, 00, 2e, 21, 01, 27, 00, 29, 27, 01, 0e, 00, 34, 21, 02, 0b, 00, 2e, 2d, 01, 27, 00, 29, 2b, 01, 0e, 00, 34, 2d, 02, 01, 00, 02] +Raw bytes (106): 0x[01, 01, 0b, 05, 00, 0d, 11, 22, 15, 0d, 11, 11, 15, 22, 15, 0d, 11, 22, 15, 0d, 11, 19, 1d, 25, 29, 10, 01, 07, 01, 01, 16, 01, 07, 0b, 00, 2e, 0d, 01, 27, 00, 29, 03, 01, 0e, 00, 34, 0d, 02, 0b, 00, 2e, 22, 01, 22, 00, 27, 1e, 00, 2c, 00, 2e, 13, 01, 0e, 00, 34, 1e, 03, 09, 00, 16, 1e, 08, 0b, 00, 2e, 21, 01, 27, 00, 29, 27, 01, 0e, 00, 34, 21, 02, 0b, 00, 2e, 2d, 01, 27, 00, 29, 2b, 01, 0e, 00, 34, 2d, 02, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 11 @@ -16,7 +16,7 @@ Number of expressions: 11 - expression 10 operands: lhs = Counter(9), rhs = Counter(10) Number of file 0 mappings: 16 - Code(Counter(0)) at (prev + 7, 1) to (start + 1, 22) -- Code(Counter(0)) at (prev + 6, 11) to (start + 0, 46) +- Code(Counter(0)) at (prev + 7, 11) to (start + 0, 46) - Code(Counter(3)) at (prev + 1, 39) to (start + 0, 41) - Code(Expression(0, Add)) at (prev + 1, 14) to (start + 0, 52) = (c1 + Zero) @@ -29,7 +29,7 @@ Number of file 0 mappings: 16 = (c4 + c5) - Code(Expression(7, Sub)) at (prev + 3, 9) to (start + 0, 22) = ((c3 - c4) - c5) -- Code(Expression(7, Sub)) at (prev + 7, 11) to (start + 0, 46) +- Code(Expression(7, Sub)) at (prev + 8, 11) to (start + 0, 46) = ((c3 - c4) - c5) - Code(Counter(8)) at (prev + 1, 39) to (start + 0, 41) - Code(Expression(9, Add)) at (prev + 1, 14) to (start + 0, 52) @@ -41,21 +41,21 @@ Number of file 0 mappings: 16 - Code(Counter(11)) at (prev + 2, 1) to (start + 0, 2) Function name: yield::main::{closure#0} -Raw bytes (14): 0x[01, 01, 00, 02, 01, 08, 29, 01, 10, 05, 02, 10, 01, 06] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 09, 08, 01, 10, 05, 02, 10, 01, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 8, 41) to (start + 1, 16) +- Code(Counter(0)) at (prev + 9, 8) to (start + 1, 16) - Code(Counter(1)) at (prev + 2, 16) to (start + 1, 6) Function name: yield::main::{closure#1} -Raw bytes (24): 0x[01, 01, 00, 04, 01, 16, 29, 01, 10, 05, 02, 09, 00, 10, 09, 01, 09, 00, 10, 0d, 01, 10, 01, 06] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 18, 08, 01, 10, 05, 02, 09, 00, 10, 09, 01, 09, 00, 10, 0d, 01, 10, 01, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 22, 41) to (start + 1, 16) +- Code(Counter(0)) at (prev + 24, 8) to (start + 1, 16) - Code(Counter(1)) at (prev + 2, 9) to (start + 0, 16) - Code(Counter(2)) at (prev + 1, 9) to (start + 0, 16) - Code(Counter(3)) at (prev + 1, 16) to (start + 1, 6) diff --git a/tests/coverage/yield.coverage b/tests/coverage/yield.coverage index e2fc9196d244..2c133cbec549 100644 --- a/tests/coverage/yield.coverage +++ b/tests/coverage/yield.coverage @@ -5,7 +5,8 @@ LL| |use std::pin::Pin; LL| | LL| 1|fn main() { - LL| 1| let mut coroutine = #[coroutine] || { + LL| 1| let mut coroutine = #[coroutine] + LL| 1| || { LL| 1| yield 1; LL| 1| return "foo"; LL| 1| }; @@ -19,7 +20,8 @@ LL| 0| _ => panic!("unexpected value from resume"), LL| | } LL| | - LL| 1| let mut coroutine = #[coroutine] || { + LL| 1| let mut coroutine = #[coroutine] + LL| 1| || { LL| 1| yield 1; LL| 1| yield 2; LL| 0| yield 3; diff --git a/tests/coverage/yield.rs b/tests/coverage/yield.rs index 64ea27066047..e02e3d356124 100644 --- a/tests/coverage/yield.rs +++ b/tests/coverage/yield.rs @@ -5,7 +5,8 @@ use std::ops::{Coroutine, CoroutineState}; use std::pin::Pin; fn main() { - let mut coroutine = #[coroutine] || { + let mut coroutine = #[coroutine] + || { yield 1; return "foo"; }; @@ -19,7 +20,8 @@ fn main() { _ => panic!("unexpected value from resume"), } - let mut coroutine = #[coroutine] || { + let mut coroutine = #[coroutine] + || { yield 1; yield 2; yield 3; diff --git a/tests/crashes/125081.rs b/tests/crashes/125081.rs deleted file mode 100644 index 7139caaa00df..000000000000 --- a/tests/crashes/125081.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ known-bug: rust-lang/rust#125081 - -use std::cell::Cell; - -fn main() { - let _: Cell<&str, "a"> = Cell::new('β); -} diff --git a/tests/mir-opt/building/custom/consts.consts.built.after.mir b/tests/mir-opt/building/custom/consts.consts.built.after.mir index a011fadcef11..7b6964849d4b 100644 --- a/tests/mir-opt/building/custom/consts.consts.built.after.mir +++ b/tests/mir-opt/building/custom/consts.consts.built.after.mir @@ -10,7 +10,7 @@ fn consts() -> () { bb0: { _1 = const 5_u8; - _2 = const consts::::{constant#0}; + _2 = const consts::::{constant#1}; _3 = const C; _4 = const D; _5 = consts::<10>; diff --git a/tests/mir-opt/building/custom/operators.g.runtime.after.mir b/tests/mir-opt/building/custom/operators.g.runtime.after.mir new file mode 100644 index 000000000000..a0ad7d0f93f4 --- /dev/null +++ b/tests/mir-opt/building/custom/operators.g.runtime.after.mir @@ -0,0 +1,13 @@ +// MIR for `g` after runtime + +fn g(_1: *const i32, _2: *const [i32]) -> () { + let mut _0: (); + let mut _3: (); + let mut _4: usize; + + bb0: { + _3 = PtrMetadata(_1); + _4 = PtrMetadata(_2); + return; + } +} diff --git a/tests/mir-opt/building/custom/operators.rs b/tests/mir-opt/building/custom/operators.rs index eb97bcc73b7e..ff0e8dcbb415 100644 --- a/tests/mir-opt/building/custom/operators.rs +++ b/tests/mir-opt/building/custom/operators.rs @@ -30,3 +30,13 @@ pub fn f(a: i32, b: bool) -> i32 { Return() }) } + +// EMIT_MIR operators.g.runtime.after.mir +#[custom_mir(dialect = "runtime")] +pub fn g(p: *const i32, q: *const [i32]) { + mir!({ + let a = PtrMetadata(p); + let b = PtrMetadata(q); + Return() + }) +} diff --git a/tests/mir-opt/const_allocation3.rs b/tests/mir-opt/const_allocation3.rs index 46be3e1e36e8..9d2006b6fe80 100644 --- a/tests/mir-opt/const_allocation3.rs +++ b/tests/mir-opt/const_allocation3.rs @@ -7,7 +7,7 @@ fn main() { FOO; } -#[repr(packed)] +#[repr(C, packed)] struct Packed { a: [u8; 28], b: &'static i32, diff --git a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff index df873600577a..45ce933a55ad 100644 --- a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff @@ -27,10 +27,12 @@ + } + } + scope 7 (inlined slice_from_raw_parts_mut::) { ++ scope 8 (inlined std::ptr::from_raw_parts_mut::<[A], A>) { ++ } + } + } + } -+ scope 8 (inlined std::ptr::drop_in_place::> - shim(Some(Option))) { ++ scope 9 (inlined std::ptr::drop_in_place::> - shim(Some(Option))) { + let mut _14: isize; + let mut _15: isize; + } diff --git a/tests/mir-opt/lower_intrinsics.get_metadata.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.get_metadata.LowerIntrinsics.panic-abort.diff new file mode 100644 index 000000000000..d256058c05ee --- /dev/null +++ b/tests/mir-opt/lower_intrinsics.get_metadata.LowerIntrinsics.panic-abort.diff @@ -0,0 +1,63 @@ +- // MIR for `get_metadata` before LowerIntrinsics ++ // MIR for `get_metadata` after LowerIntrinsics + + fn get_metadata(_1: *const i32, _2: *const [u8], _3: *const dyn Debug) -> () { + debug a => _1; + debug b => _2; + debug c => _3; + let mut _0: (); + let _4: (); + let mut _5: *const i32; + let mut _7: *const [u8]; + let mut _9: *const dyn std::fmt::Debug; + scope 1 { + debug _unit => _4; + let _6: usize; + scope 2 { + debug _usize => _6; + let _8: std::ptr::DynMetadata; + scope 3 { + debug _vtable => _8; + } + } + } + + bb0: { + StorageLive(_4); + StorageLive(_5); + _5 = _1; +- _4 = ptr_metadata::(move _5) -> [return: bb1, unwind unreachable]; ++ _4 = PtrMetadata(move _5); ++ goto -> bb1; + } + + bb1: { + StorageDead(_5); + StorageLive(_6); + StorageLive(_7); + _7 = _2; +- _6 = ptr_metadata::<[u8], usize>(move _7) -> [return: bb2, unwind unreachable]; ++ _6 = PtrMetadata(move _7); ++ goto -> bb2; + } + + bb2: { + StorageDead(_7); + StorageLive(_8); + StorageLive(_9); + _9 = _3; +- _8 = ptr_metadata::>(move _9) -> [return: bb3, unwind unreachable]; ++ _8 = PtrMetadata(move _9); ++ goto -> bb3; + } + + bb3: { + StorageDead(_9); + _0 = const (); + StorageDead(_8); + StorageDead(_6); + StorageDead(_4); + return; + } + } + diff --git a/tests/mir-opt/lower_intrinsics.get_metadata.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.get_metadata.LowerIntrinsics.panic-unwind.diff new file mode 100644 index 000000000000..d256058c05ee --- /dev/null +++ b/tests/mir-opt/lower_intrinsics.get_metadata.LowerIntrinsics.panic-unwind.diff @@ -0,0 +1,63 @@ +- // MIR for `get_metadata` before LowerIntrinsics ++ // MIR for `get_metadata` after LowerIntrinsics + + fn get_metadata(_1: *const i32, _2: *const [u8], _3: *const dyn Debug) -> () { + debug a => _1; + debug b => _2; + debug c => _3; + let mut _0: (); + let _4: (); + let mut _5: *const i32; + let mut _7: *const [u8]; + let mut _9: *const dyn std::fmt::Debug; + scope 1 { + debug _unit => _4; + let _6: usize; + scope 2 { + debug _usize => _6; + let _8: std::ptr::DynMetadata; + scope 3 { + debug _vtable => _8; + } + } + } + + bb0: { + StorageLive(_4); + StorageLive(_5); + _5 = _1; +- _4 = ptr_metadata::(move _5) -> [return: bb1, unwind unreachable]; ++ _4 = PtrMetadata(move _5); ++ goto -> bb1; + } + + bb1: { + StorageDead(_5); + StorageLive(_6); + StorageLive(_7); + _7 = _2; +- _6 = ptr_metadata::<[u8], usize>(move _7) -> [return: bb2, unwind unreachable]; ++ _6 = PtrMetadata(move _7); ++ goto -> bb2; + } + + bb2: { + StorageDead(_7); + StorageLive(_8); + StorageLive(_9); + _9 = _3; +- _8 = ptr_metadata::>(move _9) -> [return: bb3, unwind unreachable]; ++ _8 = PtrMetadata(move _9); ++ goto -> bb3; + } + + bb3: { + StorageDead(_9); + _0 = const (); + StorageDead(_8); + StorageDead(_6); + StorageDead(_4); + return; + } + } + diff --git a/tests/mir-opt/lower_intrinsics.rs b/tests/mir-opt/lower_intrinsics.rs index 180bfd0a9246..2569f4f4de5d 100644 --- a/tests/mir-opt/lower_intrinsics.rs +++ b/tests/mir-opt/lower_intrinsics.rs @@ -258,3 +258,12 @@ pub fn make_pointers(a: *const u8, b: *mut (), n: usize) { let _slice_const: *const [u16] = aggregate_raw_ptr(a, n); let _slice_mut: *mut [u64] = aggregate_raw_ptr(b, n); } + +// EMIT_MIR lower_intrinsics.get_metadata.LowerIntrinsics.diff +pub fn get_metadata(a: *const i32, b: *const [u8], c: *const dyn std::fmt::Debug) { + use std::intrinsics::ptr_metadata; + + let _unit = ptr_metadata(a); + let _usize = ptr_metadata(b); + let _vtable = ptr_metadata(c); +} diff --git a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-abort.mir index db0c84bd560f..2c6d93e10c11 100644 --- a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-abort.mir @@ -13,11 +13,10 @@ fn demo_byte_add_fat(_1: *const [u32], _2: usize) -> *const [u32] { } scope 4 (inlined std::ptr::const_ptr::::with_metadata_of::<[u32]>) { let mut _5: *const (); - let mut _7: usize; + let mut _6: usize; scope 5 (inlined std::ptr::metadata::<[u32]>) { - let mut _6: std::ptr::metadata::PtrRepr<[u32]>; } - scope 6 (inlined std::ptr::from_raw_parts::<[u32]>) { + scope 6 (inlined std::ptr::from_raw_parts::<[u32], ()>) { } } } @@ -30,13 +29,10 @@ fn demo_byte_add_fat(_1: *const [u32], _2: usize) -> *const [u32] { StorageDead(_3); StorageLive(_5); _5 = _4 as *const () (PtrToPtr); - StorageLive(_7); StorageLive(_6); - _6 = std::ptr::metadata::PtrRepr::<[u32]> { const_ptr: _1 }; - _7 = ((_6.2: std::ptr::metadata::PtrComponents<[u32]>).1: usize); + _6 = PtrMetadata(_1); + _0 = *const [u32] from (_5, _6); StorageDead(_6); - _0 = *const [u32] from (_5, _7); - StorageDead(_7); StorageDead(_5); StorageDead(_4); return; diff --git a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-unwind.mir index db0c84bd560f..2c6d93e10c11 100644 --- a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-unwind.mir @@ -13,11 +13,10 @@ fn demo_byte_add_fat(_1: *const [u32], _2: usize) -> *const [u32] { } scope 4 (inlined std::ptr::const_ptr::::with_metadata_of::<[u32]>) { let mut _5: *const (); - let mut _7: usize; + let mut _6: usize; scope 5 (inlined std::ptr::metadata::<[u32]>) { - let mut _6: std::ptr::metadata::PtrRepr<[u32]>; } - scope 6 (inlined std::ptr::from_raw_parts::<[u32]>) { + scope 6 (inlined std::ptr::from_raw_parts::<[u32], ()>) { } } } @@ -30,13 +29,10 @@ fn demo_byte_add_fat(_1: *const [u32], _2: usize) -> *const [u32] { StorageDead(_3); StorageLive(_5); _5 = _4 as *const () (PtrToPtr); - StorageLive(_7); StorageLive(_6); - _6 = std::ptr::metadata::PtrRepr::<[u32]> { const_ptr: _1 }; - _7 = ((_6.2: std::ptr::metadata::PtrComponents<[u32]>).1: usize); + _6 = PtrMetadata(_1); + _0 = *const [u32] from (_5, _6); StorageDead(_6); - _0 = *const [u32] from (_5, _7); - StorageDead(_7); StorageDead(_5); StorageDead(_4); return; diff --git a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-abort.mir index 766bd29ef41c..04fb6b838f02 100644 --- a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-abort.mir @@ -14,7 +14,7 @@ fn demo_byte_add_thin(_1: *const u32, _2: usize) -> *const u32 { scope 4 (inlined std::ptr::const_ptr::::with_metadata_of::) { scope 5 (inlined std::ptr::metadata::) { } - scope 6 (inlined std::ptr::from_raw_parts::) { + scope 6 (inlined std::ptr::from_raw_parts::) { } } } diff --git a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-unwind.mir index 766bd29ef41c..04fb6b838f02 100644 --- a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-unwind.mir @@ -14,7 +14,7 @@ fn demo_byte_add_thin(_1: *const u32, _2: usize) -> *const u32 { scope 4 (inlined std::ptr::const_ptr::::with_metadata_of::) { scope 5 (inlined std::ptr::metadata::) { } - scope 6 (inlined std::ptr::from_raw_parts::) { + scope 6 (inlined std::ptr::from_raw_parts::) { } } } diff --git a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir index eabecaed0517..1c9ed25d7f2b 100644 --- a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir @@ -37,6 +37,10 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { scope 11 (inlined slice_from_raw_parts::) { debug data => _4; debug len => _5; + scope 12 (inlined std::ptr::from_raw_parts::<[u8], u8>) { + debug data_pointer => _4; + debug metadata => _5; + } } } } diff --git a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir index eabecaed0517..1c9ed25d7f2b 100644 --- a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir @@ -37,6 +37,10 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { scope 11 (inlined slice_from_raw_parts::) { debug data => _4; debug len => _5; + scope 12 (inlined std::ptr::from_raw_parts::<[u8], u8>) { + debug data_pointer => _4; + debug metadata => _5; + } } } } diff --git a/tests/pretty/stmt_expr_attributes.rs b/tests/pretty/stmt_expr_attributes.rs index 5eb7d2fcae36..f90412682110 100644 --- a/tests/pretty/stmt_expr_attributes.rs +++ b/tests/pretty/stmt_expr_attributes.rs @@ -206,12 +206,7 @@ fn _11() { let _ = (); () }; - let const { - #![rustc_dummy] - } = - #[rustc_dummy] const { - #![rustc_dummy] - }; + let const {} = #[rustc_dummy] const {}; let mut x = 0; let _ = (#[rustc_dummy] x) = 15; let _ = (#[rustc_dummy] x) += 15; diff --git a/tests/run-make/allow-warnings-cmdline-stability/Makefile b/tests/run-make/allow-warnings-cmdline-stability/Makefile deleted file mode 100644 index 368a39af6bfe..000000000000 --- a/tests/run-make/allow-warnings-cmdline-stability/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -# Test that -A warnings makes the 'empty trait list for derive' warning go away -DEP=$(shell $(RUSTC) bar.rs) -OUT=$(shell $(RUSTC) foo.rs -A warnings 2>&1 | grep "warning" ) - -all: foo bar - test -z '$(OUT)' - -# These are just to ensure that the above commands actually work -bar: - $(RUSTC) bar.rs - -foo: bar - $(RUSTC) foo.rs -A warnings diff --git a/tests/run-make/allow-warnings-cmdline-stability/rmake.rs b/tests/run-make/allow-warnings-cmdline-stability/rmake.rs new file mode 100644 index 000000000000..8f6fe6bd0b66 --- /dev/null +++ b/tests/run-make/allow-warnings-cmdline-stability/rmake.rs @@ -0,0 +1,11 @@ +// Test that `-Awarnings` suppresses warnings for unstable APIs. + +use run_make_support::{assert_not_contains, rustc}; + +fn main() { + rustc().input("bar.rs").run(); + let output = rustc().input("foo.rs").arg("-Awarnings").run(); + + assert_not_contains(&String::from_utf8(output.stdout).unwrap(), "warning"); + assert_not_contains(&String::from_utf8(output.stderr).unwrap(), "warning"); +} diff --git a/tests/run-make/c-dynamic-dylib/Makefile b/tests/run-make/c-dynamic-dylib/Makefile index 0d4096404867..39561b28222c 100644 --- a/tests/run-make/c-dynamic-dylib/Makefile +++ b/tests/run-make/c-dynamic-dylib/Makefile @@ -4,7 +4,7 @@ # ignore-cross-compile include ../tools.mk -# ignore-macos +# ignore-apple # # This hits an assertion in the linker on older versions of osx apparently diff --git a/tests/run-make/c-dynamic-rlib/Makefile b/tests/run-make/c-dynamic-rlib/Makefile index a64e89cc0dc4..7b05e3d91a09 100644 --- a/tests/run-make/c-dynamic-rlib/Makefile +++ b/tests/run-make/c-dynamic-rlib/Makefile @@ -4,7 +4,7 @@ # ignore-cross-compile include ../tools.mk -# ignore-macos +# ignore-apple # # This hits an assertion in the linker on older versions of osx apparently diff --git a/tests/run-make/const-prop-lint/Makefile b/tests/run-make/const-prop-lint/Makefile deleted file mode 100644 index f29f282f7876..000000000000 --- a/tests/run-make/const-prop-lint/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -include ../tools.mk - -# Test that emitting an error because of arithmetic -# overflow lint does not leave .o files around -# because of interrupted codegen. - -all: - $(RUSTC) input.rs; test $$? -eq 1 - ls *.o; test $$? -ne 0 diff --git a/tests/run-make/const-prop-lint/rmake.rs b/tests/run-make/const-prop-lint/rmake.rs new file mode 100644 index 000000000000..fa27a18a591a --- /dev/null +++ b/tests/run-make/const-prop-lint/rmake.rs @@ -0,0 +1,18 @@ +// Tests that const prop lints interrupting codegen don't leave `.o` files around. + +use std::fs; + +use run_make_support::{rustc, tmp_dir}; + +fn main() { + rustc().input("input.rs").run_fail_assert_exit_code(1); + + for entry in fs::read_dir(tmp_dir()).unwrap() { + let entry = entry.unwrap(); + let path = entry.path(); + + if path.is_file() && path.extension().is_some_and(|ext| ext == "o") { + panic!("there should not be `.o` files!"); + } + } +} diff --git a/tests/run-make/crate-data-smoke/Makefile b/tests/run-make/crate-data-smoke/Makefile deleted file mode 100644 index a453f65ff3ea..000000000000 --- a/tests/run-make/crate-data-smoke/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -include ../tools.mk - -all: - [ `$(RUSTC) --print crate-name crate.rs` = "foo" ] - [ `$(RUSTC) --print file-names crate.rs` = "$(call BIN,foo)" ] - [ `$(RUSTC) --print file-names --crate-type=lib \ - --test crate.rs` = "$(call BIN,foo)" ] - [ `$(RUSTC) --print file-names --test lib.rs` = "$(call BIN,mylib)" ] - $(RUSTC) --print file-names lib.rs - $(RUSTC) --print file-names rlib.rs diff --git a/tests/run-make/crate-data-smoke/rmake.rs b/tests/run-make/crate-data-smoke/rmake.rs new file mode 100644 index 000000000000..80d43903a532 --- /dev/null +++ b/tests/run-make/crate-data-smoke/rmake.rs @@ -0,0 +1,43 @@ +use std::process::Output; + +use run_make_support::{bin_name, rust_lib_name, rustc}; + +fn compare_stdout>(output: Output, expected: S) { + assert_eq!( + String::from_utf8(output.stdout).unwrap().trim(), + expected.as_ref() + ); +} + +fn main() { + compare_stdout(rustc().print("crate-name").input("crate.rs").run(), "foo"); + compare_stdout( + rustc().print("file-names").input("crate.rs").run(), + bin_name("foo"), + ); + compare_stdout( + rustc() + .print("file-names") + .crate_type("lib") + .arg("--test") + .input("crate.rs") + .run(), + bin_name("foo"), + ); + compare_stdout( + rustc() + .print("file-names") + .arg("--test") + .input("lib.rs") + .run(), + bin_name("mylib"), + ); + compare_stdout( + rustc().print("file-names").input("lib.rs").run(), + rust_lib_name("mylib"), + ); + compare_stdout( + rustc().print("file-names").input("rlib.rs").run(), + rust_lib_name("mylib"), + ); +} diff --git a/tests/run-make/emit-stack-sizes/Makefile b/tests/run-make/emit-stack-sizes/Makefile index f636ebd28f2e..b546fcba5121 100644 --- a/tests/run-make/emit-stack-sizes/Makefile +++ b/tests/run-make/emit-stack-sizes/Makefile @@ -1,10 +1,10 @@ include ../tools.mk # ignore-windows -# ignore-macos +# ignore-apple # # This feature only works when the output object format is ELF so we ignore -# macOS and Windows +# Apple and Windows # check that the .stack_sizes section is generated all: diff --git a/tests/run-make/fpic/Makefile b/tests/run-make/fpic/Makefile deleted file mode 100644 index c38dd8d6e8c4..000000000000 --- a/tests/run-make/fpic/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -# ignore-windows -# ignore-macos - -# Test for #39529. -# `-z text` causes ld to error if there are any non-PIC sections - -all: - $(RUSTC) hello.rs -C link-args=-Wl,-z,text diff --git a/tests/run-make/fpic/hello.rs b/tests/run-make/fpic/hello.rs deleted file mode 100644 index 45590d86ba6c..000000000000 --- a/tests/run-make/fpic/hello.rs +++ /dev/null @@ -1 +0,0 @@ -fn main() { } diff --git a/tests/run-make/issue-37893/Makefile b/tests/run-make/issue-37893/Makefile deleted file mode 100644 index 44e4a321a30a..000000000000 --- a/tests/run-make/issue-37893/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: - $(RUSTC) a.rs && $(RUSTC) b.rs && $(RUSTC) c.rs diff --git a/tests/run-make/issue-85441/Makefile b/tests/run-make/issue-85441/Makefile deleted file mode 100644 index 987d7f7d4a76..000000000000 --- a/tests/run-make/issue-85441/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# only-windows-msvc - -include ../tools.mk - -# Tests that WS2_32.dll is not unnecessarily linked, see issue #85441 - -all: - $(RUSTC) empty.rs - objdump -p $(TMPDIR)/empty.exe | $(CGREP) -v -i "WS2_32.dll" diff --git a/tests/run-make/link-framework/Makefile b/tests/run-make/link-framework/Makefile index f33347ac7f8f..96d832ad4a83 100644 --- a/tests/run-make/link-framework/Makefile +++ b/tests/run-make/link-framework/Makefile @@ -1,4 +1,4 @@ -# only-macos +# only-apple # # Check that linking to a framework actually makes it to the linker. diff --git a/tests/run-make/lto-smoke/Makefile b/tests/run-make/lto-smoke/Makefile deleted file mode 100644 index 13a09fce7340..000000000000 --- a/tests/run-make/lto-smoke/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: noparam bool_true bool_false thin fat - -noparam: - $(RUSTC) lib.rs - $(RUSTC) main.rs -C lto - $(call RUN,main) - -bool_true: - $(RUSTC) lib.rs - $(RUSTC) main.rs -C lto=yes - $(call RUN,main) - - -bool_false: - $(RUSTC) lib.rs - $(RUSTC) main.rs -C lto=off - $(call RUN,main) - -thin: - $(RUSTC) lib.rs - $(RUSTC) main.rs -C lto=thin - $(call RUN,main) - -fat: - $(RUSTC) lib.rs - $(RUSTC) main.rs -C lto=fat - $(call RUN,main) - diff --git a/tests/run-make/lto-smoke/rmake.rs b/tests/run-make/lto-smoke/rmake.rs new file mode 100644 index 000000000000..692945135cd3 --- /dev/null +++ b/tests/run-make/lto-smoke/rmake.rs @@ -0,0 +1,16 @@ +// A simple smoke test to check that link time optimization +// (LTO) is accepted by the compiler, and that +// passing its various flags still results in successful compilation. +// See https://github.com/rust-lang/rust/issues/10741 + +//@ ignore-cross-compile + +use run_make_support::rustc; + +fn main() { + let lto_flags = ["-Clto", "-Clto=yes", "-Clto=off", "-Clto=thin", "-Clto=fat"]; + for flag in lto_flags { + rustc().input("lib.rs").run(); + rustc().input("main.rs").arg(flag).run(); + } +} diff --git a/tests/run-make/macos-fat-archive/Makefile b/tests/run-make/macos-fat-archive/Makefile index b6582c809e8b..0feb39a23cb5 100644 --- a/tests/run-make/macos-fat-archive/Makefile +++ b/tests/run-make/macos-fat-archive/Makefile @@ -1,4 +1,4 @@ -# only-macos +# only-apple include ../tools.mk diff --git a/tests/run-make/mixing-deps/Makefile b/tests/run-make/mixing-deps/Makefile deleted file mode 100644 index c2a5a2a0abbe..000000000000 --- a/tests/run-make/mixing-deps/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: - $(RUSTC) both.rs -C prefer-dynamic - $(RUSTC) dylib.rs -C prefer-dynamic - $(RUSTC) prog.rs - $(call RUN,prog) diff --git a/tests/run-make/mixing-deps/rmake.rs b/tests/run-make/mixing-deps/rmake.rs new file mode 100644 index 000000000000..fb31bbef9d19 --- /dev/null +++ b/tests/run-make/mixing-deps/rmake.rs @@ -0,0 +1,13 @@ +// This test invokes the main function in prog.rs, which has dependencies +// in both an rlib and a dylib. This test checks that these different library +// types can be successfully mixed. +//@ ignore-cross-compile + +use run_make_support::{run, rustc}; + +fn main() { + rustc().input("both.rs").arg("-Cprefer-dynamic").run(); + rustc().input("dylib.rs").arg("-Cprefer-dynamic").run(); + rustc().input("prog.rs").run(); + run("prog"); +} diff --git a/tests/run-make/native-link-modifier-verbatim-linker/Makefile b/tests/run-make/native-link-modifier-verbatim-linker/Makefile index 256dc2d0664e..47ed2a142918 100644 --- a/tests/run-make/native-link-modifier-verbatim-linker/Makefile +++ b/tests/run-make/native-link-modifier-verbatim-linker/Makefile @@ -1,5 +1,5 @@ # ignore-cross-compile -# ignore-macos +# ignore-apple include ../tools.mk diff --git a/tests/run-make/print-check-cfg/lib.rs b/tests/run-make/print-check-cfg/lib.rs new file mode 100644 index 000000000000..c09e4c98dffd --- /dev/null +++ b/tests/run-make/print-check-cfg/lib.rs @@ -0,0 +1 @@ +// empty crate diff --git a/tests/run-make/print-check-cfg/rmake.rs b/tests/run-make/print-check-cfg/rmake.rs new file mode 100644 index 000000000000..554884b7d579 --- /dev/null +++ b/tests/run-make/print-check-cfg/rmake.rs @@ -0,0 +1,106 @@ +//! This checks the output of `--print=check-cfg` + +extern crate run_make_support; + +use std::collections::HashSet; +use std::iter::FromIterator; +use std::ops::Deref; + +use run_make_support::rustc; + +fn main() { + check( + /*args*/ &[], + /*has_any*/ false, + /*has_any_any*/ true, + /*contains*/ &[], + ); + check( + /*args*/ &["--check-cfg=cfg()"], + /*has_any*/ false, + /*has_any_any*/ false, + /*contains*/ &["unix", "miri"], + ); + check( + /*args*/ &["--check-cfg=cfg(any())"], + /*has_any*/ true, + /*has_any_any*/ false, + /*contains*/ &["windows", "test"], + ); + check( + /*args*/ &["--check-cfg=cfg(feature)"], + /*has_any*/ false, + /*has_any_any*/ false, + /*contains*/ &["unix", "miri", "feature"], + ); + check( + /*args*/ &[r#"--check-cfg=cfg(feature, values(none(), "", "test", "lol"))"#], + /*has_any*/ false, + /*has_any_any*/ false, + /*contains*/ &["feature", "feature=\"\"", "feature=\"test\"", "feature=\"lol\""], + ); + check( + /*args*/ &[ + r#"--check-cfg=cfg(feature, values(any()))"#, + r#"--check-cfg=cfg(feature, values("tmp"))"# + ], + /*has_any*/ false, + /*has_any_any*/ false, + /*contains*/ &["unix", "miri", "feature=any()"], + ); + check( + /*args*/ &[ + r#"--check-cfg=cfg(has_foo, has_bar)"#, + r#"--check-cfg=cfg(feature, values("tmp"))"#, + r#"--check-cfg=cfg(feature, values("tmp"))"# + ], + /*has_any*/ false, + /*has_any_any*/ false, + /*contains*/ &["has_foo", "has_bar", "feature=\"tmp\""], + ); +} + +fn check(args: &[&str], has_any: bool, has_any_any: bool, contains: &[&str]) { + let output = rustc() + .input("lib.rs") + .arg("-Zunstable-options") + .arg("--print=check-cfg") + .args(&*args) + .run(); + + let stdout = String::from_utf8(output.stdout).unwrap(); + + let mut found_any = false; + let mut found_any_any = false; + let mut found = HashSet::::new(); + let mut recorded = HashSet::::new(); + + for l in stdout.lines() { + assert!(l == l.trim()); + if l == "any()" { + found_any = true; + } else if l == "any()=any()" { + found_any_any = true; + } else if let Some((left, right)) = l.split_once('=') { + if right != "any()" && right != "" { + assert!(right.starts_with("\"")); + assert!(right.ends_with("\"")); + } + assert!(!left.contains("\"")); + } else { + assert!(!l.contains("\"")); + } + assert!(recorded.insert(l.to_string()), "{}", &l); + if contains.contains(&l) { + assert!(found.insert(l.to_string()), "{}", &l); + } + } + + let should_found = HashSet::::from_iter(contains.iter().map(|s| s.to_string())); + let diff: Vec<_> = should_found.difference(&found).collect(); + + assert_eq!(found_any, has_any); + assert_eq!(found_any_any, has_any_any); + assert_eq!(found_any_any, recorded.len() == 1); + assert!(diff.is_empty(), "{:?} != {:?} (~ {:?})", &should_found, &found, &diff); +} diff --git a/tests/run-make/issue-37893/a.rs b/tests/run-make/proc-macro-init-order/a.rs similarity index 100% rename from tests/run-make/issue-37893/a.rs rename to tests/run-make/proc-macro-init-order/a.rs diff --git a/tests/run-make/issue-37893/b.rs b/tests/run-make/proc-macro-init-order/b.rs similarity index 100% rename from tests/run-make/issue-37893/b.rs rename to tests/run-make/proc-macro-init-order/b.rs diff --git a/tests/run-make/issue-37893/c.rs b/tests/run-make/proc-macro-init-order/c.rs similarity index 100% rename from tests/run-make/issue-37893/c.rs rename to tests/run-make/proc-macro-init-order/c.rs diff --git a/tests/run-make/proc-macro-init-order/rmake.rs b/tests/run-make/proc-macro-init-order/rmake.rs new file mode 100644 index 000000000000..3c3fc813381c --- /dev/null +++ b/tests/run-make/proc-macro-init-order/rmake.rs @@ -0,0 +1,15 @@ +// a.rs is a procedural macro crate, on which b.rs and c.rs depend. A now +// patched bug caused a compilation failure if the proc-macro crate was +// initialized with its dependents in this exact order. This test checks +// that compilation succeeds even when initialization is done in this order. +// See https://github.com/rust-lang/rust/issues/37893 + +//@ ignore-cross-compile + +use run_make_support::rustc; + +fn main() { + rustc().input("a.rs").run(); + rustc().input("b.rs").run(); + rustc().input("c.rs").run(); +} diff --git a/tests/run-make/rust-lld-by-default/rmake.rs b/tests/run-make/rust-lld-by-default/rmake.rs index 876968727f3c..6a8dae1043e3 100644 --- a/tests/run-make/rust-lld-by-default/rmake.rs +++ b/tests/run-make/rust-lld-by-default/rmake.rs @@ -4,8 +4,6 @@ //@ needs-rust-lld //@ only-x86_64-unknown-linux-gnu -extern crate run_make_support; - use run_make_support::regex::Regex; use run_make_support::rustc; use std::process::Output; diff --git a/tests/run-make/simple-dylib/Makefile b/tests/run-make/simple-dylib/Makefile deleted file mode 100644 index f3e1c1da88ce..000000000000 --- a/tests/run-make/simple-dylib/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# ignore-cross-compile -include ../tools.mk -all: - $(RUSTC) bar.rs --crate-type=dylib -C prefer-dynamic - $(RUSTC) foo.rs - $(call RUN,foo) diff --git a/tests/run-make/simple-dylib/bar.rs b/tests/run-make/simple-dylib/bar.rs deleted file mode 100644 index c5c0bc606cd6..000000000000 --- a/tests/run-make/simple-dylib/bar.rs +++ /dev/null @@ -1 +0,0 @@ -pub fn bar() {} diff --git a/tests/run-make/simple-dylib/foo.rs b/tests/run-make/simple-dylib/foo.rs deleted file mode 100644 index 8d68535e3b64..000000000000 --- a/tests/run-make/simple-dylib/foo.rs +++ /dev/null @@ -1,5 +0,0 @@ -extern crate bar; - -fn main() { - bar::bar(); -} diff --git a/tests/run-make/simple-rlib/Makefile b/tests/run-make/simple-rlib/Makefile deleted file mode 100644 index 28df61a15478..000000000000 --- a/tests/run-make/simple-rlib/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# ignore-cross-compile -include ../tools.mk -all: - $(RUSTC) bar.rs --crate-type=rlib - $(RUSTC) foo.rs - $(call RUN,foo) diff --git a/tests/run-make/simple-rlib/bar.rs b/tests/run-make/simple-rlib/bar.rs deleted file mode 100644 index c5c0bc606cd6..000000000000 --- a/tests/run-make/simple-rlib/bar.rs +++ /dev/null @@ -1 +0,0 @@ -pub fn bar() {} diff --git a/tests/run-make/simple-rlib/foo.rs b/tests/run-make/simple-rlib/foo.rs deleted file mode 100644 index 8d68535e3b64..000000000000 --- a/tests/run-make/simple-rlib/foo.rs +++ /dev/null @@ -1,5 +0,0 @@ -extern crate bar; - -fn main() { - bar::bar(); -} diff --git a/tests/run-make/used-cdylib-macos/Makefile b/tests/run-make/used-cdylib-macos/Makefile index 38a4c31c7b3a..bdf914a1ca95 100644 --- a/tests/run-make/used-cdylib-macos/Makefile +++ b/tests/run-make/used-cdylib-macos/Makefile @@ -1,9 +1,9 @@ include ../tools.mk -# only-macos +# only-apple # # This checks that `#[used]` passes through to the linker on -# darwin. This is subject to change in the future, see +# Apple targets. This is subject to change in the future, see # https://github.com/rust-lang/rust/pull/93718 for discussion all: diff --git a/tests/run-make/windows-binary-no-external-deps/Makefile b/tests/run-make/windows-binary-no-external-deps/Makefile deleted file mode 100644 index 8960020fed55..000000000000 --- a/tests/run-make/windows-binary-no-external-deps/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -include ../tools.mk - -# only-windows - -PATH=$(SYSTEMROOT)/system32 - -all: - $(RUSTC) hello.rs - $(TMPDIR)/hello.exe diff --git a/tests/run-make/windows-binary-no-external-deps/rmake.rs b/tests/run-make/windows-binary-no-external-deps/rmake.rs new file mode 100644 index 000000000000..6704fe041483 --- /dev/null +++ b/tests/run-make/windows-binary-no-external-deps/rmake.rs @@ -0,0 +1,21 @@ +//! Ensure that we aren't relying on any non-system DLLs when running +//! a "hello world" application by setting `PATH` to `C:\Windows\System32`. +//@ only-windows + +use run_make_support::{rustc, tmp_dir}; +use std::env; +use std::path::PathBuf; +use std::process::Command; + +fn main() { + rustc().input("hello.rs").run(); + + let windows_dir = env::var("SystemRoot").unwrap(); + let system32: PathBuf = [&windows_dir, "System32"].iter().collect(); + // Note: This does not use the support wrappers so that we can precisely control the PATH + let exe = tmp_dir().join("hello.exe"); + let status = Command::new(exe).env("PATH", &system32).spawn().unwrap().wait().unwrap(); + if !status.success() { + panic!("Command failed!\noutput status: `{status}`"); + } +} diff --git a/tests/run-make/windows-safeseh/Makefile b/tests/run-make/windows-safeseh/Makefile deleted file mode 100644 index d6a403961d79..000000000000 --- a/tests/run-make/windows-safeseh/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -# only-windows -# needs-rust-lld - -include ../tools.mk - -all: foo bar - -# Ensure that LLD can link when an .rlib contains a synthetic object -# file referencing exported or used symbols. -foo: - $(RUSTC) -C linker=rust-lld foo.rs - -# Ensure that LLD can link when /WHOLEARCHIVE: is used with an .rlib. -# Previously, lib.rmeta was not marked as (trivially) SAFESEH-aware. -bar: baz - $(RUSTC) -C linker=rust-lld -C link-arg=/WHOLEARCHIVE:libbaz.rlib bar.rs - -baz: - $(RUSTC) baz.rs diff --git a/tests/run-make/windows-safeseh/rmake.rs b/tests/run-make/windows-safeseh/rmake.rs new file mode 100644 index 000000000000..10e6b38aa8df --- /dev/null +++ b/tests/run-make/windows-safeseh/rmake.rs @@ -0,0 +1,15 @@ +//@ only-windows +//@ needs-rust-lld + +use run_make_support::rustc; + +fn main() { + // Ensure that LLD can link when an .rlib contains a synthetic object + // file referencing exported or used symbols. + rustc().input("foo.rs").linker("rust-lld").run(); + + // Ensure that LLD can link when /WHOLEARCHIVE: is used with an .rlib. + // Previously, lib.rmeta was not marked as (trivially) SAFESEH-aware. + rustc().input("baz.rs").run(); + rustc().input("bar.rs").linker("rust-lld").link_arg("/WHOLEARCHIVE:libbaz.rlib").run(); +} diff --git a/tests/run-make/windows-spawn/Makefile b/tests/run-make/windows-spawn/Makefile deleted file mode 100644 index b6cdb169bab4..000000000000 --- a/tests/run-make/windows-spawn/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -include ../tools.mk - -# only-windows - -all: - $(RUSTC) -o "$(TMPDIR)/hopefullydoesntexist bar.exe" hello.rs - $(RUSTC) spawn.rs - $(TMPDIR)/spawn.exe diff --git a/tests/run-make/windows-spawn/rmake.rs b/tests/run-make/windows-spawn/rmake.rs new file mode 100644 index 000000000000..fb9cf1e21490 --- /dev/null +++ b/tests/run-make/windows-spawn/rmake.rs @@ -0,0 +1,17 @@ +//@ only-windows + +use run_make_support::{run, rustc, tmp_dir}; + +// On Windows `Command` uses `CreateProcessW` to run a new process. +// However, in the past std used to not pass in the application name, leaving +// `CreateProcessW` to use heuristics to guess the intended name from the +// command line string. Sometimes this could go very wrong. +// E.g. in Rust 1.0 `Command::new("foo").arg("bar").spawn()` will try to launch +// `foo bar.exe` if foo.exe does not exist. Which is clearly not desired. + +fn main() { + let out_dir = tmp_dir(); + rustc().input("hello.rs").output(out_dir.join("hopefullydoesntexist bar.exe")).run(); + rustc().input("spawn.rs").run(); + run("spawn"); +} diff --git a/tests/run-make/windows-spawn/spawn.rs b/tests/run-make/windows-spawn/spawn.rs index c34da3d5fde4..a9e86d1577e5 100644 --- a/tests/run-make/windows-spawn/spawn.rs +++ b/tests/run-make/windows-spawn/spawn.rs @@ -3,10 +3,8 @@ use std::process::Command; fn main() { // Make sure it doesn't try to run "hopefullydoesntexist bar.exe". - assert_eq!(Command::new("hopefullydoesntexist") - .arg("bar") - .spawn() - .unwrap_err() - .kind(), - ErrorKind::NotFound); + assert_eq!( + Command::new("hopefullydoesntexist").arg("bar").spawn().unwrap_err().kind(), + ErrorKind::NotFound + ) } diff --git a/tests/run-make/windows-subsystem/Makefile b/tests/run-make/windows-subsystem/Makefile deleted file mode 100644 index e3cf9181de41..000000000000 --- a/tests/run-make/windows-subsystem/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: - $(RUSTC) windows.rs - $(RUSTC) console.rs diff --git a/tests/run-make/issue-85441/empty.rs b/tests/run-make/windows-ws2_32/empty.rs similarity index 100% rename from tests/run-make/issue-85441/empty.rs rename to tests/run-make/windows-ws2_32/empty.rs diff --git a/tests/run-make/windows-ws2_32/rmake.rs b/tests/run-make/windows-ws2_32/rmake.rs new file mode 100644 index 000000000000..543f8594478c --- /dev/null +++ b/tests/run-make/windows-ws2_32/rmake.rs @@ -0,0 +1,27 @@ +//@ only-msvc + +// Tests that WS2_32.dll is not unnecessarily linked, see issue #85441 + +use run_make_support::object::{self, read::Object}; +use run_make_support::{rustc, tmp_dir}; +use std::fs; + +fn main() { + rustc().input("empty.rs").run(); + rustc().input("tcp.rs").run(); + + assert!(!links_ws2_32("empty.exe")); + assert!(links_ws2_32("tcp.exe")); +} + +fn links_ws2_32(exe: &str) -> bool { + let path = tmp_dir().join(exe); + let binary_data = fs::read(path).unwrap(); + let file = object::File::parse(&*binary_data).unwrap(); + for import in file.imports().unwrap() { + if import.library().eq_ignore_ascii_case(b"WS2_32.dll") { + return true; + } + } + false +} diff --git a/tests/run-make/windows-ws2_32/tcp.rs b/tests/run-make/windows-ws2_32/tcp.rs new file mode 100644 index 000000000000..3d0248c76d78 --- /dev/null +++ b/tests/run-make/windows-ws2_32/tcp.rs @@ -0,0 +1,5 @@ +use std::net::TcpListener; + +fn main() { + TcpListener::bind("127.0.0.1:80").unwrap(); +} diff --git a/tests/run-pass-valgrind/exit-flushes.rs b/tests/run-pass-valgrind/exit-flushes.rs index fa9196a3eecb..c2072cf0bf83 100644 --- a/tests/run-pass-valgrind/exit-flushes.rs +++ b/tests/run-pass-valgrind/exit-flushes.rs @@ -1,6 +1,6 @@ //@ ignore-wasm32 no subprocess support //@ ignore-sgx no processes -//@ ignore-macos this needs valgrind 3.11 or higher; see +//@ ignore-apple this needs valgrind 3.11 or higher; see // https://github.com/rust-lang/rust/pull/30365#issuecomment-165763679 use std::env; @@ -11,8 +11,7 @@ fn main() { print!("hello!"); exit(0); } else { - let out = Command::new(env::args().next().unwrap()).arg("foo") - .output().unwrap(); + let out = Command::new(env::args().next().unwrap()).arg("foo").output().unwrap(); assert!(out.status.success()); assert_eq!(String::from_utf8(out.stdout).unwrap(), "hello!"); assert_eq!(String::from_utf8(out.stderr).unwrap(), ""); diff --git a/tests/rustdoc-ui/doctest/non_local_defs.stderr b/tests/rustdoc-ui/doctest/non_local_defs.stderr index 39a25de1aae7..2b47e6b5bc4d 100644 --- a/tests/rustdoc-ui/doctest/non_local_defs.stderr +++ b/tests/rustdoc-ui/doctest/non_local_defs.stderr @@ -1,4 +1,4 @@ -warning: non-local `macro_rules!` definition, they should be avoided as they go against expectation +warning: non-local `macro_rules!` definition, `#[macro_export]` macro should be written at top level module --> $DIR/non_local_defs.rs:9:1 | LL | macro_rules! a_macro { () => {} } @@ -6,7 +6,6 @@ LL | macro_rules! a_macro { () => {} } | = help: remove the `#[macro_export]` or make this doc-test a standalone test with its own `fn main() { ... }` = note: a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue = note: `#[warn(non_local_definitions)]` on by default diff --git a/tests/ui/abi/compatibility.rs b/tests/ui/abi/compatibility.rs index 373d1cce1d73..c27a107a639f 100644 --- a/tests/ui/abi/compatibility.rs +++ b/tests/ui/abi/compatibility.rs @@ -52,17 +52,16 @@ //@ revisions: m68k //@[m68k] compile-flags: --target m68k-unknown-linux-gnu //@[m68k] needs-llvm-components: m68k +//@ revisions: csky +//@[csky] compile-flags: --target csky-unknown-linux-gnuabiv2 +//@[csky] needs-llvm-components: csky + // FIXME: disabled on nvptx64 since the target ABI fails the sanity check // see https://github.com/rust-lang/rust/issues/117480 /* revisions: nvptx64 [nvptx64] compile-flags: --target nvptx64-nvidia-cuda [nvptx64] needs-llvm-components: nvptx */ -// FIXME: disabled since it fails on CI saying the csky component is missing -/* revisions: csky - [csky] compile-flags: --target csky-unknown-linux-gnuabiv2 - [csky] needs-llvm-components: csky -*/ #![feature(rustc_attrs, unsized_fn_params, transparent_unions)] #![cfg_attr(not(host), feature(no_core, lang_items), no_std, no_core)] #![allow(unused, improper_ctypes_definitions, internal_features)] @@ -74,8 +73,7 @@ #[cfg(host)] use std::{ - any::Any, marker::PhantomData, mem::ManuallyDrop, num::NonZero, ptr::NonNull, rc::Rc, - sync::Arc, + any::Any, marker::PhantomData, mem::ManuallyDrop, num::NonZero, ptr::NonNull, rc::Rc, sync::Arc, }; /// To work cross-target this test must be no_core. diff --git a/tests/ui/abi/fixed_x18.rs b/tests/ui/abi/fixed_x18.rs new file mode 100644 index 000000000000..f1ff3e1d5341 --- /dev/null +++ b/tests/ui/abi/fixed_x18.rs @@ -0,0 +1,25 @@ +// This tests that -Zfixed-x18 causes a compilation failure on targets other than aarch64. +// Behavior on aarch64 is tested by tests/codegen/fixed-x18.rs. +// +//@ revisions: x64 i686 arm riscv32 riscv64 +//@ error-pattern: the `-Zfixed-x18` flag is not supported +//@ dont-check-compiler-stderr +// +//@ compile-flags: -Zfixed-x18 +//@ [x64] needs-llvm-components: x86 +//@ [x64] compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=rlib +//@ [i686] needs-llvm-components: x86 +//@ [i686] compile-flags: --target=i686-unknown-linux-gnu --crate-type=rlib +//@ [arm] needs-llvm-components: arm +//@ [arm] compile-flags: --target=armv7-unknown-linux-gnueabihf --crate-type=rlib +//@ [riscv32] needs-llvm-components: riscv +//@ [riscv32] compile-flags: --target=riscv32i-unknown-none-elf --crate-type=rlib +//@ [riscv64] needs-llvm-components: riscv +//@ [riscv64] compile-flags: --target=riscv64gc-unknown-none-elf --crate-type=rlib + +#![crate_type = "lib"] +#![feature(no_core, lang_items)] +#![no_core] + +#[lang = "sized"] +trait Sized {} diff --git a/tests/ui/abi/stack-probes-lto.rs b/tests/ui/abi/stack-probes-lto.rs index 5451b72d9792..70343b0599ac 100644 --- a/tests/ui/abi/stack-probes-lto.rs +++ b/tests/ui/abi/stack-probes-lto.rs @@ -10,5 +10,9 @@ //@ compile-flags: -C lto //@ no-prefer-dynamic //@ ignore-nto Crash analysis impossible at SIGSEGV in QNX Neutrino +//@ ignore-ios Stack probes are enabled, but the SIGSEGV handler isn't +//@ ignore-tvos Stack probes are enabled, but the SIGSEGV handler isn't +//@ ignore-watchos Stack probes are enabled, but the SIGSEGV handler isn't +//@ ignore-visionos Stack probes are enabled, but the SIGSEGV handler isn't include!("stack-probes.rs"); diff --git a/tests/ui/abi/stack-probes.rs b/tests/ui/abi/stack-probes.rs index 32d4d6cd31e6..22304257593f 100644 --- a/tests/ui/abi/stack-probes.rs +++ b/tests/ui/abi/stack-probes.rs @@ -8,6 +8,10 @@ //@ ignore-sgx no processes //@ ignore-fuchsia no exception handler registered for segfault //@ ignore-nto Crash analysis impossible at SIGSEGV in QNX Neutrino +//@ ignore-ios Stack probes are enabled, but the SIGSEGV handler isn't +//@ ignore-tvos Stack probes are enabled, but the SIGSEGV handler isn't +//@ ignore-watchos Stack probes are enabled, but the SIGSEGV handler isn't +//@ ignore-visionos Stack probes are enabled, but the SIGSEGV handler isn't use std::env; use std::mem::MaybeUninit; diff --git a/tests/ui/associated-types/defaults-unsound-62211-1.next.stderr b/tests/ui/associated-types/defaults-unsound-62211-1.next.stderr index 834ae00a8d85..ffb02eccc77d 100644 --- a/tests/ui/associated-types/defaults-unsound-62211-1.next.stderr +++ b/tests/ui/associated-types/defaults-unsound-62211-1.next.stderr @@ -6,8 +6,12 @@ LL | drop(origin); | | | argument has type `::Output` | - = note: use `let _ = ...` to ignore the expression or result = note: `#[warn(dropping_copy_types)]` on by default +help: use `let _ = ...` to ignore the expression or result + | +LL - drop(origin); +LL + let _ = origin; + | warning: 1 warning emitted diff --git a/tests/ui/associated-types/defaults-unsound-62211-2.next.stderr b/tests/ui/associated-types/defaults-unsound-62211-2.next.stderr index 0f944a18ed58..e6ae8183e77d 100644 --- a/tests/ui/associated-types/defaults-unsound-62211-2.next.stderr +++ b/tests/ui/associated-types/defaults-unsound-62211-2.next.stderr @@ -6,8 +6,12 @@ LL | drop(origin); | | | argument has type `::Output` | - = note: use `let _ = ...` to ignore the expression or result = note: `#[warn(dropping_copy_types)]` on by default +help: use `let _ = ...` to ignore the expression or result + | +LL - drop(origin); +LL + let _ = origin; + | warning: 1 warning emitted diff --git a/tests/ui/attributes/key-value-expansion-scope.rs b/tests/ui/attributes/key-value-expansion-scope.rs new file mode 100644 index 000000000000..b84fe4873c37 --- /dev/null +++ b/tests/ui/attributes/key-value-expansion-scope.rs @@ -0,0 +1,64 @@ +#![doc = in_root!()] // FIXME, this is a bug +#![doc = in_mod!()] //~ ERROR cannot find macro `in_mod` in this scope +#![doc = in_mod_escape!()] // FIXME, this is a bug +#![doc = in_block!()] //~ ERROR cannot find macro `in_block` in this scope + +#[doc = in_root!()] //~ ERROR cannot find macro `in_root` in this scope +#[doc = in_mod!()] //~ ERROR cannot find macro `in_mod` in this scope +#[doc = in_mod_escape!()] //~ ERROR cannot find macro `in_mod_escape` in this scope +#[doc = in_block!()] //~ ERROR cannot find macro `in_block` in this scope +fn before() { + #![doc = in_root!()] //~ ERROR cannot find macro `in_root` in this scope + #![doc = in_mod!()] //~ ERROR cannot find macro `in_mod` in this scope + #![doc = in_mod_escape!()] //~ ERROR cannot find macro `in_mod_escape` in this scope + #![doc = in_block!()] //~ ERROR cannot find macro `in_block` in this scope +} + +macro_rules! in_root { () => { "" } } + +mod macros_stay { + #![doc = in_mod!()] // FIXME, this is a bug + + macro_rules! in_mod { () => { "" } } + + #[doc = in_mod!()] // OK + fn f() { + #![doc = in_mod!()] // OK + } +} + +#[macro_use] +mod macros_escape { + #![doc = in_mod_escape!()] // FIXME, this is a bug + + macro_rules! in_mod_escape { () => { "" } } + + #[doc = in_mod_escape!()] // OK + fn f() { + #![doc = in_mod_escape!()] // OK + } +} + +fn block() { + #![doc = in_block!()] //~ ERROR cannot find macro `in_block` in this scope + + macro_rules! in_block { () => { "" } } + + #[doc = in_block!()] // OK + fn f() { + #![doc = in_block!()] // OK + } +} + +#[doc = in_root!()] // OK +#[doc = in_mod!()] //~ ERROR cannot find macro `in_mod` in this scope +#[doc = in_mod_escape!()] // OK +#[doc = in_block!()] //~ ERROR cannot find macro `in_block` in this scope +fn after() { + #![doc = in_root!()] // OK + #![doc = in_mod!()] //~ ERROR cannot find macro `in_mod` in this scope + #![doc = in_mod_escape!()] // OK + #![doc = in_block!()] //~ ERROR cannot find macro `in_block` in this scope +} + +fn main() {} diff --git a/tests/ui/attributes/key-value-expansion-scope.stderr b/tests/ui/attributes/key-value-expansion-scope.stderr new file mode 100644 index 000000000000..a66ee9b17fb9 --- /dev/null +++ b/tests/ui/attributes/key-value-expansion-scope.stderr @@ -0,0 +1,122 @@ +error: cannot find macro `in_mod` in this scope + --> $DIR/key-value-expansion-scope.rs:2:10 + | +LL | #![doc = in_mod!()] + | ^^^^^^ + | + = help: have you added the `#[macro_use]` on the module/import? + +error: cannot find macro `in_block` in this scope + --> $DIR/key-value-expansion-scope.rs:4:10 + | +LL | #![doc = in_block!()] + | ^^^^^^^^ + | + = help: have you added the `#[macro_use]` on the module/import? + +error: cannot find macro `in_root` in this scope + --> $DIR/key-value-expansion-scope.rs:6:9 + | +LL | #[doc = in_root!()] + | ^^^^^^^ + | + = help: have you added the `#[macro_use]` on the module/import? + +error: cannot find macro `in_mod` in this scope + --> $DIR/key-value-expansion-scope.rs:7:9 + | +LL | #[doc = in_mod!()] + | ^^^^^^ + | + = help: have you added the `#[macro_use]` on the module/import? + +error: cannot find macro `in_mod_escape` in this scope + --> $DIR/key-value-expansion-scope.rs:8:9 + | +LL | #[doc = in_mod_escape!()] + | ^^^^^^^^^^^^^ + | + = help: have you added the `#[macro_use]` on the module/import? + +error: cannot find macro `in_block` in this scope + --> $DIR/key-value-expansion-scope.rs:9:9 + | +LL | #[doc = in_block!()] + | ^^^^^^^^ + | + = help: have you added the `#[macro_use]` on the module/import? + +error: cannot find macro `in_root` in this scope + --> $DIR/key-value-expansion-scope.rs:11:14 + | +LL | #![doc = in_root!()] + | ^^^^^^^ + | + = help: have you added the `#[macro_use]` on the module/import? + +error: cannot find macro `in_mod` in this scope + --> $DIR/key-value-expansion-scope.rs:12:14 + | +LL | #![doc = in_mod!()] + | ^^^^^^ + | + = help: have you added the `#[macro_use]` on the module/import? + +error: cannot find macro `in_mod_escape` in this scope + --> $DIR/key-value-expansion-scope.rs:13:14 + | +LL | #![doc = in_mod_escape!()] + | ^^^^^^^^^^^^^ + | + = help: have you added the `#[macro_use]` on the module/import? + +error: cannot find macro `in_block` in this scope + --> $DIR/key-value-expansion-scope.rs:14:14 + | +LL | #![doc = in_block!()] + | ^^^^^^^^ + | + = help: have you added the `#[macro_use]` on the module/import? + +error: cannot find macro `in_block` in this scope + --> $DIR/key-value-expansion-scope.rs:43:14 + | +LL | #![doc = in_block!()] + | ^^^^^^^^ + | + = help: have you added the `#[macro_use]` on the module/import? + +error: cannot find macro `in_mod` in this scope + --> $DIR/key-value-expansion-scope.rs:54:9 + | +LL | #[doc = in_mod!()] + | ^^^^^^ + | + = help: have you added the `#[macro_use]` on the module/import? + +error: cannot find macro `in_block` in this scope + --> $DIR/key-value-expansion-scope.rs:56:9 + | +LL | #[doc = in_block!()] + | ^^^^^^^^ + | + = help: have you added the `#[macro_use]` on the module/import? + +error: cannot find macro `in_mod` in this scope + --> $DIR/key-value-expansion-scope.rs:59:14 + | +LL | #![doc = in_mod!()] + | ^^^^^^ + | + = help: have you added the `#[macro_use]` on the module/import? + +error: cannot find macro `in_block` in this scope + --> $DIR/key-value-expansion-scope.rs:61:14 + | +LL | #![doc = in_block!()] + | ^^^^^^^^ + | + = help: have you added the `#[macro_use]` on the module/import? + +error: aborting due to 15 previous errors + diff --git a/tests/ui/backtrace/apple-no-dsymutil.rs b/tests/ui/backtrace/apple-no-dsymutil.rs index 9924cd13b0a7..e5aeced25ca3 100644 --- a/tests/ui/backtrace/apple-no-dsymutil.rs +++ b/tests/ui/backtrace/apple-no-dsymutil.rs @@ -2,7 +2,7 @@ //@ compile-flags:-Cstrip=none //@ compile-flags:-g -Csplit-debuginfo=unpacked -//@ only-macos +//@ only-apple use std::process::Command; use std::str; diff --git a/tests/ui/coherence/coherence-overlap-unnormalizable-projection-1.next.stderr b/tests/ui/coherence/coherence-overlap-unnormalizable-projection-1.next.stderr index 49b236f9d2aa..781ab0fcbf76 100644 --- a/tests/ui/coherence/coherence-overlap-unnormalizable-projection-1.next.stderr +++ b/tests/ui/coherence/coherence-overlap-unnormalizable-projection-1.next.stderr @@ -12,7 +12,7 @@ LL | impl Trait for Box {} | ^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Box<_>` | = note: downstream crates may implement trait `WithAssoc<'a>` for type `std::boxed::Box<_>` - = note: downstream crates may implement trait `WhereBound` for type `std::boxed::Box< as WithAssoc<'a>>::Assoc>` + = note: downstream crates may implement trait `WhereBound` for type `std::boxed::Box<_>` error: aborting due to 1 previous error diff --git a/tests/ui/coherence/occurs-check/opaques.next.stderr b/tests/ui/coherence/occurs-check/opaques.next.stderr index f6c5255a1869..11d1edcca2f9 100644 --- a/tests/ui/coherence/occurs-check/opaques.next.stderr +++ b/tests/ui/coherence/occurs-check/opaques.next.stderr @@ -11,7 +11,7 @@ error[E0282]: type annotations needed --> $DIR/opaques.rs:13:20 | LL | pub fn cast(x: Container, T>) -> Container { - | ^ cannot infer type for associated type `>::Assoc` + | ^ cannot infer type error: aborting due to 2 previous errors diff --git a/tests/ui/deployment-target/macos-target.rs b/tests/ui/deployment-target/macos-target.rs index be2c32e28141..197edd024746 100644 --- a/tests/ui/deployment-target/macos-target.rs +++ b/tests/ui/deployment-target/macos-target.rs @@ -1,4 +1,4 @@ -//@ only-macos +//@ only-apple //@ compile-flags: --print deployment-target //@ normalize-stdout-test: "\d+\." -> "$$CURRENT_MAJOR_VERSION." //@ normalize-stdout-test: "\d+" -> "$$CURRENT_MINOR_VERSION" diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr index 47acf5b968b7..568cb8931a19 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr +++ b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr @@ -16,6 +16,22 @@ LL | where LL | T: AsExpression, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo::check` -error: aborting due to 1 previous error +error[E0277]: the trait bound `&str: AsExpression` is not satisfied + --> $DIR/as_expression.rs:57:15 + | +LL | SelectInt.check("bar"); + | ^^^^^ the trait `AsExpression` is not implemented for `&str` + | + = help: the trait `AsExpression` is implemented for `&str` + = help: for that trait implementation, expected `Text`, found `Integer` -For more information about this error, try `rustc --explain E0277`. +error[E0271]: type mismatch resolving `<&str as AsExpression<::SqlType>>::Expression == _` + --> $DIR/as_expression.rs:57:5 + | +LL | SelectInt.check("bar"); + | ^^^^^^^^^^^^^^^^^^^^^^ types differ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0271, E0277. +For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs index 5fd5cc544009..37b4429f694c 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs +++ b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs @@ -55,6 +55,7 @@ impl Foo for T where T: Expression {} fn main() { SelectInt.check("bar"); - //[next]~^ ERROR the trait bound `&str: AsExpression<::SqlType>` is not satisfied - //[current]~^^ ERROR the trait bound `&str: AsExpression` is not satisfied + //~^ ERROR the trait bound `&str: AsExpression` is not satisfied + //[next]~| the trait bound `&str: AsExpression<::SqlType>` is not satisfied + //[next]~| type mismatch } diff --git a/tests/ui/errors/pic-linker.rs b/tests/ui/errors/pic-linker.rs new file mode 100644 index 000000000000..d90989903048 --- /dev/null +++ b/tests/ui/errors/pic-linker.rs @@ -0,0 +1,12 @@ +// `-z text` caused the linker to error if there were any non-position-independent +// code (PIC) sections. This test checks that this no longer happens. +// See https://github.com/rust-lang/rust/pull/39803 + +//@ ignore-windows +//@ ignore-macos +//@ ignore-cross-compile + +//@ compile-flags: -Clink-args=-Wl,-z,text +//@ run-pass + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-optimize_attribute.stderr b/tests/ui/feature-gates/feature-gate-optimize_attribute.stderr index 9bab366f7fef..815013733a98 100644 --- a/tests/ui/feature-gates/feature-gate-optimize_attribute.stderr +++ b/tests/ui/feature-gates/feature-gate-optimize_attribute.stderr @@ -1,13 +1,3 @@ -error[E0658]: the `#[optimize]` attribute is an experimental feature - --> $DIR/feature-gate-optimize_attribute.rs:4:1 - | -LL | #[optimize(size)] - | ^^^^^^^^^^^^^^^^^ - | - = note: see issue #54882 for more information - = help: add `#![feature(optimize_attribute)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - error[E0658]: the `#[optimize]` attribute is an experimental feature --> $DIR/feature-gate-optimize_attribute.rs:7:1 | @@ -38,6 +28,16 @@ LL | #[optimize(banana)] = help: add `#![feature(optimize_attribute)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +error[E0658]: the `#[optimize]` attribute is an experimental feature + --> $DIR/feature-gate-optimize_attribute.rs:4:1 + | +LL | #[optimize(size)] + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #54882 for more information + = help: add `#![feature(optimize_attribute)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + error[E0658]: the `#[optimize]` attribute is an experimental feature --> $DIR/feature-gate-optimize_attribute.rs:2:1 | diff --git a/tests/ui/feature-gates/feature-gate-print-check-cfg.rs b/tests/ui/feature-gates/feature-gate-print-check-cfg.rs new file mode 100644 index 000000000000..304e0c132e50 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-print-check-cfg.rs @@ -0,0 +1,3 @@ +//@ compile-flags: --print=check-cfg + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-print-check-cfg.stderr b/tests/ui/feature-gates/feature-gate-print-check-cfg.stderr new file mode 100644 index 000000000000..62ee44b94a48 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-print-check-cfg.stderr @@ -0,0 +1,2 @@ +error: the `-Z unstable-options` flag must also be passed to enable the check-cfg print option + diff --git a/tests/ui/feature-gates/issue-43106-gating-of-stable.stderr b/tests/ui/feature-gates/issue-43106-gating-of-stable.stderr index e4cc088e2cd3..677fef3a926b 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-stable.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-stable.stderr @@ -1,9 +1,3 @@ -error[E0734]: stability attributes may not be used outside of the standard library - --> $DIR/issue-43106-gating-of-stable.rs:10:1 - | -LL | #[stable()] - | ^^^^^^^^^^^ - error[E0734]: stability attributes may not be used outside of the standard library --> $DIR/issue-43106-gating-of-stable.rs:14:9 | @@ -34,6 +28,12 @@ error[E0734]: stability attributes may not be used outside of the standard libra LL | #[stable()] | ^^^^^^^^^^^ +error[E0734]: stability attributes may not be used outside of the standard library + --> $DIR/issue-43106-gating-of-stable.rs:10:1 + | +LL | #[stable()] + | ^^^^^^^^^^^ + error[E0734]: stability attributes may not be used outside of the standard library --> $DIR/issue-43106-gating-of-stable.rs:7:1 | diff --git a/tests/ui/feature-gates/issue-43106-gating-of-unstable.stderr b/tests/ui/feature-gates/issue-43106-gating-of-unstable.stderr index f7c6e631cd17..a2f361878c6d 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-unstable.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-unstable.stderr @@ -1,9 +1,3 @@ -error[E0734]: stability attributes may not be used outside of the standard library - --> $DIR/issue-43106-gating-of-unstable.rs:10:1 - | -LL | #[unstable()] - | ^^^^^^^^^^^^^ - error[E0734]: stability attributes may not be used outside of the standard library --> $DIR/issue-43106-gating-of-unstable.rs:14:9 | @@ -34,6 +28,12 @@ error[E0734]: stability attributes may not be used outside of the standard libra LL | #[unstable()] | ^^^^^^^^^^^^^ +error[E0734]: stability attributes may not be used outside of the standard library + --> $DIR/issue-43106-gating-of-unstable.rs:10:1 + | +LL | #[unstable()] + | ^^^^^^^^^^^^^ + error[E0734]: stability attributes may not be used outside of the standard library --> $DIR/issue-43106-gating-of-unstable.rs:7:1 | diff --git a/tests/ui/imports/auxiliary/simple-dylib.rs b/tests/ui/imports/auxiliary/simple-dylib.rs new file mode 100644 index 000000000000..af64aa66f31b --- /dev/null +++ b/tests/ui/imports/auxiliary/simple-dylib.rs @@ -0,0 +1,4 @@ +//@ compile-flags: -Cprefer-dynamic + +#![crate_type = "dylib"] +pub fn bar() {} diff --git a/tests/ui/imports/auxiliary/simple-rlib.rs b/tests/ui/imports/auxiliary/simple-rlib.rs new file mode 100644 index 000000000000..28a6273840f6 --- /dev/null +++ b/tests/ui/imports/auxiliary/simple-rlib.rs @@ -0,0 +1,2 @@ +#![crate_type = "rlib"] +pub fn bar() {} diff --git a/tests/ui/imports/import-from-missing-star-2.rs b/tests/ui/imports/import-from-missing-star-2.rs new file mode 100644 index 000000000000..cb341b0b0ca4 --- /dev/null +++ b/tests/ui/imports/import-from-missing-star-2.rs @@ -0,0 +1,12 @@ +mod foo { + use spam::*; //~ ERROR unresolved import `spam` [E0432] +} + +fn main() { + // Expect this to pass because the compiler knows there's a failed `*` import in `foo` that + // might have caused it. + foo::bar(); + // FIXME: these two should *fail* because they can't be fixed by fixing the glob import in `foo` + ham(); // should error but doesn't + eggs(); // should error but doesn't +} diff --git a/tests/ui/imports/import-from-missing-star-2.stderr b/tests/ui/imports/import-from-missing-star-2.stderr new file mode 100644 index 000000000000..ea3876248c93 --- /dev/null +++ b/tests/ui/imports/import-from-missing-star-2.stderr @@ -0,0 +1,11 @@ +error[E0432]: unresolved import `spam` + --> $DIR/import-from-missing-star-2.rs:2:9 + | +LL | use spam::*; + | ^^^^ maybe a missing crate `spam`? + | + = help: consider adding `extern crate spam` to use the `spam` crate + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/imports/import-from-missing-star-3.rs b/tests/ui/imports/import-from-missing-star-3.rs new file mode 100644 index 000000000000..bec51fd47b37 --- /dev/null +++ b/tests/ui/imports/import-from-missing-star-3.rs @@ -0,0 +1,43 @@ +mod foo { + use spam::*; //~ ERROR unresolved import `spam` [E0432] + + fn x() { + // Expect these to pass because the compiler knows there's a failed `*` import that might + // fix it. + eggs(); + foo::bar(); + } +} + +mod bar { + fn z() {} + fn x() { + // Expect these to pass because the compiler knows there's a failed `*` import that might + // fix it. + foo::bar(); + z(); + // FIXME: should error but doesn't because as soon as there's a single glob import error, we + // silence all resolve errors. + eggs(); + } +} + +mod baz { + fn x() { + use spam::*; //~ ERROR unresolved import `spam` [E0432] + fn qux() {} + qux(); + // Expect this to pass because the compiler knows there's a local failed `*` import that + // might have caused it. + eggs(); + // Expect this to pass because the compiler knows there's a failed `*` import in `foo` that + // might have caused it. + foo::bar(); + } +} + +fn main() { + // FIXME: should error but doesn't because as soon as there's a single glob import error, we + // silence all resolve errors. + ham(); +} diff --git a/tests/ui/imports/import-from-missing-star-3.stderr b/tests/ui/imports/import-from-missing-star-3.stderr new file mode 100644 index 000000000000..1fe5d4f19a97 --- /dev/null +++ b/tests/ui/imports/import-from-missing-star-3.stderr @@ -0,0 +1,19 @@ +error[E0432]: unresolved import `spam` + --> $DIR/import-from-missing-star-3.rs:2:9 + | +LL | use spam::*; + | ^^^^ maybe a missing crate `spam`? + | + = help: consider adding `extern crate spam` to use the `spam` crate + +error[E0432]: unresolved import `spam` + --> $DIR/import-from-missing-star-3.rs:27:13 + | +LL | use spam::*; + | ^^^^ maybe a missing crate `spam`? + | + = help: consider adding `extern crate spam` to use the `spam` crate + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/imports/import-from-missing-star.rs b/tests/ui/imports/import-from-missing-star.rs new file mode 100644 index 000000000000..cb21e16ba677 --- /dev/null +++ b/tests/ui/imports/import-from-missing-star.rs @@ -0,0 +1,10 @@ +use spam::*; //~ ERROR unresolved import `spam` [E0432] + +fn main() { + // Expect these to pass because the compiler knows there's a failed `*` import that might have + // caused it. + ham(); + eggs(); + // Even this case, as we might have expected `spam::foo` to exist. + foo::bar(); +} diff --git a/tests/ui/imports/import-from-missing-star.stderr b/tests/ui/imports/import-from-missing-star.stderr new file mode 100644 index 000000000000..f8e295078047 --- /dev/null +++ b/tests/ui/imports/import-from-missing-star.stderr @@ -0,0 +1,11 @@ +error[E0432]: unresolved import `spam` + --> $DIR/import-from-missing-star.rs:1:5 + | +LL | use spam::*; + | ^^^^ maybe a missing crate `spam`? + | + = help: consider adding `extern crate spam` to use the `spam` crate + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/imports/issue-31212.rs b/tests/ui/imports/issue-31212.rs index 556f0d18f9f2..fe69c5af2706 100644 --- a/tests/ui/imports/issue-31212.rs +++ b/tests/ui/imports/issue-31212.rs @@ -6,5 +6,5 @@ mod foo { } fn main() { - foo::f(); //~ ERROR cannot find function `f` in module `foo` + foo::f(); // cannot find function `f` in module `foo`, but silenced } diff --git a/tests/ui/imports/issue-31212.stderr b/tests/ui/imports/issue-31212.stderr index 0bb56b361cbb..5bba791fd020 100644 --- a/tests/ui/imports/issue-31212.stderr +++ b/tests/ui/imports/issue-31212.stderr @@ -4,13 +4,6 @@ error[E0432]: unresolved import `self::*` LL | pub use self::*; | ^^^^^^^ cannot glob-import a module into itself -error[E0425]: cannot find function `f` in module `foo` - --> $DIR/issue-31212.rs:9:10 - | -LL | foo::f(); - | ^ not found in `foo` +error: aborting due to 1 previous error -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0425, E0432. -For more information about an error, try `rustc --explain E0425`. +For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/imports/simple-dylib-import.rs b/tests/ui/imports/simple-dylib-import.rs new file mode 100644 index 000000000000..d8ee3496b90d --- /dev/null +++ b/tests/ui/imports/simple-dylib-import.rs @@ -0,0 +1,12 @@ +// A simple test, where foo.rs has a dependency +// on the dynamic library simple-dylib.rs. If the test passes, +// dylibs can be built and linked into another file successfully.. + +//@ aux-crate:bar=simple-dylib.rs +//@ run-pass + +extern crate bar; + +fn main() { + bar::bar(); +} diff --git a/tests/ui/imports/simple-rlib-import.rs b/tests/ui/imports/simple-rlib-import.rs new file mode 100644 index 000000000000..6eab7ba04cfa --- /dev/null +++ b/tests/ui/imports/simple-rlib-import.rs @@ -0,0 +1,12 @@ +// A simple test, where foo.rs has a dependency +// on the rlib (a static Rust-specific library format) bar.rs. If the test passes, +// rlibs can be built and linked into another file successfully.. + +//@ aux-crate:bar=simple-rlib.rs +//@ run-pass + +extern crate bar; + +fn main() { + bar::bar(); +} diff --git a/tests/ui/inference/str-as-char-butchered.rs b/tests/ui/inference/str-as-char-butchered.rs new file mode 100644 index 000000000000..6020cd3422fd --- /dev/null +++ b/tests/ui/inference/str-as-char-butchered.rs @@ -0,0 +1,7 @@ +// issue: rust-lang/rust#125081 + +fn main() { + let _: &str = 'β; + //~^ ERROR expected `while`, `for`, `loop` or `{` after a label + //~| ERROR mismatched types +} diff --git a/tests/ui/inference/str-as-char-butchered.stderr b/tests/ui/inference/str-as-char-butchered.stderr new file mode 100644 index 000000000000..ad465f979d4d --- /dev/null +++ b/tests/ui/inference/str-as-char-butchered.stderr @@ -0,0 +1,22 @@ +error: expected `while`, `for`, `loop` or `{` after a label + --> $DIR/str-as-char-butchered.rs:4:21 + | +LL | let _: &str = 'β; + | ^ expected `while`, `for`, `loop` or `{` after a label + | +help: add `'` to close the char literal + | +LL | let _: &str = 'β'; + | + + +error[E0308]: mismatched types + --> $DIR/str-as-char-butchered.rs:4:19 + | +LL | let _: &str = 'β; + | ---- ^^ expected `&str`, found `char` + | | + | expected due to this + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/inference/str-as-char-non-lit.rs b/tests/ui/inference/str-as-char-non-lit.rs new file mode 100644 index 000000000000..d38b46630dcf --- /dev/null +++ b/tests/ui/inference/str-as-char-non-lit.rs @@ -0,0 +1,9 @@ +// Don't suggest double quotes when encountering an expr of type `char` where a `&str` +// is expected if the expr is not a char literal. +// issue: rust-lang/rust#125595 + +fn main() { + let _: &str = ('a'); //~ ERROR mismatched types + let token = || 'a'; + let _: &str = token(); //~ ERROR mismatched types +} diff --git a/tests/ui/inference/str-as-char-non-lit.stderr b/tests/ui/inference/str-as-char-non-lit.stderr new file mode 100644 index 000000000000..7675fe013307 --- /dev/null +++ b/tests/ui/inference/str-as-char-non-lit.stderr @@ -0,0 +1,19 @@ +error[E0308]: mismatched types + --> $DIR/str-as-char-non-lit.rs:6:19 + | +LL | let _: &str = ('a'); + | ---- ^^^^^ expected `&str`, found `char` + | | + | expected due to this + +error[E0308]: mismatched types + --> $DIR/str-as-char-non-lit.rs:8:19 + | +LL | let _: &str = token(); + | ---- ^^^^^^^ expected `&str`, found `char` + | | + | expected due to this + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/inline-const/referencing_local_variables.rs b/tests/ui/inline-const/referencing_local_variables.rs new file mode 100644 index 000000000000..f9f0fef07f08 --- /dev/null +++ b/tests/ui/inline-const/referencing_local_variables.rs @@ -0,0 +1,6 @@ +const fn test_me(a: usize) -> usize { + const { a } + //~^ ERROR: attempt to use a non-constant value in a constant +} + +fn main() {} diff --git a/tests/ui/inline-const/referencing_local_variables.stderr b/tests/ui/inline-const/referencing_local_variables.stderr new file mode 100644 index 000000000000..4a0a54066024 --- /dev/null +++ b/tests/ui/inline-const/referencing_local_variables.stderr @@ -0,0 +1,11 @@ +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/referencing_local_variables.rs:2:13 + | +LL | const fn test_me(a: usize) -> usize { + | - this would need to be a `const` +LL | const { a } + | ^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0435`. diff --git a/tests/ui/instrument-coverage/coverage-options.bad.stderr b/tests/ui/instrument-coverage/coverage-options.bad.stderr index 9e2c19e90d59..4a272cf97fb0 100644 --- a/tests/ui/instrument-coverage/coverage-options.bad.stderr +++ b/tests/ui/instrument-coverage/coverage-options.bad.stderr @@ -1,2 +1,2 @@ -error: incorrect value `bad` for unstable option `coverage-options` - `block` | `branch` | `mcdc` was expected +error: incorrect value `bad` for unstable option `coverage-options` - `block` | `branch` | `condition` | `mcdc` was expected diff --git a/tests/ui/instrument-coverage/coverage-options.rs b/tests/ui/instrument-coverage/coverage-options.rs index 2a80ce4ab2e9..8f523a5fd11a 100644 --- a/tests/ui/instrument-coverage/coverage-options.rs +++ b/tests/ui/instrument-coverage/coverage-options.rs @@ -1,5 +1,5 @@ //@ needs-profiler-support -//@ revisions: block branch mcdc bad +//@ revisions: block branch condition mcdc bad //@ compile-flags -Cinstrument-coverage //@ [block] check-pass @@ -8,6 +8,9 @@ //@ [branch] check-pass //@ [branch] compile-flags: -Zcoverage-options=branch +//@ [condition] check-pass +//@ [condition] compile-flags: -Zcoverage-options=condition + //@ [mcdc] check-pass //@ [mcdc] compile-flags: -Zcoverage-options=mcdc diff --git a/tests/ui/instrument-coverage/mcdc-condition-limit.bad.stderr b/tests/ui/instrument-coverage/mcdc-condition-limit.bad.stderr new file mode 100644 index 000000000000..4d8d7e1560d0 --- /dev/null +++ b/tests/ui/instrument-coverage/mcdc-condition-limit.bad.stderr @@ -0,0 +1,8 @@ +warning: Conditions number of the decision (7) exceeds limit (6). MCDC analysis will not count this expression. + --> $DIR/mcdc-condition-limit.rs:29:8 + | +LL | if a && b && c && d && e && f && g { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: 1 warning emitted + diff --git a/tests/ui/instrument-coverage/mcdc-condition-limit.rs b/tests/ui/instrument-coverage/mcdc-condition-limit.rs new file mode 100644 index 000000000000..64c5f8e9b779 --- /dev/null +++ b/tests/ui/instrument-coverage/mcdc-condition-limit.rs @@ -0,0 +1,32 @@ +//@ edition: 2021 +//@ min-llvm-version: 18 +//@ revisions: good bad +//@ check-pass +//@ compile-flags: -Cinstrument-coverage -Zcoverage-options=mcdc -Zno-profiler-runtime + +// Check that we emit some kind of diagnostic when MC/DC instrumentation sees +// code that exceeds the limit of 6 conditions per decision, and falls back +// to only instrumenting that code for branch coverage. +// +// See also `tests/coverage/mcdc/condition-limit.rs`, which tests the actual +// effect on instrumentation. +// +// (The limit is enforced in `compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs`.) + +#[cfg(good)] +fn main() { + // 6 conditions is OK, so no diagnostic. + let [a, b, c, d, e, f] = <[bool; 6]>::default(); + if a && b && c && d && e && f { + core::hint::black_box("hello"); + } +} + +#[cfg(bad)] +fn main() { + // 7 conditions is too many, so issue a diagnostic. + let [a, b, c, d, e, f, g] = <[bool; 7]>::default(); + if a && b && c && d && e && f && g { //[bad]~ WARNING Conditions number of the decision + core::hint::black_box("hello"); + } +} diff --git a/tests/ui/intrinsics/intrinsic-alignment.rs b/tests/ui/intrinsics/intrinsic-alignment.rs index 4856da553a80..138273aadd2f 100644 --- a/tests/ui/intrinsics/intrinsic-alignment.rs +++ b/tests/ui/intrinsics/intrinsic-alignment.rs @@ -10,20 +10,21 @@ mod rusti { } } -#[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "hurd", - target_os = "illumos", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris", - target_os = "vxworks", - target_os = "nto", +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "hurd", + target_os = "illumos", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_os = "vxworks", + target_os = "nto", + target_vendor = "apple", ))] mod m { #[cfg(target_arch = "x86")] diff --git a/tests/ui/invalid-compile-flags/print.stderr b/tests/ui/invalid-compile-flags/print.stderr index 0a032aabdfe8..70b4a394dd02 100644 --- a/tests/ui/invalid-compile-flags/print.stderr +++ b/tests/ui/invalid-compile-flags/print.stderr @@ -1,4 +1,4 @@ error: unknown print request: `yyyy` | - = help: valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `code-models`, `crate-name`, `deployment-target`, `file-names`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `tls-models` + = help: valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `deployment-target`, `file-names`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `tls-models` diff --git a/tests/ui/issues/issue-45731.rs b/tests/ui/issues/issue-45731.rs index 8e483d08cb51..49335362dd0f 100644 --- a/tests/ui/issues/issue-45731.rs +++ b/tests/ui/issues/issue-45731.rs @@ -2,10 +2,10 @@ #![allow(unused_variables)] //@ compile-flags:--test -g -#[cfg(target_os = "macos")] +#[cfg(target_vendor = "apple")] #[test] fn simple_test() { - use std::{env, panic, fs}; + use std::{env, fs, panic}; // Find our dSYM and replace the DWARF binary with an empty file let mut dsym_path = env::current_exe().unwrap(); @@ -13,8 +13,13 @@ fn simple_test() { assert!(dsym_path.pop()); // Pop executable dsym_path.push(format!("{}.dSYM/Contents/Resources/DWARF/{0}", executable_name)); { - let file = fs::OpenOptions::new().read(false).write(true).truncate(true).create(false) - .open(&dsym_path).unwrap(); + let file = fs::OpenOptions::new() + .read(false) + .write(true) + .truncate(true) + .create(false) + .open(&dsym_path) + .unwrap(); } env::set_var("RUST_BACKTRACE", "1"); diff --git a/tests/ui/link-section.rs b/tests/ui/link-section.rs index 9299b4d08b23..1a791b88ef95 100644 --- a/tests/ui/link-section.rs +++ b/tests/ui/link-section.rs @@ -1,32 +1,32 @@ //@ run-pass #![allow(non_upper_case_globals)] -#[cfg(not(target_os = "macos"))] -#[link_section=".moretext"] +#[cfg(not(target_vendor = "apple"))] +#[link_section = ".moretext"] fn i_live_in_more_text() -> &'static str { "knock knock" } -#[cfg(not(target_os = "macos"))] -#[link_section=".imm"] +#[cfg(not(target_vendor = "apple"))] +#[link_section = ".imm"] static magic: usize = 42; -#[cfg(not(target_os = "macos"))] -#[link_section=".mut"] +#[cfg(not(target_vendor = "apple"))] +#[link_section = ".mut"] static mut frobulator: usize = 0xdeadbeef; -#[cfg(target_os = "macos")] -#[link_section="__TEXT,__moretext"] +#[cfg(target_vendor = "apple")] +#[link_section = "__TEXT,__moretext"] fn i_live_in_more_text() -> &'static str { "knock knock" } -#[cfg(target_os = "macos")] -#[link_section="__RODATA,__imm"] +#[cfg(target_vendor = "apple")] +#[link_section = "__RODATA,__imm"] static magic: usize = 42; -#[cfg(target_os = "macos")] -#[link_section="__DATA,__mut"] +#[cfg(target_vendor = "apple")] +#[link_section = "__DATA,__mut"] static mut frobulator: usize = 0xdeadbeef; pub fn main() { diff --git a/tests/ui/linkage-attr/framework.rs b/tests/ui/linkage-attr/framework.rs index 824adf62206d..08f4394db21f 100644 --- a/tests/ui/linkage-attr/framework.rs +++ b/tests/ui/linkage-attr/framework.rs @@ -1,5 +1,5 @@ // Check that linking frameworks on Apple platforms works. -//@ only-macos +//@ only-apple //@ revisions: omit link weak both //@ [omit]build-fail //@ [link]run-pass diff --git a/tests/ui/osx-frameworks.rs b/tests/ui/linkage-attr/kind-framework.rs similarity index 58% rename from tests/ui/osx-frameworks.rs rename to tests/ui/linkage-attr/kind-framework.rs index b0d7a3a9c07a..c2f90809e03a 100644 --- a/tests/ui/osx-frameworks.rs +++ b/tests/ui/linkage-attr/kind-framework.rs @@ -1,4 +1,4 @@ -//@ ignore-macos this is supposed to succeed on osx +//@ ignore-apple this is supposed to succeed on Apple platforms (though it won't necessarily link) #[link(name = "foo", kind = "framework")] extern "C" {} diff --git a/tests/ui/osx-frameworks.stderr b/tests/ui/linkage-attr/kind-framework.stderr similarity index 89% rename from tests/ui/osx-frameworks.stderr rename to tests/ui/linkage-attr/kind-framework.stderr index 8582b8123bfe..93dacd68e294 100644 --- a/tests/ui/osx-frameworks.stderr +++ b/tests/ui/linkage-attr/kind-framework.stderr @@ -1,5 +1,5 @@ error[E0455]: link kind `framework` is only supported on Apple targets - --> $DIR/osx-frameworks.rs:3:29 + --> $DIR/kind-framework.rs:3:29 | LL | #[link(name = "foo", kind = "framework")] | ^^^^^^^^^^^ diff --git a/tests/ui/issues/issue-33992.rs b/tests/ui/linkage-attr/linkage-attr-does-not-panic-llvm-issue-33992.rs similarity index 96% rename from tests/ui/issues/issue-33992.rs rename to tests/ui/linkage-attr/linkage-attr-does-not-panic-llvm-issue-33992.rs index 495751436e12..a169997927eb 100644 --- a/tests/ui/issues/issue-33992.rs +++ b/tests/ui/linkage-attr/linkage-attr-does-not-panic-llvm-issue-33992.rs @@ -1,6 +1,6 @@ //@ run-pass //@ ignore-windows -//@ ignore-macos +//@ ignore-apple //@ ignore-wasm32 common linkage not implemented right now #![feature(linkage)] diff --git a/tests/ui/linkage-attr/linkage1.rs b/tests/ui/linkage-attr/linkage1.rs index 2edb80bf1b02..19bf601d9d20 100644 --- a/tests/ui/linkage-attr/linkage1.rs +++ b/tests/ui/linkage-attr/linkage1.rs @@ -1,6 +1,6 @@ //@ run-pass //@ ignore-windows -//@ ignore-macos +//@ ignore-apple //@ ignore-emscripten doesn't support this linkage //@ ignore-sgx weak linkage not permitted //@ aux-build:linkage1.rs diff --git a/tests/ui/issues/issue-18804/auxiliary/lib.rs b/tests/ui/linkage-attr/propagate-generic-issue-18804/auxiliary/lib.rs similarity index 100% rename from tests/ui/issues/issue-18804/auxiliary/lib.rs rename to tests/ui/linkage-attr/propagate-generic-issue-18804/auxiliary/lib.rs diff --git a/tests/ui/issues/issue-18804/main.rs b/tests/ui/linkage-attr/propagate-generic-issue-18804/main.rs similarity index 91% rename from tests/ui/issues/issue-18804/main.rs rename to tests/ui/linkage-attr/propagate-generic-issue-18804/main.rs index d83fe697470b..56a9358cce3c 100644 --- a/tests/ui/issues/issue-18804/main.rs +++ b/tests/ui/linkage-attr/propagate-generic-issue-18804/main.rs @@ -4,7 +4,7 @@ //@ ignore-emscripten no weak symbol support //@ ignore-windows no extern_weak linkage -//@ ignore-macos no extern_weak linkage +//@ ignore-apple no extern_weak linkage //@ aux-build:lib.rs diff --git a/tests/ui/lint/dropping_copy_types-issue-125189-can-not-fixed.rs b/tests/ui/lint/dropping_copy_types-issue-125189-can-not-fixed.rs new file mode 100644 index 000000000000..12c984c932ac --- /dev/null +++ b/tests/ui/lint/dropping_copy_types-issue-125189-can-not-fixed.rs @@ -0,0 +1,14 @@ +//@ check-fail + +#![deny(dropping_copy_types)] + +fn main() { + let y = 1; + let z = 2; + match y { + 0 => drop(y), //~ ERROR calls to `std::mem::drop` + 1 => drop(z), //~ ERROR calls to `std::mem::drop` + 2 => drop(3), //~ ERROR calls to `std::mem::drop` + _ => {}, + } +} diff --git a/tests/ui/lint/dropping_copy_types-issue-125189-can-not-fixed.stderr b/tests/ui/lint/dropping_copy_types-issue-125189-can-not-fixed.stderr new file mode 100644 index 000000000000..6c73e5ea90b4 --- /dev/null +++ b/tests/ui/lint/dropping_copy_types-issue-125189-can-not-fixed.stderr @@ -0,0 +1,37 @@ +error: calls to `std::mem::drop` with a value that implements `Copy` does nothing + --> $DIR/dropping_copy_types-issue-125189-can-not-fixed.rs:9:14 + | +LL | 0 => drop(y), + | ^^^^^-^ + | | + | argument has type `i32` + | + = note: use `let _ = ...` to ignore the expression or result +note: the lint level is defined here + --> $DIR/dropping_copy_types-issue-125189-can-not-fixed.rs:3:9 + | +LL | #![deny(dropping_copy_types)] + | ^^^^^^^^^^^^^^^^^^^ + +error: calls to `std::mem::drop` with a value that implements `Copy` does nothing + --> $DIR/dropping_copy_types-issue-125189-can-not-fixed.rs:10:14 + | +LL | 1 => drop(z), + | ^^^^^-^ + | | + | argument has type `i32` + | + = note: use `let _ = ...` to ignore the expression or result + +error: calls to `std::mem::drop` with a value that implements `Copy` does nothing + --> $DIR/dropping_copy_types-issue-125189-can-not-fixed.rs:11:14 + | +LL | 2 => drop(3), + | ^^^^^-^ + | | + | argument has type `i32` + | + = note: use `let _ = ...` to ignore the expression or result + +error: aborting due to 3 previous errors + diff --git a/tests/ui/lint/dropping_copy_types-issue-125189.fixed b/tests/ui/lint/dropping_copy_types-issue-125189.fixed new file mode 100644 index 000000000000..2dfd68d4cc16 --- /dev/null +++ b/tests/ui/lint/dropping_copy_types-issue-125189.fixed @@ -0,0 +1,10 @@ +//@ check-fail +//@ run-rustfix + +#![deny(dropping_copy_types)] + +fn main() { + let y = 1; + let _ = 3.2; //~ ERROR calls to `std::mem::drop` + let _ = y; //~ ERROR calls to `std::mem::drop` +} diff --git a/tests/ui/lint/dropping_copy_types-issue-125189.rs b/tests/ui/lint/dropping_copy_types-issue-125189.rs new file mode 100644 index 000000000000..1f42efabba9f --- /dev/null +++ b/tests/ui/lint/dropping_copy_types-issue-125189.rs @@ -0,0 +1,10 @@ +//@ check-fail +//@ run-rustfix + +#![deny(dropping_copy_types)] + +fn main() { + let y = 1; + drop(3.2); //~ ERROR calls to `std::mem::drop` + drop(y); //~ ERROR calls to `std::mem::drop` +} diff --git a/tests/ui/lint/dropping_copy_types-issue-125189.stderr b/tests/ui/lint/dropping_copy_types-issue-125189.stderr new file mode 100644 index 000000000000..ba3e36f5b6ec --- /dev/null +++ b/tests/ui/lint/dropping_copy_types-issue-125189.stderr @@ -0,0 +1,35 @@ +error: calls to `std::mem::drop` with a value that implements `Copy` does nothing + --> $DIR/dropping_copy_types-issue-125189.rs:8:5 + | +LL | drop(3.2); + | ^^^^^---^ + | | + | argument has type `f64` + | +note: the lint level is defined here + --> $DIR/dropping_copy_types-issue-125189.rs:4:9 + | +LL | #![deny(dropping_copy_types)] + | ^^^^^^^^^^^^^^^^^^^ +help: use `let _ = ...` to ignore the expression or result + | +LL - drop(3.2); +LL + let _ = 3.2; + | + +error: calls to `std::mem::drop` with a value that implements `Copy` does nothing + --> $DIR/dropping_copy_types-issue-125189.rs:9:5 + | +LL | drop(y); + | ^^^^^-^ + | | + | argument has type `i32` + | +help: use `let _ = ...` to ignore the expression or result + | +LL - drop(y); +LL + let _ = y; + | + +error: aborting due to 2 previous errors + diff --git a/tests/ui/lint/dropping_copy_types.stderr b/tests/ui/lint/dropping_copy_types.stderr index b6291aa5ed63..41aa66a4efc6 100644 --- a/tests/ui/lint/dropping_copy_types.stderr +++ b/tests/ui/lint/dropping_copy_types.stderr @@ -6,12 +6,16 @@ LL | drop(s1); | | | argument has type `SomeStruct` | - = note: use `let _ = ...` to ignore the expression or result note: the lint level is defined here --> $DIR/dropping_copy_types.rs:3:9 | LL | #![warn(dropping_copy_types)] | ^^^^^^^^^^^^^^^^^^^ +help: use `let _ = ...` to ignore the expression or result + | +LL - drop(s1); +LL + let _ = s1; + | warning: calls to `std::mem::drop` with a value that implements `Copy` does nothing --> $DIR/dropping_copy_types.rs:35:5 @@ -21,7 +25,11 @@ LL | drop(s2); | | | argument has type `SomeStruct` | - = note: use `let _ = ...` to ignore the expression or result +help: use `let _ = ...` to ignore the expression or result + | +LL - drop(s2); +LL + let _ = s2; + | warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing --> $DIR/dropping_copy_types.rs:36:5 @@ -31,8 +39,12 @@ LL | drop(s3); | | | argument has type `&SomeStruct` | - = note: use `let _ = ...` to ignore the expression or result = note: `#[warn(dropping_references)]` on by default +help: use `let _ = ...` to ignore the expression or result + | +LL - drop(s3); +LL + let _ = s3; + | warning: calls to `std::mem::drop` with a value that implements `Copy` does nothing --> $DIR/dropping_copy_types.rs:37:5 @@ -42,7 +54,11 @@ LL | drop(s4); | | | argument has type `SomeStruct` | - = note: use `let _ = ...` to ignore the expression or result +help: use `let _ = ...` to ignore the expression or result + | +LL - drop(s4); +LL + let _ = s4; + | warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing --> $DIR/dropping_copy_types.rs:38:5 @@ -52,7 +68,11 @@ LL | drop(s5); | | | argument has type `&SomeStruct` | - = note: use `let _ = ...` to ignore the expression or result +help: use `let _ = ...` to ignore the expression or result + | +LL - drop(s5); +LL + let _ = s5; + | warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing --> $DIR/dropping_copy_types.rs:50:5 @@ -62,7 +82,11 @@ LL | drop(a2); | | | argument has type `&AnotherStruct` | - = note: use `let _ = ...` to ignore the expression or result +help: use `let _ = ...` to ignore the expression or result + | +LL - drop(a2); +LL + let _ = a2; + | warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing --> $DIR/dropping_copy_types.rs:52:5 @@ -72,7 +96,11 @@ LL | drop(a4); | | | argument has type `&AnotherStruct` | - = note: use `let _ = ...` to ignore the expression or result +help: use `let _ = ...` to ignore the expression or result + | +LL - drop(a4); +LL + let _ = a4; + | warning: calls to `std::mem::drop` with a value that implements `Copy` does nothing --> $DIR/dropping_copy_types.rs:71:13 @@ -82,7 +110,11 @@ LL | drop(println_and(13)); | | | argument has type `i32` | - = note: use `let _ = ...` to ignore the expression or result +help: use `let _ = ...` to ignore the expression or result + | +LL - drop(println_and(13)); +LL + let _ = println_and(13); + | warning: calls to `std::mem::drop` with a value that implements `Copy` does nothing --> $DIR/dropping_copy_types.rs:74:14 diff --git a/tests/ui/lint/dropping_references-can-fixed.fixed b/tests/ui/lint/dropping_references-can-fixed.fixed new file mode 100644 index 000000000000..f704d3c72df7 --- /dev/null +++ b/tests/ui/lint/dropping_references-can-fixed.fixed @@ -0,0 +1,31 @@ +//@ check-fail +//@ run-rustfix + +#![deny(dropping_references)] + +struct SomeStruct; + +fn main() { + let _ = &SomeStruct; //~ ERROR calls to `std::mem::drop` + + let mut owned1 = SomeStruct; + let _ = &owned1; //~ ERROR calls to `std::mem::drop` + let _ = &&owned1; //~ ERROR calls to `std::mem::drop` + let _ = &mut owned1; //~ ERROR calls to `std::mem::drop` + drop(owned1); + + let reference1 = &SomeStruct; + let _ = reference1; //~ ERROR calls to `std::mem::drop` + + let reference2 = &mut SomeStruct; + let _ = reference2; //~ ERROR calls to `std::mem::drop` + + let ref reference3 = SomeStruct; + let _ = reference3; //~ ERROR calls to `std::mem::drop` +} + +#[allow(dead_code)] +fn test_generic_fn_drop(val: T) { + let _ = &val; //~ ERROR calls to `std::mem::drop` + drop(val); +} diff --git a/tests/ui/lint/dropping_references-can-fixed.rs b/tests/ui/lint/dropping_references-can-fixed.rs new file mode 100644 index 000000000000..70d1c16d66b4 --- /dev/null +++ b/tests/ui/lint/dropping_references-can-fixed.rs @@ -0,0 +1,31 @@ +//@ check-fail +//@ run-rustfix + +#![deny(dropping_references)] + +struct SomeStruct; + +fn main() { + drop(&SomeStruct); //~ ERROR calls to `std::mem::drop` + + let mut owned1 = SomeStruct; + drop(&owned1); //~ ERROR calls to `std::mem::drop` + drop(&&owned1); //~ ERROR calls to `std::mem::drop` + drop(&mut owned1); //~ ERROR calls to `std::mem::drop` + drop(owned1); + + let reference1 = &SomeStruct; + drop(reference1); //~ ERROR calls to `std::mem::drop` + + let reference2 = &mut SomeStruct; + drop(reference2); //~ ERROR calls to `std::mem::drop` + + let ref reference3 = SomeStruct; + drop(reference3); //~ ERROR calls to `std::mem::drop` +} + +#[allow(dead_code)] +fn test_generic_fn_drop(val: T) { + drop(&val); //~ ERROR calls to `std::mem::drop` + drop(val); +} diff --git a/tests/ui/lint/dropping_references-can-fixed.stderr b/tests/ui/lint/dropping_references-can-fixed.stderr new file mode 100644 index 000000000000..42cdb81b524a --- /dev/null +++ b/tests/ui/lint/dropping_references-can-fixed.stderr @@ -0,0 +1,119 @@ +error: calls to `std::mem::drop` with a reference instead of an owned value does nothing + --> $DIR/dropping_references-can-fixed.rs:9:5 + | +LL | drop(&SomeStruct); + | ^^^^^-----------^ + | | + | argument has type `&SomeStruct` + | +note: the lint level is defined here + --> $DIR/dropping_references-can-fixed.rs:4:9 + | +LL | #![deny(dropping_references)] + | ^^^^^^^^^^^^^^^^^^^ +help: use `let _ = ...` to ignore the expression or result + | +LL - drop(&SomeStruct); +LL + let _ = &SomeStruct; + | + +error: calls to `std::mem::drop` with a reference instead of an owned value does nothing + --> $DIR/dropping_references-can-fixed.rs:12:5 + | +LL | drop(&owned1); + | ^^^^^-------^ + | | + | argument has type `&SomeStruct` + | +help: use `let _ = ...` to ignore the expression or result + | +LL - drop(&owned1); +LL + let _ = &owned1; + | + +error: calls to `std::mem::drop` with a reference instead of an owned value does nothing + --> $DIR/dropping_references-can-fixed.rs:13:5 + | +LL | drop(&&owned1); + | ^^^^^--------^ + | | + | argument has type `&&SomeStruct` + | +help: use `let _ = ...` to ignore the expression or result + | +LL - drop(&&owned1); +LL + let _ = &&owned1; + | + +error: calls to `std::mem::drop` with a reference instead of an owned value does nothing + --> $DIR/dropping_references-can-fixed.rs:14:5 + | +LL | drop(&mut owned1); + | ^^^^^-----------^ + | | + | argument has type `&mut SomeStruct` + | +help: use `let _ = ...` to ignore the expression or result + | +LL - drop(&mut owned1); +LL + let _ = &mut owned1; + | + +error: calls to `std::mem::drop` with a reference instead of an owned value does nothing + --> $DIR/dropping_references-can-fixed.rs:18:5 + | +LL | drop(reference1); + | ^^^^^----------^ + | | + | argument has type `&SomeStruct` + | +help: use `let _ = ...` to ignore the expression or result + | +LL - drop(reference1); +LL + let _ = reference1; + | + +error: calls to `std::mem::drop` with a reference instead of an owned value does nothing + --> $DIR/dropping_references-can-fixed.rs:21:5 + | +LL | drop(reference2); + | ^^^^^----------^ + | | + | argument has type `&mut SomeStruct` + | +help: use `let _ = ...` to ignore the expression or result + | +LL - drop(reference2); +LL + let _ = reference2; + | + +error: calls to `std::mem::drop` with a reference instead of an owned value does nothing + --> $DIR/dropping_references-can-fixed.rs:24:5 + | +LL | drop(reference3); + | ^^^^^----------^ + | | + | argument has type `&SomeStruct` + | +help: use `let _ = ...` to ignore the expression or result + | +LL - drop(reference3); +LL + let _ = reference3; + | + +error: calls to `std::mem::drop` with a reference instead of an owned value does nothing + --> $DIR/dropping_references-can-fixed.rs:29:5 + | +LL | drop(&val); + | ^^^^^----^ + | | + | argument has type `&T` + | +help: use `let _ = ...` to ignore the expression or result + | +LL - drop(&val); +LL + let _ = &val; + | + +error: aborting due to 8 previous errors + diff --git a/tests/ui/lint/dropping_references.stderr b/tests/ui/lint/dropping_references.stderr index 7e25a46216ec..312334b82ad4 100644 --- a/tests/ui/lint/dropping_references.stderr +++ b/tests/ui/lint/dropping_references.stderr @@ -6,12 +6,16 @@ LL | drop(&SomeStruct); | | | argument has type `&SomeStruct` | - = note: use `let _ = ...` to ignore the expression or result note: the lint level is defined here --> $DIR/dropping_references.rs:3:9 | LL | #![warn(dropping_references)] | ^^^^^^^^^^^^^^^^^^^ +help: use `let _ = ...` to ignore the expression or result + | +LL - drop(&SomeStruct); +LL + let _ = &SomeStruct; + | warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing --> $DIR/dropping_references.rs:11:5 @@ -21,7 +25,11 @@ LL | drop(&owned1); | | | argument has type `&SomeStruct` | - = note: use `let _ = ...` to ignore the expression or result +help: use `let _ = ...` to ignore the expression or result + | +LL - drop(&owned1); +LL + let _ = &owned1; + | warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing --> $DIR/dropping_references.rs:12:5 @@ -31,7 +39,11 @@ LL | drop(&&owned1); | | | argument has type `&&SomeStruct` | - = note: use `let _ = ...` to ignore the expression or result +help: use `let _ = ...` to ignore the expression or result + | +LL - drop(&&owned1); +LL + let _ = &&owned1; + | warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing --> $DIR/dropping_references.rs:13:5 @@ -41,7 +53,11 @@ LL | drop(&mut owned1); | | | argument has type `&mut SomeStruct` | - = note: use `let _ = ...` to ignore the expression or result +help: use `let _ = ...` to ignore the expression or result + | +LL - drop(&mut owned1); +LL + let _ = &mut owned1; + | warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing --> $DIR/dropping_references.rs:17:5 @@ -51,7 +67,11 @@ LL | drop(reference1); | | | argument has type `&SomeStruct` | - = note: use `let _ = ...` to ignore the expression or result +help: use `let _ = ...` to ignore the expression or result + | +LL - drop(reference1); +LL + let _ = reference1; + | warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing --> $DIR/dropping_references.rs:20:5 @@ -61,7 +81,11 @@ LL | drop(reference2); | | | argument has type `&mut SomeStruct` | - = note: use `let _ = ...` to ignore the expression or result +help: use `let _ = ...` to ignore the expression or result + | +LL - drop(reference2); +LL + let _ = reference2; + | warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing --> $DIR/dropping_references.rs:23:5 @@ -71,7 +95,11 @@ LL | drop(reference3); | | | argument has type `&SomeStruct` | - = note: use `let _ = ...` to ignore the expression or result +help: use `let _ = ...` to ignore the expression or result + | +LL - drop(reference3); +LL + let _ = reference3; + | warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing --> $DIR/dropping_references.rs:28:5 @@ -81,7 +109,11 @@ LL | drop(&val); | | | argument has type `&T` | - = note: use `let _ = ...` to ignore the expression or result +help: use `let _ = ...` to ignore the expression or result + | +LL - drop(&val); +LL + let _ = &val; + | warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing --> $DIR/dropping_references.rs:36:5 @@ -91,7 +123,11 @@ LL | std::mem::drop(&SomeStruct); | | | argument has type `&SomeStruct` | - = note: use `let _ = ...` to ignore the expression or result +help: use `let _ = ...` to ignore the expression or result + | +LL - std::mem::drop(&SomeStruct); +LL + let _ = &SomeStruct; + | warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing --> $DIR/dropping_references.rs:91:13 @@ -101,7 +137,11 @@ LL | drop(println_and(&13)); | | | argument has type `&i32` | - = note: use `let _ = ...` to ignore the expression or result +help: use `let _ = ...` to ignore the expression or result + | +LL - drop(println_and(&13)); +LL + let _ = println_and(&13); + | warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing --> $DIR/dropping_references.rs:94:14 diff --git a/tests/ui/lint/forgetting_copy_types-can-fixed.fixed b/tests/ui/lint/forgetting_copy_types-can-fixed.fixed new file mode 100644 index 000000000000..c5d65ecc1d42 --- /dev/null +++ b/tests/ui/lint/forgetting_copy_types-can-fixed.fixed @@ -0,0 +1,22 @@ +//@ check-fail +//@ run-rustfix + +#![deny(forgetting_copy_types)] +#![allow(unused_mut)] +#![allow(unused_imports)] + +use std::vec::Vec; +use std::mem::forget; + +#[derive(Copy, Clone)] +struct SomeStruct; + +fn main() { + let s1 = SomeStruct {}; + let s2 = s1; + let mut s3 = s1; + + let _ = s1; //~ ERROR calls to `std::mem::forget` + let _ = s2; //~ ERROR calls to `std::mem::forget` + let _ = s3; //~ ERROR calls to `std::mem::forget` +} diff --git a/tests/ui/lint/forgetting_copy_types-can-fixed.rs b/tests/ui/lint/forgetting_copy_types-can-fixed.rs new file mode 100644 index 000000000000..c55722942800 --- /dev/null +++ b/tests/ui/lint/forgetting_copy_types-can-fixed.rs @@ -0,0 +1,22 @@ +//@ check-fail +//@ run-rustfix + +#![deny(forgetting_copy_types)] +#![allow(unused_mut)] +#![allow(unused_imports)] + +use std::vec::Vec; +use std::mem::forget; + +#[derive(Copy, Clone)] +struct SomeStruct; + +fn main() { + let s1 = SomeStruct {}; + let s2 = s1; + let mut s3 = s1; + + forget(s1); //~ ERROR calls to `std::mem::forget` + forget(s2); //~ ERROR calls to `std::mem::forget` + forget(s3); //~ ERROR calls to `std::mem::forget` +} diff --git a/tests/ui/lint/forgetting_copy_types-can-fixed.stderr b/tests/ui/lint/forgetting_copy_types-can-fixed.stderr new file mode 100644 index 000000000000..cb7bbf02222e --- /dev/null +++ b/tests/ui/lint/forgetting_copy_types-can-fixed.stderr @@ -0,0 +1,49 @@ +error: calls to `std::mem::forget` with a value that implements `Copy` does nothing + --> $DIR/forgetting_copy_types-can-fixed.rs:19:5 + | +LL | forget(s1); + | ^^^^^^^--^ + | | + | argument has type `SomeStruct` + | +note: the lint level is defined here + --> $DIR/forgetting_copy_types-can-fixed.rs:4:9 + | +LL | #![deny(forgetting_copy_types)] + | ^^^^^^^^^^^^^^^^^^^^^ +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(s1); +LL + let _ = s1; + | + +error: calls to `std::mem::forget` with a value that implements `Copy` does nothing + --> $DIR/forgetting_copy_types-can-fixed.rs:20:5 + | +LL | forget(s2); + | ^^^^^^^--^ + | | + | argument has type `SomeStruct` + | +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(s2); +LL + let _ = s2; + | + +error: calls to `std::mem::forget` with a value that implements `Copy` does nothing + --> $DIR/forgetting_copy_types-can-fixed.rs:21:5 + | +LL | forget(s3); + | ^^^^^^^--^ + | | + | argument has type `SomeStruct` + | +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(s3); +LL + let _ = s3; + | + +error: aborting due to 3 previous errors + diff --git a/tests/ui/lint/forgetting_copy_types.stderr b/tests/ui/lint/forgetting_copy_types.stderr index 36d1ef5c53e9..980ee6caba25 100644 --- a/tests/ui/lint/forgetting_copy_types.stderr +++ b/tests/ui/lint/forgetting_copy_types.stderr @@ -6,12 +6,16 @@ LL | forget(s1); | | | argument has type `SomeStruct` | - = note: use `let _ = ...` to ignore the expression or result note: the lint level is defined here --> $DIR/forgetting_copy_types.rs:3:9 | LL | #![warn(forgetting_copy_types)] | ^^^^^^^^^^^^^^^^^^^^^ +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(s1); +LL + let _ = s1; + | warning: calls to `std::mem::forget` with a value that implements `Copy` does nothing --> $DIR/forgetting_copy_types.rs:35:5 @@ -21,7 +25,11 @@ LL | forget(s2); | | | argument has type `SomeStruct` | - = note: use `let _ = ...` to ignore the expression or result +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(s2); +LL + let _ = s2; + | warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing --> $DIR/forgetting_copy_types.rs:36:5 @@ -31,8 +39,12 @@ LL | forget(s3); | | | argument has type `&SomeStruct` | - = note: use `let _ = ...` to ignore the expression or result = note: `#[warn(forgetting_references)]` on by default +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(s3); +LL + let _ = s3; + | warning: calls to `std::mem::forget` with a value that implements `Copy` does nothing --> $DIR/forgetting_copy_types.rs:37:5 @@ -42,7 +54,11 @@ LL | forget(s4); | | | argument has type `SomeStruct` | - = note: use `let _ = ...` to ignore the expression or result +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(s4); +LL + let _ = s4; + | warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing --> $DIR/forgetting_copy_types.rs:38:5 @@ -52,7 +68,11 @@ LL | forget(s5); | | | argument has type `&SomeStruct` | - = note: use `let _ = ...` to ignore the expression or result +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(s5); +LL + let _ = s5; + | warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing --> $DIR/forgetting_copy_types.rs:50:5 @@ -62,7 +82,11 @@ LL | forget(a2); | | | argument has type `&AnotherStruct` | - = note: use `let _ = ...` to ignore the expression or result +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(a2); +LL + let _ = a2; + | warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing --> $DIR/forgetting_copy_types.rs:52:5 @@ -72,7 +96,11 @@ LL | forget(a3); | | | argument has type `&AnotherStruct` | - = note: use `let _ = ...` to ignore the expression or result +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(a3); +LL + let _ = a3; + | warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing --> $DIR/forgetting_copy_types.rs:53:5 @@ -82,7 +110,11 @@ LL | forget(a4); | | | argument has type `&AnotherStruct` | - = note: use `let _ = ...` to ignore the expression or result +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(a4); +LL + let _ = a4; + | warning: 8 warnings emitted diff --git a/tests/ui/lint/forgetting_references-can-fixed.fixed b/tests/ui/lint/forgetting_references-can-fixed.fixed new file mode 100644 index 000000000000..64475f042840 --- /dev/null +++ b/tests/ui/lint/forgetting_references-can-fixed.fixed @@ -0,0 +1,40 @@ +//@ check-fail +//@ run-rustfix + +#![deny(forgetting_references)] + +use std::mem::forget; + +struct SomeStruct; + +fn main() { + let _ = &SomeStruct; //~ ERROR calls to `std::mem::forget` + + let mut owned = SomeStruct; + let _ = &owned; //~ ERROR calls to `std::mem::forget` + let _ = &&owned; //~ ERROR calls to `std::mem::forget` + let _ = &mut owned; //~ ERROR calls to `std::mem::forget` + forget(owned); + + let reference1 = &SomeStruct; + let _ = &*reference1; //~ ERROR calls to `std::mem::forget` + + let reference2 = &mut SomeStruct; + let _ = reference2; //~ ERROR calls to `std::mem::forget` + + let ref reference3 = SomeStruct; + let _ = reference3; //~ ERROR calls to `std::mem::forget` +} + +#[allow(dead_code)] +fn test_generic_fn_forget(val: T) { + let _ = &val; //~ ERROR calls to `std::mem::forget` + forget(val); +} + +#[allow(dead_code)] +fn test_similarly_named_function() { + fn forget(_val: T) {} + forget(&SomeStruct); //OK; call to unrelated function which happens to have the same name + let _ = &SomeStruct; //~ ERROR calls to `std::mem::forget` +} diff --git a/tests/ui/lint/forgetting_references-can-fixed.rs b/tests/ui/lint/forgetting_references-can-fixed.rs new file mode 100644 index 000000000000..4c9ef541d341 --- /dev/null +++ b/tests/ui/lint/forgetting_references-can-fixed.rs @@ -0,0 +1,40 @@ +//@ check-fail +//@ run-rustfix + +#![deny(forgetting_references)] + +use std::mem::forget; + +struct SomeStruct; + +fn main() { + forget(&SomeStruct); //~ ERROR calls to `std::mem::forget` + + let mut owned = SomeStruct; + forget(&owned); //~ ERROR calls to `std::mem::forget` + forget(&&owned); //~ ERROR calls to `std::mem::forget` + forget(&mut owned); //~ ERROR calls to `std::mem::forget` + forget(owned); + + let reference1 = &SomeStruct; + forget(&*reference1); //~ ERROR calls to `std::mem::forget` + + let reference2 = &mut SomeStruct; + forget(reference2); //~ ERROR calls to `std::mem::forget` + + let ref reference3 = SomeStruct; + forget(reference3); //~ ERROR calls to `std::mem::forget` +} + +#[allow(dead_code)] +fn test_generic_fn_forget(val: T) { + forget(&val); //~ ERROR calls to `std::mem::forget` + forget(val); +} + +#[allow(dead_code)] +fn test_similarly_named_function() { + fn forget(_val: T) {} + forget(&SomeStruct); //OK; call to unrelated function which happens to have the same name + std::mem::forget(&SomeStruct); //~ ERROR calls to `std::mem::forget` +} diff --git a/tests/ui/lint/forgetting_references-can-fixed.stderr b/tests/ui/lint/forgetting_references-can-fixed.stderr new file mode 100644 index 000000000000..05eb636ab459 --- /dev/null +++ b/tests/ui/lint/forgetting_references-can-fixed.stderr @@ -0,0 +1,133 @@ +error: calls to `std::mem::forget` with a reference instead of an owned value does nothing + --> $DIR/forgetting_references-can-fixed.rs:11:5 + | +LL | forget(&SomeStruct); + | ^^^^^^^-----------^ + | | + | argument has type `&SomeStruct` + | +note: the lint level is defined here + --> $DIR/forgetting_references-can-fixed.rs:4:9 + | +LL | #![deny(forgetting_references)] + | ^^^^^^^^^^^^^^^^^^^^^ +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(&SomeStruct); +LL + let _ = &SomeStruct; + | + +error: calls to `std::mem::forget` with a reference instead of an owned value does nothing + --> $DIR/forgetting_references-can-fixed.rs:14:5 + | +LL | forget(&owned); + | ^^^^^^^------^ + | | + | argument has type `&SomeStruct` + | +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(&owned); +LL + let _ = &owned; + | + +error: calls to `std::mem::forget` with a reference instead of an owned value does nothing + --> $DIR/forgetting_references-can-fixed.rs:15:5 + | +LL | forget(&&owned); + | ^^^^^^^-------^ + | | + | argument has type `&&SomeStruct` + | +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(&&owned); +LL + let _ = &&owned; + | + +error: calls to `std::mem::forget` with a reference instead of an owned value does nothing + --> $DIR/forgetting_references-can-fixed.rs:16:5 + | +LL | forget(&mut owned); + | ^^^^^^^----------^ + | | + | argument has type `&mut SomeStruct` + | +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(&mut owned); +LL + let _ = &mut owned; + | + +error: calls to `std::mem::forget` with a reference instead of an owned value does nothing + --> $DIR/forgetting_references-can-fixed.rs:20:5 + | +LL | forget(&*reference1); + | ^^^^^^^------------^ + | | + | argument has type `&SomeStruct` + | +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(&*reference1); +LL + let _ = &*reference1; + | + +error: calls to `std::mem::forget` with a reference instead of an owned value does nothing + --> $DIR/forgetting_references-can-fixed.rs:23:5 + | +LL | forget(reference2); + | ^^^^^^^----------^ + | | + | argument has type `&mut SomeStruct` + | +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(reference2); +LL + let _ = reference2; + | + +error: calls to `std::mem::forget` with a reference instead of an owned value does nothing + --> $DIR/forgetting_references-can-fixed.rs:26:5 + | +LL | forget(reference3); + | ^^^^^^^----------^ + | | + | argument has type `&SomeStruct` + | +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(reference3); +LL + let _ = reference3; + | + +error: calls to `std::mem::forget` with a reference instead of an owned value does nothing + --> $DIR/forgetting_references-can-fixed.rs:31:5 + | +LL | forget(&val); + | ^^^^^^^----^ + | | + | argument has type `&T` + | +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(&val); +LL + let _ = &val; + | + +error: calls to `std::mem::forget` with a reference instead of an owned value does nothing + --> $DIR/forgetting_references-can-fixed.rs:39:5 + | +LL | std::mem::forget(&SomeStruct); + | ^^^^^^^^^^^^^^^^^-----------^ + | | + | argument has type `&SomeStruct` + | +help: use `let _ = ...` to ignore the expression or result + | +LL - std::mem::forget(&SomeStruct); +LL + let _ = &SomeStruct; + | + +error: aborting due to 9 previous errors + diff --git a/tests/ui/lint/forgetting_references.rs b/tests/ui/lint/forgetting_references.rs index ecfa23ee4970..d0ec2a77ab1c 100644 --- a/tests/ui/lint/forgetting_references.rs +++ b/tests/ui/lint/forgetting_references.rs @@ -23,6 +23,16 @@ fn main() { let ref reference3 = SomeStruct; forget(reference3); //~ WARN calls to `std::mem::forget` + + let ref reference4 = SomeStruct; + + let a = 1; + match a { + 1 => forget(&*reference1), //~ WARN calls to `std::mem::forget` + 2 => forget(reference3), //~ WARN calls to `std::mem::forget` + 3 => forget(reference4), //~ WARN calls to `std::mem::forget` + _ => {} + } } #[allow(dead_code)] diff --git a/tests/ui/lint/forgetting_references.stderr b/tests/ui/lint/forgetting_references.stderr index 5624b690789f..afd5030a6805 100644 --- a/tests/ui/lint/forgetting_references.stderr +++ b/tests/ui/lint/forgetting_references.stderr @@ -6,12 +6,16 @@ LL | forget(&SomeStruct); | | | argument has type `&SomeStruct` | - = note: use `let _ = ...` to ignore the expression or result note: the lint level is defined here --> $DIR/forgetting_references.rs:3:9 | LL | #![warn(forgetting_references)] | ^^^^^^^^^^^^^^^^^^^^^ +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(&SomeStruct); +LL + let _ = &SomeStruct; + | warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing --> $DIR/forgetting_references.rs:13:5 @@ -21,7 +25,11 @@ LL | forget(&owned); | | | argument has type `&SomeStruct` | - = note: use `let _ = ...` to ignore the expression or result +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(&owned); +LL + let _ = &owned; + | warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing --> $DIR/forgetting_references.rs:14:5 @@ -31,7 +39,11 @@ LL | forget(&&owned); | | | argument has type `&&SomeStruct` | - = note: use `let _ = ...` to ignore the expression or result +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(&&owned); +LL + let _ = &&owned; + | warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing --> $DIR/forgetting_references.rs:15:5 @@ -41,7 +53,11 @@ LL | forget(&mut owned); | | | argument has type `&mut SomeStruct` | - = note: use `let _ = ...` to ignore the expression or result +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(&mut owned); +LL + let _ = &mut owned; + | warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing --> $DIR/forgetting_references.rs:19:5 @@ -51,7 +67,11 @@ LL | forget(&*reference1); | | | argument has type `&SomeStruct` | - = note: use `let _ = ...` to ignore the expression or result +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(&*reference1); +LL + let _ = &*reference1; + | warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing --> $DIR/forgetting_references.rs:22:5 @@ -61,7 +81,11 @@ LL | forget(reference2); | | | argument has type `&mut SomeStruct` | - = note: use `let _ = ...` to ignore the expression or result +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(reference2); +LL + let _ = reference2; + | warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing --> $DIR/forgetting_references.rs:25:5 @@ -71,27 +95,69 @@ LL | forget(reference3); | | | argument has type `&SomeStruct` | +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(reference3); +LL + let _ = reference3; + | + +warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing + --> $DIR/forgetting_references.rs:31:14 + | +LL | 1 => forget(&*reference1), + | ^^^^^^^------------^ + | | + | argument has type `&SomeStruct` + | = note: use `let _ = ...` to ignore the expression or result warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing - --> $DIR/forgetting_references.rs:30:5 + --> $DIR/forgetting_references.rs:32:14 + | +LL | 2 => forget(reference3), + | ^^^^^^^----------^ + | | + | argument has type `&SomeStruct` + | + = note: use `let _ = ...` to ignore the expression or result + +warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing + --> $DIR/forgetting_references.rs:33:14 + | +LL | 3 => forget(reference4), + | ^^^^^^^----------^ + | | + | argument has type `&SomeStruct` + | + = note: use `let _ = ...` to ignore the expression or result + +warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing + --> $DIR/forgetting_references.rs:40:5 | LL | forget(&val); | ^^^^^^^----^ | | | argument has type `&T` | - = note: use `let _ = ...` to ignore the expression or result +help: use `let _ = ...` to ignore the expression or result + | +LL - forget(&val); +LL + let _ = &val; + | warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing - --> $DIR/forgetting_references.rs:38:5 + --> $DIR/forgetting_references.rs:48:5 | LL | std::mem::forget(&SomeStruct); | ^^^^^^^^^^^^^^^^^-----------^ | | | argument has type `&SomeStruct` | - = note: use `let _ = ...` to ignore the expression or result +help: use `let _ = ...` to ignore the expression or result + | +LL - std::mem::forget(&SomeStruct); +LL + let _ = &SomeStruct; + | -warning: 9 warnings emitted +warning: 12 warnings emitted diff --git a/tests/ui/lint/non-local-defs/cargo-update.stderr b/tests/ui/lint/non-local-defs/cargo-update.stderr index e9e33b9aa173..888fd2e61837 100644 --- a/tests/ui/lint/non-local-defs/cargo-update.stderr +++ b/tests/ui/lint/non-local-defs/cargo-update.stderr @@ -1,14 +1,18 @@ -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/cargo-update.rs:17:1 | LL | non_local_macro::non_local_impl!(LocalStruct); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | `LocalStruct` is not local + | `Debug` is not local + | move the `impl` block outside of this constant `_IMPL_DEBUG` | - = help: move this `impl` block outside the of the current constant `_IMPL_DEBUG` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: the macro `non_local_macro::non_local_impl` may come from an old version of the `non_local_macro` crate, try updating your dependency with `cargo update -p non_local_macro` + = note: items in an anonymous const item (`const _: () = { ... }`) are treated as in the same scope as the anonymous const's declaration + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue = note: `#[warn(non_local_definitions)]` on by default = note: this warning originates in the macro `non_local_macro::non_local_impl` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/lint/non-local-defs/consts.stderr b/tests/ui/lint/non-local-defs/consts.stderr index d15b452b004e..48bdaa60823f 100644 --- a/tests/ui/lint/non-local-defs/consts.stderr +++ b/tests/ui/lint/non-local-defs/consts.stderr @@ -1,102 +1,129 @@ -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/consts.rs:13:5 | LL | const Z: () = { - | - help: use a const-anon item to suppress this lint: `_` + | ----------- + | | | + | | help: use a const-anon item to suppress this lint: `_` + | move the `impl` block outside of this constant `Z` ... LL | impl Uto for &Test {} - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^---^^^^^----- + | | | + | | `&'_ Test` is not local + | `Uto` is not local | - = help: move this `impl` block outside the of the current constant `Z` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: items in an anonymous const item (`const _: () = { ... }`) are treated as in the same scope as the anonymous const's declaration = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue = note: `#[warn(non_local_definitions)]` on by default -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/consts.rs:24:5 | +LL | static A: u32 = { + | ------------- move the `impl` block outside of this static `A` LL | impl Uto2 for Test {} - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^----^^^^^---- + | | | + | | `Test` is not local + | `Uto2` is not local | - = help: move this `impl` block outside the of the current static `A` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: items in an anonymous const item (`const _: () = { ... }`) are treated as in the same scope as the anonymous const's declaration = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/consts.rs:32:5 | +LL | const B: u32 = { + | ------------ move the `impl` block outside of this constant `B` LL | impl Uto3 for Test {} - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^----^^^^^---- + | | | + | | `Test` is not local + | `Uto3` is not local | - = help: move this `impl` block outside the of the current constant `B` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: items in an anonymous const item (`const _: () = { ... }`) are treated as in the same scope as the anonymous const's declaration = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/consts.rs:43:5 | -LL | / impl Test { -LL | | -LL | | fn foo() {} -LL | | } - | |_____^ +LL | fn main() { + | --------- move the `impl` block outside of this function `main` +LL | impl Test { + | ^^^^^---- + | | + | `Test` is not local | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: methods and associated constants are still usable outside the current expression, only `impl Local` and `impl dyn Local` can ever be private, and only if the type is nested in the same item as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/consts.rs:50:9 | -LL | / impl Test { -LL | | -LL | | fn hoo() {} -LL | | } - | |_________^ +LL | fn main() { + | --------- move the `impl` block outside of this function `main` +... +LL | impl Test { + | ^^^^^---- + | | + | `Test` is not local | - = help: move this `impl` block outside the of the current inline constant `` and up 2 bodies - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: methods and associated constants are still usable outside the current expression, only `impl Local` and `impl dyn Local` can ever be private, and only if the type is nested in the same item as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/consts.rs:59:9 | -LL | / impl Test { -LL | | -LL | | fn foo2() {} -LL | | } - | |_________^ +LL | const _: u32 = { + | ------------ move the `impl` block outside of this constant `_` and up 2 bodies +LL | impl Test { + | ^^^^^---- + | | + | `Test` is not local | - = help: move this `impl` block outside the of the current constant `_` and up 2 bodies - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: methods and associated constants are still usable outside the current expression, only `impl Local` and `impl dyn Local` can ever be private, and only if the type is nested in the same item as the `impl` + = note: items in an anonymous const item (`const _: () = { ... }`) are treated as in the same scope as the anonymous const's declaration = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/consts.rs:72:9 | +LL | let _a = || { + | -- move the `impl` block outside of this closure `` and up 2 bodies LL | impl Uto9 for Test {} - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^----^^^^^---- + | | | + | | `Test` is not local + | `Uto9` is not local | - = help: move this `impl` block outside the of the current closure `` and up 2 bodies - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/consts.rs:79:9 | -LL | impl Uto10 for Test {} - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | type A = [u32; { + | ____________________- +LL | | impl Uto10 for Test {} + | | ^^^^^-----^^^^^---- + | | | | + | | | `Test` is not local + | | `Uto10` is not local +LL | | +... | +LL | | }]; + | |_____- move the `impl` block outside of this constant expression `` and up 2 bodies | - = help: move this `impl` block outside the of the current constant expression `` and up 2 bodies - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: 8 warnings emitted diff --git a/tests/ui/lint/non-local-defs/exhaustive-trait.stderr b/tests/ui/lint/non-local-defs/exhaustive-trait.stderr index 8d58d4dd27c5..67df0e31d5bd 100644 --- a/tests/ui/lint/non-local-defs/exhaustive-trait.stderr +++ b/tests/ui/lint/non-local-defs/exhaustive-trait.stderr @@ -1,98 +1,97 @@ -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/exhaustive-trait.rs:7:5 | -LL | / impl PartialEq<()> for Dog { -LL | | -LL | | fn eq(&self, _: &()) -> bool { -LL | | todo!() -LL | | } -LL | | } - | |_____^ +LL | fn main() { + | --------- move the `impl` block outside of this function `main` +LL | impl PartialEq<()> for Dog { + | ^^^^^---------^^^^^^^^^--- + | | | + | | `Dog` is not local + | `PartialEq` is not local | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue = note: `#[warn(non_local_definitions)]` on by default -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/exhaustive-trait.rs:14:5 | -LL | / impl PartialEq<()> for &Dog { -LL | | -LL | | fn eq(&self, _: &()) -> bool { -LL | | todo!() -LL | | } -LL | | } - | |_____^ +LL | fn main() { + | --------- move the `impl` block outside of this function `main` +... +LL | impl PartialEq<()> for &Dog { + | ^^^^^---------^^^^^^^^^---- + | | | + | | `&'_ Dog` is not local + | `PartialEq` is not local | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/exhaustive-trait.rs:21:5 | -LL | / impl PartialEq for () { -LL | | -LL | | fn eq(&self, _: &Dog) -> bool { -LL | | todo!() -LL | | } -LL | | } - | |_____^ +LL | fn main() { + | --------- move the `impl` block outside of this function `main` +... +LL | impl PartialEq for () { + | ^^^^^---------^^^^^^^^^^-- + | | | + | | `()` is not local + | `PartialEq` is not local | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/exhaustive-trait.rs:28:5 | -LL | / impl PartialEq<&Dog> for () { -LL | | -LL | | fn eq(&self, _: &&Dog) -> bool { -LL | | todo!() -LL | | } -LL | | } - | |_____^ +LL | fn main() { + | --------- move the `impl` block outside of this function `main` +... +LL | impl PartialEq<&Dog> for () { + | ^^^^^---------^^^^^^^^^^^-- + | | | + | | `()` is not local + | `PartialEq` is not local | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/exhaustive-trait.rs:35:5 | -LL | / impl PartialEq for &Dog { -LL | | -LL | | fn eq(&self, _: &Dog) -> bool { -LL | | todo!() -LL | | } -LL | | } - | |_____^ +LL | fn main() { + | --------- move the `impl` block outside of this function `main` +... +LL | impl PartialEq for &Dog { + | ^^^^^---------^^^^^^^^^^---- + | | | + | | `&'_ Dog` is not local + | `PartialEq` is not local | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/exhaustive-trait.rs:42:5 | -LL | / impl PartialEq<&Dog> for &Dog { -LL | | -LL | | fn eq(&self, _: &&Dog) -> bool { -LL | | todo!() -LL | | } -LL | | } - | |_____^ +LL | fn main() { + | --------- move the `impl` block outside of this function `main` +... +LL | impl PartialEq<&Dog> for &Dog { + | ^^^^^---------^^^^^^^^^^^---- + | | | + | | `&'_ Dog` is not local + | `PartialEq` is not local | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: 6 warnings emitted diff --git a/tests/ui/lint/non-local-defs/exhaustive.stderr b/tests/ui/lint/non-local-defs/exhaustive.stderr index b3697969c4f8..1e0d5caec383 100644 --- a/tests/ui/lint/non-local-defs/exhaustive.stderr +++ b/tests/ui/lint/non-local-defs/exhaustive.stderr @@ -1,238 +1,344 @@ -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/exhaustive.rs:10:5 | -LL | / impl Test { -LL | | -LL | | fn foo() {} -LL | | } - | |_____^ +LL | fn main() { + | --------- move the `impl` block outside of this function `main` +LL | impl Test { + | ^^^^^---- + | | + | `Test` is not local | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: methods and associated constants are still usable outside the current expression, only `impl Local` and `impl dyn Local` can ever be private, and only if the type is nested in the same item as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue = note: `#[warn(non_local_definitions)]` on by default -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/exhaustive.rs:15:5 | -LL | / impl Display for Test { -LL | | -LL | | fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { -LL | | todo!() -LL | | } -LL | | } - | |_____^ +LL | fn main() { + | --------- move the `impl` block outside of this function `main` +... +LL | impl Display for Test { + | ^^^^^-------^^^^^---- + | | | + | | `Test` is not local + | `Display` is not local | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/exhaustive.rs:22:5 | +LL | fn main() { + | --------- move the `impl` block outside of this function `main` +... LL | impl dyn Trait {} - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^----- + | | + | `Trait` is not local | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: methods and associated constants are still usable outside the current expression, only `impl Local` and `impl dyn Local` can ever be private, and only if the type is nested in the same item as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/exhaustive.rs:25:5 | +LL | fn main() { + | --------- move the `impl` block outside of this function `main` +... LL | impl Trait for Vec { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^-----^^^^^---^^^ + | | | + | | `Vec` is not local + | `Trait` is not local | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/exhaustive.rs:28:5 | +LL | fn main() { + | --------- move the `impl` block outside of this function `main` +... LL | impl Trait for &dyn Trait {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^-----^^^^^---------- + | | | + | | `&'_ dyn Trait` is not local + | `Trait` is not local | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/exhaustive.rs:31:5 | +LL | fn main() { + | --------- move the `impl` block outside of this function `main` +... LL | impl Trait for *mut Test {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^-----^^^^^--------- + | | | + | | `*mut Test` is not local + | `Trait` is not local | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/exhaustive.rs:34:5 | +LL | fn main() { + | --------- move the `impl` block outside of this function `main` +... LL | impl Trait for *mut [Test] {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^-----^^^^^----------- + | | | + | | `*mut [Test]` is not local + | `Trait` is not local | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/exhaustive.rs:37:5 | +LL | fn main() { + | --------- move the `impl` block outside of this function `main` +... LL | impl Trait for [Test; 8] {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^-----^^^^^--------- + | | | + | | `[Test; 8]` is not local + | `Trait` is not local | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/exhaustive.rs:40:5 | +LL | fn main() { + | --------- move the `impl` block outside of this function `main` +... LL | impl Trait for (Test,) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^-----^^^^^------- + | | | + | | `(Test,)` is not local + | `Trait` is not local | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/exhaustive.rs:43:5 | +LL | fn main() { + | --------- move the `impl` block outside of this function `main` +... LL | impl Trait for fn(Test) -> () {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^-----^^^^^-------------- + | | | + | | `fn(: Test) -> ()` is not local + | `Trait` is not local | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/exhaustive.rs:46:5 | +LL | fn main() { + | --------- move the `impl` block outside of this function `main` +... LL | impl Trait for fn() -> Test {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^-----^^^^^------------ + | | | + | | `fn() -> Test` is not local + | `Trait` is not local | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/exhaustive.rs:50:9 | +LL | let _a = || { + | -- move the `impl` block outside of this closure `` and up 2 bodies LL | impl Trait for Test {} - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^-----^^^^^---- + | | | + | | `Test` is not local + | `Trait` is not local | - = help: move this `impl` block outside the of the current closure `` and up 2 bodies - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/exhaustive.rs:58:5 | LL | impl Trait for *mut InsideMain {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^-----^^^^^--------------- + | | | + | | `*mut InsideMain` is not local + | | help: remove `*mut ` to make the `impl` local + | `Trait` is not local | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` +help: move the `impl` block outside of this function `main` + --> $DIR/exhaustive.rs:9:1 + | +LL | fn main() { + | ^^^^^^^^^ +... +LL | struct InsideMain; + | ----------------- may need to be moved as well = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/exhaustive.rs:60:5 | LL | impl Trait for *mut [InsideMain] {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^-----^^^^^----------------- + | | | + | | `*mut [InsideMain]` is not local + | `Trait` is not local | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` +help: move the `impl` block outside of this function `main` + --> $DIR/exhaustive.rs:9:1 + | +LL | fn main() { + | ^^^^^^^^^ +... +LL | struct InsideMain; + | ----------------- may need to be moved as well = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/exhaustive.rs:62:5 | LL | impl Trait for [InsideMain; 8] {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^-----^^^^^--------------- + | | | + | | `[InsideMain; 8]` is not local + | `Trait` is not local | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` +help: move the `impl` block outside of this function `main` + --> $DIR/exhaustive.rs:9:1 + | +LL | fn main() { + | ^^^^^^^^^ +... +LL | struct InsideMain; + | ----------------- may need to be moved as well = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/exhaustive.rs:64:5 | LL | impl Trait for (InsideMain,) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^-----^^^^^------------- + | | | + | | `(InsideMain,)` is not local + | `Trait` is not local | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` +help: move the `impl` block outside of this function `main` + --> $DIR/exhaustive.rs:9:1 + | +LL | fn main() { + | ^^^^^^^^^ +... +LL | struct InsideMain; + | ----------------- may need to be moved as well = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/exhaustive.rs:66:5 | LL | impl Trait for fn(InsideMain) -> () {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^-----^^^^^-------------------- + | | | + | | `fn(: InsideMain) -> ()` is not local + | `Trait` is not local | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` +help: move the `impl` block outside of this function `main` + --> $DIR/exhaustive.rs:9:1 + | +LL | fn main() { + | ^^^^^^^^^ +... +LL | struct InsideMain; + | ----------------- may need to be moved as well = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/exhaustive.rs:68:5 | LL | impl Trait for fn() -> InsideMain {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^-----^^^^^------------------ + | | | + | | `fn() -> InsideMain` is not local + | `Trait` is not local | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` +help: move the `impl` block outside of this function `main` + --> $DIR/exhaustive.rs:9:1 + | +LL | fn main() { + | ^^^^^^^^^ +... +LL | struct InsideMain; + | ----------------- may need to be moved as well = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/exhaustive.rs:72:9 | -LL | / impl Display for InsideMain { -LL | | -LL | | fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { -LL | | todo!() -LL | | } -LL | | } - | |_________^ +LL | fn inside_inside() { + | ------------------ move the `impl` block outside of this function `inside_inside` and up 2 bodies +LL | impl Display for InsideMain { + | ^^^^^-------^^^^^---------- + | | | + | | `InsideMain` is not local + | `Display` is not local | - = help: move this `impl` block outside the of the current function `inside_inside` and up 2 bodies - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/exhaustive.rs:79:9 | -LL | / impl InsideMain { -LL | | -LL | | fn bar() {} -LL | | } - | |_________^ +LL | fn inside_inside() { + | ------------------ move the `impl` block outside of this function `inside_inside` and up 2 bodies +... +LL | impl InsideMain { + | ^^^^^---------- + | | + | `InsideMain` is not local | - = help: move this `impl` block outside the of the current function `inside_inside` and up 2 bodies - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: methods and associated constants are still usable outside the current expression, only `impl Local` and `impl dyn Local` can ever be private, and only if the type is nested in the same item as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: 20 warnings emitted diff --git a/tests/ui/lint/non-local-defs/from-local-for-global.stderr b/tests/ui/lint/non-local-defs/from-local-for-global.stderr index 0cd385049aa6..67fd937d134c 100644 --- a/tests/ui/lint/non-local-defs/from-local-for-global.stderr +++ b/tests/ui/lint/non-local-defs/from-local-for-global.stderr @@ -1,77 +1,99 @@ -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/from-local-for-global.rs:8:5 | -LL | / impl From for () { -LL | | -LL | | fn from(_: Cat) -> () { -LL | | todo!() -LL | | } -LL | | } - | |_____^ +LL | fn main() { + | --------- move the `impl` block outside of this function `main` +LL | impl From for () { + | ^^^^^----^^^^^^^^^^-- + | | | + | | `()` is not local + | `From` is not local | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue = note: `#[warn(non_local_definitions)]` on by default -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/from-local-for-global.rs:18:5 | -LL | / impl From>> for () { -LL | | -LL | | fn from(_: Wrap>) -> Self { -LL | | todo!() -LL | | } -LL | | } - | |_____^ +LL | impl From>> for () { + | ^^^^^----^^^^^^^^^^^^^^^^^^^^^^^^^^^-- + | | | + | `From` is not local `()` is not local | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` +help: move the `impl` block outside of this function `main` + --> $DIR/from-local-for-global.rs:7:1 + | +LL | fn main() { + | ^^^^^^^^^ +... +LL | struct Elephant; + | --------------- may need to be moved as well = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/from-local-for-global.rs:32:5 | LL | impl StillNonLocal for &Foo {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^-------------^^^^^---- + | | | + | | `&'_ Foo` is not local + | | help: remove `&` to make the `impl` local + | `StillNonLocal` is not local | - = help: move this `impl` block outside the of the current function `only_global` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` +help: move the `impl` block outside of this function `only_global` + --> $DIR/from-local-for-global.rs:30:1 + | +LL | fn only_global() { + | ^^^^^^^^^^^^^^^^ +LL | struct Foo; + | ---------- may need to be moved as well = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/from-local-for-global.rs:40:5 | -LL | / impl From for GlobalSameFunction { -LL | | -LL | | fn from(x: Local1) -> GlobalSameFunction { -LL | | x.0 -LL | | } -LL | | } - | |_____^ +LL | impl From for GlobalSameFunction { + | ^^^^^----^^^^^^^^^^^^^------------------ + | | | + | | `GlobalSameFunction` is not local + | `From` is not local | - = help: move this `impl` block outside the of the current function `same_function` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` +help: move the `impl` block outside of this function `same_function` + --> $DIR/from-local-for-global.rs:38:1 + | +LL | fn same_function() { + | ^^^^^^^^^^^^^^^^^^ +LL | struct Local1(GlobalSameFunction); + | ------------- may need to be moved as well = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/from-local-for-global.rs:48:5 | -LL | / impl From for GlobalSameFunction { -LL | | -LL | | fn from(x: Local2) -> GlobalSameFunction { -LL | | x.0 -LL | | } -LL | | } - | |_____^ +LL | impl From for GlobalSameFunction { + | ^^^^^----^^^^^^^^^^^^^------------------ + | | | + | | `GlobalSameFunction` is not local + | `From` is not local | - = help: move this `impl` block outside the of the current function `same_function` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` +help: move the `impl` block outside of this function `same_function` + --> $DIR/from-local-for-global.rs:38:1 + | +LL | fn same_function() { + | ^^^^^^^^^^^^^^^^^^ +... +LL | struct Local2(GlobalSameFunction); + | ------------- may need to be moved as well = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: 5 warnings emitted diff --git a/tests/ui/lint/non-local-defs/generics.stderr b/tests/ui/lint/non-local-defs/generics.stderr index 681d9e45e7a0..ed2f87a4ed2d 100644 --- a/tests/ui/lint/non-local-defs/generics.stderr +++ b/tests/ui/lint/non-local-defs/generics.stderr @@ -1,113 +1,160 @@ -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/generics.rs:9:5 | LL | impl Global for Vec { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^------^^^^^---^^^ + | | | + | | `Vec` is not local + | `Global` is not local | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` +help: move the `impl` block outside of this function `main` + --> $DIR/generics.rs:6:1 + | +LL | fn main() { + | ^^^^^^^^^ +LL | trait Local {}; + | ----------- may need to be moved as well = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue = note: `#[warn(non_local_definitions)]` on by default -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/generics.rs:20:5 | LL | impl Uto7 for Test where Local: std::any::Any {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^----^^^^^---- + | | | + | | `Test` is not local + | `Uto7` is not local | - = help: move this `impl` block outside the of the current function `bad` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` +help: move the `impl` block outside of this function `bad` + --> $DIR/generics.rs:18:1 + | +LL | fn bad() { + | ^^^^^^^^ +LL | struct Local; + | ------------ may need to be moved as well = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/generics.rs:23:5 | +LL | fn bad() { + | -------- move the `impl` block outside of this function `bad` +... LL | impl Uto8 for T {} - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^----^^^^^- + | | | + | | `T` is not local + | `Uto8` is not local | - = help: move this `impl` block outside the of the current function `bad` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/generics.rs:32:5 | -LL | / impl Default for UwU { -LL | | -LL | | fn default() -> Self { -LL | | UwU(OwO) -LL | | } -LL | | } - | |_____^ +LL | impl Default for UwU { + | ^^^^^-------^^^^^---^^^^^ + | | | + | | `UwU` is not local + | `Default` is not local | - = help: move this `impl` block outside the of the current function `fun` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` +help: move the `impl` block outside of this function `fun` + --> $DIR/generics.rs:29:1 + | +LL | fn fun() { + | ^^^^^^^^ +LL | #[derive(Debug)] +LL | struct OwO; + | ---------- may need to be moved as well = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/generics.rs:43:5 | -LL | / impl AsRef for () { -LL | | -LL | | fn as_ref(&self) -> &Cat { &Cat } -LL | | } - | |_____^ +LL | impl AsRef for () { + | ^^^^^-----^^^^^^^^^^-- + | | | + | | `()` is not local + | `AsRef` is not local | - = help: move this `impl` block outside the of the current function `meow` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` +help: move the `impl` block outside of this function `meow` + --> $DIR/generics.rs:40:1 + | +LL | fn meow() { + | ^^^^^^^^^ +LL | #[derive(Debug)] +LL | struct Cat; + | ---------- may need to be moved as well = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/generics.rs:54:5 | -LL | / impl PartialEq for G { -LL | | -LL | | fn eq(&self, _: &B) -> bool { -LL | | true -LL | | } -LL | | } - | |_____^ +LL | impl PartialEq for G { + | ^^^^^---------^^^^^^^^- + | | | + | | `G` is not local + | `PartialEq` is not local | - = help: move this `impl` block outside the of the current function `fun2` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` +help: move the `impl` block outside of this function `fun2` + --> $DIR/generics.rs:51:1 + | +LL | fn fun2() { + | ^^^^^^^^^ +LL | #[derive(Debug, Default)] +LL | struct B; + | -------- may need to be moved as well = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/generics.rs:69:5 | -LL | / impl From>> for () { -LL | | -LL | | fn from(_: Wrap>) -> Self { -LL | | todo!() -LL | | } -LL | | } - | |_____^ +LL | impl From>> for () { + | ^^^^^----^^^^^^^^^^^^^^^^^^^^^^^-- + | | | + | `From` is not local `()` is not local | - = help: move this `impl` block outside the of the current function `rawr` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` +help: move the `impl` block outside of this function `rawr` + --> $DIR/generics.rs:66:1 + | +LL | fn rawr() { + | ^^^^^^^^^ +LL | struct Lion; + | ----------- may need to be moved as well = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/generics.rs:76:5 | -LL | / impl From<()> for Wrap { -LL | | -LL | | fn from(_: ()) -> Self { -LL | | todo!() -LL | | } -LL | | } - | |_____^ +LL | impl From<()> for Wrap { + | ^^^^^----^^^^^^^^^----^^^^^^ + | | | + | | `Wrap` is not local + | `From` is not local | - = help: move this `impl` block outside the of the current function `rawr` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` +help: move the `impl` block outside of this function `rawr` + --> $DIR/generics.rs:66:1 + | +LL | fn rawr() { + | ^^^^^^^^^ +LL | struct Lion; + | ----------- may need to be moved as well = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: 8 warnings emitted diff --git a/tests/ui/lint/non-local-defs/inside-macro_rules.stderr b/tests/ui/lint/non-local-defs/inside-macro_rules.stderr index 319682b973d5..b52301d1aa08 100644 --- a/tests/ui/lint/non-local-defs/inside-macro_rules.stderr +++ b/tests/ui/lint/non-local-defs/inside-macro_rules.stderr @@ -1,15 +1,19 @@ -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/inside-macro_rules.rs:9:13 | +LL | fn my_func() { + | ------------ move the `impl` block outside of this function `my_func` LL | impl MacroTrait for OutsideStruct {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^----------^^^^^------------- + | | | + | | `OutsideStruct` is not local + | `MacroTrait` is not local ... LL | m!(); | ---- in this macro invocation | - = help: move this `impl` block outside the of the current function `my_func` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue = note: `#[warn(non_local_definitions)]` on by default = note: this warning originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/lint/non-local-defs/macro_rules.stderr b/tests/ui/lint/non-local-defs/macro_rules.stderr index 125d8e97d87f..4e86fc7b987e 100644 --- a/tests/ui/lint/non-local-defs/macro_rules.stderr +++ b/tests/ui/lint/non-local-defs/macro_rules.stderr @@ -1,4 +1,4 @@ -warning: non-local `macro_rules!` definition, they should be avoided as they go against expectation +warning: non-local `macro_rules!` definition, `#[macro_export]` macro should be written at top level module --> $DIR/macro_rules.rs:10:5 | LL | macro_rules! m0 { () => { } }; @@ -6,11 +6,10 @@ LL | macro_rules! m0 { () => { } }; | = help: remove the `#[macro_export]` or move this `macro_rules!` outside the of the current constant `B` = note: a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue = note: `#[warn(non_local_definitions)]` on by default -warning: non-local `macro_rules!` definition, they should be avoided as they go against expectation +warning: non-local `macro_rules!` definition, `#[macro_export]` macro should be written at top level module --> $DIR/macro_rules.rs:16:1 | LL | non_local_macro::non_local_macro_rules!(my_macro); @@ -18,12 +17,11 @@ LL | non_local_macro::non_local_macro_rules!(my_macro); | = help: remove the `#[macro_export]` or move this `macro_rules!` outside the of the current constant `_MACRO_EXPORT` = note: a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue = note: the macro `non_local_macro::non_local_macro_rules` may come from an old version of the `non_local_macro` crate, try updating your dependency with `cargo update -p non_local_macro` = note: this warning originates in the macro `non_local_macro::non_local_macro_rules` (in Nightly builds, run with -Z macro-backtrace for more info) -warning: non-local `macro_rules!` definition, they should be avoided as they go against expectation +warning: non-local `macro_rules!` definition, `#[macro_export]` macro should be written at top level module --> $DIR/macro_rules.rs:21:5 | LL | macro_rules! m { () => { } }; @@ -31,10 +29,9 @@ LL | macro_rules! m { () => { } }; | = help: remove the `#[macro_export]` or move this `macro_rules!` outside the of the current function `main` = note: a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -warning: non-local `macro_rules!` definition, they should be avoided as they go against expectation +warning: non-local `macro_rules!` definition, `#[macro_export]` macro should be written at top level module --> $DIR/macro_rules.rs:29:13 | LL | macro_rules! m2 { () => { } }; @@ -42,7 +39,6 @@ LL | macro_rules! m2 { () => { } }; | = help: remove the `#[macro_export]` or move this `macro_rules!` outside the of the current associated function `bar` and up 2 bodies = note: a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: 4 warnings emitted diff --git a/tests/ui/lint/non-local-defs/suggest-moving-inner.rs b/tests/ui/lint/non-local-defs/suggest-moving-inner.rs new file mode 100644 index 000000000000..61b32e5bad9f --- /dev/null +++ b/tests/ui/lint/non-local-defs/suggest-moving-inner.rs @@ -0,0 +1,17 @@ +//@ check-pass + +trait Trait {} + +fn main() { + mod below { + pub struct Type(T); + } + struct InsideMain; + trait HasFoo {} + + impl Trait for &Vec> + //~^ WARN non-local `impl` definition + where + T: HasFoo + {} +} diff --git a/tests/ui/lint/non-local-defs/suggest-moving-inner.stderr b/tests/ui/lint/non-local-defs/suggest-moving-inner.stderr new file mode 100644 index 000000000000..f0de0f72e74f --- /dev/null +++ b/tests/ui/lint/non-local-defs/suggest-moving-inner.stderr @@ -0,0 +1,29 @@ +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item + --> $DIR/suggest-moving-inner.rs:12:5 + | +LL | impl Trait for &Vec> + | ^^^^^^^^-----^^^^^^^^^^^^^^^^^---------------------------------- + | | | + | | `&'_ Vec>` is not local + | `Trait` is not local + | + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` +help: move the `impl` block outside of this function `main` + --> $DIR/suggest-moving-inner.rs:5:1 + | +LL | fn main() { + | ^^^^^^^^^ +LL | mod below { +LL | pub struct Type(T); + | ------------------ may need to be moved as well +LL | } +LL | struct InsideMain; + | ----------------- may need to be moved as well +LL | trait HasFoo {} + | ------------ may need to be moved as well + = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue + = note: `#[warn(non_local_definitions)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/lint/non-local-defs/trait-solver-overflow-123573.stderr b/tests/ui/lint/non-local-defs/trait-solver-overflow-123573.stderr index 9a8ab810835c..80930ce1bcdf 100644 --- a/tests/ui/lint/non-local-defs/trait-solver-overflow-123573.stderr +++ b/tests/ui/lint/non-local-defs/trait-solver-overflow-123573.stderr @@ -1,12 +1,22 @@ -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/trait-solver-overflow-123573.rs:12:5 | LL | impl Test for &Local {} - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^----^^^^^------ + | | | + | | `&'_ Local` is not local + | | help: remove `&` to make the `impl` local + | `Test` is not local | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` +help: move the `impl` block outside of this function `main` + --> $DIR/trait-solver-overflow-123573.rs:10:1 + | +LL | fn main() { + | ^^^^^^^^^ +LL | struct Local {} + | ------------ may need to be moved as well = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue = note: `#[warn(non_local_definitions)]` on by default diff --git a/tests/ui/lint/non-local-defs/weird-exprs.stderr b/tests/ui/lint/non-local-defs/weird-exprs.stderr index 015a0cce43b2..cd414d636d34 100644 --- a/tests/ui/lint/non-local-defs/weird-exprs.stderr +++ b/tests/ui/lint/non-local-defs/weird-exprs.stderr @@ -1,71 +1,116 @@ -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/weird-exprs.rs:8:5 | -LL | impl Uto for *mut Test {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | type A = [u32; { + | ________________- +LL | | impl Uto for *mut Test {} + | | ^^^^^---^^^^^--------- + | | | | + | | | `*mut Test` is not local + | | `Uto` is not local +LL | | +... | +LL | | }]; + | |_- move the `impl` block outside of this constant expression `` | - = help: move this `impl` block outside the of the current constant expression `` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue = note: `#[warn(non_local_definitions)]` on by default -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/weird-exprs.rs:16:9 | -LL | impl Uto for Test {} - | ^^^^^^^^^^^^^^^^^^^^ +LL | Discr = { + | _____________- +LL | | impl Uto for Test {} + | | ^^^^^---^^^^^---- + | | | | + | | | `Test` is not local + | | `Uto` is not local +LL | | +... | +LL | | } + | |_____- move the `impl` block outside of this constant expression `` | - = help: move this `impl` block outside the of the current constant expression `` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/weird-exprs.rs:25:9 | -LL | / impl Test { +LL | let _array = [0i32; { + | _________________________- +LL | | impl Test { + | | ^^^^^---- + | | | + | | `Test` is not local LL | | LL | | fn bar() {} -LL | | } - | |_________^ +... | +LL | | 1 +LL | | }]; + | |_____- move the `impl` block outside of this constant expression `` and up 2 bodies | - = help: move this `impl` block outside the of the current constant expression `` and up 2 bodies - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: methods and associated constants are still usable outside the current expression, only `impl Local` and `impl dyn Local` can ever be private, and only if the type is nested in the same item as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/weird-exprs.rs:34:9 | -LL | impl Uto for &Test {} - | ^^^^^^^^^^^^^^^^^^^^^ +LL | type A = [u32; { + | ____________________- +LL | | impl Uto for &Test {} + | | ^^^^^---^^^^^----- + | | | | + | | | `&'_ Test` is not local + | | `Uto` is not local +LL | | +... | +LL | | }]; + | |_____- move the `impl` block outside of this constant expression `` and up 2 bodies | - = help: move this `impl` block outside the of the current constant expression `` and up 2 bodies - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/weird-exprs.rs:41:9 | -LL | impl Uto for &(Test,) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn a(_: [u32; { + | ___________________- +LL | | impl Uto for &(Test,) {} + | | ^^^^^---^^^^^-------- + | | | | + | | | `&'_ (Test,)` is not local + | | `Uto` is not local +LL | | +... | +LL | | }]) {} + | |_____- move the `impl` block outside of this constant expression `` and up 2 bodies | - = help: move this `impl` block outside the of the current constant expression `` and up 2 bodies - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue -warning: non-local `impl` definition, they should be avoided as they go against expectation +warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/weird-exprs.rs:48:9 | -LL | impl Uto for &(Test,Test) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn b() -> [u32; { + | _____________________- +LL | | impl Uto for &(Test,Test) {} + | | ^^^^^---^^^^^------------ + | | | | + | | | `&'_ (Test, Test)` is not local + | | `Uto` is not local +LL | | +... | +LL | | }] { todo!() } + | |_____- move the `impl` block outside of this constant expression `` and up 2 bodies | - = help: move this `impl` block outside the of the current constant expression `` and up 2 bodies - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type + = note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue warning: 6 warnings emitted diff --git a/tests/ui/manual/manual-link-framework.rs b/tests/ui/manual/manual-link-framework.rs index 06fd76f68df1..43cdda0a4e6a 100644 --- a/tests/ui/manual/manual-link-framework.rs +++ b/tests/ui/manual/manual-link-framework.rs @@ -1,7 +1,5 @@ -//@ ignore-macos -//@ ignore-ios +//@ ignore-apple //@ compile-flags:-l framework=foo //@ error-pattern: library kind `framework` is only supported on Apple targets -fn main() { -} +fn main() {} diff --git a/tests/ui/panic-runtime/abort-link-to-unwinding-crates.rs b/tests/ui/panic-runtime/abort-link-to-unwinding-crates.rs index 11e4929f12e0..ce6644e67586 100644 --- a/tests/ui/panic-runtime/abort-link-to-unwinding-crates.rs +++ b/tests/ui/panic-runtime/abort-link-to-unwinding-crates.rs @@ -5,12 +5,11 @@ //@ no-prefer-dynamic //@ ignore-wasm32 no processes //@ ignore-sgx no processes -//@ ignore-macos extern crate exit_success_if_unwind; -use std::process::Command; use std::env; +use std::process::Command; fn main() { let mut args = env::args_os(); @@ -25,7 +24,6 @@ fn main() { let mut cmd = Command::new(env::args_os().next().unwrap()); cmd.arg("foo"); - // ARMv6 hanges while printing the backtrace, see #41004 if cfg!(target_arch = "arm") && cfg!(target_env = "gnu") { cmd.env("RUST_BACKTRACE", "0"); diff --git a/tests/ui/panic-runtime/abort.rs b/tests/ui/panic-runtime/abort.rs index 22bd2ecfb00e..caf0243ebdb2 100644 --- a/tests/ui/panic-runtime/abort.rs +++ b/tests/ui/panic-runtime/abort.rs @@ -4,10 +4,9 @@ //@ no-prefer-dynamic //@ ignore-wasm32 no processes //@ ignore-sgx no processes -//@ ignore-macos -use std::process::Command; use std::env; +use std::process::Command; struct Bomb; @@ -23,7 +22,6 @@ fn main() { if let Some(s) = args.next() { if &*s == "foo" { - let _bomb = Bomb; panic!("try to catch me"); diff --git a/tests/ui/panic-runtime/link-to-abort.rs b/tests/ui/panic-runtime/link-to-abort.rs index 2a7052616f2c..a4013f2a6cf7 100644 --- a/tests/ui/panic-runtime/link-to-abort.rs +++ b/tests/ui/panic-runtime/link-to-abort.rs @@ -2,7 +2,6 @@ //@ compile-flags:-C panic=abort //@ no-prefer-dynamic -//@ ignore-macos #![feature(panic_abort)] diff --git a/tests/ui/proc-macro/nested-macro-rules.stderr b/tests/ui/proc-macro/nested-macro-rules.stderr index 270e9161b033..8fe041d61b81 100644 --- a/tests/ui/proc-macro/nested-macro-rules.stderr +++ b/tests/ui/proc-macro/nested-macro-rules.stderr @@ -1,4 +1,4 @@ -warning: non-local `macro_rules!` definition, they should be avoided as they go against expectation +warning: non-local `macro_rules!` definition, `#[macro_export]` macro should be written at top level module --> $DIR/auxiliary/nested-macro-rules.rs:7:9 | LL | macro_rules! outer_macro { @@ -19,7 +19,6 @@ LL | nested_macro_rules::outer_macro!(SecondStruct, SecondAttrStruct); | = help: remove the `#[macro_export]` or move this `macro_rules!` outside the of the current function `main` = note: a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue note: the lint level is defined here --> $DIR/nested-macro-rules.rs:8:9 diff --git a/tests/ui/runtime/out-of-stack.rs b/tests/ui/runtime/out-of-stack.rs index a62398df8b80..c5300635ad92 100644 --- a/tests/ui/runtime/out-of-stack.rs +++ b/tests/ui/runtime/out-of-stack.rs @@ -7,6 +7,10 @@ //@ ignore-sgx no processes //@ ignore-fuchsia must translate zircon signal to SIGABRT, FIXME (#58590) //@ ignore-nto no stack overflow handler used (no alternate stack available) +//@ ignore-ios stack overflow handlers aren't enabled +//@ ignore-tvos stack overflow handlers aren't enabled +//@ ignore-watchos stack overflow handlers aren't enabled +//@ ignore-visionos stack overflow handlers aren't enabled #![feature(rustc_private)] diff --git a/tests/ui/structs-enums/enum-rec/issue-17431-6.rs b/tests/ui/structs-enums/enum-rec/issue-17431-6.rs index d8343704f12b..0183bdba1119 100644 --- a/tests/ui/structs-enums/enum-rec/issue-17431-6.rs +++ b/tests/ui/structs-enums/enum-rec/issue-17431-6.rs @@ -1,4 +1,4 @@ -//@ ignore-macos: cycle error does not appear on apple +//@ ignore-apple: cycle error does not appear on apple use std::sync::Mutex; diff --git a/tests/ui/structs-enums/rec-align-u64.rs b/tests/ui/structs-enums/rec-align-u64.rs index 72601bb16fff..8ea72fdf45c8 100644 --- a/tests/ui/structs-enums/rec-align-u64.rs +++ b/tests/ui/structs-enums/rec-align-u64.rs @@ -30,21 +30,21 @@ struct Outer { t: Inner } - -#[cfg(any(target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "fuchsia", - target_os = "hurd", - target_os = "illumos", - target_os = "linux", - target_os = "macos", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris", - target_os = "vxworks", - target_os = "nto", +#[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "hurd", + target_os = "illumos", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_os = "vxworks", + target_os = "nto", + target_vendor = "apple", ))] mod m { #[cfg(target_arch = "x86")] diff --git a/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr b/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr index 170f2c7d34c4..9dde1963bd49 100644 --- a/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr +++ b/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr @@ -1,8 +1,8 @@ -error[E0284]: type annotations needed: cannot satisfy `the constant `{ || {} }` can be evaluated` +error[E0284]: type annotations needed: cannot satisfy `{ || {} } == _` --> $DIR/const-region-infer-to-static-in-binder.rs:4:10 | LL | struct X; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `the constant `{ || {} }` can be evaluated` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `{ || {} } == _` error: using function pointers as const generic parameters is forbidden --> $DIR/const-region-infer-to-static-in-binder.rs:4:20 diff --git a/tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.rs b/tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.rs new file mode 100644 index 000000000000..5c13a871a7b8 --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.rs @@ -0,0 +1,89 @@ +//@ compile-flags: -Znext-solver + +// A regression test for #125269. We previously ended up +// recursively proving `&<_ as SpeciesPackedElem>::Assoc: Typed` +// for all aliases which ended up causing exponential blowup. +// +// This has been fixed by eagerly normalizing the associated +// type before computing the nested goals, resulting in an +// immediate inductive cycle. + +pub trait Typed {} + +pub struct SpeciesCases(E); + +pub trait SpeciesPackedElim { + type Ogre; + type Cyclops; + type Wendigo; + type Cavetroll; + type Mountaintroll; + type Swamptroll; + type Dullahan; + type Werewolf; + type Occultsaurok; + type Mightysaurok; + type Slysaurok; + type Mindflayer; + type Minotaur; + type Tidalwarrior; + type Yeti; + type Harvester; + type Blueoni; + type Redoni; + type Cultistwarlord; + type Cultistwarlock; + type Huskbrute; + type Tursus; + type Gigasfrost; + type AdletElder; + type SeaBishop; + type HaniwaGeneral; + type TerracottaBesieger; + type TerracottaDemolisher; + type TerracottaPunisher; + type TerracottaPursuer; + type Cursekeeper; +} + +impl<'b, E: SpeciesPackedElim> Typed for &'b SpeciesCases +where + &'b E::Ogre: Typed, + &'b E::Cyclops: Typed, + &'b E::Wendigo: Typed, + &'b E::Cavetroll: Typed, + &'b E::Mountaintroll: Typed, + &'b E::Swamptroll: Typed, + &'b E::Dullahan: Typed, + &'b E::Werewolf: Typed, + &'b E::Occultsaurok: Typed, + &'b E::Mightysaurok: Typed, + &'b E::Slysaurok: Typed, + &'b E::Mindflayer: Typed, + &'b E::Minotaur: Typed, + &'b E::Tidalwarrior: Typed, + &'b E::Yeti: Typed, + &'b E::Harvester: Typed, + &'b E::Blueoni: Typed, + &'b E::Redoni: Typed, + &'b E::Cultistwarlord: Typed, + &'b E::Cultistwarlock: Typed, + &'b E::Huskbrute: Typed, + &'b E::Tursus: Typed, + &'b E::Gigasfrost: Typed, + &'b E::AdletElder: Typed, + &'b E::SeaBishop: Typed, + &'b E::HaniwaGeneral: Typed, + &'b E::TerracottaBesieger: Typed, + &'b E::TerracottaDemolisher: Typed, + &'b E::TerracottaPunisher: Typed, + &'b E::TerracottaPursuer: Typed, + &'b E::Cursekeeper: Typed, +{} + +fn foo() {} + +fn main() { + foo::<&_>(); + //~^ ERROR overflow evaluating the requirement `&_: Typed` +} diff --git a/tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.stderr b/tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.stderr new file mode 100644 index 000000000000..d350eb0f7795 --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.stderr @@ -0,0 +1,15 @@ +error[E0275]: overflow evaluating the requirement `&_: Typed` + --> $DIR/cycle-modulo-ambig-aliases.rs:87:11 + | +LL | foo::<&_>(); + | ^^ + | +note: required by a bound in `foo` + --> $DIR/cycle-modulo-ambig-aliases.rs:84:11 + | +LL | fn foo() {} + | ^^^^^ required by this bound in `foo` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/next-solver/dyn-any-dont-prefer-impl.rs b/tests/ui/traits/next-solver/dyn-any-dont-prefer-impl.rs index a63fe729fd68..1554d74f2145 100644 --- a/tests/ui/traits/next-solver/dyn-any-dont-prefer-impl.rs +++ b/tests/ui/traits/next-solver/dyn-any-dont-prefer-impl.rs @@ -1,5 +1,5 @@ //@ compile-flags: -Znext-solver -//@ check-pass +//@ run-pass // Test that selection prefers the builtin trait object impl for `Any` // instead of the user defined impl. Both impls apply to the trait diff --git a/tests/ui/unpretty/expanded-exhaustive.stdout b/tests/ui/unpretty/expanded-exhaustive.stdout index 325bace7b562..8737063bf3cc 100644 --- a/tests/ui/unpretty/expanded-exhaustive.stdout +++ b/tests/ui/unpretty/expanded-exhaustive.stdout @@ -82,7 +82,8 @@ mod expressions { fn expr_const_block() { const {}; const { 1 }; - const { + const + { struct S; }; } diff --git a/tests/ui/unsized/unsized3-rpass.rs b/tests/ui/unsized/unsized3-rpass.rs index 1b3e932bfe6d..ff35051774bc 100644 --- a/tests/ui/unsized/unsized3-rpass.rs +++ b/tests/ui/unsized/unsized3-rpass.rs @@ -87,7 +87,7 @@ pub fn main() { let obj: Box = Box::new(St { f: 42 }); let obj: &Tr = &*obj; let data: Box<_> = Box::new(Qux_ { f: St { f: 234 } }); - let x: &Qux = &*ptr::from_raw_parts::((&*data as *const _).cast(), ptr::metadata(obj)); + let x: &Qux = &*ptr::from_raw_parts::(&*data as *const _, ptr::metadata(obj)); assert_eq!(x.f.foo(), 234); } } diff --git a/tests/run-make/windows-subsystem/console.rs b/tests/ui/windows-subsystem/console.rs similarity index 78% rename from tests/run-make/windows-subsystem/console.rs rename to tests/ui/windows-subsystem/console.rs index 61a92eb6a9db..8f0ca2de370d 100644 --- a/tests/run-make/windows-subsystem/console.rs +++ b/tests/ui/windows-subsystem/console.rs @@ -1,3 +1,4 @@ +//@ run-pass #![windows_subsystem = "console"] fn main() {} diff --git a/tests/ui/windows-subsystem-invalid.rs b/tests/ui/windows-subsystem/windows-subsystem-invalid.rs similarity index 100% rename from tests/ui/windows-subsystem-invalid.rs rename to tests/ui/windows-subsystem/windows-subsystem-invalid.rs diff --git a/tests/ui/windows-subsystem-invalid.stderr b/tests/ui/windows-subsystem/windows-subsystem-invalid.stderr similarity index 100% rename from tests/ui/windows-subsystem-invalid.stderr rename to tests/ui/windows-subsystem/windows-subsystem-invalid.stderr diff --git a/tests/run-make/windows-subsystem/windows.rs b/tests/ui/windows-subsystem/windows.rs similarity index 78% rename from tests/run-make/windows-subsystem/windows.rs rename to tests/ui/windows-subsystem/windows.rs index 1138248f07da..65db0fec7a8b 100644 --- a/tests/run-make/windows-subsystem/windows.rs +++ b/tests/ui/windows-subsystem/windows.rs @@ -1,3 +1,4 @@ +//@ run-pass #![windows_subsystem = "windows"] fn main() {}