diff options
185 files changed, 3551 insertions, 1400 deletions
diff --git a/Cargo.lock b/Cargo.lock index 696727c106b..c58147ad757 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1170,13 +1170,13 @@ dependencies = [ [[package]] name = "errno" -version = "0.2.8" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" dependencies = [ "errno-dragonfly", "libc", - "winapi", + "windows-sys 0.48.0", ] [[package]] @@ -1831,14 +1831,14 @@ dependencies = [ [[package]] name = "is-terminal" -version = "0.4.4" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b6b32576413a8e69b90e952e4a026476040d81017b80445deda5f2d3921857" +checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" dependencies = [ "hermit-abi 0.3.0", "io-lifetimes", "rustix", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -2025,9 +2025,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.1.4" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" +checksum = "36eb31c1778188ae1e64398743890d0877fef36d11521ac60406b42016e8c2cf" [[package]] name = "litemap" @@ -4350,16 +4350,16 @@ dependencies = [ [[package]] name = "rustix" -version = "0.36.5" +version = "0.37.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3807b5d10909833d3e9acd1eb5fb988f79376ff10fce42937de71a449c4c588" +checksum = "2aae838e49b3d63e9274e1c01833cc8139d3fec468c3b84688c628f44b1ae11d" dependencies = [ "bitflags", "errno", "io-lifetimes", "libc", "linux-raw-sys", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] @@ -4791,12 +4791,12 @@ dependencies = [ [[package]] name = "terminal_size" -version = "0.2.3" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb20089a8ba2b69debd491f8d2d023761cbf196e999218c591fa1e7e15a21907" +checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237" dependencies = [ "rustix", - "windows-sys 0.42.0", + "windows-sys 0.48.0", ] [[package]] @@ -5514,6 +5514,15 @@ dependencies = [ ] [[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.0", +] + +[[package]] name = "windows-targets" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 8dd03aaa72d..5db0f72919d 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -702,7 +702,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { .copied() .find_map(find_fn_kind_from_did), ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => tcx - .bound_explicit_item_bounds(def_id) + .explicit_item_bounds(def_id) .subst_iter_copied(tcx, substs) .find_map(find_fn_kind_from_did), ty::Closure(_, substs) => match substs.as_closure().kind() { diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index ee2aca6fc93..fca6012a408 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -4,6 +4,8 @@ builtin_macros_requires_cfg_pattern = builtin_macros_expected_one_cfg_pattern = expected 1 cfg-pattern +builtin_macros_alloc_error_must_be_fn = alloc_error_handler must be a function + builtin_macros_assert_requires_boolean = macro requires a boolean expression as an argument .label = boolean expression required diff --git a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs new file mode 100644 index 00000000000..82bae9157e7 --- /dev/null +++ b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs @@ -0,0 +1,97 @@ +use crate::errors; +use crate::util::check_builtin_macro_attribute; + +use rustc_ast::ptr::P; +use rustc_ast::{self as ast, FnHeader, FnSig, Generics, StmtKind}; +use rustc_ast::{Fn, ItemKind, Stmt, TyKind, Unsafe}; +use rustc_expand::base::{Annotatable, ExtCtxt}; +use rustc_span::symbol::{kw, sym, Ident}; +use rustc_span::Span; +use thin_vec::{thin_vec, ThinVec}; + +pub fn expand( + ecx: &mut ExtCtxt<'_>, + _span: Span, + meta_item: &ast::MetaItem, + item: Annotatable, +) -> Vec<Annotatable> { + check_builtin_macro_attribute(ecx, meta_item, sym::alloc_error_handler); + + let orig_item = item.clone(); + + // Allow using `#[alloc_error_handler]` on an item statement + // FIXME - if we get deref patterns, use them to reduce duplication here + let (item, is_stmt, sig_span) = + if let Annotatable::Item(item) = &item + && let ItemKind::Fn(fn_kind) = &item.kind + { + (item, false, ecx.with_def_site_ctxt(fn_kind.sig.span)) + } else if let Annotatable::Stmt(stmt) = &item + && let StmtKind::Item(item) = &stmt.kind + && let ItemKind::Fn(fn_kind) = &item.kind + { + (item, true, ecx.with_def_site_ctxt(fn_kind.sig.span)) + } else { + ecx.sess.parse_sess.span_diagnostic.emit_err(errors::AllocErrorMustBeFn {span: item.span() }); + return vec![orig_item]; + }; + + // Generate a bunch of new items using the AllocFnFactory + let span = ecx.with_def_site_ctxt(item.span); + + // Generate item statements for the allocator methods. + let stmts = thin_vec![generate_handler(ecx, item.ident, span, sig_span)]; + + // Generate anonymous constant serving as container for the allocator methods. + let const_ty = ecx.ty(sig_span, TyKind::Tup(ThinVec::new())); + let const_body = ecx.expr_block(ecx.block(span, stmts)); + let const_item = ecx.item_const(span, Ident::new(kw::Underscore, span), const_ty, const_body); + let const_item = if is_stmt { + Annotatable::Stmt(P(ecx.stmt_item(span, const_item))) + } else { + Annotatable::Item(const_item) + }; + + // Return the original item and the new methods. + vec![orig_item, const_item] +} + +// #[rustc_std_internal_symbol] +// unsafe fn __rg_oom(size: usize, align: usize) -> ! { +// handler(core::alloc::Layout::from_size_align_unchecked(size, align)) +// } +fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: Span) -> Stmt { + let usize = cx.path_ident(span, Ident::new(sym::usize, span)); + let ty_usize = cx.ty_path(usize); + let size = Ident::from_str_and_span("size", span); + let align = Ident::from_str_and_span("align", span); + + let layout_new = cx.std_path(&[sym::alloc, sym::Layout, sym::from_size_align_unchecked]); + let layout_new = cx.expr_path(cx.path(span, layout_new)); + let layout = cx.expr_call( + span, + layout_new, + thin_vec![cx.expr_ident(span, size), cx.expr_ident(span, align)], + ); + + let call = cx.expr_call_ident(sig_span, handler, thin_vec![layout]); + + let never = ast::FnRetTy::Ty(cx.ty(span, TyKind::Never)); + let params = thin_vec![cx.param(span, size, ty_usize.clone()), cx.param(span, align, ty_usize)]; + let decl = cx.fn_decl(params, never); + let header = FnHeader { unsafety: Unsafe::Yes(span), ..FnHeader::default() }; + let sig = FnSig { decl, header, span: span }; + + let body = Some(cx.block_expr(call)); + let kind = ItemKind::Fn(Box::new(Fn { + defaultness: ast::Defaultness::Final, + sig, + generics: Generics::default(), + body, + })); + + let attrs = thin_vec![cx.attr_word(sym::rustc_std_internal_symbol, span)]; + + let item = cx.item(span, Ident::from_str_and_span("__rg_oom", span), attrs, kind); + cx.stmt_item(sig_span, item) +} diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index bf0ac3f0ee3..630f9b87bc3 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -20,6 +20,13 @@ pub(crate) struct OneCfgPattern { } #[derive(Diagnostic)] +#[diag(builtin_macros_alloc_error_must_be_fn)] +pub(crate) struct AllocErrorMustBeFn { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] #[diag(builtin_macros_assert_requires_boolean)] pub(crate) struct AssertRequiresBoolean { #[primary_span] diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index b6170161d6b..8f86ef44aa3 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -27,6 +27,7 @@ use rustc_expand::proc_macro::BangProcMacro; use rustc_fluent_macro::fluent_messages; use rustc_span::symbol::sym; +mod alloc_error_handler; mod assert; mod cfg; mod cfg_accessible; @@ -103,6 +104,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { } register_attr! { + alloc_error_handler: alloc_error_handler::expand, bench: test::expand_bench, cfg_accessible: cfg_accessible::Expander, cfg_eval: cfg_eval::expand, diff --git a/compiler/rustc_codegen_cranelift/example/alloc_example.rs b/compiler/rustc_codegen_cranelift/example/alloc_example.rs index e39c3272958..4ede2fe4efe 100644 --- a/compiler/rustc_codegen_cranelift/example/alloc_example.rs +++ b/compiler/rustc_codegen_cranelift/example/alloc_example.rs @@ -1,4 +1,4 @@ -#![feature(start, core_intrinsics)] +#![feature(start, core_intrinsics, alloc_error_handler)] #![no_std] extern crate alloc; @@ -22,6 +22,11 @@ fn panic_handler(_: &core::panic::PanicInfo) -> ! { core::intrinsics::abort(); } +#[alloc_error_handler] +fn alloc_error_handler(_: alloc::alloc::Layout) -> ! { + core::intrinsics::abort(); +} + #[start] fn main(_argc: isize, _argv: *const *const u8) -> isize { let world: Box<&str> = Box::new("Hello World!\0"); diff --git a/compiler/rustc_codegen_cranelift/src/allocator.rs b/compiler/rustc_codegen_cranelift/src/allocator.rs index 9fb8079a21f..2c246ceb37d 100644 --- a/compiler/rustc_codegen_cranelift/src/allocator.rs +++ b/compiler/rustc_codegen_cranelift/src/allocator.rs @@ -6,6 +6,7 @@ use crate::prelude::*; use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS}; use rustc_codegen_ssa::base::allocator_kind_for_codegen; use rustc_session::config::OomStrategy; +use rustc_span::symbol::sym; /// Returns whether an allocator shim was created pub(crate) fn codegen( @@ -14,7 +15,13 @@ pub(crate) fn codegen( unwind_context: &mut UnwindContext, ) -> bool { let Some(kind) = allocator_kind_for_codegen(tcx) else { return false }; - codegen_inner(module, unwind_context, kind, tcx.sess.opts.unstable_opts.oom); + codegen_inner( + module, + unwind_context, + kind, + tcx.alloc_error_handler_kind(()).unwrap(), + tcx.sess.opts.unstable_opts.oom, + ); true } @@ -22,6 +29,7 @@ fn codegen_inner( module: &mut impl Module, unwind_context: &mut UnwindContext, kind: AllocatorKind, + alloc_error_handler_kind: AllocatorKind, oom_strategy: OomStrategy, ) { let usize_ty = module.target_config().pointer_type(); @@ -63,6 +71,19 @@ fn codegen_inner( ); } + let sig = Signature { + call_conv: module.target_config().default_call_conv, + params: vec![AbiParam::new(usize_ty), AbiParam::new(usize_ty)], + returns: vec![], + }; + crate::common::create_wrapper_function( + module, + unwind_context, + sig, + "__rust_alloc_error_handler", + &alloc_error_handler_kind.fn_name(sym::oom), + ); + let data_id = module.declare_data(OomStrategy::SYMBOL, Linkage::Export, false, false).unwrap(); let mut data_ctx = DataContext::new(); data_ctx.set_align(1); diff --git a/compiler/rustc_codegen_gcc/example/alloc_example.rs b/compiler/rustc_codegen_gcc/example/alloc_example.rs index faff1dca23f..754e7931412 100644 --- a/compiler/rustc_codegen_gcc/example/alloc_example.rs +++ b/compiler/rustc_codegen_gcc/example/alloc_example.rs @@ -1,4 +1,4 @@ -#![feature(start, core_intrinsics, lang_items)] +#![feature(start, core_intrinsics, alloc_error_handler, lang_items)] #![no_std] extern crate alloc; @@ -21,6 +21,11 @@ fn panic_handler(_: &core::panic::PanicInfo) -> ! { core::intrinsics::abort(); } +#[alloc_error_handler] +fn alloc_error_handler(_: alloc::alloc::Layout) -> ! { + core::intrinsics::abort(); +} + #[lang = "eh_personality"] fn eh_personality() -> ! { loop {} diff --git a/compiler/rustc_codegen_gcc/src/allocator.rs b/compiler/rustc_codegen_gcc/src/allocator.rs index e90db44ece1..4bad33ee879 100644 --- a/compiler/rustc_codegen_gcc/src/allocator.rs +++ b/compiler/rustc_codegen_gcc/src/allocator.rs @@ -5,10 +5,11 @@ use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS use rustc_middle::bug; use rustc_middle::ty::TyCtxt; use rustc_session::config::OomStrategy; +use rustc_span::symbol::sym; use crate::GccContext; -pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_name: &str, kind: AllocatorKind) { +pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_name: &str, kind: AllocatorKind, alloc_error_handler_kind: AllocatorKind) { let context = &mods.context; let usize = match tcx.sess.target.pointer_width { @@ -86,6 +87,37 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_nam // as described in https://github.com/rust-lang/rust/commit/77a96ed5646f7c3ee8897693decc4626fe380643 } + let types = [usize, usize]; + let name = "__rust_alloc_error_handler".to_string(); + let args: Vec<_> = types.iter().enumerate() + .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index))) + .collect(); + let func = context.new_function(None, FunctionType::Exported, void, &args, name, false); + + if tcx.sess.target.default_hidden_visibility { + #[cfg(feature="master")] + func.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden)); + } + + let callee = alloc_error_handler_kind.fn_name(sym::oom); + let args: Vec<_> = types.iter().enumerate() + .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index))) + .collect(); + let callee = context.new_function(None, FunctionType::Extern, void, &args, callee, false); + #[cfg(feature="master")] + callee.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden)); + + let block = func.new_block("entry"); + + let args = args + .iter() + .enumerate() + .map(|(i, _)| func.get_param(i as i32).to_rvalue()) + .collect::<Vec<_>>(); + let _ret = context.new_call(None, callee, &args); + //llvm::LLVMSetTailCall(ret, True); + block.end_with_void_return(None); + let name = OomStrategy::SYMBOL.to_string(); let global = context.new_global(None, GlobalKind::Exported, i8, name); let value = tcx.sess.opts.unstable_opts.oom.should_panic(); diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs index 65de02b3567..738cdb6f119 100644 --- a/compiler/rustc_codegen_gcc/src/asm.rs +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -593,6 +593,8 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister { InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => "r", InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::wreg) => "w", InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => "r", + InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::reg) => "r", + InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::freg) => "f", InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => "r", InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_addr) => "a", InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_data) => "d", @@ -667,6 +669,8 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl InlineAsmRegClass::Avr(_) => unimplemented!(), InlineAsmRegClass::Bpf(_) => unimplemented!(), InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => cx.type_i32(), + InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::reg) => cx.type_i32(), + InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::freg) => cx.type_f32(), InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => cx.type_i32(), InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_addr) => cx.type_i32(), InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_data) => cx.type_i32(), @@ -804,6 +808,7 @@ fn modifier_to_gcc(arch: InlineAsmArch, reg: InlineAsmRegClass, modifier: Option } } InlineAsmRegClass::Hexagon(_) => None, + InlineAsmRegClass::LoongArch(_) => None, InlineAsmRegClass::Mips(_) => None, InlineAsmRegClass::Nvptx(_) => None, InlineAsmRegClass::PowerPC(_) => None, diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index 1a20dbcebd4..1cabb05de97 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -163,11 +163,11 @@ impl CodegenBackend for GccCodegenBackend { } impl ExtraBackendMethods for GccCodegenBackend { - fn codegen_allocator<'tcx>(&self, tcx: TyCtxt<'tcx>, module_name: &str, kind: AllocatorKind) -> Self::Module { + fn codegen_allocator<'tcx>(&self, tcx: TyCtxt<'tcx>, module_name: &str, kind: AllocatorKind, alloc_error_handler_kind: AllocatorKind) -> Self::Module { let mut mods = GccContext { context: Context::default(), }; - unsafe { allocator::codegen(tcx, &mut mods, module_name, kind); } + unsafe { allocator::codegen(tcx, &mut mods, module_name, kind, alloc_error_handler_kind); } mods } diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs index fc9251dda82..668d9292705 100644 --- a/compiler/rustc_codegen_llvm/src/allocator.rs +++ b/compiler/rustc_codegen_llvm/src/allocator.rs @@ -4,6 +4,7 @@ use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS use rustc_middle::bug; use rustc_middle::ty::TyCtxt; use rustc_session::config::{DebugInfo, OomStrategy}; +use rustc_span::symbol::sym; use crate::debuginfo; use crate::llvm::{self, False, True}; @@ -14,6 +15,7 @@ pub(crate) unsafe fn codegen( module_llvm: &mut ModuleLlvm, module_name: &str, kind: AllocatorKind, + alloc_error_handler_kind: AllocatorKind, ) { let llcx = &*module_llvm.llcx; let llmod = module_llvm.llmod(); @@ -98,6 +100,52 @@ pub(crate) unsafe fn codegen( llvm::LLVMDisposeBuilder(llbuilder); } + // rust alloc error handler + let args = [usize, usize]; // size, align + + let ty = llvm::LLVMFunctionType(void, args.as_ptr(), args.len() as c_uint, False); + let name = "__rust_alloc_error_handler"; + let llfn = llvm::LLVMRustGetOrInsertFunction(llmod, name.as_ptr().cast(), name.len(), ty); + // -> ! DIFlagNoReturn + let no_return = llvm::AttributeKind::NoReturn.create_attr(llcx); + attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[no_return]); + + if tcx.sess.target.default_hidden_visibility { + llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); + } + if tcx.sess.must_emit_unwind_tables() { + let uwtable = attributes::uwtable_attr(llcx); + attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[uwtable]); + } + + let callee = alloc_error_handler_kind.fn_name(sym::oom); + let callee = llvm::LLVMRustGetOrInsertFunction(llmod, callee.as_ptr().cast(), callee.len(), ty); + // -> ! DIFlagNoReturn + attributes::apply_to_llfn(callee, llvm::AttributePlace::Function, &[no_return]); + llvm::LLVMRustSetVisibility(callee, llvm::Visibility::Hidden); + + let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, "entry\0".as_ptr().cast()); + + let llbuilder = llvm::LLVMCreateBuilderInContext(llcx); + llvm::LLVMPositionBuilderAtEnd(llbuilder, llbb); + let args = args + .iter() + .enumerate() + .map(|(i, _)| llvm::LLVMGetParam(llfn, i as c_uint)) + .collect::<Vec<_>>(); + let ret = llvm::LLVMRustBuildCall( + llbuilder, + ty, + callee, + args.as_ptr(), + args.len() as c_uint, + [].as_ptr(), + 0 as c_uint, + ); + llvm::LLVMSetTailCall(ret, True); + llvm::LLVMBuildRetVoid(llbuilder); + llvm::LLVMDisposeBuilder(llbuilder); + // __rust_alloc_error_handler_should_panic let name = OomStrategy::SYMBOL; let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_ptr().cast(), name.len(), i8); diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 1a3865360a3..98d5b3599d9 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -236,6 +236,7 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { InlineAsmArch::Nvptx64 => {} InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {} InlineAsmArch::Hexagon => {} + InlineAsmArch::LoongArch64 => {} InlineAsmArch::Mips | InlineAsmArch::Mips64 => {} InlineAsmArch::S390x => {} InlineAsmArch::SpirV => {} @@ -633,6 +634,8 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) -> InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg) | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg) => "w", InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => "r", + InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::reg) => "r", + InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::freg) => "f", InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => "r", InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => "f", InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => "h", @@ -719,6 +722,7 @@ fn modifier_to_llvm( } } InlineAsmRegClass::Hexagon(_) => None, + InlineAsmRegClass::LoongArch(_) => None, InlineAsmRegClass::Mips(_) => None, InlineAsmRegClass::Nvptx(_) => None, InlineAsmRegClass::PowerPC(_) => None, @@ -803,6 +807,8 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &' cx.type_vector(cx.type_i64(), 2) } InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => cx.type_i32(), + InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::reg) => cx.type_i32(), + InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::freg) => cx.type_f32(), InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => cx.type_i32(), InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => cx.type_f32(), InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => cx.type_i16(), diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 00b2dc1287a..8305a0a4c28 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -115,10 +115,11 @@ impl ExtraBackendMethods for LlvmCodegenBackend { tcx: TyCtxt<'tcx>, module_name: &str, kind: AllocatorKind, + alloc_error_handler_kind: AllocatorKind, ) -> ModuleLlvm { let mut module_llvm = ModuleLlvm::new_metadata(tcx, module_name); unsafe { - allocator::codegen(tcx, &mut module_llvm, module_name, kind); + allocator::codegen(tcx, &mut module_llvm, module_name, kind, alloc_error_handler_kind); } module_llvm } diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index bda0cf764e5..8f2f829c17c 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -219,7 +219,7 @@ fn exported_symbols_provider_local( for symbol_name in ALLOCATOR_METHODS .iter() .map(|method| format!("__rust_{}", method.name)) - .chain([OomStrategy::SYMBOL.to_string()]) + .chain(["__rust_alloc_error_handler".to_string(), OomStrategy::SYMBOL.to_string()]) { let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name)); diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 3e9d29df02c..c5ca7936a2b 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -635,9 +635,16 @@ pub fn codegen_crate<B: ExtraBackendMethods>( if let Some(kind) = allocator_kind_for_codegen(tcx) { let llmod_id = cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], Some("allocator")).to_string(); - let module_llvm = tcx - .sess - .time("write_allocator_module", || backend.codegen_allocator(tcx, &llmod_id, kind)); + let module_llvm = tcx.sess.time("write_allocator_module", || { + backend.codegen_allocator( + tcx, + &llmod_id, + kind, + // If allocator_kind is Some then alloc_error_handler_kind must + // also be Some. + tcx.alloc_error_handler_kind(()).unwrap(), + ) + }); ongoing_codegen.submit_pre_codegened_module_to_llvm( tcx, diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index 2e88b7ce219..64bebe50ddb 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -123,6 +123,7 @@ pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Se tcx: TyCtxt<'tcx>, module_name: &str, kind: AllocatorKind, + alloc_error_handler_kind: AllocatorKind, ) -> Self::Module; /// This generates the codegen unit and returns it along with /// a `u64` giving an estimate of the unit's processing cost. diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 426d2c4034b..004017ec5f3 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -31,6 +31,7 @@ #![feature(unwrap_infallible)] #![feature(strict_provenance)] #![feature(ptr_alignment_type)] +#![feature(macro_metavar_expr)] #![allow(rustc::default_hash_types)] #![allow(rustc::potential_query_instability)] #![deny(rustc::untranslatable_diagnostic)] diff --git a/compiler/rustc_data_structures/src/tagged_ptr.rs b/compiler/rustc_data_structures/src/tagged_ptr.rs index 8568aac67c0..2914eece679 100644 --- a/compiler/rustc_data_structures/src/tagged_ptr.rs +++ b/compiler/rustc_data_structures/src/tagged_ptr.rs @@ -24,6 +24,7 @@ use crate::aligned::Aligned; mod copy; mod drop; +mod impl_tag; pub use copy::CopyTaggedPtr; pub use drop::TaggedPtr; @@ -141,6 +142,30 @@ pub unsafe trait Tag: Copy { unsafe fn from_usize(tag: usize) -> Self; } +/// Returns the number of bits available for use for tags in a pointer to `T` +/// (this is based on `T`'s alignment). +pub const fn bits_for<T: ?Sized + Aligned>() -> u32 { + crate::aligned::align_of::<T>().as_nonzero().trailing_zeros() +} + +/// Returns the correct [`Tag::BITS`] constant for a set of tag values. +pub const fn bits_for_tags(mut tags: &[usize]) -> u32 { + let mut bits = 0; + + while let &[tag, ref rest @ ..] = tags { + tags = rest; + + // bits required to represent `tag`, + // position of the most significant 1 + let b = usize::BITS - tag.leading_zeros(); + if b > bits { + bits = b; + } + } + + bits +} + unsafe impl<T: ?Sized + Aligned> Pointer for Box<T> { const BITS: u32 = bits_for::<Self::Target>(); @@ -221,12 +246,6 @@ unsafe impl<'a, T: 'a + ?Sized + Aligned> Pointer for &'a mut T { } } -/// Returns the number of bits available for use for tags in a pointer to `T` -/// (this is based on `T`'s alignment). -pub const fn bits_for<T: ?Sized + Aligned>() -> u32 { - crate::aligned::align_of::<T>().as_nonzero().trailing_zeros() -} - /// A tag type used in [`CopyTaggedPtr`] and [`TaggedPtr`] tests. #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[cfg(test)] diff --git a/compiler/rustc_data_structures/src/tagged_ptr/impl_tag.rs b/compiler/rustc_data_structures/src/tagged_ptr/impl_tag.rs new file mode 100644 index 00000000000..cb7f7d318dc --- /dev/null +++ b/compiler/rustc_data_structures/src/tagged_ptr/impl_tag.rs @@ -0,0 +1,144 @@ +/// Implements [`Tag`] for a given type. +/// +/// You can use `impl_tag` on structs and enums. +/// You need to specify the type and all its possible values, +/// which can only be paths with optional fields. +/// +/// [`Tag`]: crate::tagged_ptr::Tag +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// #![feature(macro_metavar_expr)] +/// use rustc_data_structures::{impl_tag, tagged_ptr::Tag}; +/// +/// #[derive(Copy, Clone, PartialEq, Debug)] +/// enum SomeTag { +/// A, +/// B, +/// X { v: bool }, +/// Y(bool, bool), +/// } +/// +/// impl_tag! { +/// // The type for which the `Tag` will be implemented +/// impl Tag for SomeTag; +/// // You need to specify all possible tag values: +/// SomeTag::A, // 0 +/// SomeTag::B, // 1 +/// // For variants with fields, you need to specify the fields: +/// SomeTag::X { v: true }, // 2 +/// SomeTag::X { v: false }, // 3 +/// // For tuple variants use named syntax: +/// SomeTag::Y { 0: true, 1: true }, // 4 +/// SomeTag::Y { 0: false, 1: true }, // 5 +/// SomeTag::Y { 0: true, 1: false }, // 6 +/// SomeTag::Y { 0: false, 1: false }, // 7 +/// } +/// +/// // Tag values are assigned in order: +/// assert_eq!(SomeTag::A.into_usize(), 0); +/// assert_eq!(SomeTag::X { v: false }.into_usize(), 3); +/// assert_eq!(SomeTag::Y(false, true).into_usize(), 5); +/// +/// assert_eq!(unsafe { SomeTag::from_usize(1) }, SomeTag::B); +/// assert_eq!(unsafe { SomeTag::from_usize(2) }, SomeTag::X { v: true }); +/// assert_eq!(unsafe { SomeTag::from_usize(7) }, SomeTag::Y(false, false)); +/// ``` +/// +/// Structs are supported: +/// +/// ``` +/// #![feature(macro_metavar_expr)] +/// # use rustc_data_structures::impl_tag; +/// #[derive(Copy, Clone)] +/// struct Flags { a: bool, b: bool } +/// +/// impl_tag! { +/// impl Tag for Flags; +/// Flags { a: true, b: true }, +/// Flags { a: false, b: true }, +/// Flags { a: true, b: false }, +/// Flags { a: false, b: false }, +/// } +/// ``` +/// +/// Not specifying all values results in a compile error: +/// +/// ```compile_fail,E0004 +/// #![feature(macro_metavar_expr)] +/// # use rustc_data_structures::impl_tag; +/// #[derive(Copy, Clone)] +/// enum E { +/// A, +/// B, +/// } +/// +/// impl_tag! { +/// impl Tag for E; +/// E::A, +/// } +/// ``` +#[macro_export] +macro_rules! impl_tag { + ( + impl Tag for $Self:ty; + $( + $($path:ident)::* $( { $( $fields:tt )* })?, + )* + ) => { + // Safety: + // `bits_for_tags` is called on the same `${index()}`-es as + // `into_usize` returns, thus `BITS` constant is correct. + unsafe impl $crate::tagged_ptr::Tag for $Self { + const BITS: u32 = $crate::tagged_ptr::bits_for_tags(&[ + $( + ${index()}, + $( ${ignore(path)} )* + )* + ]); + + #[inline] + fn into_usize(self) -> usize { + // This forbids use of repeating patterns (`Enum::V`&`Enum::V`, etc) + // (or at least it should, see <https://github.com/rust-lang/rust/issues/110613>) + #[forbid(unreachable_patterns)] + match self { + // `match` is doing heavy lifting here, by requiring exhaustiveness + $( + $($path)::* $( { $( $fields )* } )? => ${index()}, + )* + } + } + + #[inline] + unsafe fn from_usize(tag: usize) -> Self { + match tag { + $( + ${index()} => $($path)::* $( { $( $fields )* } )?, + )* + + // Safety: + // `into_usize` only returns `${index()}` of the same + // repetition as we are filtering above, thus if this is + // reached, the safety contract of this function was + // already breached. + _ => unsafe { + debug_assert!( + false, + "invalid tag: {tag}\ + (this is a bug in the caller of `from_usize`)" + ); + std::hint::unreachable_unchecked() + }, + } + } + + } + }; +} + +#[cfg(test)] +mod tests; diff --git a/compiler/rustc_data_structures/src/tagged_ptr/impl_tag/tests.rs b/compiler/rustc_data_structures/src/tagged_ptr/impl_tag/tests.rs new file mode 100644 index 00000000000..62c926153e1 --- /dev/null +++ b/compiler/rustc_data_structures/src/tagged_ptr/impl_tag/tests.rs @@ -0,0 +1,34 @@ +#[test] +fn bits_constant() { + use crate::tagged_ptr::Tag; + + #[derive(Copy, Clone)] + struct Unit; + impl_tag! { impl Tag for Unit; Unit, } + assert_eq!(Unit::BITS, 0); + + #[derive(Copy, Clone)] + enum Enum3 { + A, + B, + C, + } + impl_tag! { impl Tag for Enum3; Enum3::A, Enum3::B, Enum3::C, } + assert_eq!(Enum3::BITS, 2); + + #[derive(Copy, Clone)] + struct Eight(bool, bool, bool); + impl_tag! { + impl Tag for Eight; + Eight { 0: true, 1: true, 2: true }, + Eight { 0: true, 1: true, 2: false }, + Eight { 0: true, 1: false, 2: true }, + Eight { 0: true, 1: false, 2: false }, + Eight { 0: false, 1: true, 2: true }, + Eight { 0: false, 1: true, 2: false }, + Eight { 0: false, 1: false, 2: true }, + Eight { 0: false, 1: false, 2: false }, + } + + assert_eq!(Eight::BITS, 3); +} diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 1a80b4fc314..5fac485de64 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -58,8 +58,16 @@ use std::str; use std::sync::LazyLock; use std::time::Instant; +// This import blocks the use of panicking `print` and `println` in all the code +// below. Please use `safe_print` and `safe_println` to avoid ICE when +// encountering an I/O error during print. +#[allow(unused_imports)] +use std::{compile_error as print, compile_error as println}; + pub mod args; pub mod pretty; +#[macro_use] +mod print; mod session_diagnostics; use crate::session_diagnostics::{ @@ -511,7 +519,7 @@ fn handle_explain(registry: Registry, code: &str, output: ErrorOutputType) { if io::stdout().is_terminal() { show_content_with_pager(&text); } else { - print!("{text}"); + safe_print!("{text}"); } } Err(InvalidErrorCode) => { @@ -547,7 +555,7 @@ fn show_content_with_pager(content: &str) { // If pager fails for whatever reason, we should still print the content // to standard output if fallback_to_println { - print!("{content}"); + safe_print!("{content}"); } } @@ -601,7 +609,7 @@ pub fn list_metadata(sess: &Session, metadata_loader: &dyn MetadataLoader) -> Co let path = &(*ifile); let mut v = Vec::new(); locator::list_file_metadata(&sess.target, path, metadata_loader, &mut v).unwrap(); - println!("{}", String::from_utf8(v).unwrap()); + safe_println!("{}", String::from_utf8(v).unwrap()); } Input::Str { .. } => { early_error(ErrorOutputType::default(), "cannot list metadata for stdin"); @@ -642,12 +650,12 @@ fn print_crate_info( TargetList => { let mut targets = rustc_target::spec::TARGETS.to_vec(); targets.sort_unstable(); - println!("{}", targets.join("\n")); + safe_println!("{}", targets.join("\n")); } - Sysroot => println!("{}", sess.sysroot.display()), - TargetLibdir => println!("{}", sess.target_tlib_path.dir.display()), + Sysroot => safe_println!("{}", sess.sysroot.display()), + TargetLibdir => safe_println!("{}", sess.target_tlib_path.dir.display()), TargetSpec => { - println!("{}", serde_json::to_string_pretty(&sess.target.to_json()).unwrap()); + safe_println!("{}", serde_json::to_string_pretty(&sess.target.to_json()).unwrap()); } AllTargetSpecs => { let mut targets = BTreeMap::new(); @@ -656,7 +664,7 @@ fn print_crate_info( let target = Target::expect_builtin(&triple); targets.insert(name, target.to_json()); } - println!("{}", serde_json::to_string_pretty(&targets).unwrap()); + safe_println!("{}", serde_json::to_string_pretty(&targets).unwrap()); } FileNames | CrateName => { let Some(attrs) = attrs.as_ref() else { @@ -666,14 +674,14 @@ fn print_crate_info( let t_outputs = rustc_interface::util::build_output_filenames(attrs, sess); let id = rustc_session::output::find_crate_name(sess, attrs); if *req == PrintRequest::CrateName { - println!("{id}"); + safe_println!("{id}"); continue; } let crate_types = collect_crate_types(sess, attrs); for &style in &crate_types { let fname = rustc_session::output::filename_for_input(sess, style, id, &t_outputs); - println!("{}", fname.file_name().unwrap().to_string_lossy()); + safe_println!("{}", fname.file_name().unwrap().to_string_lossy()); } } Cfg => { @@ -707,13 +715,13 @@ fn print_crate_info( cfgs.sort(); for cfg in cfgs { - println!("{cfg}"); + safe_println!("{cfg}"); } } CallingConventions => { let mut calling_conventions = rustc_target::spec::abi::all_names(); calling_conventions.sort_unstable(); - println!("{}", calling_conventions.join("\n")); + safe_println!("{}", calling_conventions.join("\n")); } RelocationModels | CodeModels @@ -733,7 +741,7 @@ fn print_crate_info( let stable = sess.target.options.supported_split_debuginfo.contains(split); let unstable_ok = sess.unstable_options(); if stable || unstable_ok { - println!("{split}"); + safe_println!("{split}"); } } } @@ -770,14 +778,14 @@ pub fn version_at_macro_invocation( ) { let verbose = matches.opt_present("verbose"); - println!("{binary} {version}"); + safe_println!("{binary} {version}"); if verbose { - println!("binary: {binary}"); - println!("commit-hash: {commit_hash}"); - println!("commit-date: {commit_date}"); - println!("host: {}", config::host_triple()); - println!("release: {release}"); + safe_println!("binary: {binary}"); + safe_println!("commit-hash: {commit_hash}"); + safe_println!("commit-date: {commit_date}"); + safe_println!("host: {}", config::host_triple()); + safe_println!("release: {release}"); let debug_flags = matches.opt_strs("Z"); let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend=")); @@ -807,7 +815,7 @@ fn usage(verbose: bool, include_unstable_options: bool, nightly_build: bool) { } else { "" }; - println!( + safe_println!( "{options}{at_path}\nAdditional help: -C help Print codegen options -W help \ @@ -820,7 +828,7 @@ fn usage(verbose: bool, include_unstable_options: bool, nightly_build: bool) { } fn print_wall_help() { - println!( + safe_println!( " The flag `-Wall` does not exist in `rustc`. Most useful lints are enabled by default. Use `rustc -W help` to see all available lints. It's more common to put @@ -832,7 +840,7 @@ the command line flag directly. /// Write to stdout lint command options, together with a list of all available lints pub fn describe_lints(sess: &Session, lint_store: &LintStore, loaded_plugins: bool) { - println!( + safe_println!( " Available lint options: -W <foo> Warn about <foo> @@ -877,21 +885,21 @@ Available lint options: s }; - println!("Lint checks provided by rustc:\n"); + safe_println!("Lint checks provided by rustc:\n"); let print_lints = |lints: Vec<&Lint>| { - println!(" {} {:7.7} {}", padded("name"), "default", "meaning"); - println!(" {} {:7.7} {}", padded("----"), "-------", "-------"); + safe_println!(" {} {:7.7} {}", padded("name"), "default", "meaning"); + safe_println!(" {} {:7.7} {}", padded("----"), "-------", "-------"); for lint in lints { let name = lint.name_lower().replace('_', "-"); - println!( + safe_println!( " {} {:7.7} {}", padded(&name), lint.default_level(sess.edition()).as_str(), lint.desc ); } - println!("\n"); + safe_println!("\n"); }; print_lints(builtin); @@ -912,14 +920,14 @@ Available lint options: s }; - println!("Lint groups provided by rustc:\n"); + safe_println!("Lint groups provided by rustc:\n"); let print_lint_groups = |lints: Vec<(&'static str, Vec<LintId>)>, all_warnings| { - println!(" {} sub-lints", padded("name")); - println!(" {} ---------", padded("----")); + safe_println!(" {} sub-lints", padded("name")); + safe_println!(" {} ---------", padded("----")); if all_warnings { - println!(" {} all lints that are set to issue warnings", padded("warnings")); + safe_println!(" {} all lints that are set to issue warnings", padded("warnings")); } for (name, to) in lints { @@ -929,26 +937,26 @@ Available lint options: .map(|x| x.to_string().replace('_', "-")) .collect::<Vec<String>>() .join(", "); - println!(" {} {}", padded(&name), desc); + safe_println!(" {} {}", padded(&name), desc); } - println!("\n"); + safe_println!("\n"); }; print_lint_groups(builtin_groups, true); match (loaded_plugins, plugin.len(), plugin_groups.len()) { (false, 0, _) | (false, _, 0) => { - println!("Lint tools like Clippy can provide additional lints and lint groups."); + safe_println!("Lint tools like Clippy can provide additional lints and lint groups."); } (false, ..) => panic!("didn't load lint plugins but got them anyway!"), - (true, 0, 0) => println!("This crate does not load any lint plugins or lint groups."), + (true, 0, 0) => safe_println!("This crate does not load any lint plugins or lint groups."), (true, l, g) => { if l > 0 { - println!("Lint checks provided by plugins loaded by this crate:\n"); + safe_println!("Lint checks provided by plugins loaded by this crate:\n"); print_lints(plugin); } if g > 0 { - println!("Lint groups provided by plugins loaded by this crate:\n"); + safe_println!("Lint groups provided by plugins loaded by this crate:\n"); print_lint_groups(plugin_groups, false); } } @@ -996,12 +1004,12 @@ pub fn describe_flag_categories(matches: &Matches) -> bool { } fn describe_debug_flags() { - println!("\nAvailable options:\n"); + safe_println!("\nAvailable options:\n"); print_flag_list("-Z", config::Z_OPTIONS); } fn describe_codegen_flags() { - println!("\nAvailable codegen options:\n"); + safe_println!("\nAvailable codegen options:\n"); print_flag_list("-C", config::CG_OPTIONS); } @@ -1012,7 +1020,7 @@ fn print_flag_list<T>( let max_len = flag_list.iter().map(|&(name, _, _, _)| name.chars().count()).max().unwrap_or(0); for &(name, _, _, desc) in flag_list { - println!( + safe_println!( " {} {:>width$}=val -- {}", cmdline_opt, name.replace('_', "-"), diff --git a/compiler/rustc_driver_impl/src/print.rs b/compiler/rustc_driver_impl/src/print.rs new file mode 100644 index 00000000000..70de55320f7 --- /dev/null +++ b/compiler/rustc_driver_impl/src/print.rs @@ -0,0 +1,20 @@ +use std::fmt; +use std::io::{self, Write as _}; + +macro_rules! safe_print { + ($($arg:tt)*) => {{ + $crate::print::print(std::format_args!($($arg)*)); + }}; +} + +macro_rules! safe_println { + ($($arg:tt)*) => { + safe_print!("{}\n", std::format_args!($($arg)*)) + }; +} + +pub(crate) fn print(args: fmt::Arguments<'_>) { + if let Err(_) = io::stdout().write_fmt(args) { + rustc_errors::FatalError.raise(); + } +} diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 594e6cca912..48f5bd1cb50 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -291,6 +291,8 @@ declare_features! ( (active, abi_x86_interrupt, "1.17.0", Some(40180), None), /// Allows additional const parameter types, such as `&'static str` or user defined types (incomplete, adt_const_params, "1.56.0", Some(95174), None), + /// Allows defining an `#[alloc_error_handler]`. + (active, alloc_error_handler, "1.29.0", Some(51540), None), /// Allows trait methods with arbitrary self types. (active, arbitrary_self_types, "1.23.0", Some(44874), None), /// Allows using `const` operands in inline assembly. diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index c978d6472c8..876a31abdf8 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -47,8 +47,6 @@ declare_features! ( (removed, advanced_slice_patterns, "1.0.0", Some(62254), None, Some("merged into `#![feature(slice_patterns)]`")), - /// Allows defining an `#[alloc_error_handler]`. - (removed, alloc_error_handler, "CURRENT_RUSTC_VERSION", Some(51540), None, Some("now handled by panic handler")), (removed, allocator, "1.0.0", None, None, None), /// Allows a test to fail without failing the whole suite. (removed, allow_fail, "1.19.0", Some(46488), None, Some("removed due to no clear use cases")), diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 1d7965ff5f6..f32ae509e33 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -225,3 +225,40 @@ hir_analysis_functions_names_duplicated = functions names are duplicated hir_analysis_simd_ffi_highly_experimental = use of SIMD type{$snip} in FFI is highly experimental and may result in invalid code .help = add `#![feature(simd_ffi)]` to the crate attributes to enable + +hir_analysis_impl_not_marked_default = `{$ident}` specializes an item from a parent `impl`, but that item is not marked `default` + .label = cannot specialize default item `{$ident}` + .ok_label = parent `impl` is here + .note = to specialize, `{$ident}` in the parent `impl` must be marked `default` + +hir_analysis_impl_not_marked_default_err = `{$ident}` specializes an item from a parent `impl`, but that item is not marked `default` + .note = parent implementation is in crate `{$cname}` + +hir_analysis_missing_trait_item = not all trait items implemented, missing: `{$missing_items_msg}` + .label = missing `{$missing_items_msg}` in implementation + +hir_analysis_missing_trait_item_suggestion = implement the missing item: `{$snippet}` + +hir_analysis_missing_trait_item_label = `{$item}` from trait + +hir_analysis_missing_one_of_trait_item = not all trait items implemented, missing one of: `{$missing_items_msg}` + .label = missing one of `{$missing_items_msg}` in implementation + .note = required because of this annotation + +hir_analysis_missing_trait_item_unstable = not all trait items implemented, missing: `{$missing_item_name}` + .note = default implementation of `{$missing_item_name}` is unstable + .some_note = use of unstable library feature '{$feature}': {$r} + .none_note = use of unstable library feature '{$feature}' + +hir_analysis_transparent_enum_variant = transparent enum needs exactly one variant, but has {$number} + .label = needs exactly one variant, but has {$number} + .many_label = too many variants in `{$path}` + .multi_label = variant here + +hir_analysis_transparent_non_zero_sized_enum = the variant of a transparent {$desc} needs at most one non-zero-sized field, but has {$field_count} + .label = needs at most one non-zero-sized field, but has {$field_count} + .labels = this field is non-zero-sized + +hir_analysis_transparent_non_zero_sized = transparent {$desc} needs at most one non-zero-sized field, but has {$field_count} + .label = needs at most one non-zero-sized field, but has {$field_count} + .labels = this field is non-zero-sized diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index ad2624a5d2d..65c2f5955cd 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -320,7 +320,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( }; let prohibit_opaque = tcx .explicit_item_bounds(def_id) - .iter() + .subst_identity_iter_copied() .try_for_each(|(predicate, _)| predicate.visit_with(&mut visitor)); if let Some(ty) = prohibit_opaque.break_value() { diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index fe87aae8ed1..48214b899a4 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -839,7 +839,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ImplTraitInTraitCollector<'_, 'tcx> { }); self.types.insert(proj.def_id, (infer_ty, proj.substs)); // Recurse into bounds - for (pred, pred_span) in self.interner().bound_explicit_item_bounds(proj.def_id).subst_iter_copied(self.interner(), proj.substs) { + for (pred, pred_span) in self.interner().explicit_item_bounds(proj.def_id).subst_iter_copied(self.interner(), proj.substs) { let pred = pred.fold_with(self); let pred = self.ocx.normalize( &ObligationCause::misc(self.span, self.body_id), @@ -2023,7 +2023,7 @@ pub(super) fn check_type_bounds<'tcx>( }; let obligations: Vec<_> = tcx - .bound_explicit_item_bounds(trait_ty.def_id) + .explicit_item_bounds(trait_ty.def_id) .subst_iter_copied(tcx, rebased_substs) .map(|(concrete_ty_bound, span)| { debug!("check_type_bounds: concrete_ty_bound = {:?}", concrete_ty_bound); diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 4b3f3cf169d..08154cdae47 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -74,7 +74,7 @@ pub use check::check_abi; use check::check_mod_item_types; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_errors::{pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder}; +use rustc_errors::{pluralize, struct_span_err, Diagnostic, DiagnosticBuilder}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; use rustc_index::bit_set::BitSet; @@ -90,6 +90,7 @@ use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor; use std::num::NonZeroU32; +use crate::errors; use crate::require_c_abi_if_c_variadic; use crate::util::common::indenter; @@ -171,29 +172,13 @@ fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId) { fn report_forbidden_specialization(tcx: TyCtxt<'_>, impl_item: DefId, parent_impl: DefId) { let span = tcx.def_span(impl_item); let ident = tcx.item_name(impl_item); - let mut err = struct_span_err!( - tcx.sess, - span, - E0520, - "`{}` specializes an item from a parent `impl`, but that item is not marked `default`", - ident, - ); - err.span_label(span, format!("cannot specialize default item `{}`", ident)); - - match tcx.span_of_impl(parent_impl) { - Ok(span) => { - err.span_label(span, "parent `impl` is here"); - err.note(&format!( - "to specialize, `{}` in the parent `impl` must be marked `default`", - ident - )); - } - Err(cname) => { - err.note(&format!("parent implementation is in crate `{cname}`")); - } - } - err.emit(); + let err = match tcx.span_of_impl(parent_impl) { + Ok(sp) => errors::ImplNotMarkedDefault::Ok { span, ident, ok_label: sp }, + Err(cname) => errors::ImplNotMarkedDefault::Err { span, ident, cname }, + }; + + tcx.sess.emit_err(err); } fn missing_items_err( @@ -211,15 +196,6 @@ fn missing_items_err( .collect::<Vec<_>>() .join("`, `"); - let impl_span = tcx.def_span(impl_def_id); - let mut err = struct_span_err!( - tcx.sess, - impl_span, - E0046, - "not all trait items implemented, missing: `{missing_items_msg}`", - ); - err.span_label(impl_span, format!("missing `{missing_items_msg}` in implementation")); - // `Span` before impl block closing brace. let hi = full_impl_span.hi() - BytePos(1); // Point at the place right before the closing brace of the relevant `impl` to suggest @@ -228,6 +204,8 @@ fn missing_items_err( // Obtain the level of indentation ending in `sugg_sp`. let padding = tcx.sess.source_map().indentation_before(sugg_sp).unwrap_or_else(|| String::new()); + let (mut missing_trait_item, mut missing_trait_item_none, mut missing_trait_item_label) = + (Vec::new(), Vec::new(), Vec::new()); for &trait_item in missing_items { let snippet = suggestion_signature( @@ -236,16 +214,30 @@ fn missing_items_err( tcx.impl_trait_ref(impl_def_id).unwrap().subst_identity(), ); let code = format!("{}{}\n{}", padding, snippet, padding); - let msg = format!("implement the missing item: `{snippet}`"); - let appl = Applicability::HasPlaceholders; if let Some(span) = tcx.hir().span_if_local(trait_item.def_id) { - err.span_label(span, format!("`{}` from trait", trait_item.name)); - err.tool_only_span_suggestion(sugg_sp, &msg, code, appl); + missing_trait_item_label + .push(errors::MissingTraitItemLabel { span, item: trait_item.name }); + missing_trait_item.push(errors::MissingTraitItemSuggestion { + span: sugg_sp, + code, + snippet, + }); } else { - err.span_suggestion_hidden(sugg_sp, &msg, code, appl); + missing_trait_item_none.push(errors::MissingTraitItemSuggestionNone { + span: sugg_sp, + code, + snippet, + }) } } - err.emit(); + + tcx.sess.emit_err(errors::MissingTraitItem { + span: tcx.span_of_impl(impl_def_id.to_def_id()).unwrap(), + missing_items_msg, + missing_trait_item_label, + missing_trait_item, + missing_trait_item_none, + }); } fn missing_items_must_implement_one_of_err( @@ -257,19 +249,11 @@ fn missing_items_must_implement_one_of_err( let missing_items_msg = missing_items.iter().map(Ident::to_string).collect::<Vec<_>>().join("`, `"); - let mut err = struct_span_err!( - tcx.sess, - impl_span, - E0046, - "not all trait items implemented, missing one of: `{missing_items_msg}`", - ); - err.span_label(impl_span, format!("missing one of `{missing_items_msg}` in implementation")); - - if let Some(annotation_span) = annotation_span { - err.span_note(annotation_span, "required because of this annotation"); - } - - err.emit(); + tcx.sess.emit_err(errors::MissingOneOfTraitItem { + span: impl_span, + note: annotation_span, + missing_items_msg, + }); } fn default_body_is_unstable( @@ -281,25 +265,31 @@ fn default_body_is_unstable( issue: Option<NonZeroU32>, ) { let missing_item_name = tcx.associated_item(item_did).name; - let use_of_unstable_library_feature_note = match reason { - Some(r) => format!("use of unstable library feature '{feature}': {r}"), - None => format!("use of unstable library feature '{feature}'"), + let (mut some_note, mut none_note, mut reason_str) = (false, false, String::new()); + match reason { + Some(r) => { + some_note = true; + reason_str = r.to_string(); + } + None => none_note = true, }; - let mut err = struct_span_err!( - tcx.sess, - impl_span, - E0046, - "not all trait items implemented, missing: `{missing_item_name}`", - ); - err.note(format!("default implementation of `{missing_item_name}` is unstable")); - err.note(use_of_unstable_library_feature_note); + let mut err = tcx.sess.create_err(errors::MissingTraitItemUnstable { + span: impl_span, + some_note, + none_note, + missing_item_name, + feature, + reason: reason_str, + }); + rustc_session::parse::add_feature_diagnostics_for_issue( &mut err, &tcx.sess.parse_sess, feature, rustc_feature::GateIssue::Library(issue), ); + err.emit(); } @@ -488,16 +478,18 @@ fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>, sp: Span, d .iter() .map(|variant| tcx.hir().span_if_local(variant.def_id).unwrap()) .collect(); - let msg = format!("needs exactly one variant, but has {}", adt.variants().len(),); - let mut err = struct_span_err!(tcx.sess, sp, E0731, "transparent enum {msg}"); - err.span_label(sp, &msg); + let (mut spans, mut many) = (Vec::new(), None); if let [start @ .., end] = &*variant_spans { - for variant_span in start { - err.span_label(*variant_span, ""); - } - err.span_label(*end, &format!("too many variants in `{}`", tcx.def_path_str(did))); + spans = start.to_vec(); + many = Some(*end); } - err.emit(); + tcx.sess.emit_err(errors::TransparentEnumVariant { + span: sp, + spans, + many, + number: adt.variants().len(), + path: tcx.def_path_str(did), + }); } /// Emit an error when encountering two or more non-zero-sized fields in a transparent @@ -509,21 +501,21 @@ fn bad_non_zero_sized_fields<'tcx>( field_spans: impl Iterator<Item = Span>, sp: Span, ) { - let msg = format!("needs at most one non-zero-sized field, but has {field_count}"); - let mut err = struct_span_err!( - tcx.sess, - sp, - E0690, - "{}transparent {} {}", - if adt.is_enum() { "the variant of a " } else { "" }, - adt.descr(), - msg, - ); - err.span_label(sp, &msg); - for sp in field_spans { - err.span_label(sp, "this field is non-zero-sized"); + if adt.is_enum() { + tcx.sess.emit_err(errors::TransparentNonZeroSizedEnum { + span: sp, + spans: field_spans.collect(), + field_count, + desc: adt.descr(), + }); + } else { + tcx.sess.emit_err(errors::TransparentNonZeroSized { + span: sp, + spans: field_spans.collect(), + field_count, + desc: adt.descr(), + }); } - err.emit(); } // FIXME: Consider moving this method to a more fitting place. diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index b2ebbf993a1..0eafab017c7 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -360,7 +360,9 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe tcx, param_env, item_def_id, - tcx.explicit_item_bounds(item_def_id).to_vec(), + tcx.explicit_item_bounds(item_def_id) + .subst_identity_iter_copied() + .collect::<Vec<_>>(), &FxIndexSet::default(), gat_def_id.def_id, gat_generics, @@ -1125,7 +1127,7 @@ fn check_associated_type_bounds(wfcx: &WfCheckingCtxt<'_, '_>, item: ty::AssocIt let bounds = wfcx.tcx().explicit_item_bounds(item.def_id); debug!("check_associated_type_bounds: bounds={:?}", bounds); - let wf_obligations = bounds.iter().flat_map(|&(bound, bound_span)| { + let wf_obligations = bounds.subst_identity_iter_copied().flat_map(|(bound, bound_span)| { let normalized_bound = wfcx.normalize(span, None, bound); traits::wf::predicate_obligations( wfcx.infcx, @@ -1588,7 +1590,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> { } }); for (bound, bound_span) in tcx - .bound_explicit_item_bounds(opaque_ty.def_id) + .explicit_item_bounds(opaque_ty.def_id) .subst_iter_copied(tcx, opaque_ty.substs) { let bound = self.wfcx.normalize(bound_span, None, bound); diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 2e56d24638c..80d6bc7db9e 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -79,14 +79,14 @@ fn opaque_type_bounds<'tcx>( pub(super) fn explicit_item_bounds( tcx: TyCtxt<'_>, def_id: LocalDefId, -) -> &'_ [(ty::Predicate<'_>, Span)] { +) -> ty::EarlyBinder<&'_ [(ty::Predicate<'_>, Span)]> { match tcx.opt_rpitit_info(def_id.to_def_id()) { // RPITIT's bounds are the same as opaque type bounds, but with // a projection self type. Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) => { let item = tcx.hir().get_by_def_id(opaque_def_id.expect_local()).expect_item(); let opaque_ty = item.expect_opaque_ty(); - return opaque_type_bounds( + return ty::EarlyBinder(opaque_type_bounds( tcx, opaque_def_id.expect_local(), opaque_ty.bounds, @@ -95,7 +95,7 @@ pub(super) fn explicit_item_bounds( ty::InternalSubsts::identity_for_item(tcx, def_id), ), item.span, - ); + )); } // These should have been fed! Some(ty::ImplTraitInTraitData::Impl { .. }) => unreachable!(), @@ -103,7 +103,7 @@ pub(super) fn explicit_item_bounds( } let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); - match tcx.hir().get(hir_id) { + let bounds = match tcx.hir().get(hir_id) { hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Type(bounds, _), span, @@ -123,16 +123,18 @@ pub(super) fn explicit_item_bounds( opaque_type_bounds(tcx, def_id, bounds, item_ty, *span) } _ => bug!("item_bounds called on {:?}", def_id), - } + }; + ty::EarlyBinder(bounds) } pub(super) fn item_bounds( tcx: TyCtxt<'_>, def_id: DefId, ) -> ty::EarlyBinder<&'_ ty::List<ty::Predicate<'_>>> { - let bounds = tcx.mk_predicates_from_iter(util::elaborate( - tcx, - tcx.explicit_item_bounds(def_id).iter().map(|&(bound, _span)| bound), - )); - ty::EarlyBinder(bounds) + tcx.explicit_item_bounds(def_id).map_bound(|bounds| { + tcx.mk_predicates_from_iter(util::elaborate( + tcx, + bounds.iter().map(|&(bound, _span)| bound), + )) + }) } diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 2a3a683489d..cfce2463b18 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -631,3 +631,141 @@ pub(crate) struct SIMDFFIHighlyExperimental { pub span: Span, pub snip: String, } + +#[derive(Diagnostic)] +pub enum ImplNotMarkedDefault { + #[diag(hir_analysis_impl_not_marked_default, code = "E0520")] + #[note] + Ok { + #[primary_span] + #[label] + span: Span, + #[label(hir_analysis_ok_label)] + ok_label: Span, + ident: Symbol, + }, + #[diag(hir_analysis_impl_not_marked_default_err, code = "E0520")] + #[note] + Err { + #[primary_span] + #[label] + span: Span, + cname: Symbol, + ident: Symbol, + }, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_missing_trait_item, code = "E0046")] +pub(crate) struct MissingTraitItem { + #[primary_span] + #[label] + pub span: Span, + #[subdiagnostic] + pub missing_trait_item_label: Vec<MissingTraitItemLabel>, + #[subdiagnostic] + pub missing_trait_item: Vec<MissingTraitItemSuggestion>, + #[subdiagnostic] + pub missing_trait_item_none: Vec<MissingTraitItemSuggestionNone>, + pub missing_items_msg: String, +} + +#[derive(Subdiagnostic)] +#[label(hir_analysis_missing_trait_item_label)] +pub(crate) struct MissingTraitItemLabel { + #[primary_span] + pub span: Span, + pub item: Symbol, +} + +#[derive(Subdiagnostic)] +#[suggestion( + hir_analysis_missing_trait_item_suggestion, + style = "tool-only", + applicability = "has-placeholders", + code = "{code}" +)] +pub(crate) struct MissingTraitItemSuggestion { + #[primary_span] + pub span: Span, + pub code: String, + pub snippet: String, +} + +#[derive(Subdiagnostic)] +#[suggestion( + hir_analysis_missing_trait_item_suggestion, + style = "hidden", + applicability = "has-placeholders", + code = "{code}" +)] +pub(crate) struct MissingTraitItemSuggestionNone { + #[primary_span] + pub span: Span, + pub code: String, + pub snippet: String, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_missing_one_of_trait_item, code = "E0046")] +pub(crate) struct MissingOneOfTraitItem { + #[primary_span] + #[label] + pub span: Span, + #[note] + pub note: Option<Span>, + pub missing_items_msg: String, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_missing_trait_item_unstable, code = "E0046")] +#[note] +pub(crate) struct MissingTraitItemUnstable { + #[primary_span] + pub span: Span, + #[note(hir_analysis_some_note)] + pub some_note: bool, + #[note(hir_analysis_none_note)] + pub none_note: bool, + pub missing_item_name: Symbol, + pub feature: Symbol, + pub reason: String, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_transparent_enum_variant, code = "E0731")] +pub(crate) struct TransparentEnumVariant { + #[primary_span] + #[label] + pub span: Span, + #[label(hir_analysis_multi_label)] + pub spans: Vec<Span>, + #[label(hir_analysis_many_label)] + pub many: Option<Span>, + pub number: usize, + pub path: String, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_transparent_non_zero_sized_enum, code = "E0690")] +pub(crate) struct TransparentNonZeroSizedEnum<'a> { + #[primary_span] + #[label] + pub span: Span, + #[label(hir_analysis_labels)] + pub spans: Vec<Span>, + pub field_count: usize, + pub desc: &'a str, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_transparent_non_zero_sized, code = "E0690")] +pub(crate) struct TransparentNonZeroSized<'a> { + #[primary_span] + #[label] + pub span: Span, + #[label(hir_analysis_labels)] + pub spans: Vec<Span>, + pub field_count: usize, + pub desc: &'a str, +} diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs index 4d240e90b14..e735b048d73 100644 --- a/compiler/rustc_hir_analysis/src/variance/mod.rs +++ b/compiler/rustc_hir_analysis/src/variance/mod.rs @@ -153,8 +153,7 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc let mut collector = OpaqueTypeLifetimeCollector { tcx, root_def_id: item_def_id.to_def_id(), variances }; let id_substs = ty::InternalSubsts::identity_for_item(tcx, item_def_id); - for pred in tcx.bound_explicit_item_bounds(item_def_id.to_def_id()).transpose_iter() { - let pred = pred.map_bound(|(pred, _)| *pred).subst(tcx, id_substs); + for (pred, _) in tcx.explicit_item_bounds(item_def_id).subst_iter_copied(tcx, id_substs) { debug!(?pred); // We only ignore opaque type substs if the opaque type is the outermost type. diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index 6c2ce62722a..aefde8109a0 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -530,7 +530,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for ty in [first_ty, second_ty] { for (pred, _) in self .tcx - .bound_explicit_item_bounds(rpit_def_id) + .explicit_item_bounds(rpit_def_id) .subst_iter_copied(self.tcx, substs) { let pred = pred.kind().rebind(match pred.kind().skip_binder() { diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 8c2495e1dd8..7046269c2de 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -172,7 +172,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => self .deduce_closure_signature_from_predicates( expected_ty, - self.tcx.bound_explicit_item_bounds(def_id).subst_iter_copied(self.tcx, substs), + self.tcx.explicit_item_bounds(def_id).subst_iter_copied(self.tcx, substs), ), ty::Dynamic(ref object_type, ..) => { let sig = object_type.projection_bounds().find_map(|pb| { @@ -713,13 +713,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => self .tcx - .bound_explicit_item_bounds(def_id) + .explicit_item_bounds(def_id) .subst_iter_copied(self.tcx, substs) .find_map(|(p, s)| get_future_output(p, s))?, ty::Error(_) => return None, ty::Alias(ty::Projection, proj) if self.tcx.is_impl_trait_in_trait(proj.def_id) => self .tcx - .bound_explicit_item_bounds(proj.def_id) + .explicit_item_bounds(proj.def_id) .subst_iter_copied(self.tcx, proj.substs) .find_map(|(p, s)| get_future_output(p, s))?, _ => span_bug!( diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs index 8feef332de8..5b432475fc3 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs @@ -571,7 +571,7 @@ fn check_must_not_suspend_ty<'tcx>( // FIXME: support adding the attribute to TAITs ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => { let mut has_emitted = false; - for &(predicate, _) in fcx.tcx.explicit_item_bounds(def) { + for &(predicate, _) in fcx.tcx.explicit_item_bounds(def).skip_binder() { // We only look at the `DefId`, so it is safe to skip the binder here. if let ty::PredicateKind::Clause(ty::Clause::Trait(ref poly_trait_predicate)) = predicate.kind().skip_binder() diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index 0456dd56c34..fab9a8a5f4f 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -300,8 +300,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { trait_def_id: DefId, self_ty: Ty<'tcx>, opt_input_types: Option<&[Ty<'tcx>]>, - ) -> (traits::Obligation<'tcx, ty::Predicate<'tcx>>, &'tcx ty::List<ty::subst::GenericArg<'tcx>>) - { + ) -> (traits::PredicateObligation<'tcx>, &'tcx ty::List<ty::subst::GenericArg<'tcx>>) { // Construct a trait-reference `self_ty : Trait<input_tys>` let substs = InternalSubsts::for_item(self.tcx, trait_def_id, |param, _| { match param.kind { diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index b0c376a26f6..547f851526f 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -402,7 +402,7 @@ impl<'tcx> InferCtxt<'tcx> { let future_trait = self.tcx.require_lang_item(LangItem::Future, None); let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0]; - self.tcx.bound_explicit_item_bounds(def_id).subst_iter_copied(self.tcx, substs).find_map( + self.tcx.explicit_item_bounds(def_id).subst_iter_copied(self.tcx, substs).find_map( |(predicate, _)| { predicate .kind() diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 680465bdab6..334395945ea 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -540,7 +540,7 @@ impl<'tcx> InferCtxt<'tcx> { .obligations; } - let item_bounds = tcx.bound_explicit_item_bounds(def_id.to_def_id()); + let item_bounds = tcx.explicit_item_bounds(def_id); for (predicate, _) in item_bounds.subst_iter_copied(tcx, substs) { let predicate = predicate.fold_with(&mut BottomUpFolder { diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index 9dd4f0a8e4c..8ce8b4e2024 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -123,7 +123,7 @@ pub struct FulfillmentError<'tcx> { #[derive(Clone)] pub enum FulfillmentErrorCode<'tcx> { /// Inherently impossible to fulfill; this trait is implemented if and only if it is already implemented. - CodeCycle(Vec<Obligation<'tcx, ty::Predicate<'tcx>>>), + CodeCycle(Vec<PredicateObligation<'tcx>>), CodeSelectionError(SelectionError<'tcx>), CodeProjectionError(MismatchedProjectionTypes<'tcx>), CodeSubtypeError(ExpectedFound<Ty<'tcx>>, TypeError<'tcx>), // always comes from a SubtypePredicate diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index ce0f90bc1cc..7b0b5102c2d 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -777,7 +777,7 @@ fn test_unstable_options_tracking_hash() { tracked!(no_link, true); tracked!(no_profiler_runtime, true); tracked!(no_unique_section_names, true); - tracked!(oom, OomStrategy::Unwind); + tracked!(oom, OomStrategy::Panic); tracked!(osx_rpath_install_name, true); tracked!(packed_bundled_libs, true); tracked!(panic_abort_tests, true); diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs index f9d43fe2200..15715c8fca0 100644 --- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs +++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs @@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { // For every projection predicate in the opaque type's explicit bounds, // check that the type that we're assigning actually satisfies the bounds // of the associated type. - for &(pred, pred_span) in cx.tcx.explicit_item_bounds(def_id) { + for (pred, pred_span) in cx.tcx.explicit_item_bounds(def_id).subst_identity_iter_copied() { // Liberate bound regions in the predicate since we // don't actually care about lifetimes in this check. let predicate = cx.tcx.liberate_late_bound_regions(def_id, pred.kind()); @@ -112,7 +112,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { // with `impl Send: OtherTrait`. for (assoc_pred, assoc_pred_span) in cx .tcx - .bound_explicit_item_bounds(proj.projection_ty.def_id) + .explicit_item_bounds(proj.projection_ty.def_id) .subst_iter_copied(cx.tcx, &proj.projection_ty.substs) { let assoc_pred = assoc_pred.fold_with(proj_replacer); diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index d677d51881e..eb175e96997 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -254,7 +254,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { } ty::Adt(def, _) => is_def_must_use(cx, def.did(), span), ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => { - elaborate(cx.tcx, cx.tcx.explicit_item_bounds(def).iter().cloned()) + elaborate(cx.tcx, cx.tcx.explicit_item_bounds(def).subst_identity_iter_copied()) // We only care about self bounds for the impl-trait .filter_only_self() .find_map(|(pred, _span)| { diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 90cce9a8650..1acdc95ca8d 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -410,10 +410,15 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( } Options.RelaxELFRelocations = RelaxELFRelocations; Options.UseInitArray = UseInitArray; + +#if LLVM_VERSION_LT(17, 0) if (ForceEmulatedTls) { Options.ExplicitEmulatedTLS = true; Options.EmulatedTLS = true; } +#else + Options.EmulatedTLS = ForceEmulatedTls || Trip.hasDefaultEmulatedTLS(); +#endif if (TrapUnreachable) { // Tell LLVM to codegen `unreachable` into an explicit trap instruction. diff --git a/compiler/rustc_metadata/messages.ftl b/compiler/rustc_metadata/messages.ftl index f0158aeae85..79b8b417257 100644 --- a/compiler/rustc_metadata/messages.ftl +++ b/compiler/rustc_metadata/messages.ftl @@ -155,9 +155,19 @@ metadata_no_multiple_global_alloc = metadata_prev_global_alloc = previous global allocator defined here +metadata_no_multiple_alloc_error_handler = + cannot define multiple allocation error handlers + .label = cannot define a new allocation error handler + +metadata_prev_alloc_error_handler = + previous allocation error handler defined here + metadata_conflicting_global_alloc = the `#[global_allocator]` in {$other_crate_name} conflicts with global allocator in: {$crate_name} +metadata_conflicting_alloc_error_handler = + the `#[alloc_error_handler]` in {$other_crate_name} conflicts with allocation error handler in: {$crate_name} + metadata_global_alloc_required = no global memory allocator found but one is required; link to std or add `#[global_allocator]` to a static item that implements the GlobalAlloc trait diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 8bacd136647..179453238f2 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -38,8 +38,13 @@ pub struct CStore { /// This crate needs an allocator and either provides it itself, or finds it in a dependency. /// If the above is true, then this field denotes the kind of the found allocator. allocator_kind: Option<AllocatorKind>, + /// This crate needs an allocation error handler and either provides it itself, or finds it in a dependency. + /// If the above is true, then this field denotes the kind of the found allocator. + alloc_error_handler_kind: Option<AllocatorKind>, /// This crate has a `#[global_allocator]` item. has_global_allocator: bool, + /// This crate has a `#[alloc_error_handler]` item. + has_alloc_error_handler: bool, /// The interned [StableCrateId]s. pub(crate) stable_crate_ids: StableCrateIdMap, @@ -216,10 +221,18 @@ impl CStore { self.allocator_kind } + pub(crate) fn alloc_error_handler_kind(&self) -> Option<AllocatorKind> { + self.alloc_error_handler_kind + } + pub(crate) fn has_global_allocator(&self) -> bool { self.has_global_allocator } + pub(crate) fn has_alloc_error_handler(&self) -> bool { + self.has_alloc_error_handler + } + pub fn report_unused_deps(&self, tcx: TyCtxt<'_>) { let json_unused_externs = tcx.sess.opts.json_unused_externs; @@ -255,7 +268,9 @@ impl CStore { metas: IndexVec::from_iter(iter::once(None)), injected_panic_runtime: None, allocator_kind: None, + alloc_error_handler_kind: None, has_global_allocator: false, + has_alloc_error_handler: false, stable_crate_ids, unused_externs: Vec::new(), } @@ -761,6 +776,14 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { } spans => !spans.is_empty(), }; + self.cstore.has_alloc_error_handler = match &*alloc_error_handler_spans(krate) { + [span1, span2, ..] => { + self.sess + .emit_err(errors::NoMultipleAllocErrorHandler { span2: *span2, span1: *span1 }); + true + } + spans => !spans.is_empty(), + }; // Check to see if we actually need an allocator. This desire comes // about through the `#![needs_allocator]` attribute and is typically @@ -801,6 +824,21 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { } } } + let mut alloc_error_handler = + self.cstore.has_alloc_error_handler.then(|| Symbol::intern("this crate")); + for (_, data) in self.cstore.iter_crate_data() { + if data.has_alloc_error_handler() { + match alloc_error_handler { + Some(other_crate) => { + self.sess.emit_err(errors::ConflictingAllocErrorHandler { + crate_name: data.name(), + other_crate_name: other_crate, + }); + } + None => alloc_error_handler = Some(data.name()), + } + } + } if global_allocator.is_some() { self.cstore.allocator_kind = Some(AllocatorKind::Global); @@ -816,6 +854,14 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { } self.cstore.allocator_kind = Some(AllocatorKind::Default); } + + if alloc_error_handler.is_some() { + self.cstore.alloc_error_handler_kind = Some(AllocatorKind::Global); + } else { + // The alloc crate provides a default allocation error handler if + // one isn't specified. + self.cstore.alloc_error_handler_kind = Some(AllocatorKind::Default); + } } fn inject_dependency_if( @@ -991,6 +1037,28 @@ fn global_allocator_spans(krate: &ast::Crate) -> Vec<Span> { f.spans } +fn alloc_error_handler_spans(krate: &ast::Crate) -> Vec<Span> { + struct Finder { + name: Symbol, + spans: Vec<Span>, + } + impl<'ast> visit::Visitor<'ast> for Finder { + fn visit_item(&mut self, item: &'ast ast::Item) { + if item.ident.name == self.name + && attr::contains_name(&item.attrs, sym::rustc_std_internal_symbol) + { + self.spans.push(item.span); + } + visit::walk_item(self, item) + } + } + + let name = Symbol::intern(&AllocatorKind::Global.fn_name(sym::oom)); + let mut f = Finder { name, spans: Vec::new() }; + visit::walk_crate(&mut f, krate); + f.spans +} + // On Windows the compiler would sometimes intermittently fail to open the // proc-macro DLL with `Error::LoadLibraryExW`. It is suspected that something in the // system still holds a lock on the file, so we retry a few times before calling it diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs index 7ecb551a3e5..51b41b5f6a2 100644 --- a/compiler/rustc_metadata/src/errors.rs +++ b/compiler/rustc_metadata/src/errors.rs @@ -353,6 +353,16 @@ pub struct NoMultipleGlobalAlloc { } #[derive(Diagnostic)] +#[diag(metadata_no_multiple_alloc_error_handler)] +pub struct NoMultipleAllocErrorHandler { + #[primary_span] + #[label] + pub span2: Span, + #[label(metadata_prev_alloc_error_handler)] + pub span1: Span, +} + +#[derive(Diagnostic)] #[diag(metadata_conflicting_global_alloc)] pub struct ConflictingGlobalAlloc { pub crate_name: Symbol, @@ -360,6 +370,13 @@ pub struct ConflictingGlobalAlloc { } #[derive(Diagnostic)] +#[diag(metadata_conflicting_alloc_error_handler)] +pub struct ConflictingAllocErrorHandler { + pub crate_name: Symbol, + pub other_crate_name: Symbol, +} + +#[derive(Diagnostic)] #[diag(metadata_global_alloc_required)] pub struct GlobalAllocRequired; diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 820a502d04c..a310cbb8029 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -23,7 +23,7 @@ use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState}; use rustc_middle::ty::codec::TyDecoder; use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::GeneratorDiagnosticData; -use rustc_middle::ty::{self, ParameterizedOverTcx, Ty, TyCtxt, Visibility}; +use rustc_middle::ty::{self, ParameterizedOverTcx, Predicate, Ty, TyCtxt, Visibility}; use rustc_serialize::opaque::MemDecoder; use rustc_serialize::{Decodable, Decoder}; use rustc_session::cstore::{ @@ -373,16 +373,6 @@ impl<'a, 'tcx> TyDecoder for DecodeContext<'a, 'tcx> { self.tcx() } - #[inline] - fn peek_byte(&self) -> u8 { - self.opaque.data[self.opaque.position()] - } - - #[inline] - fn position(&self) -> usize { - self.opaque.position() - } - fn cached_ty_for_shorthand<F>(&mut self, shorthand: usize, or_insert_with: F) -> Ty<'tcx> where F: FnOnce(&mut Self) -> Ty<'tcx>, @@ -404,7 +394,7 @@ impl<'a, 'tcx> TyDecoder for DecodeContext<'a, 'tcx> { where F: FnOnce(&mut Self) -> R, { - let new_opaque = MemDecoder::new(self.opaque.data, pos); + let new_opaque = MemDecoder::new(self.opaque.data(), pos); let old_opaque = mem::replace(&mut self.opaque, new_opaque); let old_state = mem::replace(&mut self.lazy_state, LazyState::NoNode); let r = f(self); @@ -625,17 +615,12 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for Symbol { SYMBOL_OFFSET => { // read str offset let pos = d.read_usize(); - let old_pos = d.opaque.position(); // move to str offset and read - d.opaque.set_position(pos); - let s = d.read_str(); - let sym = Symbol::intern(s); - - // restore position - d.opaque.set_position(old_pos); - - sym + d.opaque.with_position(pos, |d| { + let s = d.read_str(); + Symbol::intern(s) + }) } SYMBOL_PREINTERNED => { let symbol_index = d.read_u32(); @@ -857,6 +842,20 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { ) } + fn get_explicit_item_bounds( + self, + index: DefIndex, + tcx: TyCtxt<'tcx>, + ) -> ty::EarlyBinder<&'tcx [(Predicate<'tcx>, Span)]> { + let lazy = self.root.tables.explicit_item_bounds.get(self, index); + let output = if lazy.is_default() { + &mut [] + } else { + tcx.arena.alloc_from_iter(lazy.decode((self, tcx))) + }; + ty::EarlyBinder(&*output) + } + fn get_variant(self, kind: &DefKind, index: DefIndex, parent_did: DefId) -> ty::VariantDef { let adt_kind = match kind { DefKind::Variant => ty::AdtKind::Enum, @@ -1683,6 +1682,10 @@ impl CrateMetadata { self.root.has_global_allocator } + pub(crate) fn has_alloc_error_handler(&self) -> bool { + self.root.has_alloc_error_handler + } + pub(crate) fn has_default_lib_allocator(&self) -> bool { self.root.has_default_lib_allocator } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 4aa3768fc3b..4a3b783c636 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -203,7 +203,7 @@ impl IntoArgs for (CrateNum, SimplifiedType) { } provide! { tcx, def_id, other, cdata, - explicit_item_bounds => { table_defaulted_array } + explicit_item_bounds => { cdata.get_explicit_item_bounds(def_id.index, tcx) } explicit_predicates_of => { table } generics_of => { table } inferred_outlives_of => { table_defaulted_array } @@ -290,6 +290,7 @@ provide! { tcx, def_id, other, cdata, is_panic_runtime => { cdata.root.panic_runtime } is_compiler_builtins => { cdata.root.compiler_builtins } has_global_allocator => { cdata.root.has_global_allocator } + has_alloc_error_handler => { cdata.root.has_alloc_error_handler } has_panic_handler => { cdata.root.has_panic_handler } is_profiler_runtime => { cdata.root.profiler_runtime } required_panic_strategy => { cdata.root.required_panic_strategy } @@ -378,6 +379,7 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { // resolve! Does this work? Unsure! That's what the issue is about *providers = Providers { allocator_kind: |tcx, ()| CStore::from_tcx(tcx).allocator_kind(), + alloc_error_handler_kind: |tcx, ()| CStore::from_tcx(tcx).alloc_error_handler_kind(), is_private_dep: |_tcx, LocalCrate| false, native_library: |tcx, id| { tcx.native_libraries(id.krate) @@ -494,6 +496,7 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { dependency_formats: |tcx, ()| Lrc::new(crate::dependency_format::calculate(tcx)), has_global_allocator: |tcx, LocalCrate| CStore::from_tcx(tcx).has_global_allocator(), + has_alloc_error_handler: |tcx, LocalCrate| CStore::from_tcx(tcx).has_alloc_error_handler(), postorder_cnums: |tcx, ()| { tcx.arena .alloc_slice(&CStore::from_tcx(tcx).crate_dependencies_in_postorder(LOCAL_CRATE)) diff --git a/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs b/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs index 02cab561b8f..05402a58701 100644 --- a/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs +++ b/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs @@ -45,9 +45,6 @@ impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for DefPathHashMapRef<'tcx> { impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for DefPathHashMapRef<'static> { fn decode(d: &mut DecodeContext<'a, 'tcx>) -> DefPathHashMapRef<'static> { - // Import TyDecoder so we can access the DecodeContext::position() method - use crate::rustc_middle::ty::codec::TyDecoder; - let len = d.read_usize(); let pos = d.position(); let o = slice_owned(d.blob().clone(), |blob| &blob[pos..pos + len]); diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index fd8e49efea0..f5ffdd27cae 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -676,6 +676,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { panic_in_drop_strategy: tcx.sess.opts.unstable_opts.panic_in_drop, edition: tcx.sess.edition(), has_global_allocator: tcx.has_global_allocator(LOCAL_CRATE), + has_alloc_error_handler: tcx.has_alloc_error_handler(LOCAL_CRATE), has_panic_handler: tcx.has_panic_handler(LOCAL_CRATE), has_default_lib_allocator: attr::contains_name(&attrs, sym::default_lib_allocator), proc_macro_data, @@ -1422,7 +1423,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_explicit_item_bounds(&mut self, def_id: DefId) { debug!("EncodeContext::encode_explicit_item_bounds({:?})", def_id); - let bounds = self.tcx.explicit_item_bounds(def_id); + let bounds = self.tcx.explicit_item_bounds(def_id).skip_binder(); record_defaulted_array!(self.tables.explicit_item_bounds[def_id] <- bounds); } diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 1bb0eabc64f..dd02463e16a 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -225,6 +225,7 @@ pub(crate) struct CrateRoot { panic_in_drop_strategy: PanicStrategy, edition: Edition, has_global_allocator: bool, + has_alloc_error_handler: bool, has_panic_handler: bool, has_default_lib_allocator: bool, diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 76a8367b2c4..e9172e767e0 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -60,6 +60,7 @@ #![feature(const_option)] #![feature(trait_alias)] #![feature(ptr_alignment_type)] +#![feature(macro_metavar_expr)] #![recursion_limit = "512"] #![allow(rustc::potential_query_instability)] diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 4b7bc60926e..84b5d6b0d0f 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -251,7 +251,7 @@ rustc_queries! { /// `key` is the `DefId` of the associated type or opaque type. /// /// Bounds from the parent (e.g. with nested impl trait) are not included. - query explicit_item_bounds(key: DefId) -> &'tcx [(ty::Predicate<'tcx>, Span)] { + query explicit_item_bounds(key: DefId) -> ty::EarlyBinder<&'tcx [(ty::Predicate<'tcx>, Span)]> { desc { |tcx| "finding item bounds for `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } separate_provide_extern @@ -1351,6 +1351,13 @@ rustc_queries! { desc { "checking if the crate has_global_allocator" } separate_provide_extern } + query has_alloc_error_handler(_: CrateNum) -> bool { + // This query depends on untracked global state in CStore + eval_always + fatal_cycle + desc { "checking if the crate has_alloc_error_handler" } + separate_provide_extern + } query has_panic_handler(_: CrateNum) -> bool { fatal_cycle desc { "checking if the crate has_panic_handler" } @@ -1723,6 +1730,10 @@ rustc_queries! { eval_always desc { "getting the allocator kind for the current crate" } } + query alloc_error_handler_kind(_: ()) -> Option<AllocatorKind> { + eval_always + desc { "alloc error handler kind for the current crate" } + } query upvars_mentioned(def_id: DefId) -> Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>> { desc { |tcx| "collecting upvars mentioned in `{}`", tcx.def_path_str(def_id) } diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 5454d406dd1..3793d85c85a 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -530,6 +530,16 @@ macro_rules! implement_ty_decoder { fn read_raw_bytes(&mut self, len: usize) -> &[u8] { self.opaque.read_raw_bytes(len) } + + #[inline] + fn position(&self) -> usize { + self.opaque.position() + } + + #[inline] + fn peek_byte(&self) -> u8 { + self.opaque.peek_byte() + } } } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 4a4f6770fc4..7df4be263d5 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1603,7 +1603,7 @@ impl<'tcx> TyCtxt<'tcx> { let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = ty.kind() else { return false }; let future_trait = self.require_lang_item(LangItem::Future, None); - self.explicit_item_bounds(def_id).iter().any(|(predicate, _)| { + self.explicit_item_bounds(def_id).skip_binder().iter().any(|&(predicate, _)| { let ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) = predicate.kind().skip_binder() else { return false; }; diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 17647d13f99..8e4e708b73c 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -861,6 +861,11 @@ impl<'tcx> PolyTraitPredicate<'tcx> { pub fn is_const_if_const(self) -> bool { self.skip_binder().is_const_if_const() } + + #[inline] + pub fn polarity(self) -> ImplPolarity { + self.skip_binder().polarity + } } /// `A: B` @@ -1497,29 +1502,12 @@ struct ParamTag { constness: hir::Constness, } -unsafe impl rustc_data_structures::tagged_ptr::Tag for ParamTag { - const BITS: u32 = 2; - - #[inline] - fn into_usize(self) -> usize { - match self { - Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::NotConst } => 0, - Self { reveal: traits::Reveal::All, constness: hir::Constness::NotConst } => 1, - Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::Const } => 2, - Self { reveal: traits::Reveal::All, constness: hir::Constness::Const } => 3, - } - } - - #[inline] - unsafe fn from_usize(ptr: usize) -> Self { - match ptr { - 0 => Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::NotConst }, - 1 => Self { reveal: traits::Reveal::All, constness: hir::Constness::NotConst }, - 2 => Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::Const }, - 3 => Self { reveal: traits::Reveal::All, constness: hir::Constness::Const }, - _ => std::hint::unreachable_unchecked(), - } - } +impl_tag! { + impl Tag for ParamTag; + ParamTag { reveal: traits::Reveal::UserFacing, constness: hir::Constness::NotConst }, + ParamTag { reveal: traits::Reveal::All, constness: hir::Constness::NotConst }, + ParamTag { reveal: traits::Reveal::UserFacing, constness: hir::Constness::Const }, + ParamTag { reveal: traits::Reveal::All, constness: hir::Constness::Const }, } impl<'tcx> fmt::Debug for ParamEnv<'tcx> { diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 4c95d0f8415..1c1432ecd5a 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -914,7 +914,7 @@ pub trait PrettyPrinter<'tcx>: // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`, // by looking up the projections associated with the def_id. - let bounds = tcx.bound_explicit_item_bounds(def_id); + let bounds = tcx.explicit_item_bounds(def_id); let mut traits = FxIndexMap::default(); let mut fn_traits = FxIndexMap::default(); diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index a2611022406..b35b514d795 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -95,7 +95,7 @@ impl<'tcx> fmt::Debug for ty::FnSig<'tcx> { impl<'tcx> fmt::Debug for ty::ConstVid<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "_#{}c", self.index) + write!(f, "?{}c", self.index) } } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 29ae42be096..82dec7d98ad 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1436,7 +1436,7 @@ pub struct ConstVid<'tcx> { rustc_index::newtype_index! { /// A **region** (lifetime) **v**ariable **ID**. #[derive(HashStable)] - #[debug_format = "'_#{}r"] + #[debug_format = "'?{}"] pub struct RegionVid {} } diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index a439211ca33..63b2acdbe4e 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -612,6 +612,12 @@ where ) -> SubstIter<'s, 'tcx, I> { SubstIter { it: self.0.into_iter(), tcx, substs } } + + /// Similar to [`subst_identity`](EarlyBinder::subst_identity), + /// but on an iterator of `TypeFoldable` values. + pub fn subst_identity_iter(self) -> I::IntoIter { + self.0.into_iter() + } } pub struct SubstIter<'s, 'tcx, I: IntoIterator> { @@ -664,6 +670,12 @@ where ) -> SubstIterCopied<'s, 'tcx, I> { SubstIterCopied { it: self.0.into_iter(), tcx, substs } } + + /// Similar to [`subst_identity`](EarlyBinder::subst_identity), + /// but on an iterator of values that deref to a `TypeFoldable`. + pub fn subst_identity_iter_copied(self) -> impl Iterator<Item = <I::Item as Deref>::Target> { + self.0.into_iter().map(|v| *v) + } } pub struct SubstIterCopied<'a, 'tcx, I: IntoIterator> { diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 7127fdbf26a..4c346b00256 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -701,13 +701,6 @@ impl<'tcx> TyCtxt<'tcx> { if visitor.found_recursion { Err(expanded_type) } else { Ok(expanded_type) } } - pub fn bound_explicit_item_bounds( - self, - def_id: DefId, - ) -> ty::EarlyBinder<&'tcx [(ty::Predicate<'tcx>, rustc_span::Span)]> { - ty::EarlyBinder(self.explicit_item_bounds(def_id)) - } - /// Returns names of captured upvars for closures and generators. /// /// Here are some examples: diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index 34a7ee9e264..e44dd084b2d 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -1800,7 +1800,7 @@ fn check_must_not_suspend_ty<'tcx>( // FIXME: support adding the attribute to TAITs ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => { let mut has_emitted = false; - for &(predicate, _) in tcx.explicit_item_bounds(def) { + for &(predicate, _) in tcx.explicit_item_bounds(def).skip_binder() { // We only look at the `DefId`, so it is safe to skip the binder here. if let ty::PredicateKind::Clause(ty::Clause::Trait(ref poly_trait_predicate)) = predicate.kind().skip_binder() diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 9567329192d..c607c7fd5f4 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -269,7 +269,7 @@ where // and are visited by shallow visitors. self.visit_predicates(ty::GenericPredicates { parent: None, - predicates: tcx.explicit_item_bounds(def_id), + predicates: tcx.explicit_item_bounds(def_id).skip_binder(), })?; } } @@ -1784,7 +1784,7 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> { fn bounds(&mut self) -> &mut Self { self.visit_predicates(ty::GenericPredicates { parent: None, - predicates: self.tcx.explicit_item_bounds(self.item_def_id), + predicates: self.tcx.explicit_item_bounds(self.item_def_id).skip_binder(), }); self } diff --git a/compiler/rustc_query_impl/src/on_disk_cache.rs b/compiler/rustc_query_impl/src/on_disk_cache.rs index 91b56660b15..c0f2d7803d4 100644 --- a/compiler/rustc_query_impl/src/on_disk_cache.rs +++ b/compiler/rustc_query_impl/src/on_disk_cache.rs @@ -169,13 +169,12 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> { // Decode the *position* of the footer, which can be found in the // last 8 bytes of the file. - decoder.set_position(data.len() - IntEncodedWithFixedSize::ENCODED_SIZE); - let footer_pos = IntEncodedWithFixedSize::decode(&mut decoder).0 as usize; - + let footer_pos = decoder + .with_position(decoder.len() - IntEncodedWithFixedSize::ENCODED_SIZE, |decoder| { + IntEncodedWithFixedSize::decode(decoder).0 as usize + }); // Decode the file footer, which contains all the lookup tables, etc. - decoder.set_position(footer_pos); - - decode_tagged(&mut decoder, TAG_FILE_FOOTER) + decoder.with_position(footer_pos, |decoder| decode_tagged(decoder, TAG_FILE_FOOTER)) }; Self { @@ -522,29 +521,13 @@ impl<'a, 'tcx> CacheDecoder<'a, 'tcx> { } } -trait DecoderWithPosition: Decoder { - fn position(&self) -> usize; -} - -impl<'a> DecoderWithPosition for MemDecoder<'a> { - fn position(&self) -> usize { - self.position() - } -} - -impl<'a, 'tcx> DecoderWithPosition for CacheDecoder<'a, 'tcx> { - fn position(&self) -> usize { - self.opaque.position() - } -} - // Decodes something that was encoded with `encode_tagged()` and verify that the // tag matches and the correct amount of bytes was read. fn decode_tagged<D, T, V>(decoder: &mut D, expected_tag: T) -> V where T: Decodable<D> + Eq + std::fmt::Debug, V: Decodable<D>, - D: DecoderWithPosition, + D: Decoder, { let start_pos = decoder.position(); @@ -568,16 +551,6 @@ impl<'a, 'tcx> TyDecoder for CacheDecoder<'a, 'tcx> { self.tcx } - #[inline] - fn position(&self) -> usize { - self.opaque.position() - } - - #[inline] - fn peek_byte(&self) -> u8 { - self.opaque.data[self.opaque.position()] - } - fn cached_ty_for_shorthand<F>(&mut self, shorthand: usize, or_insert_with: F) -> Ty<'tcx> where F: FnOnce(&mut Self) -> Ty<'tcx>, @@ -600,9 +573,9 @@ impl<'a, 'tcx> TyDecoder for CacheDecoder<'a, 'tcx> { where F: FnOnce(&mut Self) -> R, { - debug_assert!(pos < self.opaque.data.len()); + debug_assert!(pos < self.opaque.len()); - let new_opaque = MemDecoder::new(self.opaque.data, pos); + let new_opaque = MemDecoder::new(self.opaque.data(), pos); let old_opaque = mem::replace(&mut self.opaque, new_opaque); let r = f(self); self.opaque = old_opaque; @@ -743,17 +716,12 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for Symbol { SYMBOL_OFFSET => { // read str offset let pos = d.read_usize(); - let old_pos = d.opaque.position(); // move to str offset and read - d.opaque.set_position(pos); - let s = d.read_str(); - let sym = Symbol::intern(s); - - // restore position - d.opaque.set_position(old_pos); - - sym + d.opaque.with_position(pos, |d| { + let s = d.read_str(); + Symbol::intern(s) + }) } SYMBOL_PREINTERNED => { let symbol_index = d.read_u32(); diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs index 59c1333fb5a..edddfda6242 100644 --- a/compiler/rustc_query_system/src/dep_graph/serialized.rs +++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs @@ -94,21 +94,19 @@ impl<'a, K: DepKind + Decodable<MemDecoder<'a>>> Decodable<MemDecoder<'a>> { #[instrument(level = "debug", skip(d))] fn decode(d: &mut MemDecoder<'a>) -> SerializedDepGraph<K> { - let start_position = d.position(); - // The last 16 bytes are the node count and edge count. debug!("position: {:?}", d.position()); - d.set_position(d.data.len() - 2 * IntEncodedWithFixedSize::ENCODED_SIZE); + let (node_count, edge_count) = + d.with_position(d.len() - 2 * IntEncodedWithFixedSize::ENCODED_SIZE, |d| { + debug!("position: {:?}", d.position()); + let node_count = IntEncodedWithFixedSize::decode(d).0 as usize; + let edge_count = IntEncodedWithFixedSize::decode(d).0 as usize; + (node_count, edge_count) + }); debug!("position: {:?}", d.position()); - let node_count = IntEncodedWithFixedSize::decode(d).0 as usize; - let edge_count = IntEncodedWithFixedSize::decode(d).0 as usize; debug!(?node_count, ?edge_count); - debug!("position: {:?}", d.position()); - d.set_position(start_position); - debug!("position: {:?}", d.position()); - let mut nodes = IndexVec::with_capacity(node_count); let mut fingerprints = IndexVec::with_capacity(node_count); let mut edge_list_indices = IndexVec::with_capacity(node_count); diff --git a/compiler/rustc_serialize/src/leb128.rs b/compiler/rustc_serialize/src/leb128.rs index 7dad9aa01fa..e568b9e6786 100644 --- a/compiler/rustc_serialize/src/leb128.rs +++ b/compiler/rustc_serialize/src/leb128.rs @@ -1,3 +1,6 @@ +use crate::opaque::MemDecoder; +use crate::serialize::Decoder; + /// Returns the length of the longest LEB128 encoding for `T`, assuming `T` is an integer type pub const fn max_leb128_len<T>() -> usize { // The longest LEB128 encoding for an integer uses 7 bits per byte. @@ -50,21 +53,19 @@ impl_write_unsigned_leb128!(write_usize_leb128, usize); macro_rules! impl_read_unsigned_leb128 { ($fn_name:ident, $int_ty:ty) => { #[inline] - pub fn $fn_name(slice: &[u8], position: &mut usize) -> $int_ty { + pub fn $fn_name(decoder: &mut MemDecoder<'_>) -> $int_ty { // The first iteration of this loop is unpeeled. This is a // performance win because this code is hot and integer values less // than 128 are very common, typically occurring 50-80% or more of // the time, even for u64 and u128. - let byte = slice[*position]; - *position += 1; + let byte = decoder.read_u8(); if (byte & 0x80) == 0 { return byte as $int_ty; } let mut result = (byte & 0x7F) as $int_ty; let mut shift = 7; loop { - let byte = slice[*position]; - *position += 1; + let byte = decoder.read_u8(); if (byte & 0x80) == 0 { result |= (byte as $int_ty) << shift; return result; @@ -127,14 +128,13 @@ impl_write_signed_leb128!(write_isize_leb128, isize); macro_rules! impl_read_signed_leb128 { ($fn_name:ident, $int_ty:ty) => { #[inline] - pub fn $fn_name(slice: &[u8], position: &mut usize) -> $int_ty { + pub fn $fn_name(decoder: &mut MemDecoder<'_>) -> $int_ty { let mut result = 0; let mut shift = 0; let mut byte; loop { - byte = slice[*position]; - *position += 1; + byte = decoder.read_u8(); result |= <$int_ty>::from(byte & 0x7F) << shift; shift += 7; diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs index 1f8d2336c4e..ce8503918b4 100644 --- a/compiler/rustc_serialize/src/lib.rs +++ b/compiler/rustc_serialize/src/lib.rs @@ -16,6 +16,7 @@ Core encoding and decoding interfaces. #![feature(maybe_uninit_slice)] #![feature(new_uninit)] #![feature(allocator_api)] +#![feature(ptr_sub_ptr)] #![cfg_attr(test, feature(test))] #![allow(rustc::internal)] #![deny(rustc::untranslatable_diagnostic)] diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs index 53e5c896736..b7976ea3b1c 100644 --- a/compiler/rustc_serialize/src/opaque.rs +++ b/compiler/rustc_serialize/src/opaque.rs @@ -2,7 +2,9 @@ use crate::leb128::{self, largest_max_leb128_len}; use crate::serialize::{Decodable, Decoder, Encodable, Encoder}; use std::fs::File; use std::io::{self, Write}; +use std::marker::PhantomData; use std::mem::MaybeUninit; +use std::ops::Range; use std::path::Path; use std::ptr; @@ -510,39 +512,126 @@ impl Encoder for FileEncoder { // Decoder // ----------------------------------------------------------------------------- +// Conceptually, `MemDecoder` wraps a `&[u8]` with a cursor into it that is always valid. +// This is implemented with three pointers, two which represent the original slice and a +// third that is our cursor. +// It is an invariant of this type that start <= current <= end. +// Additionally, the implementation of this type never modifies start and end. pub struct MemDecoder<'a> { - pub data: &'a [u8], - position: usize, + start: *const u8, + current: *const u8, + end: *const u8, + _marker: PhantomData<&'a u8>, } impl<'a> MemDecoder<'a> { #[inline] pub fn new(data: &'a [u8], position: usize) -> MemDecoder<'a> { - MemDecoder { data, position } + let Range { start, end } = data.as_ptr_range(); + MemDecoder { start, current: data[position..].as_ptr(), end, _marker: PhantomData } } #[inline] - pub fn position(&self) -> usize { - self.position + pub fn data(&self) -> &'a [u8] { + // SAFETY: This recovers the original slice, only using members we never modify. + unsafe { std::slice::from_raw_parts(self.start, self.len()) } } #[inline] - pub fn set_position(&mut self, pos: usize) { - self.position = pos + pub fn len(&self) -> usize { + // SAFETY: This recovers the length of the original slice, only using members we never modify. + unsafe { self.end.sub_ptr(self.start) } + } + + #[inline] + pub fn remaining(&self) -> usize { + // SAFETY: This type guarantees current <= end. + unsafe { self.end.sub_ptr(self.current) } + } + + #[cold] + #[inline(never)] + fn decoder_exhausted() -> ! { + panic!("MemDecoder exhausted") } #[inline] - pub fn advance(&mut self, bytes: usize) { - self.position += bytes; + fn read_byte(&mut self) -> u8 { + if self.current == self.end { + Self::decoder_exhausted(); + } + // SAFETY: This type guarantees current <= end, and we just checked current == end. + unsafe { + let byte = *self.current; + self.current = self.current.add(1); + byte + } + } + + #[inline] + fn read_array<const N: usize>(&mut self) -> [u8; N] { + self.read_raw_bytes(N).try_into().unwrap() + } + + // The trait method doesn't have a lifetime parameter, and we need a version of this + // that definitely returns a slice based on the underlying storage as opposed to + // the Decoder itself in order to implement read_str efficiently. + #[inline] + fn read_raw_bytes_inherent(&mut self, bytes: usize) -> &'a [u8] { + if bytes > self.remaining() { + Self::decoder_exhausted(); + } + // SAFETY: We just checked if this range is in-bounds above. + unsafe { + let slice = std::slice::from_raw_parts(self.current, bytes); + self.current = self.current.add(bytes); + slice + } + } + + /// While we could manually expose manipulation of the decoder position, + /// all current users of that method would need to reset the position later, + /// incurring the bounds check of set_position twice. + #[inline] + pub fn with_position<F, T>(&mut self, pos: usize, func: F) -> T + where + F: Fn(&mut MemDecoder<'a>) -> T, + { + struct SetOnDrop<'a, 'guarded> { + decoder: &'guarded mut MemDecoder<'a>, + current: *const u8, + } + impl Drop for SetOnDrop<'_, '_> { + fn drop(&mut self) { + self.decoder.current = self.current; + } + } + + if pos >= self.len() { + Self::decoder_exhausted(); + } + let previous = self.current; + // SAFETY: We just checked if this add is in-bounds above. + unsafe { + self.current = self.start.add(pos); + } + let guard = SetOnDrop { current: previous, decoder: self }; + func(guard.decoder) } } macro_rules! read_leb128 { - ($dec:expr, $fun:ident) => {{ leb128::$fun($dec.data, &mut $dec.position) }}; + ($dec:expr, $fun:ident) => {{ leb128::$fun($dec) }}; } impl<'a> Decoder for MemDecoder<'a> { #[inline] + fn position(&self) -> usize { + // SAFETY: This type guarantees start <= current + unsafe { self.current.sub_ptr(self.start) } + } + + #[inline] fn read_u128(&mut self) -> u128 { read_leb128!(self, read_u128_leb128) } @@ -559,17 +648,12 @@ impl<'a> Decoder for MemDecoder<'a> { #[inline] fn read_u16(&mut self) -> u16 { - let bytes = [self.data[self.position], self.data[self.position + 1]]; - let value = u16::from_le_bytes(bytes); - self.position += 2; - value + u16::from_le_bytes(self.read_array()) } #[inline] fn read_u8(&mut self) -> u8 { - let value = self.data[self.position]; - self.position += 1; - value + self.read_byte() } #[inline] @@ -594,17 +678,12 @@ impl<'a> Decoder for MemDecoder<'a> { #[inline] fn read_i16(&mut self) -> i16 { - let bytes = [self.data[self.position], self.data[self.position + 1]]; - let value = i16::from_le_bytes(bytes); - self.position += 2; - value + i16::from_le_bytes(self.read_array()) } #[inline] fn read_i8(&mut self) -> i8 { - let value = self.data[self.position]; - self.position += 1; - value as i8 + self.read_byte() as i8 } #[inline] @@ -625,22 +704,26 @@ impl<'a> Decoder for MemDecoder<'a> { } #[inline] - fn read_str(&mut self) -> &'a str { + fn read_str(&mut self) -> &str { let len = self.read_usize(); - let sentinel = self.data[self.position + len]; - assert!(sentinel == STR_SENTINEL); - let s = unsafe { - std::str::from_utf8_unchecked(&self.data[self.position..self.position + len]) - }; - self.position += len + 1; - s + let bytes = self.read_raw_bytes_inherent(len + 1); + assert!(bytes[len] == STR_SENTINEL); + unsafe { std::str::from_utf8_unchecked(&bytes[..len]) } } #[inline] - fn read_raw_bytes(&mut self, bytes: usize) -> &'a [u8] { - let start = self.position; - self.position += bytes; - &self.data[start..self.position] + fn read_raw_bytes(&mut self, bytes: usize) -> &[u8] { + self.read_raw_bytes_inherent(bytes) + } + + #[inline] + fn peek_byte(&self) -> u8 { + if self.current == self.end { + Self::decoder_exhausted(); + } + // SAFETY: This type guarantees current is inbounds or one-past-the-end, which is end. + // Since we just checked current == end, the current pointer must be inbounds. + unsafe { *self.current } } } diff --git a/compiler/rustc_serialize/src/serialize.rs b/compiler/rustc_serialize/src/serialize.rs index 527abc23727..a6d9c7b7d42 100644 --- a/compiler/rustc_serialize/src/serialize.rs +++ b/compiler/rustc_serialize/src/serialize.rs @@ -84,6 +84,8 @@ pub trait Decoder { fn read_char(&mut self) -> char; fn read_str(&mut self) -> &str; fn read_raw_bytes(&mut self, len: usize) -> &[u8]; + fn peek_byte(&self) -> u8; + fn position(&self) -> usize; } /// Trait for types that can be serialized diff --git a/compiler/rustc_serialize/tests/leb128.rs b/compiler/rustc_serialize/tests/leb128.rs index 314c07db981..7872e778431 100644 --- a/compiler/rustc_serialize/tests/leb128.rs +++ b/compiler/rustc_serialize/tests/leb128.rs @@ -3,6 +3,7 @@ use rustc_serialize::leb128::*; use std::mem::MaybeUninit; +use rustc_serialize::Decoder; macro_rules! impl_test_unsigned_leb128 { ($test_name:ident, $write_fn_name:ident, $read_fn_name:ident, $int_ty:ident) => { @@ -28,12 +29,12 @@ macro_rules! impl_test_unsigned_leb128 { stream.extend($write_fn_name(&mut buf, x)); } - let mut position = 0; + let mut decoder = rustc_serialize::opaque::MemDecoder::new(&stream, 0); for &expected in &values { - let actual = $read_fn_name(&stream, &mut position); + let actual = $read_fn_name(&mut decoder); assert_eq!(expected, actual); } - assert_eq!(stream.len(), position); + assert_eq!(stream.len(), decoder.position()); } }; } @@ -74,12 +75,12 @@ macro_rules! impl_test_signed_leb128 { stream.extend($write_fn_name(&mut buf, x)); } - let mut position = 0; + let mut decoder = rustc_serialize::opaque::MemDecoder::new(&stream, 0); for &expected in &values { - let actual = $read_fn_name(&stream, &mut position); + let actual = $read_fn_name(&mut decoder); assert_eq!(expected, actual); } - assert_eq!(stream.len(), position); + assert_eq!(stream.len(), decoder.position()); } }; } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 419b6afe7c6..79eb31bb105 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -3048,9 +3048,9 @@ pub(crate) mod dep_tracking { #[derive(Clone, Copy, PartialEq, Hash, Debug, Encodable, Decodable, HashStable_Generic)] pub enum OomStrategy { /// Generate a panic that can be caught by `catch_unwind`. - Unwind, + Panic, - /// Calls the panic hook as normal but aborts instead of unwinding. + /// Abort the process immediately. Abort, } @@ -3059,7 +3059,7 @@ impl OomStrategy { pub fn should_panic(self) -> u8 { match self { - OomStrategy::Unwind => 1, + OomStrategy::Panic => 1, OomStrategy::Abort => 0, } } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 98bcacbe7ff..d9f03fe1407 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -662,7 +662,7 @@ mod parse { pub(crate) fn parse_oom_strategy(slot: &mut OomStrategy, v: Option<&str>) -> bool { match v { - Some("unwind") => *slot = OomStrategy::Unwind, + Some("panic") => *slot = OomStrategy::Panic, Some("abort") => *slot = OomStrategy::Abort, _ => return false, } diff --git a/compiler/rustc_target/src/asm/loongarch.rs b/compiler/rustc_target/src/asm/loongarch.rs new file mode 100644 index 00000000000..7ace1647ded --- /dev/null +++ b/compiler/rustc_target/src/asm/loongarch.rs @@ -0,0 +1,131 @@ +use super::{InlineAsmArch, InlineAsmType}; +use rustc_macros::HashStable_Generic; +use rustc_span::Symbol; +use std::fmt; + +def_reg_class! { + LoongArch LoongArchInlineAsmRegClass { + reg, + freg, + } +} + +impl LoongArchInlineAsmRegClass { + pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] { + &[] + } + + pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> { + None + } + + pub fn suggest_modifier( + self, + _arch: InlineAsmArch, + _ty: InlineAsmType, + ) -> Option<(char, &'static str)> { + None + } + + pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> { + None + } + + pub fn supported_types( + self, + arch: InlineAsmArch, + ) -> &'static [(InlineAsmType, Option<Symbol>)] { + match (self, arch) { + (Self::reg, InlineAsmArch::LoongArch64) => types! { _: I8, I16, I32, I64, F32, F64; }, + (Self::reg, _) => types! { _: I8, I16, I32, F32; }, + (Self::freg, _) => types! { _: F32, F64; }, + } + } +} + +// The reserved registers are taken from <https://github.com/llvm/llvm-project/blob/main/llvm/lib/Target/LoongArch/LoongArchRegisterInfo.cpp#79> +def_regs! { + LoongArch LoongArchInlineAsmReg LoongArchInlineAsmRegClass { + r1: reg = ["$r1","$ra"], + r4: reg = ["$r4","$a0"], + r5: reg = ["$r5","$a1"], + r6: reg = ["$r6","$a2"], + r7: reg = ["$r7","$a3"], + r8: reg = ["$r8","$a4"], + r9: reg = ["$r9","$a5"], + r10: reg = ["$r10","$a6"], + r11: reg = ["$r11","$a7"], + r12: reg = ["$r12","$t0"], + r13: reg = ["$r13","$t1"], + r14: reg = ["$r14","$t2"], + r15: reg = ["$r15","$t3"], + r16: reg = ["$r16","$t4"], + r17: reg = ["$r17","$t5"], + r18: reg = ["$r18","$t6"], + r19: reg = ["$r19","$t7"], + r20: reg = ["$r20","$t8"], + r23: reg = ["$r23","$s0"], + r24: reg = ["$r24","$s1"], + r25: reg = ["$r25","$s2"], + r26: reg = ["$r26","$s3"], + r27: reg = ["$r27","$s4"], + r28: reg = ["$r28","$s5"], + r29: reg = ["$r29","$s6"], + r30: reg = ["$r30","$s7"], + f0: freg = ["$f0","$fa0"], + f1: freg = ["$f1","$fa1"], + f2: freg = ["$f2","$fa2"], + f3: freg = ["$f3","$fa3"], + f4: freg = ["$f4","$fa4"], + f5: freg = ["$f5","$fa5"], + f6: freg = ["$f6","$fa6"], + f7: freg = ["$f7","$fa7"], + f8: freg = ["$f8","$ft0"], + f9: freg = ["$f9","$ft1"], + f10: freg = ["$f10","$ft2"], + f11: freg = ["$f11","$ft3"], + f12: freg = ["$f12","$ft4"], + f13: freg = ["$f13","$ft5"], + f14: freg = ["$f14","$ft6"], + f15: freg = ["$f15","$ft7"], + f16: freg = ["$f16","$ft8"], + f17: freg = ["$f17","$ft9"], + f18: freg = ["$f18","$ft10"], + f19: freg = ["$f19","$ft11"], + f20: freg = ["$f20","$ft12"], + f21: freg = ["$f21","$ft13"], + f22: freg = ["$f22","$ft14"], + f23: freg = ["$f23","$ft15"], + f24: freg = ["$f24","$fs0"], + f25: freg = ["$f25","$fs1"], + f26: freg = ["$f26","$fs2"], + f27: freg = ["$f27","$fs3"], + f28: freg = ["$f28","$fs4"], + f29: freg = ["$f29","$fs5"], + f30: freg = ["$f30","$fs6"], + f31: freg = ["$f31","$fs7"], + #error = ["$r0","$zero"] => + "constant zero cannot be used as an operand for inline asm", + #error = ["$r2","$tp"] => + "reserved for TLS", + #error = ["$r3","$sp"] => + "the stack pointer cannot be used as an operand for inline asm", + #error = ["$r21"] => + "reserved by the ABI", + #error = ["$r22","$fp"] => + "the frame pointer cannot be used as an operand for inline asm", + #error = ["$r31","$s8"] => + "$r31 is used internally by LLVM and cannot be used as an operand for inline asm", + } +} + +impl LoongArchInlineAsmReg { + pub fn emit( + self, + out: &mut dyn fmt::Write, + _arch: InlineAsmArch, + _modifier: Option<char>, + ) -> fmt::Result { + out.write_str(self.name()) + } +} diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index 3f9c850b352..266691b2c88 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -168,6 +168,7 @@ mod arm; mod avr; mod bpf; mod hexagon; +mod loongarch; mod m68k; mod mips; mod msp430; @@ -184,6 +185,7 @@ pub use arm::{ArmInlineAsmReg, ArmInlineAsmRegClass}; pub use avr::{AvrInlineAsmReg, AvrInlineAsmRegClass}; pub use bpf::{BpfInlineAsmReg, BpfInlineAsmRegClass}; pub use hexagon::{HexagonInlineAsmReg, HexagonInlineAsmRegClass}; +pub use loongarch::{LoongArchInlineAsmReg, LoongArchInlineAsmRegClass}; pub use m68k::{M68kInlineAsmReg, M68kInlineAsmRegClass}; pub use mips::{MipsInlineAsmReg, MipsInlineAsmRegClass}; pub use msp430::{Msp430InlineAsmReg, Msp430InlineAsmRegClass}; @@ -205,6 +207,7 @@ pub enum InlineAsmArch { RiscV64, Nvptx64, Hexagon, + LoongArch64, Mips, Mips64, PowerPC, @@ -234,6 +237,7 @@ impl FromStr for InlineAsmArch { "powerpc" => Ok(Self::PowerPC), "powerpc64" => Ok(Self::PowerPC64), "hexagon" => Ok(Self::Hexagon), + "loongarch64" => Ok(Self::LoongArch64), "mips" => Ok(Self::Mips), "mips64" => Ok(Self::Mips64), "s390x" => Ok(Self::S390x), @@ -259,6 +263,7 @@ pub enum InlineAsmReg { Nvptx(NvptxInlineAsmReg), PowerPC(PowerPCInlineAsmReg), Hexagon(HexagonInlineAsmReg), + LoongArch(LoongArchInlineAsmReg), Mips(MipsInlineAsmReg), S390x(S390xInlineAsmReg), SpirV(SpirVInlineAsmReg), @@ -280,6 +285,7 @@ impl InlineAsmReg { Self::RiscV(r) => r.name(), Self::PowerPC(r) => r.name(), Self::Hexagon(r) => r.name(), + Self::LoongArch(r) => r.name(), Self::Mips(r) => r.name(), Self::S390x(r) => r.name(), Self::Bpf(r) => r.name(), @@ -298,6 +304,7 @@ impl InlineAsmReg { Self::RiscV(r) => InlineAsmRegClass::RiscV(r.reg_class()), Self::PowerPC(r) => InlineAsmRegClass::PowerPC(r.reg_class()), Self::Hexagon(r) => InlineAsmRegClass::Hexagon(r.reg_class()), + Self::LoongArch(r) => InlineAsmRegClass::LoongArch(r.reg_class()), Self::Mips(r) => InlineAsmRegClass::Mips(r.reg_class()), Self::S390x(r) => InlineAsmRegClass::S390x(r.reg_class()), Self::Bpf(r) => InlineAsmRegClass::Bpf(r.reg_class()), @@ -324,6 +331,7 @@ impl InlineAsmReg { Self::PowerPC(PowerPCInlineAsmReg::parse(name)?) } InlineAsmArch::Hexagon => Self::Hexagon(HexagonInlineAsmReg::parse(name)?), + InlineAsmArch::LoongArch64 => Self::LoongArch(LoongArchInlineAsmReg::parse(name)?), InlineAsmArch::Mips | InlineAsmArch::Mips64 => { Self::Mips(MipsInlineAsmReg::parse(name)?) } @@ -354,6 +362,9 @@ impl InlineAsmReg { Self::RiscV(r) => r.validate(arch, reloc_model, target_features, target, is_clobber), Self::PowerPC(r) => r.validate(arch, reloc_model, target_features, target, is_clobber), Self::Hexagon(r) => r.validate(arch, reloc_model, target_features, target, is_clobber), + Self::LoongArch(r) => { + r.validate(arch, reloc_model, target_features, target, is_clobber) + } Self::Mips(r) => r.validate(arch, reloc_model, target_features, target, is_clobber), Self::S390x(r) => r.validate(arch, reloc_model, target_features, target, is_clobber), Self::Bpf(r) => r.validate(arch, reloc_model, target_features, target, is_clobber), @@ -379,6 +390,7 @@ impl InlineAsmReg { Self::RiscV(r) => r.emit(out, arch, modifier), Self::PowerPC(r) => r.emit(out, arch, modifier), Self::Hexagon(r) => r.emit(out, arch, modifier), + Self::LoongArch(r) => r.emit(out, arch, modifier), Self::Mips(r) => r.emit(out, arch, modifier), Self::S390x(r) => r.emit(out, arch, modifier), Self::Bpf(r) => r.emit(out, arch, modifier), @@ -397,6 +409,7 @@ impl InlineAsmReg { Self::RiscV(_) => cb(self), Self::PowerPC(r) => r.overlapping_regs(|r| cb(Self::PowerPC(r))), Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))), + Self::LoongArch(_) => cb(self), Self::Mips(_) => cb(self), Self::S390x(_) => cb(self), Self::Bpf(r) => r.overlapping_regs(|r| cb(Self::Bpf(r))), @@ -418,6 +431,7 @@ pub enum InlineAsmRegClass { Nvptx(NvptxInlineAsmRegClass), PowerPC(PowerPCInlineAsmRegClass), Hexagon(HexagonInlineAsmRegClass), + LoongArch(LoongArchInlineAsmRegClass), Mips(MipsInlineAsmRegClass), S390x(S390xInlineAsmRegClass), SpirV(SpirVInlineAsmRegClass), @@ -440,6 +454,7 @@ impl InlineAsmRegClass { Self::Nvptx(r) => r.name(), Self::PowerPC(r) => r.name(), Self::Hexagon(r) => r.name(), + Self::LoongArch(r) => r.name(), Self::Mips(r) => r.name(), Self::S390x(r) => r.name(), Self::SpirV(r) => r.name(), @@ -464,6 +479,7 @@ impl InlineAsmRegClass { Self::Nvptx(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Nvptx), Self::PowerPC(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::PowerPC), Self::Hexagon(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Hexagon), + Self::LoongArch(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::LoongArch), Self::Mips(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Mips), Self::S390x(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::S390x), Self::SpirV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::SpirV), @@ -495,6 +511,7 @@ impl InlineAsmRegClass { Self::Nvptx(r) => r.suggest_modifier(arch, ty), Self::PowerPC(r) => r.suggest_modifier(arch, ty), Self::Hexagon(r) => r.suggest_modifier(arch, ty), + Self::LoongArch(r) => r.suggest_modifier(arch, ty), Self::Mips(r) => r.suggest_modifier(arch, ty), Self::S390x(r) => r.suggest_modifier(arch, ty), Self::SpirV(r) => r.suggest_modifier(arch, ty), @@ -522,6 +539,7 @@ impl InlineAsmRegClass { Self::Nvptx(r) => r.default_modifier(arch), Self::PowerPC(r) => r.default_modifier(arch), Self::Hexagon(r) => r.default_modifier(arch), + Self::LoongArch(r) => r.default_modifier(arch), Self::Mips(r) => r.default_modifier(arch), Self::S390x(r) => r.default_modifier(arch), Self::SpirV(r) => r.default_modifier(arch), @@ -548,6 +566,7 @@ impl InlineAsmRegClass { Self::Nvptx(r) => r.supported_types(arch), Self::PowerPC(r) => r.supported_types(arch), Self::Hexagon(r) => r.supported_types(arch), + Self::LoongArch(r) => r.supported_types(arch), Self::Mips(r) => r.supported_types(arch), Self::S390x(r) => r.supported_types(arch), Self::SpirV(r) => r.supported_types(arch), @@ -575,6 +594,7 @@ impl InlineAsmRegClass { Self::PowerPC(PowerPCInlineAsmRegClass::parse(name)?) } InlineAsmArch::Hexagon => Self::Hexagon(HexagonInlineAsmRegClass::parse(name)?), + InlineAsmArch::LoongArch64 => Self::LoongArch(LoongArchInlineAsmRegClass::parse(name)?), InlineAsmArch::Mips | InlineAsmArch::Mips64 => { Self::Mips(MipsInlineAsmRegClass::parse(name)?) } @@ -601,6 +621,7 @@ impl InlineAsmRegClass { Self::Nvptx(r) => r.valid_modifiers(arch), Self::PowerPC(r) => r.valid_modifiers(arch), Self::Hexagon(r) => r.valid_modifiers(arch), + Self::LoongArch(r) => r.valid_modifiers(arch), Self::Mips(r) => r.valid_modifiers(arch), Self::S390x(r) => r.valid_modifiers(arch), Self::SpirV(r) => r.valid_modifiers(arch), @@ -760,6 +781,11 @@ pub fn allocatable_registers( hexagon::fill_reg_map(arch, reloc_model, target_features, target, &mut map); map } + InlineAsmArch::LoongArch64 => { + let mut map = loongarch::regclass_map(); + loongarch::fill_reg_map(arch, reloc_model, target_features, target, &mut map); + map + } InlineAsmArch::Mips | InlineAsmArch::Mips64 => { let mut map = mips::regclass_map(); mips::fill_reg_map(arch, reloc_model, target_features, target, &mut map); diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 8e7097ce4a7..c97473e6241 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -86,8 +86,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ) -> QueryResult<'tcx> { if let Some(poly_trait_pred) = assumption.to_opt_poly_trait_pred() && poly_trait_pred.def_id() == goal.predicate.def_id() + && poly_trait_pred.polarity() == goal.predicate.polarity { - // FIXME: Constness and polarity + // FIXME: Constness ecx.probe(|ecx| { let assumption_trait_pred = ecx.instantiate_binder_with_infer(poly_trait_pred); @@ -111,6 +112,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ) -> QueryResult<'tcx> { if let Some(poly_trait_pred) = assumption.to_opt_poly_trait_pred() && poly_trait_pred.def_id() == goal.predicate.def_id() + && poly_trait_pred.polarity() == goal.predicate.polarity { // FIXME: Constness and polarity ecx.probe(|ecx| { @@ -147,6 +149,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { + if goal.predicate.polarity != ty::ImplPolarity::Positive { + return Err(NoSolution); + } + if let Some(result) = ecx.disqualify_auto_trait_candidate_due_to_possible_impl(goal) { return result; } @@ -161,6 +167,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { + if goal.predicate.polarity != ty::ImplPolarity::Positive { + return Err(NoSolution); + } + let tcx = ecx.tcx(); ecx.probe(|ecx| { @@ -176,6 +186,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { + if goal.predicate.polarity != ty::ImplPolarity::Positive { + return Err(NoSolution); + } + ecx.probe_and_evaluate_goal_for_constituent_tys( goal, structural_traits::instantiate_constituent_tys_for_sized_trait, @@ -186,6 +200,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { + if goal.predicate.polarity != ty::ImplPolarity::Positive { + return Err(NoSolution); + } + ecx.probe_and_evaluate_goal_for_constituent_tys( goal, structural_traits::instantiate_constituent_tys_for_copy_clone_trait, @@ -196,6 +214,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { + if goal.predicate.polarity != ty::ImplPolarity::Positive { + return Err(NoSolution); + } + if goal.predicate.self_ty().has_non_region_infer() { return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); } @@ -217,6 +239,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { + if goal.predicate.polarity != ty::ImplPolarity::Positive { + return Err(NoSolution); + } + if let ty::FnPtr(..) = goal.predicate.self_ty().kind() { ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } else { @@ -229,6 +255,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { goal: Goal<'tcx, Self>, goal_kind: ty::ClosureKind, ) -> QueryResult<'tcx> { + if goal.predicate.polarity != ty::ImplPolarity::Positive { + return Err(NoSolution); + } + let tcx = ecx.tcx(); let tupled_inputs_and_output = match structural_traits::extract_tupled_inputs_and_output_from_callable( @@ -259,6 +289,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { + if goal.predicate.polarity != ty::ImplPolarity::Positive { + return Err(NoSolution); + } + if let ty::Tuple(..) = goal.predicate.self_ty().kind() { ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } else { @@ -268,8 +302,12 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_builtin_pointee_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, - _goal: Goal<'tcx, Self>, + goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { + if goal.predicate.polarity != ty::ImplPolarity::Positive { + return Err(NoSolution); + } + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } @@ -277,6 +315,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { + if goal.predicate.polarity != ty::ImplPolarity::Positive { + return Err(NoSolution); + } + let ty::Generator(def_id, _, _) = *goal.predicate.self_ty().kind() else { return Err(NoSolution); }; @@ -297,6 +339,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { + if goal.predicate.polarity != ty::ImplPolarity::Positive { + return Err(NoSolution); + } + let self_ty = goal.predicate.self_ty(); let ty::Generator(def_id, substs, _) = *self_ty.kind() else { return Err(NoSolution); @@ -326,6 +372,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { + if goal.predicate.polarity != ty::ImplPolarity::Positive { + return Err(NoSolution); + } + let tcx = ecx.tcx(); let a_ty = goal.predicate.self_ty(); let b_ty = goal.predicate.trait_ref.substs.type_at(1); @@ -447,6 +497,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> Vec<CanonicalResponse<'tcx>> { + if goal.predicate.polarity != ty::ImplPolarity::Positive { + return vec![]; + } + let tcx = ecx.tcx(); let a_ty = goal.predicate.self_ty(); @@ -521,8 +575,12 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_builtin_discriminant_kind_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, - _goal: Goal<'tcx, Self>, + goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { + if goal.predicate.polarity != ty::ImplPolarity::Positive { + return Err(NoSolution); + } + // `DiscriminantKind` is automatically implemented for every type. ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } @@ -531,6 +589,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { + if goal.predicate.polarity != ty::ImplPolarity::Positive { + return Err(NoSolution); + } + if !goal.param_env.is_const() { // `Destruct` is automatically implemented for every type in // non-const environments. @@ -545,6 +607,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { + if goal.predicate.polarity != ty::ImplPolarity::Positive { + return Err(NoSolution); + } + // `rustc_transmute` does not have support for type or const params if goal.has_non_region_placeholders() { return Err(NoSolution); diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 222af4c2ace..e82672e8368 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -591,7 +591,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { fn evaluate_nested_obligations( &self, ty: Ty<'_>, - nested: impl Iterator<Item = Obligation<'tcx, ty::Predicate<'tcx>>>, + nested: impl Iterator<Item = PredicateObligation<'tcx>>, computed_preds: &mut FxIndexSet<ty::Predicate<'tcx>>, fresh_preds: &mut FxHashSet<ty::Predicate<'tcx>>, predicates: &mut VecDeque<ty::PolyTraitPredicate<'tcx>>, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 61e382bbe49..ce187fbdf84 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -15,8 +15,7 @@ use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use crate::traits::query::normalize::QueryNormalizeExt as _; use crate::traits::specialize::to_pretty_impl_header; use crate::traits::NormalizeExt; -use on_unimplemented::OnUnimplementedNote; -use on_unimplemented::TypeErrCtxtExt as _; +use on_unimplemented::{AppendConstMessage, OnUnimplementedNote, TypeErrCtxtExt as _}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_errors::{ pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, @@ -706,35 +705,19 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { conversion on the error value using the `From` trait" .to_owned(), ), - Some(None), + Some(AppendConstMessage::Default), ) } else { (message, note, append_const_msg) }; - let err_msg = message - .and_then(|cannot_do_this| { - match (predicate_is_const, append_const_msg) { - // do nothing if predicate is not const - (false, _) => Some(cannot_do_this), - // suggested using default post message - (true, Some(None)) => { - Some(format!("{cannot_do_this} in const contexts")) - } - // overridden post message - (true, Some(Some(post_message))) => { - Some(format!("{cannot_do_this}{post_message}")) - } - // fallback to generic message - (true, None) => None, - } - }) - .unwrap_or_else(|| { - format!( - "the trait bound `{}` is not satisfied{}", - trait_predicate, post_message, - ) - }); + let err_msg = self.get_standard_error_message( + &trait_predicate, + message, + predicate_is_const, + append_const_msg, + post_message, + ); let (err_msg, safe_transmute_explanation) = if Some(trait_ref.def_id()) == self.tcx.lang_items().transmute_trait() @@ -762,22 +745,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } if Some(trait_ref.def_id()) == tcx.lang_items().tuple_trait() { - match obligation.cause.code().peel_derives() { - ObligationCauseCode::RustCall => { - err.set_primary_message("functions with the \"rust-call\" ABI must take a single non-self tuple argument"); - } - ObligationCauseCode::BindingObligation(def_id, _) - | ObligationCauseCode::ItemObligation(def_id) - if tcx.is_fn_trait(*def_id) => - { - err.code(rustc_errors::error_code!(E0059)); - err.set_primary_message(format!( - "type parameter to bare `{}` trait must be a tuple", - tcx.def_path_str(*def_id) - )); - } - _ => {} - } + self.add_tuple_trait_message( + &obligation.cause.code().peel_derives(), + &mut err, + ); } if Some(trait_ref.def_id()) == tcx.lang_items().drop_trait() @@ -787,33 +758,13 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err.note("See <https://github.com/rust-lang/rust/pull/94901> for more details"); } - let explanation = if let ObligationCauseCode::MainFunctionType = - obligation.cause.code() - { - "consider using `()`, or a `Result`".to_owned() - } else { - let ty_desc = match trait_ref.skip_binder().self_ty().kind() { - ty::FnDef(_, _) => Some("fn item"), - ty::Closure(_, _) => Some("closure"), - _ => None, - }; + let explanation = get_explanation_based_on_obligation( + &obligation, + trait_ref, + &trait_predicate, + pre_message, + ); - match ty_desc { - Some(desc) => format!( - "{}the trait `{}` is not implemented for {} `{}`", - pre_message, - trait_predicate.print_modifiers_and_trait_path(), - desc, - trait_ref.skip_binder().self_ty(), - ), - None => format!( - "{}the trait `{}` is not implemented for `{}`", - pre_message, - trait_predicate.print_modifiers_and_trait_path(), - trait_ref.skip_binder().self_ty(), - ), - } - }; self.check_for_binding_assigned_block_without_tail_expression( &obligation, &mut err, @@ -850,28 +801,14 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { self.suggest_borrowing_for_object_cast(&mut err, &root_obligation, *concrete_ty, *obj_ty); } - let mut unsatisfied_const = false; - if trait_predicate.is_const_if_const() && obligation.param_env.is_const() { - let non_const_predicate = trait_ref.without_const(); - let non_const_obligation = Obligation { - cause: obligation.cause.clone(), - param_env: obligation.param_env.without_const(), - predicate: non_const_predicate.to_predicate(tcx), - recursion_depth: obligation.recursion_depth, - }; - if self.predicate_may_hold(&non_const_obligation) { - unsatisfied_const = true; - err.span_note( - span, - &format!( - "the trait `{}` is implemented for `{}`, \ - but that implementation is not `const`", - non_const_predicate.print_modifiers_and_trait_path(), - trait_ref.skip_binder().self_ty(), - ), - ); - } - } + let UnsatisfiedConst(unsatisfied_const) = self + .maybe_add_note_for_unsatisfied_const( + &obligation, + trait_ref, + &trait_predicate, + &mut err, + span, + ); if let Some((msg, span)) = type_def { err.span_label(span, &msg); @@ -969,137 +906,16 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ); } - let body_def_id = obligation.cause.body_id; - // Try to report a help message - if is_fn_trait - && let Ok((implemented_kind, params)) = self.type_implements_fn_trait( - obligation.param_env, - trait_ref.self_ty(), - trait_predicate.skip_binder().constness, - trait_predicate.skip_binder().polarity, - ) - { - // If the type implements `Fn`, `FnMut`, or `FnOnce`, suppress the following - // suggestion to add trait bounds for the type, since we only typically implement - // these traits once. - - // Note if the `FnMut` or `FnOnce` is less general than the trait we're trying - // to implement. - let selected_kind = - self.tcx.fn_trait_kind_from_def_id(trait_ref.def_id()) - .expect("expected to map DefId to ClosureKind"); - if !implemented_kind.extends(selected_kind) { - err.note( - &format!( - "`{}` implements `{}`, but it must implement `{}`, which is more general", - trait_ref.skip_binder().self_ty(), - implemented_kind, - selected_kind - ) - ); - } - - // Note any argument mismatches - let given_ty = params.skip_binder(); - let expected_ty = trait_ref.skip_binder().substs.type_at(1); - if let ty::Tuple(given) = given_ty.kind() - && let ty::Tuple(expected) = expected_ty.kind() - { - if expected.len() != given.len() { - // Note number of types that were expected and given - err.note( - &format!( - "expected a closure taking {} argument{}, but one taking {} argument{} was given", - given.len(), - pluralize!(given.len()), - expected.len(), - pluralize!(expected.len()), - ) - ); - } else if !self.same_type_modulo_infer(given_ty, expected_ty) { - // Print type mismatch - let (expected_args, given_args) = - self.cmp(given_ty, expected_ty); - err.note_expected_found( - &"a closure with arguments", - expected_args, - &"a closure with arguments", - given_args, - ); - } - } - } else if !trait_ref.has_non_region_infer() - && self.predicate_can_apply(obligation.param_env, trait_predicate) - { - // If a where-clause may be useful, remind the - // user that they can add it. - // - // don't display an on-unimplemented note, as - // these notes will often be of the form - // "the type `T` can't be frobnicated" - // which is somewhat confusing. - self.suggest_restricting_param_bound( - &mut err, - trait_predicate, - None, - obligation.cause.body_id, - ); - } else if !suggested && !unsatisfied_const { - // Can't show anything else useful, try to find similar impls. - let impl_candidates = self.find_similar_impl_candidates(trait_predicate); - if !self.report_similar_impl_candidates( - &impl_candidates, - trait_ref, - body_def_id, - &mut err, - true, - ) { - // This is *almost* equivalent to - // `obligation.cause.code().peel_derives()`, but it gives us the - // trait predicate for that corresponding root obligation. This - // lets us get a derived obligation from a type parameter, like - // when calling `string.strip_suffix(p)` where `p` is *not* an - // implementer of `Pattern<'_>`. - let mut code = obligation.cause.code(); - let mut trait_pred = trait_predicate; - let mut peeled = false; - while let Some((parent_code, parent_trait_pred)) = code.parent() { - code = parent_code; - if let Some(parent_trait_pred) = parent_trait_pred { - trait_pred = parent_trait_pred; - peeled = true; - } - } - let def_id = trait_pred.def_id(); - // Mention *all* the `impl`s for the *top most* obligation, the - // user might have meant to use one of them, if any found. We skip - // auto-traits or fundamental traits that might not be exactly what - // the user might expect to be presented with. Instead this is - // useful for less general traits. - if peeled - && !self.tcx.trait_is_auto(def_id) - && !self.tcx.lang_items().iter().any(|(_, id)| id == def_id) - { - let trait_ref = trait_pred.to_poly_trait_ref(); - let impl_candidates = - self.find_similar_impl_candidates(trait_pred); - self.report_similar_impl_candidates( - &impl_candidates, - trait_ref, - body_def_id, - &mut err, - true, - ); - } - } - - self.maybe_suggest_convert_to_slice( - &mut err, - trait_ref, - impl_candidates.as_slice(), - span, - ); - } + self.try_to_add_help_message( + &obligation, + trait_ref, + &trait_predicate, + &mut err, + span, + is_fn_trait, + suggested, + unsatisfied_const, + ); // Changing mutability doesn't make a difference to whether we have // an `Unsize` impl (Fixes ICE in #71036) @@ -1194,59 +1010,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => { let found_kind = self.closure_kind(closure_substs).unwrap(); - let closure_span = self.tcx.def_span(closure_def_id); - let mut err = struct_span_err!( - self.tcx.sess, - closure_span, - E0525, - "expected a closure that implements the `{}` trait, \ - but this closure only implements `{}`", - kind, - found_kind - ); - - err.span_label( - closure_span, - format!("this closure implements `{}`, not `{}`", found_kind, kind), - ); - err.span_label( - obligation.cause.span, - format!("the requirement to implement `{}` derives from here", kind), - ); - - // Additional context information explaining why the closure only implements - // a particular trait. - if let Some(typeck_results) = &self.typeck_results { - let hir_id = self - .tcx - .hir() - .local_def_id_to_hir_id(closure_def_id.expect_local()); - match (found_kind, typeck_results.closure_kind_origins().get(hir_id)) { - (ty::ClosureKind::FnOnce, Some((span, place))) => { - err.span_label( - *span, - format!( - "closure is `FnOnce` because it moves the \ - variable `{}` out of its environment", - ty::place_to_string_for_capture(tcx, place) - ), - ); - } - (ty::ClosureKind::FnMut, Some((span, place))) => { - err.span_label( - *span, - format!( - "closure is `FnMut` because it mutates the \ - variable `{}` here", - ty::place_to_string_for_capture(tcx, place) - ), - ); - } - _ => {} - } - } - - err + self.report_closure_error(&obligation, closure_def_id, found_kind, kind) } ty::PredicateKind::WellFormed(ty) => { @@ -1327,117 +1091,21 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { found_trait_ref, expected_trait_ref, terr @ TypeError::CyclicTy(_), - ) => { - let self_ty = found_trait_ref.self_ty().skip_binder(); - let (cause, terr) = if let ty::Closure(def_id, _) = self_ty.kind() { - ( - ObligationCause::dummy_with_span(tcx.def_span(def_id)), - TypeError::CyclicTy(self_ty), - ) - } else { - (obligation.cause.clone(), terr) - }; - self.report_and_explain_type_error( - TypeTrace::poly_trait_refs(&cause, true, expected_trait_ref, found_trait_ref), - terr, - ) - } + ) => self.report_type_parameter_mismatch_cyclic_type_error( + &obligation, + found_trait_ref, + expected_trait_ref, + terr, + ), OutputTypeParameterMismatch(found_trait_ref, expected_trait_ref, _) => { - let found_trait_ref = self.resolve_vars_if_possible(found_trait_ref); - let expected_trait_ref = self.resolve_vars_if_possible(expected_trait_ref); - - if expected_trait_ref.self_ty().references_error() { - return; - } - - let Some(found_trait_ty) = found_trait_ref.self_ty().no_bound_vars() else { - return; - }; - - let found_did = match *found_trait_ty.kind() { - ty::Closure(did, _) - | ty::Foreign(did) - | ty::FnDef(did, _) - | ty::Generator(did, ..) => Some(did), - ty::Adt(def, _) => Some(def.did()), - _ => None, - }; - - let found_node = found_did.and_then(|did| self.tcx.hir().get_if_local(did)); - let found_span = found_did.and_then(|did| self.tcx.hir().span_if_local(did)); - - if self.reported_closure_mismatch.borrow().contains(&(span, found_span)) { - // We check closures twice, with obligations flowing in different directions, - // but we want to complain about them only once. - return; - } - - self.reported_closure_mismatch.borrow_mut().insert((span, found_span)); - - let mut not_tupled = false; - - let found = match found_trait_ref.skip_binder().substs.type_at(1).kind() { - ty::Tuple(ref tys) => vec![ArgKind::empty(); tys.len()], - _ => { - not_tupled = true; - vec![ArgKind::empty()] - } - }; - - let expected_ty = expected_trait_ref.skip_binder().substs.type_at(1); - let expected = match expected_ty.kind() { - ty::Tuple(ref tys) => { - tys.iter().map(|t| ArgKind::from_expected_ty(t, Some(span))).collect() - } - _ => { - not_tupled = true; - vec![ArgKind::Arg("_".to_owned(), expected_ty.to_string())] - } - }; - - // If this is a `Fn` family trait and either the expected or found - // is not tupled, then fall back to just a regular mismatch error. - // This shouldn't be common unless manually implementing one of the - // traits manually, but don't make it more confusing when it does - // happen. - if Some(expected_trait_ref.def_id()) != tcx.lang_items().gen_trait() && not_tupled { - self.report_and_explain_type_error( - TypeTrace::poly_trait_refs( - &obligation.cause, - true, - expected_trait_ref, - found_trait_ref, - ), - ty::error::TypeError::Mismatch, - ) - } else if found.len() == expected.len() { - self.report_closure_arg_mismatch( - span, - found_span, - found_trait_ref, - expected_trait_ref, - obligation.cause.code(), - found_node, - obligation.param_env, - ) - } else { - let (closure_span, closure_arg_span, found) = found_did - .and_then(|did| { - let node = self.tcx.hir().get_if_local(did)?; - let (found_span, closure_arg_span, found) = - self.get_fn_like_arguments(node)?; - Some((Some(found_span), closure_arg_span, found)) - }) - .unwrap_or((found_span, None, found)); - - self.report_arg_count_mismatch( - span, - closure_span, - expected, - found, - found_trait_ty.is_closure(), - closure_arg_span, - ) + match self.report_type_parameter_mismatch_error( + &obligation, + span, + found_trait_ref, + expected_trait_ref, + ) { + Some(err) => err, + None => return, } } @@ -1452,45 +1120,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ) } SelectionError::NotConstEvaluatable(NotConstEvaluatable::MentionsParam) => { - if !self.tcx.features().generic_const_exprs { - let mut err = self.tcx.sess.struct_span_err( - span, - "constant expression depends on a generic parameter", - ); - // FIXME(const_generics): we should suggest to the user how they can resolve this - // issue. However, this is currently not actually possible - // (see https://github.com/rust-lang/rust/issues/66962#issuecomment-575907083). - // - // Note that with `feature(generic_const_exprs)` this case should not - // be reachable. - err.note("this may fail depending on what value the parameter takes"); - err.emit(); - return; - } - - match obligation.predicate.kind().skip_binder() { - ty::PredicateKind::ConstEvaluatable(ct) => { - let ty::ConstKind::Unevaluated(uv) = ct.kind() else { - bug!("const evaluatable failed for non-unevaluated const `{ct:?}`"); - }; - let mut err = - self.tcx.sess.struct_span_err(span, "unconstrained generic constant"); - let const_span = self.tcx.def_span(uv.def); - match self.tcx.sess.source_map().span_to_snippet(const_span) { - Ok(snippet) => err.help(&format!( - "try adding a `where` bound using this expression: `where [(); {}]:`", - snippet - )), - _ => err.help("consider adding a `where` bound using this expression"), - }; - err - } - _ => { - span_bug!( - span, - "unexpected non-ConstEvaluatable predicate, this should not be reachable" - ) - } + match self.report_not_const_evaluatable_error(&obligation, span) { + Some(err) => err, + None => return, } } @@ -1562,6 +1194,14 @@ trait InferCtxtPrivExt<'tcx> { other: bool, ) -> bool; + fn report_similar_impl_candidates_for_root_obligation( + &self, + obligation: &PredicateObligation<'tcx>, + trait_predicate: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>, + body_def_id: LocalDefId, + err: &mut Diagnostic, + ); + /// Gets the parent trait chain start fn get_parent_trait_ref( &self, @@ -1625,12 +1265,86 @@ trait InferCtxtPrivExt<'tcx> { cause_code: &ObligationCauseCode<'tcx>, ) -> bool; + fn get_standard_error_message( + &self, + trait_predicate: &ty::PolyTraitPredicate<'tcx>, + message: Option<String>, + predicate_is_const: bool, + append_const_msg: Option<AppendConstMessage>, + post_message: String, + ) -> String; + fn get_safe_transmute_error_and_reason( &self, - obligation: Obligation<'tcx, ty::Predicate<'tcx>>, - trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, + obligation: PredicateObligation<'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>, span: Span, ) -> (String, Option<String>); + + fn add_tuple_trait_message( + &self, + obligation_cause_code: &ObligationCauseCode<'tcx>, + err: &mut Diagnostic, + ); + + fn try_to_add_help_message( + &self, + obligation: &PredicateObligation<'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>, + trait_predicate: &ty::PolyTraitPredicate<'tcx>, + err: &mut Diagnostic, + span: Span, + is_fn_trait: bool, + suggested: bool, + unsatisfied_const: bool, + ); + + fn add_help_message_for_fn_trait( + &self, + trait_ref: ty::PolyTraitRef<'tcx>, + err: &mut Diagnostic, + implemented_kind: ty::ClosureKind, + params: ty::Binder<'tcx, Ty<'tcx>>, + ); + + fn maybe_add_note_for_unsatisfied_const( + &self, + obligation: &PredicateObligation<'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>, + trait_predicate: &ty::PolyTraitPredicate<'tcx>, + err: &mut Diagnostic, + span: Span, + ) -> UnsatisfiedConst; + + fn report_closure_error( + &self, + obligation: &PredicateObligation<'tcx>, + closure_def_id: DefId, + found_kind: ty::ClosureKind, + kind: ty::ClosureKind, + ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>; + + fn report_type_parameter_mismatch_cyclic_type_error( + &self, + obligation: &PredicateObligation<'tcx>, + found_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, + expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, + terr: TypeError<'tcx>, + ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>; + + fn report_type_parameter_mismatch_error( + &self, + obligation: &PredicateObligation<'tcx>, + span: Span, + found_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, + expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, + ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>; + + fn report_not_const_evaluatable_error( + &self, + obligation: &PredicateObligation<'tcx>, + span: Span, + ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>; } impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { @@ -2198,6 +1912,51 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { report(normalized_impl_candidates, err) } + fn report_similar_impl_candidates_for_root_obligation( + &self, + obligation: &PredicateObligation<'tcx>, + trait_predicate: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>, + body_def_id: LocalDefId, + err: &mut Diagnostic, + ) { + // This is *almost* equivalent to + // `obligation.cause.code().peel_derives()`, but it gives us the + // trait predicate for that corresponding root obligation. This + // lets us get a derived obligation from a type parameter, like + // when calling `string.strip_suffix(p)` where `p` is *not* an + // implementer of `Pattern<'_>`. + let mut code = obligation.cause.code(); + let mut trait_pred = trait_predicate; + let mut peeled = false; + while let Some((parent_code, parent_trait_pred)) = code.parent() { + code = parent_code; + if let Some(parent_trait_pred) = parent_trait_pred { + trait_pred = parent_trait_pred; + peeled = true; + } + } + let def_id = trait_pred.def_id(); + // Mention *all* the `impl`s for the *top most* obligation, the + // user might have meant to use one of them, if any found. We skip + // auto-traits or fundamental traits that might not be exactly what + // the user might expect to be presented with. Instead this is + // useful for less general traits. + if peeled + && !self.tcx.trait_is_auto(def_id) + && !self.tcx.lang_items().iter().any(|(_, id)| id == def_id) + { + let trait_ref = trait_pred.to_poly_trait_ref(); + let impl_candidates = self.find_similar_impl_candidates(trait_pred); + self.report_similar_impl_candidates( + &impl_candidates, + trait_ref, + body_def_id, + err, + true, + ); + } + } + /// Gets the parent trait chain start fn get_parent_trait_ref( &self, @@ -2930,10 +2689,40 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { false } + fn get_standard_error_message( + &self, + trait_predicate: &ty::PolyTraitPredicate<'tcx>, + message: Option<String>, + predicate_is_const: bool, + append_const_msg: Option<AppendConstMessage>, + post_message: String, + ) -> String { + message + .and_then(|cannot_do_this| { + match (predicate_is_const, append_const_msg) { + // do nothing if predicate is not const + (false, _) => Some(cannot_do_this), + // suggested using default post message + (true, Some(AppendConstMessage::Default)) => { + Some(format!("{cannot_do_this} in const contexts")) + } + // overridden post message + (true, Some(AppendConstMessage::Custom(custom_msg))) => { + Some(format!("{cannot_do_this}{custom_msg}")) + } + // fallback to generic message + (true, None) => None, + } + }) + .unwrap_or_else(|| { + format!("the trait bound `{}` is not satisfied{}", trait_predicate, post_message) + }) + } + fn get_safe_transmute_error_and_reason( &self, - obligation: Obligation<'tcx, ty::Predicate<'tcx>>, - trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, + obligation: PredicateObligation<'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>, span: Span, ) -> (String, Option<String>) { // Erase regions because layout code doesn't particularly care about regions. @@ -2991,8 +2780,449 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { _ => span_bug!(span, "Unsupported rustc_transmute::Reason variant"), } } + + fn add_tuple_trait_message( + &self, + obligation_cause_code: &ObligationCauseCode<'tcx>, + err: &mut Diagnostic, + ) { + match obligation_cause_code { + ObligationCauseCode::RustCall => { + err.set_primary_message("functions with the \"rust-call\" ABI must take a single non-self tuple argument"); + } + ObligationCauseCode::BindingObligation(def_id, _) + | ObligationCauseCode::ItemObligation(def_id) + if self.tcx.is_fn_trait(*def_id) => + { + err.code(rustc_errors::error_code!(E0059)); + err.set_primary_message(format!( + "type parameter to bare `{}` trait must be a tuple", + self.tcx.def_path_str(*def_id) + )); + } + _ => {} + } + } + + fn try_to_add_help_message( + &self, + obligation: &PredicateObligation<'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>, + trait_predicate: &ty::PolyTraitPredicate<'tcx>, + err: &mut Diagnostic, + span: Span, + is_fn_trait: bool, + suggested: bool, + unsatisfied_const: bool, + ) { + let body_def_id = obligation.cause.body_id; + // Try to report a help message + if is_fn_trait + && let Ok((implemented_kind, params)) = self.type_implements_fn_trait( + obligation.param_env, + trait_ref.self_ty(), + trait_predicate.skip_binder().constness, + trait_predicate.skip_binder().polarity, + ) + { + self.add_help_message_for_fn_trait(trait_ref, err, implemented_kind, params); + } else if !trait_ref.has_non_region_infer() + && self.predicate_can_apply(obligation.param_env, *trait_predicate) + { + // If a where-clause may be useful, remind the + // user that they can add it. + // + // don't display an on-unimplemented note, as + // these notes will often be of the form + // "the type `T` can't be frobnicated" + // which is somewhat confusing. + self.suggest_restricting_param_bound( + err, + *trait_predicate, + None, + obligation.cause.body_id, + ); + } else if !suggested && !unsatisfied_const { + // Can't show anything else useful, try to find similar impls. + let impl_candidates = self.find_similar_impl_candidates(*trait_predicate); + if !self.report_similar_impl_candidates( + &impl_candidates, + trait_ref, + body_def_id, + err, + true, + ) { + self.report_similar_impl_candidates_for_root_obligation(&obligation, *trait_predicate, body_def_id, err); + } + + self.maybe_suggest_convert_to_slice( + err, + trait_ref, + impl_candidates.as_slice(), + span, + ); + } + } + + fn add_help_message_for_fn_trait( + &self, + trait_ref: ty::PolyTraitRef<'tcx>, + err: &mut Diagnostic, + implemented_kind: ty::ClosureKind, + params: ty::Binder<'tcx, Ty<'tcx>>, + ) { + // If the type implements `Fn`, `FnMut`, or `FnOnce`, suppress the following + // suggestion to add trait bounds for the type, since we only typically implement + // these traits once. + + // Note if the `FnMut` or `FnOnce` is less general than the trait we're trying + // to implement. + let selected_kind = self + .tcx + .fn_trait_kind_from_def_id(trait_ref.def_id()) + .expect("expected to map DefId to ClosureKind"); + if !implemented_kind.extends(selected_kind) { + err.note(&format!( + "`{}` implements `{}`, but it must implement `{}`, which is more general", + trait_ref.skip_binder().self_ty(), + implemented_kind, + selected_kind + )); + } + + // Note any argument mismatches + let given_ty = params.skip_binder(); + let expected_ty = trait_ref.skip_binder().substs.type_at(1); + if let ty::Tuple(given) = given_ty.kind() + && let ty::Tuple(expected) = expected_ty.kind() + { + if expected.len() != given.len() { + // Note number of types that were expected and given + err.note( + &format!( + "expected a closure taking {} argument{}, but one taking {} argument{} was given", + given.len(), + pluralize!(given.len()), + expected.len(), + pluralize!(expected.len()), + ) + ); + } else if !self.same_type_modulo_infer(given_ty, expected_ty) { + // Print type mismatch + let (expected_args, given_args) = + self.cmp(given_ty, expected_ty); + err.note_expected_found( + &"a closure with arguments", + expected_args, + &"a closure with arguments", + given_args, + ); + } + } + } + + fn maybe_add_note_for_unsatisfied_const( + &self, + obligation: &PredicateObligation<'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>, + trait_predicate: &ty::PolyTraitPredicate<'tcx>, + err: &mut Diagnostic, + span: Span, + ) -> UnsatisfiedConst { + let mut unsatisfied_const = UnsatisfiedConst(false); + if trait_predicate.is_const_if_const() && obligation.param_env.is_const() { + let non_const_predicate = trait_ref.without_const(); + let non_const_obligation = Obligation { + cause: obligation.cause.clone(), + param_env: obligation.param_env.without_const(), + predicate: non_const_predicate.to_predicate(self.tcx), + recursion_depth: obligation.recursion_depth, + }; + if self.predicate_may_hold(&non_const_obligation) { + unsatisfied_const = UnsatisfiedConst(true); + err.span_note( + span, + &format!( + "the trait `{}` is implemented for `{}`, \ + but that implementation is not `const`", + non_const_predicate.print_modifiers_and_trait_path(), + trait_ref.skip_binder().self_ty(), + ), + ); + } + } + unsatisfied_const + } + + fn report_closure_error( + &self, + obligation: &PredicateObligation<'tcx>, + closure_def_id: DefId, + found_kind: ty::ClosureKind, + kind: ty::ClosureKind, + ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + let closure_span = self.tcx.def_span(closure_def_id); + let mut err = struct_span_err!( + self.tcx.sess, + closure_span, + E0525, + "expected a closure that implements the `{}` trait, \ + but this closure only implements `{}`", + kind, + found_kind + ); + + err.span_label( + closure_span, + format!("this closure implements `{}`, not `{}`", found_kind, kind), + ); + err.span_label( + obligation.cause.span, + format!("the requirement to implement `{}` derives from here", kind), + ); + + // Additional context information explaining why the closure only implements + // a particular trait. + if let Some(typeck_results) = &self.typeck_results { + let hir_id = self.tcx.hir().local_def_id_to_hir_id(closure_def_id.expect_local()); + match (found_kind, typeck_results.closure_kind_origins().get(hir_id)) { + (ty::ClosureKind::FnOnce, Some((span, place))) => { + err.span_label( + *span, + format!( + "closure is `FnOnce` because it moves the \ + variable `{}` out of its environment", + ty::place_to_string_for_capture(self.tcx, place) + ), + ); + } + (ty::ClosureKind::FnMut, Some((span, place))) => { + err.span_label( + *span, + format!( + "closure is `FnMut` because it mutates the \ + variable `{}` here", + ty::place_to_string_for_capture(self.tcx, place) + ), + ); + } + _ => {} + } + } + + err + } + + fn report_type_parameter_mismatch_cyclic_type_error( + &self, + obligation: &PredicateObligation<'tcx>, + found_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, + expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, + terr: TypeError<'tcx>, + ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { + let self_ty = found_trait_ref.self_ty().skip_binder(); + let (cause, terr) = if let ty::Closure(def_id, _) = self_ty.kind() { + ( + ObligationCause::dummy_with_span(self.tcx.def_span(def_id)), + TypeError::CyclicTy(self_ty), + ) + } else { + (obligation.cause.clone(), terr) + }; + self.report_and_explain_type_error( + TypeTrace::poly_trait_refs(&cause, true, expected_trait_ref, found_trait_ref), + terr, + ) + } + + fn report_type_parameter_mismatch_error( + &self, + obligation: &PredicateObligation<'tcx>, + span: Span, + found_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, + expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, + ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> { + let found_trait_ref = self.resolve_vars_if_possible(found_trait_ref); + let expected_trait_ref = self.resolve_vars_if_possible(expected_trait_ref); + + if expected_trait_ref.self_ty().references_error() { + return None; + } + + let Some(found_trait_ty) = found_trait_ref.self_ty().no_bound_vars() else { + return None; + }; + + let found_did = match *found_trait_ty.kind() { + ty::Closure(did, _) | ty::Foreign(did) | ty::FnDef(did, _) | ty::Generator(did, ..) => { + Some(did) + } + ty::Adt(def, _) => Some(def.did()), + _ => None, + }; + + let found_node = found_did.and_then(|did| self.tcx.hir().get_if_local(did)); + let found_span = found_did.and_then(|did| self.tcx.hir().span_if_local(did)); + + if self.reported_closure_mismatch.borrow().contains(&(span, found_span)) { + // We check closures twice, with obligations flowing in different directions, + // but we want to complain about them only once. + return None; + } + + self.reported_closure_mismatch.borrow_mut().insert((span, found_span)); + + let mut not_tupled = false; + + let found = match found_trait_ref.skip_binder().substs.type_at(1).kind() { + ty::Tuple(ref tys) => vec![ArgKind::empty(); tys.len()], + _ => { + not_tupled = true; + vec![ArgKind::empty()] + } + }; + + let expected_ty = expected_trait_ref.skip_binder().substs.type_at(1); + let expected = match expected_ty.kind() { + ty::Tuple(ref tys) => { + tys.iter().map(|t| ArgKind::from_expected_ty(t, Some(span))).collect() + } + _ => { + not_tupled = true; + vec![ArgKind::Arg("_".to_owned(), expected_ty.to_string())] + } + }; + + // If this is a `Fn` family trait and either the expected or found + // is not tupled, then fall back to just a regular mismatch error. + // This shouldn't be common unless manually implementing one of the + // traits manually, but don't make it more confusing when it does + // happen. + Some( + if Some(expected_trait_ref.def_id()) != self.tcx.lang_items().gen_trait() && not_tupled + { + self.report_and_explain_type_error( + TypeTrace::poly_trait_refs( + &obligation.cause, + true, + expected_trait_ref, + found_trait_ref, + ), + ty::error::TypeError::Mismatch, + ) + } else if found.len() == expected.len() { + self.report_closure_arg_mismatch( + span, + found_span, + found_trait_ref, + expected_trait_ref, + obligation.cause.code(), + found_node, + obligation.param_env, + ) + } else { + let (closure_span, closure_arg_span, found) = found_did + .and_then(|did| { + let node = self.tcx.hir().get_if_local(did)?; + let (found_span, closure_arg_span, found) = + self.get_fn_like_arguments(node)?; + Some((Some(found_span), closure_arg_span, found)) + }) + .unwrap_or((found_span, None, found)); + + self.report_arg_count_mismatch( + span, + closure_span, + expected, + found, + found_trait_ty.is_closure(), + closure_arg_span, + ) + }, + ) + } + + fn report_not_const_evaluatable_error( + &self, + obligation: &PredicateObligation<'tcx>, + span: Span, + ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> { + if !self.tcx.features().generic_const_exprs { + let mut err = self + .tcx + .sess + .struct_span_err(span, "constant expression depends on a generic parameter"); + // FIXME(const_generics): we should suggest to the user how they can resolve this + // issue. However, this is currently not actually possible + // (see https://github.com/rust-lang/rust/issues/66962#issuecomment-575907083). + // + // Note that with `feature(generic_const_exprs)` this case should not + // be reachable. + err.note("this may fail depending on what value the parameter takes"); + err.emit(); + return None; + } + + match obligation.predicate.kind().skip_binder() { + ty::PredicateKind::ConstEvaluatable(ct) => { + let ty::ConstKind::Unevaluated(uv) = ct.kind() else { + bug!("const evaluatable failed for non-unevaluated const `{ct:?}`"); + }; + let mut err = self.tcx.sess.struct_span_err(span, "unconstrained generic constant"); + let const_span = self.tcx.def_span(uv.def); + match self.tcx.sess.source_map().span_to_snippet(const_span) { + Ok(snippet) => err.help(&format!( + "try adding a `where` bound using this expression: `where [(); {}]:`", + snippet + )), + _ => err.help("consider adding a `where` bound using this expression"), + }; + Some(err) + } + _ => { + span_bug!( + span, + "unexpected non-ConstEvaluatable predicate, this should not be reachable" + ) + } + } + } } +struct UnsatisfiedConst(pub bool); + +fn get_explanation_based_on_obligation<'tcx>( + obligation: &PredicateObligation<'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>, + trait_predicate: &ty::PolyTraitPredicate<'tcx>, + pre_message: String, +) -> String { + if let ObligationCauseCode::MainFunctionType = obligation.cause.code() { + "consider using `()`, or a `Result`".to_owned() + } else { + let ty_desc = match trait_ref.skip_binder().self_ty().kind() { + ty::FnDef(_, _) => Some("fn item"), + ty::Closure(_, _) => Some("closure"), + _ => None, + }; + + match ty_desc { + Some(desc) => format!( + "{}the trait `{}` is not implemented for {} `{}`", + pre_message, + trait_predicate.print_modifiers_and_trait_path(), + desc, + trait_ref.skip_binder().self_ty(), + ), + None => format!( + "{}the trait `{}` is not implemented for `{}`", + pre_message, + trait_predicate.print_modifiers_and_trait_path(), + trait_ref.skip_binder().self_ty(), + ), + } + } +} /// Crude way of getting back an `Expr` from a `Span`. pub struct FindExprBySpan<'hir> { pub span: Span, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index a9c4e126816..88525e1b720 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -327,7 +327,7 @@ pub struct OnUnimplementedDirective { pub label: Option<OnUnimplementedFormatString>, pub note: Option<OnUnimplementedFormatString>, pub parent_label: Option<OnUnimplementedFormatString>, - pub append_const_msg: Option<Option<Symbol>>, + pub append_const_msg: Option<AppendConstMessage>, } /// For the `#[rustc_on_unimplemented]` attribute @@ -337,11 +337,21 @@ pub struct OnUnimplementedNote { pub label: Option<String>, pub note: Option<String>, pub parent_label: Option<String>, - /// Append a message for `~const Trait` errors. `None` means not requested and - /// should fallback to a generic message, `Some(None)` suggests using the default - /// appended message, `Some(Some(s))` suggests use the `s` message instead of the - /// default one.. - pub append_const_msg: Option<Option<Symbol>>, + // If none, should fall back to a generic message + pub append_const_msg: Option<AppendConstMessage>, +} + +/// Append a message for `~const Trait` errors. +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub enum AppendConstMessage { + Default, + Custom(Symbol), +} + +impl Default for AppendConstMessage { + fn default() -> Self { + AppendConstMessage::Default + } } impl<'tcx> OnUnimplementedDirective { @@ -419,10 +429,10 @@ impl<'tcx> OnUnimplementedDirective { } } else if item.has_name(sym::append_const_msg) && append_const_msg.is_none() { if let Some(msg) = item.value_str() { - append_const_msg = Some(Some(msg)); + append_const_msg = Some(AppendConstMessage::Custom(msg)); continue; } else if item.is_word() { - append_const_msg = Some(None); + append_const_msg = Some(AppendConstMessage::Default); continue; } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 73207f183a1..c969e5d4975 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -386,7 +386,7 @@ pub trait TypeErrCtxtExt<'tcx> { fn maybe_suggest_convert_to_slice( &self, err: &mut Diagnostic, - trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, + trait_ref: ty::PolyTraitRef<'tcx>, candidate_impls: &[ImplCandidate<'tcx>], span: Span, ); @@ -3848,7 +3848,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { fn maybe_suggest_convert_to_slice( &self, err: &mut Diagnostic, - trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, + trait_ref: ty::PolyTraitRef<'tcx>, candidate_impls: &[ImplCandidate<'tcx>], span: Span, ) { diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index b8ad1925e4e..73e2efc3b00 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -297,8 +297,8 @@ fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span tcx.associated_items(trait_def_id) .in_definition_order() .filter(|item| item.kind == ty::AssocKind::Type) - .flat_map(|item| tcx.explicit_item_bounds(item.def_id)) - .filter_map(|pred_span| predicate_references_self(tcx, *pred_span)) + .flat_map(|item| tcx.explicit_item_bounds(item.def_id).subst_identity_iter_copied()) + .filter_map(|pred_span| predicate_references_self(tcx, pred_span)) .collect() } diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs index 9683e48478e..c319b2e31c7 100644 --- a/compiler/rustc_traits/src/chalk/db.rs +++ b/compiler/rustc_traits/src/chalk/db.rs @@ -50,12 +50,11 @@ impl<'tcx> RustIrDatabase<'tcx> { where ty::Predicate<'tcx>: LowerInto<'tcx, std::option::Option<T>>, { - let bounds = self.interner.tcx.bound_explicit_item_bounds(def_id); - bounds - .0 - .iter() - .map(|(bound, _)| bounds.rebind(*bound).subst(self.interner.tcx, &bound_vars)) - .filter_map(|bound| LowerInto::<Option<_>>::lower_into(bound, self.interner)) + self.interner + .tcx + .explicit_item_bounds(def_id) + .subst_iter_copied(self.interner.tcx, &bound_vars) + .filter_map(|(bound, _)| LowerInto::<Option<_>>::lower_into(bound, self.interner)) .collect() } } @@ -506,15 +505,11 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t let identity_substs = InternalSubsts::identity_for_item(self.interner.tcx, opaque_ty_id.0); - let explicit_item_bounds = self.interner.tcx.bound_explicit_item_bounds(opaque_ty_id.0); + let explicit_item_bounds = self.interner.tcx.explicit_item_bounds(opaque_ty_id.0); let bounds = explicit_item_bounds - .0 - .iter() + .subst_iter_copied(self.interner.tcx, &bound_vars) .map(|(bound, _)| { - explicit_item_bounds.rebind(*bound).subst(self.interner.tcx, &bound_vars) - }) - .map(|bound| { bound.fold_with(&mut ReplaceOpaqueTyFolder { tcx: self.interner.tcx, opaque_ty_id, diff --git a/compiler/rustc_type_ir/src/codec.rs b/compiler/rustc_type_ir/src/codec.rs index ee249050cc6..3b638934629 100644 --- a/compiler/rustc_type_ir/src/codec.rs +++ b/compiler/rustc_type_ir/src/codec.rs @@ -27,10 +27,13 @@ pub trait TyEncoder: Encoder { const CLEAR_CROSS_CRATE: bool; fn position(&self) -> usize; + fn type_shorthands(&mut self) -> &mut FxHashMap<<Self::I as Interner>::Ty, usize>; + fn predicate_shorthands( &mut self, ) -> &mut FxHashMap<<Self::I as Interner>::PredicateKind, usize>; + fn encode_alloc_id(&mut self, alloc_id: &<Self::I as Interner>::AllocId); } @@ -40,10 +43,6 @@ pub trait TyDecoder: Decoder { fn interner(&self) -> Self::I; - fn peek_byte(&self) -> u8; - - fn position(&self) -> usize; - fn cached_ty_for_shorthand<F>( &mut self, shorthand: usize, diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index a3c98ae007e..95237dda8c2 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -537,7 +537,7 @@ pub struct FloatVarValue(pub FloatTy); rustc_index::newtype_index! { /// A **ty**pe **v**ariable **ID**. - #[debug_format = "_#{}t"] + #[debug_format = "?{}t"] pub struct TyVid {} } @@ -739,13 +739,13 @@ impl fmt::Debug for FloatVarValue { impl fmt::Debug for IntVid { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "_#{}i", self.index) + write!(f, "?{}i", self.index) } } impl fmt::Debug for FloatVid { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "_#{}f", self.index) + write!(f, "?{}f", self.index) } } diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml index 8975ba3f06b..95c07abf731 100644 --- a/library/alloc/Cargo.toml +++ b/library/alloc/Cargo.toml @@ -35,6 +35,3 @@ compiler-builtins-mem = ['compiler_builtins/mem'] compiler-builtins-c = ["compiler_builtins/c"] compiler-builtins-no-asm = ["compiler_builtins/no-asm"] compiler-builtins-mangled-names = ["compiler_builtins/mangled-names"] - -# Make panics and failed asserts immediately abort without formatting any message -panic_immediate_abort = ["core/panic_immediate_abort"] diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 0db23e55a86..6f2ba957bcd 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -14,11 +14,6 @@ use core::ptr::{self, NonNull}; #[doc(inline)] pub use core::alloc::*; -#[cfg(not(no_global_oom_handling))] -use core::any::Any; -#[cfg(not(no_global_oom_handling))] -use core::panic::BoxMeUp; - #[cfg(test)] mod tests; @@ -348,77 +343,14 @@ pub(crate) unsafe fn box_free<T: ?Sized, A: Allocator>(ptr: Unique<T>, alloc: A) } } -/// Payload passed to the panic handler when `handle_alloc_error` is called. -#[unstable(feature = "panic_oom_payload", issue = "none")] -#[derive(Debug)] -pub struct AllocErrorPanicPayload { - layout: Layout, -} - -impl AllocErrorPanicPayload { - /// Internal function for the standard library to clone a payload. - #[unstable(feature = "std_internals", issue = "none")] - #[doc(hidden)] - pub fn internal_clone(&self) -> Self { - AllocErrorPanicPayload { layout: self.layout } - } - - /// Returns the [`Layout`] of the allocation attempt that caused the error. - #[unstable(feature = "panic_oom_payload", issue = "none")] - pub fn layout(&self) -> Layout { - self.layout - } -} - -#[unstable(feature = "std_internals", issue = "none")] -#[cfg(not(no_global_oom_handling))] -unsafe impl BoxMeUp for AllocErrorPanicPayload { - fn take_box(&mut self) -> *mut (dyn Any + Send) { - use crate::boxed::Box; - Box::into_raw(Box::new(self.internal_clone())) - } - - fn get(&mut self) -> &(dyn Any + Send) { - self - } -} - // # Allocation error handler -#[cfg(all(not(no_global_oom_handling), not(test)))] -fn rust_oom(layout: Layout) -> ! { - if cfg!(feature = "panic_immediate_abort") { - core::intrinsics::abort() - } - - extern "Rust" { - // NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call - // that gets resolved to the `#[panic_handler]` function. - #[lang = "panic_impl"] - fn panic_impl(pi: &core::panic::PanicInfo<'_>) -> !; - - // This symbol is emitted by rustc . - // Its value depends on the -Zoom={unwind,abort} compiler option. - static __rust_alloc_error_handler_should_panic: u8; - } - - // Hack to work around issues with the lifetime of Arguments. - match format_args!("memory allocation of {} bytes failed", layout.size()) { - fmt => { - // Create a PanicInfo with a custom payload for the panic handler. - let can_unwind = unsafe { __rust_alloc_error_handler_should_panic != 0 }; - let mut pi = core::panic::PanicInfo::internal_constructor( - Some(&fmt), - core::panic::Location::caller(), - can_unwind, - ); - let payload = AllocErrorPanicPayload { layout }; - pi.set_payload(&payload); - - // SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call. - unsafe { panic_impl(&pi) } - } - } +#[cfg(not(no_global_oom_handling))] +extern "Rust" { + // This is the magic symbol to call the global alloc error handler. rustc generates + // it to call `__rg_oom` if there is a `#[alloc_error_handler]`, or to call the + // default implementations below (`__rdl_oom`) otherwise. + fn __rust_alloc_error_handler(size: usize, align: usize) -> !; } /// Abort on memory allocation error or failure. @@ -426,6 +358,13 @@ fn rust_oom(layout: Layout) -> ! { /// Callers of memory allocation APIs wishing to abort computation /// in response to an allocation error are encouraged to call this function, /// rather than directly invoking `panic!` or similar. +/// +/// The default behavior of this function is to print a message to standard error +/// and abort the process. +/// It can be replaced with [`set_alloc_error_hook`] and [`take_alloc_error_hook`]. +/// +/// [`set_alloc_error_hook`]: ../../std/alloc/fn.set_alloc_error_hook.html +/// [`take_alloc_error_hook`]: ../../std/alloc/fn.take_alloc_error_hook.html #[stable(feature = "global_alloc", since = "1.28.0")] #[rustc_const_unstable(feature = "const_alloc_error", issue = "92523")] #[cfg(all(not(no_global_oom_handling), not(test)))] @@ -436,7 +375,9 @@ pub const fn handle_alloc_error(layout: Layout) -> ! { } fn rt_error(layout: Layout) -> ! { - rust_oom(layout); + unsafe { + __rust_alloc_error_handler(layout.size(), layout.align()); + } } unsafe { core::intrinsics::const_eval_select((layout,), ct_error, rt_error) } @@ -446,7 +387,6 @@ pub const fn handle_alloc_error(layout: Layout) -> ! { #[cfg(all(not(no_global_oom_handling), test))] pub use std::alloc::handle_alloc_error; -#[cfg(bootstrap)] #[cfg(all(not(no_global_oom_handling), not(test)))] #[doc(hidden)] #[allow(unused_attributes)] @@ -458,7 +398,7 @@ pub mod __alloc_error_handler { pub unsafe fn __rdl_oom(size: usize, _align: usize) -> ! { extern "Rust" { // This symbol is emitted by rustc next to __rust_alloc_error_handler. - // Its value depends on the -Zoom={unwind,abort} compiler option. + // Its value depends on the -Zoom={panic,abort} compiler option. static __rust_alloc_error_handler_should_panic: u8; } diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs index 1743a155c5a..0cb7e82beb0 100644 --- a/library/alloc/src/collections/linked_list.rs +++ b/library/alloc/src/collections/linked_list.rs @@ -18,9 +18,10 @@ use core::hash::{Hash, Hasher}; use core::iter::FusedIterator; use core::marker::PhantomData; use core::mem; -use core::ptr::NonNull; +use core::ptr::{NonNull, Unique}; use super::SpecExtend; +use crate::alloc::{Allocator, Global}; use crate::boxed::Box; #[cfg(test)] @@ -47,11 +48,15 @@ mod tests; #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "LinkedList")] #[rustc_insignificant_dtor] -pub struct LinkedList<T> { +pub struct LinkedList< + T, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { head: Option<NonNull<Node<T>>>, tail: Option<NonNull<Node<T>>>, len: usize, - marker: PhantomData<Box<Node<T>>>, + alloc: A, + marker: PhantomData<Box<Node<T>, A>>, } struct Node<T> { @@ -81,6 +86,7 @@ impl<T: fmt::Debug> fmt::Debug for Iter<'_, T> { head: self.head, tail: self.tail, len: self.len, + alloc: Global, marker: PhantomData, })) .field(&self.len) @@ -117,6 +123,7 @@ impl<T: fmt::Debug> fmt::Debug for IterMut<'_, T> { head: self.head, tail: self.tail, len: self.len, + alloc: Global, marker: PhantomData, })) .field(&self.len) @@ -132,12 +139,15 @@ impl<T: fmt::Debug> fmt::Debug for IterMut<'_, T> { /// [`into_iter`]: LinkedList::into_iter #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] -pub struct IntoIter<T> { - list: LinkedList<T>, +pub struct IntoIter< + T, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + list: LinkedList<T, A>, } #[stable(feature = "collection_debug", since = "1.17.0")] -impl<T: fmt::Debug> fmt::Debug for IntoIter<T> { +impl<T: fmt::Debug, A: Allocator> fmt::Debug for IntoIter<T, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("IntoIter").field(&self.list).finish() } @@ -148,22 +158,25 @@ impl<T> Node<T> { Node { next: None, prev: None, element } } - fn into_element(self: Box<Self>) -> T { + fn into_element<A: Allocator>(self: Box<Self, A>) -> T { self.element } } // private methods -impl<T> LinkedList<T> { +impl<T, A: Allocator> LinkedList<T, A> { /// Adds the given node to the front of the list. + /// + /// # Safety + /// `node` must point to a valid node that was boxed using the list's allocator. #[inline] - fn push_front_node(&mut self, mut node: Box<Node<T>>) { + unsafe fn push_front_node(&mut self, node: Unique<Node<T>>) { // This method takes care not to create mutable references to whole nodes, // to maintain validity of aliasing pointers into `element`. unsafe { - node.next = self.head; - node.prev = None; - let node = Some(Box::leak(node).into()); + (*node.as_ptr()).next = self.head; + (*node.as_ptr()).prev = None; + let node = Some(NonNull::from(node)); match self.head { None => self.tail = node, @@ -178,11 +191,11 @@ impl<T> LinkedList<T> { /// Removes and returns the node at the front of the list. #[inline] - fn pop_front_node(&mut self) -> Option<Box<Node<T>>> { + fn pop_front_node(&mut self) -> Option<Box<Node<T>, &A>> { // This method takes care not to create mutable references to whole nodes, // to maintain validity of aliasing pointers into `element`. self.head.map(|node| unsafe { - let node = Box::from_raw(node.as_ptr()); + let node = Box::from_raw_in(node.as_ptr(), &self.alloc); self.head = node.next; match self.head { @@ -197,14 +210,17 @@ impl<T> LinkedList<T> { } /// Adds the given node to the back of the list. + /// + /// # Safety + /// `node` must point to a valid node that was boxed using the list's allocator. #[inline] - fn push_back_node(&mut self, mut node: Box<Node<T>>) { + unsafe fn push_back_node(&mut self, node: Unique<Node<T>>) { // This method takes care not to create mutable references to whole nodes, // to maintain validity of aliasing pointers into `element`. unsafe { - node.next = None; - node.prev = self.tail; - let node = Some(Box::leak(node).into()); + (*node.as_ptr()).next = None; + (*node.as_ptr()).prev = self.tail; + let node = Some(NonNull::from(node)); match self.tail { None => self.head = node, @@ -219,11 +235,11 @@ impl<T> LinkedList<T> { /// Removes and returns the node at the back of the list. #[inline] - fn pop_back_node(&mut self) -> Option<Box<Node<T>>> { + fn pop_back_node(&mut self) -> Option<Box<Node<T>, &A>> { // This method takes care not to create mutable references to whole nodes, // to maintain validity of aliasing pointers into `element`. self.tail.map(|node| unsafe { - let node = Box::from_raw(node.as_ptr()); + let node = Box::from_raw_in(node.as_ptr(), &self.alloc); self.tail = node.prev; match self.tail { @@ -321,7 +337,10 @@ impl<T> LinkedList<T> { &mut self, split_node: Option<NonNull<Node<T>>>, at: usize, - ) -> Self { + ) -> Self + where + A: Clone, + { // The split node is the new head node of the second part if let Some(mut split_node) = split_node { let first_part_head; @@ -342,6 +361,7 @@ impl<T> LinkedList<T> { head: first_part_head, tail: first_part_tail, len: at, + alloc: self.alloc.clone(), marker: PhantomData, }; @@ -351,7 +371,7 @@ impl<T> LinkedList<T> { first_part } else { - mem::replace(self, LinkedList::new()) + mem::replace(self, LinkedList::new_in(self.alloc.clone())) } } @@ -360,7 +380,10 @@ impl<T> LinkedList<T> { &mut self, split_node: Option<NonNull<Node<T>>>, at: usize, - ) -> Self { + ) -> Self + where + A: Clone, + { // The split node is the new tail node of the first part and owns // the head of the second part. if let Some(mut split_node) = split_node { @@ -382,6 +405,7 @@ impl<T> LinkedList<T> { head: second_part_head, tail: second_part_tail, len: self.len - at, + alloc: self.alloc.clone(), marker: PhantomData, }; @@ -391,7 +415,7 @@ impl<T> LinkedList<T> { second_part } else { - mem::replace(self, LinkedList::new()) + mem::replace(self, LinkedList::new_in(self.alloc.clone())) } } } @@ -420,7 +444,7 @@ impl<T> LinkedList<T> { #[stable(feature = "rust1", since = "1.0.0")] #[must_use] pub const fn new() -> Self { - LinkedList { head: None, tail: None, len: 0, marker: PhantomData } + LinkedList { head: None, tail: None, len: 0, alloc: Global, marker: PhantomData } } /// Moves all elements from `other` to the end of the list. @@ -471,7 +495,26 @@ impl<T> LinkedList<T> { } } } +} +impl<T, A: Allocator> LinkedList<T, A> { + /// Constructs an empty `LinkedList<T, A>`. + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api)] + /// + /// use std::alloc::System; + /// use std::collections::LinkedList; + /// + /// let list: LinkedList<u32, _> = LinkedList::new_in(System); + /// ``` + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + pub const fn new_in(alloc: A) -> Self { + LinkedList { head: None, tail: None, len: 0, alloc, marker: PhantomData } + } /// Provides a forward iterator. /// /// # Examples @@ -532,7 +575,7 @@ impl<T> LinkedList<T> { #[inline] #[must_use] #[unstable(feature = "linked_list_cursors", issue = "58533")] - pub fn cursor_front(&self) -> Cursor<'_, T> { + pub fn cursor_front(&self) -> Cursor<'_, T, A> { Cursor { index: 0, current: self.head, list: self } } @@ -542,7 +585,7 @@ impl<T> LinkedList<T> { #[inline] #[must_use] #[unstable(feature = "linked_list_cursors", issue = "58533")] - pub fn cursor_front_mut(&mut self) -> CursorMut<'_, T> { + pub fn cursor_front_mut(&mut self) -> CursorMut<'_, T, A> { CursorMut { index: 0, current: self.head, list: self } } @@ -552,7 +595,7 @@ impl<T> LinkedList<T> { #[inline] #[must_use] #[unstable(feature = "linked_list_cursors", issue = "58533")] - pub fn cursor_back(&self) -> Cursor<'_, T> { + pub fn cursor_back(&self) -> Cursor<'_, T, A> { Cursor { index: self.len.checked_sub(1).unwrap_or(0), current: self.tail, list: self } } @@ -562,7 +605,7 @@ impl<T> LinkedList<T> { #[inline] #[must_use] #[unstable(feature = "linked_list_cursors", issue = "58533")] - pub fn cursor_back_mut(&mut self) -> CursorMut<'_, T> { + pub fn cursor_back_mut(&mut self) -> CursorMut<'_, T, A> { CursorMut { index: self.len.checked_sub(1).unwrap_or(0), current: self.tail, list: self } } @@ -638,7 +681,15 @@ impl<T> LinkedList<T> { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn clear(&mut self) { - *self = Self::new(); + // We need to drop the nodes while keeping self.alloc + // We can do this by moving (head, tail, len) into a new list that borrows self.alloc + drop(LinkedList { + head: self.head.take(), + tail: self.tail.take(), + len: mem::take(&mut self.len), + alloc: &self.alloc, + marker: PhantomData, + }); } /// Returns `true` if the `LinkedList` contains an element equal to the @@ -790,7 +841,12 @@ impl<T> LinkedList<T> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn push_front(&mut self, elt: T) { - self.push_front_node(Box::new(Node::new(elt))); + let node = Box::new_in(Node::new(elt), &self.alloc); + let node_ptr = Unique::from(Box::leak(node)); + // SAFETY: node_ptr is a unique pointer to a node we boxed with self.alloc + unsafe { + self.push_front_node(node_ptr); + } } /// Removes the first element and returns it, or `None` if the list is @@ -833,7 +889,12 @@ impl<T> LinkedList<T> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn push_back(&mut self, elt: T) { - self.push_back_node(Box::new(Node::new(elt))); + let node = Box::new_in(Node::new(elt), &self.alloc); + let node_ptr = Unique::from(Box::leak(node)); + // SAFETY: node_ptr is a unique pointer to a node we boxed with self.alloc + unsafe { + self.push_back_node(node_ptr); + } } /// Removes the last element from a list and returns it, or `None` if @@ -883,13 +944,16 @@ impl<T> LinkedList<T> { /// assert_eq!(split.pop_front(), None); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn split_off(&mut self, at: usize) -> LinkedList<T> { + pub fn split_off(&mut self, at: usize) -> LinkedList<T, A> + where + A: Clone, + { let len = self.len(); assert!(at <= len, "Cannot split off at a nonexistent index"); if at == 0 { - return mem::take(self); + return mem::replace(self, Self::new_in(self.alloc.clone())); } else if at == len { - return Self::new(); + return Self::new_in(self.alloc.clone()); } // Below, we iterate towards the `i-1`th node, either from the start or the end, @@ -987,7 +1051,7 @@ impl<T> LinkedList<T> { /// assert_eq!(odds.into_iter().collect::<Vec<_>>(), vec![1, 3, 5, 9, 11, 13, 15]); /// ``` #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] - pub fn drain_filter<F>(&mut self, filter: F) -> DrainFilter<'_, T, F> + pub fn drain_filter<F>(&mut self, filter: F) -> DrainFilter<'_, T, F, A> where F: FnMut(&mut T) -> bool, { @@ -1000,11 +1064,11 @@ impl<T> LinkedList<T> { } #[stable(feature = "rust1", since = "1.0.0")] -unsafe impl<#[may_dangle] T> Drop for LinkedList<T> { +unsafe impl<#[may_dangle] T, A: Allocator> Drop for LinkedList<T, A> { fn drop(&mut self) { - struct DropGuard<'a, T>(&'a mut LinkedList<T>); + struct DropGuard<'a, T, A: Allocator>(&'a mut LinkedList<T, A>); - impl<'a, T> Drop for DropGuard<'a, T> { + impl<'a, T, A: Allocator> Drop for DropGuard<'a, T, A> { fn drop(&mut self) { // Continue the same loop we do below. This only runs when a destructor has // panicked. If another one panics this will abort. @@ -1012,11 +1076,10 @@ unsafe impl<#[may_dangle] T> Drop for LinkedList<T> { } } - while let Some(node) = self.pop_front_node() { - let guard = DropGuard(self); - drop(node); - mem::forget(guard); - } + // Wrap self so that if a destructor panics, we can try to keep looping + let guard = DropGuard(self); + while guard.0.pop_front_node().is_some() {} + mem::forget(guard); } } @@ -1159,14 +1222,18 @@ impl<T> Default for IterMut<'_, T> { /// /// When created, cursors start at the front of the list, or the "ghost" non-element if the list is empty. #[unstable(feature = "linked_list_cursors", issue = "58533")] -pub struct Cursor<'a, T: 'a> { +pub struct Cursor< + 'a, + T: 'a, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { index: usize, current: Option<NonNull<Node<T>>>, - list: &'a LinkedList<T>, + list: &'a LinkedList<T, A>, } #[unstable(feature = "linked_list_cursors", issue = "58533")] -impl<T> Clone for Cursor<'_, T> { +impl<T, A: Allocator> Clone for Cursor<'_, T, A> { fn clone(&self) -> Self { let Cursor { index, current, list } = *self; Cursor { index, current, list } @@ -1174,7 +1241,7 @@ impl<T> Clone for Cursor<'_, T> { } #[unstable(feature = "linked_list_cursors", issue = "58533")] -impl<T: fmt::Debug> fmt::Debug for Cursor<'_, T> { +impl<T: fmt::Debug, A: Allocator> fmt::Debug for Cursor<'_, T, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("Cursor").field(&self.list).field(&self.index()).finish() } @@ -1191,20 +1258,24 @@ impl<T: fmt::Debug> fmt::Debug for Cursor<'_, T> { /// To accommodate this, there is a "ghost" non-element that yields `None` between the head and /// tail of the list. #[unstable(feature = "linked_list_cursors", issue = "58533")] -pub struct CursorMut<'a, T: 'a> { +pub struct CursorMut< + 'a, + T: 'a, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { index: usize, current: Option<NonNull<Node<T>>>, - list: &'a mut LinkedList<T>, + list: &'a mut LinkedList<T, A>, } #[unstable(feature = "linked_list_cursors", issue = "58533")] -impl<T: fmt::Debug> fmt::Debug for CursorMut<'_, T> { +impl<T: fmt::Debug, A: Allocator> fmt::Debug for CursorMut<'_, T, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("CursorMut").field(&self.list).field(&self.index()).finish() } } -impl<'a, T> Cursor<'a, T> { +impl<'a, T, A: Allocator> Cursor<'a, T, A> { /// Returns the cursor position index within the `LinkedList`. /// /// This returns `None` if the cursor is currently pointing to the @@ -1321,7 +1392,7 @@ impl<'a, T> Cursor<'a, T> { } } -impl<'a, T> CursorMut<'a, T> { +impl<'a, T, A: Allocator> CursorMut<'a, T, A> { /// Returns the cursor position index within the `LinkedList`. /// /// This returns `None` if the cursor is currently pointing to the @@ -1426,7 +1497,7 @@ impl<'a, T> CursorMut<'a, T> { /// `CursorMut` is frozen for the lifetime of the `Cursor`. #[must_use] #[unstable(feature = "linked_list_cursors", issue = "58533")] - pub fn as_cursor(&self) -> Cursor<'_, T> { + pub fn as_cursor(&self) -> Cursor<'_, T, A> { Cursor { list: self.list, current: self.current, index: self.index } } } @@ -1434,6 +1505,51 @@ impl<'a, T> CursorMut<'a, T> { // Now the list editing operations impl<'a, T> CursorMut<'a, T> { + /// Inserts the elements from the given `LinkedList` after the current one. + /// + /// If the cursor is pointing at the "ghost" non-element then the new elements are + /// inserted at the start of the `LinkedList`. + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn splice_after(&mut self, list: LinkedList<T>) { + unsafe { + let (splice_head, splice_tail, splice_len) = match list.detach_all_nodes() { + Some(parts) => parts, + _ => return, + }; + let node_next = match self.current { + None => self.list.head, + Some(node) => node.as_ref().next, + }; + self.list.splice_nodes(self.current, node_next, splice_head, splice_tail, splice_len); + if self.current.is_none() { + // The "ghost" non-element's index has changed. + self.index = self.list.len; + } + } + } + + /// Inserts the elements from the given `LinkedList` before the current one. + /// + /// If the cursor is pointing at the "ghost" non-element then the new elements are + /// inserted at the end of the `LinkedList`. + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn splice_before(&mut self, list: LinkedList<T>) { + unsafe { + let (splice_head, splice_tail, splice_len) = match list.detach_all_nodes() { + Some(parts) => parts, + _ => return, + }; + let node_prev = match self.current { + None => self.list.tail, + Some(node) => node.as_ref().prev, + }; + self.list.splice_nodes(node_prev, self.current, splice_head, splice_tail, splice_len); + self.index += splice_len; + } + } +} + +impl<'a, T, A: Allocator> CursorMut<'a, T, A> { /// Inserts a new element into the `LinkedList` after the current one. /// /// If the cursor is pointing at the "ghost" non-element then the new element is @@ -1441,7 +1557,7 @@ impl<'a, T> CursorMut<'a, T> { #[unstable(feature = "linked_list_cursors", issue = "58533")] pub fn insert_after(&mut self, item: T) { unsafe { - let spliced_node = Box::leak(Box::new(Node::new(item))).into(); + let spliced_node = Box::leak(Box::new_in(Node::new(item), &self.list.alloc)).into(); let node_next = match self.current { None => self.list.head, Some(node) => node.as_ref().next, @@ -1461,7 +1577,7 @@ impl<'a, T> CursorMut<'a, T> { #[unstable(feature = "linked_list_cursors", issue = "58533")] pub fn insert_before(&mut self, item: T) { unsafe { - let spliced_node = Box::leak(Box::new(Node::new(item))).into(); + let spliced_node = Box::leak(Box::new_in(Node::new(item), &self.list.alloc)).into(); let node_prev = match self.current { None => self.list.tail, Some(node) => node.as_ref().prev, @@ -1497,7 +1613,10 @@ impl<'a, T> CursorMut<'a, T> { /// If the cursor is currently pointing to the "ghost" non-element then no element /// is removed and `None` is returned. #[unstable(feature = "linked_list_cursors", issue = "58533")] - pub fn remove_current_as_list(&mut self) -> Option<LinkedList<T>> { + pub fn remove_current_as_list(&mut self) -> Option<LinkedList<T, A>> + where + A: Clone, + { let mut unlinked_node = self.current?; unsafe { self.current = unlinked_node.as_ref().next; @@ -1509,54 +1628,12 @@ impl<'a, T> CursorMut<'a, T> { head: Some(unlinked_node), tail: Some(unlinked_node), len: 1, + alloc: self.list.alloc.clone(), marker: PhantomData, }) } } - /// Inserts the elements from the given `LinkedList` after the current one. - /// - /// If the cursor is pointing at the "ghost" non-element then the new elements are - /// inserted at the start of the `LinkedList`. - #[unstable(feature = "linked_list_cursors", issue = "58533")] - pub fn splice_after(&mut self, list: LinkedList<T>) { - unsafe { - let (splice_head, splice_tail, splice_len) = match list.detach_all_nodes() { - Some(parts) => parts, - _ => return, - }; - let node_next = match self.current { - None => self.list.head, - Some(node) => node.as_ref().next, - }; - self.list.splice_nodes(self.current, node_next, splice_head, splice_tail, splice_len); - if self.current.is_none() { - // The "ghost" non-element's index has changed. - self.index = self.list.len; - } - } - } - - /// Inserts the elements from the given `LinkedList` before the current one. - /// - /// If the cursor is pointing at the "ghost" non-element then the new elements are - /// inserted at the end of the `LinkedList`. - #[unstable(feature = "linked_list_cursors", issue = "58533")] - pub fn splice_before(&mut self, list: LinkedList<T>) { - unsafe { - let (splice_head, splice_tail, splice_len) = match list.detach_all_nodes() { - Some(parts) => parts, - _ => return, - }; - let node_prev = match self.current { - None => self.list.tail, - Some(node) => node.as_ref().prev, - }; - self.list.splice_nodes(node_prev, self.current, splice_head, splice_tail, splice_len); - self.index += splice_len; - } - } - /// Splits the list into two after the current element. This will return a /// new list consisting of everything after the cursor, with the original /// list retaining everything before. @@ -1564,7 +1641,10 @@ impl<'a, T> CursorMut<'a, T> { /// If the cursor is pointing at the "ghost" non-element then the entire contents /// of the `LinkedList` are moved. #[unstable(feature = "linked_list_cursors", issue = "58533")] - pub fn split_after(&mut self) -> LinkedList<T> { + pub fn split_after(&mut self) -> LinkedList<T, A> + where + A: Clone, + { let split_off_idx = if self.index == self.list.len { 0 } else { self.index + 1 }; if self.index == self.list.len { // The "ghost" non-element's index has changed to 0. @@ -1580,7 +1660,10 @@ impl<'a, T> CursorMut<'a, T> { /// If the cursor is pointing at the "ghost" non-element then the entire contents /// of the `LinkedList` are moved. #[unstable(feature = "linked_list_cursors", issue = "58533")] - pub fn split_before(&mut self) -> LinkedList<T> { + pub fn split_before(&mut self) -> LinkedList<T, A> + where + A: Clone, + { let split_off_idx = self.index; self.index = 0; unsafe { self.list.split_off_before_node(self.current, split_off_idx) } @@ -1722,11 +1805,15 @@ impl<'a, T> CursorMut<'a, T> { /// An iterator produced by calling `drain_filter` on LinkedList. #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] -pub struct DrainFilter<'a, T: 'a, F: 'a> -where +pub struct DrainFilter< + 'a, + T: 'a, + F: 'a, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> where F: FnMut(&mut T) -> bool, { - list: &'a mut LinkedList<T>, + list: &'a mut LinkedList<T, A>, it: Option<NonNull<Node<T>>>, pred: F, idx: usize, @@ -1734,7 +1821,7 @@ where } #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] -impl<T, F> Iterator for DrainFilter<'_, T, F> +impl<T, F, A: Allocator> Iterator for DrainFilter<'_, T, F, A> where F: FnMut(&mut T) -> bool, { @@ -1763,16 +1850,16 @@ where } #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] -impl<T, F> Drop for DrainFilter<'_, T, F> +impl<T, F, A: Allocator> Drop for DrainFilter<'_, T, F, A> where F: FnMut(&mut T) -> bool, { fn drop(&mut self) { - struct DropGuard<'r, 'a, T, F>(&'r mut DrainFilter<'a, T, F>) + struct DropGuard<'r, 'a, T, F, A: Allocator>(&'r mut DrainFilter<'a, T, F, A>) where F: FnMut(&mut T) -> bool; - impl<'r, 'a, T, F> Drop for DropGuard<'r, 'a, T, F> + impl<'r, 'a, T, F, A: Allocator> Drop for DropGuard<'r, 'a, T, F, A> where F: FnMut(&mut T) -> bool, { @@ -1800,7 +1887,7 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl<T> Iterator for IntoIter<T> { +impl<T, A: Allocator> Iterator for IntoIter<T, A> { type Item = T; #[inline] @@ -1815,7 +1902,7 @@ impl<T> Iterator for IntoIter<T> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<T> DoubleEndedIterator for IntoIter<T> { +impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> { #[inline] fn next_back(&mut self) -> Option<T> { self.list.pop_back() @@ -1823,10 +1910,10 @@ impl<T> DoubleEndedIterator for IntoIter<T> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<T> ExactSizeIterator for IntoIter<T> {} +impl<T, A: Allocator> ExactSizeIterator for IntoIter<T, A> {} #[stable(feature = "fused", since = "1.26.0")] -impl<T> FusedIterator for IntoIter<T> {} +impl<T, A: Allocator> FusedIterator for IntoIter<T, A> {} #[stable(feature = "default_iters", since = "CURRENT_RUSTC_VERSION")] impl<T> Default for IntoIter<T> { @@ -1852,19 +1939,19 @@ impl<T> FromIterator<T> for LinkedList<T> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<T> IntoIterator for LinkedList<T> { +impl<T, A: Allocator> IntoIterator for LinkedList<T, A> { type Item = T; - type IntoIter = IntoIter<T>; + type IntoIter = IntoIter<T, A>; /// Consumes the list into an iterator yielding elements by value. #[inline] - fn into_iter(self) -> IntoIter<T> { + fn into_iter(self) -> IntoIter<T, A> { IntoIter { list: self } } } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> IntoIterator for &'a LinkedList<T> { +impl<'a, T, A: Allocator> IntoIterator for &'a LinkedList<T, A> { type Item = &'a T; type IntoIter = Iter<'a, T>; @@ -1874,7 +1961,7 @@ impl<'a, T> IntoIterator for &'a LinkedList<T> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> IntoIterator for &'a mut LinkedList<T> { +impl<'a, T, A: Allocator> IntoIterator for &'a mut LinkedList<T, A> { type Item = &'a mut T; type IntoIter = IterMut<'a, T>; @@ -1884,7 +1971,7 @@ impl<'a, T> IntoIterator for &'a mut LinkedList<T> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<T> Extend<T> for LinkedList<T> { +impl<T, A: Allocator> Extend<T> for LinkedList<T, A> { fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) { <Self as SpecExtend<I>>::spec_extend(self, iter); } @@ -1895,7 +1982,7 @@ impl<T> Extend<T> for LinkedList<T> { } } -impl<I: IntoIterator> SpecExtend<I> for LinkedList<I::Item> { +impl<I: IntoIterator, A: Allocator> SpecExtend<I> for LinkedList<I::Item, A> { default fn spec_extend(&mut self, iter: I) { iter.into_iter().for_each(move |elt| self.push_back(elt)); } @@ -1908,7 +1995,7 @@ impl<T> SpecExtend<LinkedList<T>> for LinkedList<T> { } #[stable(feature = "extend_ref", since = "1.2.0")] -impl<'a, T: 'a + Copy> Extend<&'a T> for LinkedList<T> { +impl<'a, T: 'a + Copy, A: Allocator> Extend<&'a T> for LinkedList<T, A> { fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) { self.extend(iter.into_iter().cloned()); } @@ -1920,7 +2007,7 @@ impl<'a, T: 'a + Copy> Extend<&'a T> for LinkedList<T> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<T: PartialEq> PartialEq for LinkedList<T> { +impl<T: PartialEq, A: Allocator> PartialEq for LinkedList<T, A> { fn eq(&self, other: &Self) -> bool { self.len() == other.len() && self.iter().eq(other) } @@ -1931,17 +2018,17 @@ impl<T: PartialEq> PartialEq for LinkedList<T> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<T: Eq> Eq for LinkedList<T> {} +impl<T: Eq, A: Allocator> Eq for LinkedList<T, A> {} #[stable(feature = "rust1", since = "1.0.0")] -impl<T: PartialOrd> PartialOrd for LinkedList<T> { +impl<T: PartialOrd, A: Allocator> PartialOrd for LinkedList<T, A> { fn partial_cmp(&self, other: &Self) -> Option<Ordering> { self.iter().partial_cmp(other) } } #[stable(feature = "rust1", since = "1.0.0")] -impl<T: Ord> Ord for LinkedList<T> { +impl<T: Ord, A: Allocator> Ord for LinkedList<T, A> { #[inline] fn cmp(&self, other: &Self) -> Ordering { self.iter().cmp(other) @@ -1949,9 +2036,11 @@ impl<T: Ord> Ord for LinkedList<T> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<T: Clone> Clone for LinkedList<T> { +impl<T: Clone, A: Allocator + Clone> Clone for LinkedList<T, A> { fn clone(&self) -> Self { - self.iter().cloned().collect() + let mut list = Self::new_in(self.alloc.clone()); + list.extend(self.iter().cloned()); + list } fn clone_from(&mut self, other: &Self) { @@ -1969,14 +2058,14 @@ impl<T: Clone> Clone for LinkedList<T> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<T: fmt::Debug> fmt::Debug for LinkedList<T> { +impl<T: fmt::Debug, A: Allocator> fmt::Debug for LinkedList<T, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self).finish() } } #[stable(feature = "rust1", since = "1.0.0")] -impl<T: Hash> Hash for LinkedList<T> { +impl<T: Hash, A: Allocator> Hash for LinkedList<T, A> { fn hash<H: Hasher>(&self, state: &mut H) { state.write_length_prefix(self.len()); for elt in self { @@ -2016,10 +2105,10 @@ fn assert_covariance() { } #[stable(feature = "rust1", since = "1.0.0")] -unsafe impl<T: Send> Send for LinkedList<T> {} +unsafe impl<T: Send, A: Allocator + Send> Send for LinkedList<T, A> {} #[stable(feature = "rust1", since = "1.0.0")] -unsafe impl<T: Sync> Sync for LinkedList<T> {} +unsafe impl<T: Sync, A: Allocator + Sync> Sync for LinkedList<T, A> {} #[stable(feature = "rust1", since = "1.0.0")] unsafe impl<T: Sync> Send for Iter<'_, T> {} @@ -2034,13 +2123,13 @@ unsafe impl<T: Send> Send for IterMut<'_, T> {} unsafe impl<T: Sync> Sync for IterMut<'_, T> {} #[unstable(feature = "linked_list_cursors", issue = "58533")] -unsafe impl<T: Sync> Send for Cursor<'_, T> {} +unsafe impl<T: Sync, A: Allocator + Sync> Send for Cursor<'_, T, A> {} #[unstable(feature = "linked_list_cursors", issue = "58533")] -unsafe impl<T: Sync> Sync for Cursor<'_, T> {} +unsafe impl<T: Sync, A: Allocator + Sync> Sync for Cursor<'_, T, A> {} #[unstable(feature = "linked_list_cursors", issue = "58533")] -unsafe impl<T: Send> Send for CursorMut<'_, T> {} +unsafe impl<T: Send, A: Allocator + Send> Send for CursorMut<'_, T, A> {} #[unstable(feature = "linked_list_cursors", issue = "58533")] -unsafe impl<T: Sync> Sync for CursorMut<'_, T> {} +unsafe impl<T: Sync, A: Allocator + Sync> Sync for CursorMut<'_, T, A> {} diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 2c6a266e2a1..a002421aeef 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -135,7 +135,6 @@ #![feature(maybe_uninit_slice)] #![feature(maybe_uninit_uninit_array)] #![feature(maybe_uninit_uninit_array_transpose)] -#![feature(panic_internals)] #![feature(pattern)] #![feature(pointer_byte_offsets)] #![feature(provide_any)] diff --git a/library/alloc/src/task.rs b/library/alloc/src/task.rs index 9d8e309a978..5d9772b878b 100644 --- a/library/alloc/src/task.rs +++ b/library/alloc/src/task.rs @@ -39,6 +39,7 @@ use crate::sync::Arc; /// use std::sync::Arc; /// use std::task::{Context, Poll, Wake}; /// use std::thread::{self, Thread}; +/// use core::pin::pin; /// /// /// A waker that wakes up the current thread when called. /// struct ThreadWaker(Thread); @@ -52,7 +53,7 @@ use crate::sync::Arc; /// /// Run a future to completion on the current thread. /// fn block_on<T>(fut: impl Future<Output = T>) -> T { /// // Pin the future so it can be polled. -/// let mut fut = Box::pin(fut); +/// let mut fut = pin!(fut); /// /// // Create a new context to be passed to the future. /// let t = thread::current(); diff --git a/library/core/benches/num/flt2dec/strategy/grisu.rs b/library/core/benches/num/flt2dec/strategy/grisu.rs index 6bea5e55d37..17d6b474ad2 100644 --- a/library/core/benches/num/flt2dec/strategy/grisu.rs +++ b/library/core/benches/num/flt2dec/strategy/grisu.rs @@ -81,3 +81,30 @@ fn bench_big_exact_inf(b: &mut Bencher) { format_exact(black_box(&decoded), &mut buf, i16::MIN); }); } + +#[bench] +fn bench_one_exact_inf(b: &mut Bencher) { + let decoded = decode_finite(1.0); + let mut buf = [MaybeUninit::new(0); 1024]; + b.iter(|| { + format_exact(black_box(&decoded), &mut buf, i16::MIN); + }); +} + +#[bench] +fn bench_trailing_zero_exact_inf(b: &mut Bencher) { + let decoded = decode_finite(250.000000000000000000000000); + let mut buf = [MaybeUninit::new(0); 1024]; + b.iter(|| { + format_exact(black_box(&decoded), &mut buf, i16::MIN); + }); +} + +#[bench] +fn bench_halfway_point_exact_inf(b: &mut Bencher) { + let decoded = decode_finite(1.00000000000000011102230246251565404236316680908203125); + let mut buf = [MaybeUninit::new(0); 1024]; + b.iter(|| { + format_exact(black_box(&decoded), &mut buf, i16::MIN); + }); +} diff --git a/library/core/src/cell/lazy.rs b/library/core/src/cell/lazy.rs index 44adcfa1a94..1b213f6a294 100644 --- a/library/core/src/cell/lazy.rs +++ b/library/core/src/cell/lazy.rs @@ -63,6 +63,34 @@ impl<T, F: FnOnce() -> T> LazyCell<T, F> { LazyCell { state: UnsafeCell::new(State::Uninit(f)) } } + /// Consumes this `LazyCell` returning the stored value. + /// + /// Returns `Ok(value)` if `Lazy` is initialized and `Err(f)` otherwise. + /// + /// # Examples + /// + /// ``` + /// #![feature(lazy_cell)] + /// #![feature(lazy_cell_consume)] + /// + /// use std::cell::LazyCell; + /// + /// let hello = "Hello, World!".to_string(); + /// + /// let lazy = LazyCell::new(|| hello.to_uppercase()); + /// + /// assert_eq!(&*lazy, "HELLO, WORLD!"); + /// assert_eq!(LazyCell::into_inner(lazy).ok(), Some("HELLO, WORLD!".to_string())); + /// ``` + #[unstable(feature = "lazy_cell_consume", issue = "109736")] + pub fn into_inner(this: Self) -> Result<T, F> { + match this.state.into_inner() { + State::Init(data) => Ok(data), + State::Uninit(f) => Err(f), + State::Poisoned => panic!("LazyCell instance has previously been poisoned"), + } + } + /// Forces the evaluation of this lazy value and returns a reference to /// the result. /// diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index cc3179ee780..7c93c93b4a0 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1531,6 +1531,16 @@ pub(crate) mod builtin { /* compiler built-in */ } + /// Attribute macro applied to a function to register it as a handler for allocation failure. + /// + /// See also [`std::alloc::handle_alloc_error`](../../../std/alloc/fn.handle_alloc_error.html). + #[unstable(feature = "alloc_error_handler", issue = "51540")] + #[allow_internal_unstable(rustc_attrs)] + #[rustc_builtin_macro] + pub macro alloc_error_handler($item:item) { + /* compiler built-in */ + } + /// Keeps the item it's applied to if the passed path is accessible, and removes it otherwise. #[unstable( feature = "cfg_accessible", diff --git a/library/core/src/num/flt2dec/strategy/grisu.rs b/library/core/src/num/flt2dec/strategy/grisu.rs index ed3e0edaff2..b9f0d114c6a 100644 --- a/library/core/src/num/flt2dec/strategy/grisu.rs +++ b/library/core/src/num/flt2dec/strategy/grisu.rs @@ -487,6 +487,22 @@ pub fn format_exact_opt<'a>( let vint = (v.f >> e) as u32; let vfrac = v.f & ((1 << e) - 1); + let requested_digits = buf.len(); + + const POW10_UP_TO_9: [u32; 10] = + [1, 10, 100, 1000, 10_000, 100_000, 1_000_000, 10_000_000, 100_000_000, 1_000_000_000]; + + // We deviate from the original algorithm here and do some early checks to determine if we can satisfy requested_digits. + // If we determine that we can't, we exit early and avoid most of the heavy lifting that the algorithm otherwise does. + // + // When vfrac is zero, we can easily determine if vint can satisfy requested digits: + // If requested_digits >= 11, vint is not able to exhaust the count by itself since 10^(11 -1) > u32 max value >= vint. + // If vint < 10^(requested_digits - 1), vint cannot exhaust the count. + // Otherwise, vint might be able to exhaust the count and we need to execute the rest of the code. + if (vfrac == 0) && ((requested_digits >= 11) || (vint < POW10_UP_TO_9[requested_digits - 1])) { + return None; + } + // both old `v` and new `v` (scaled by `10^-k`) has an error of < 1 ulp (Theorem 5.1). // as we don't know the error is positive or negative, we use two approximations // spaced equally and have the maximal error of 2 ulps (same to the shortest case). diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/v1.rs index 9c4c0f6ab7a..10525a16f3a 100644 --- a/library/core/src/prelude/v1.rs +++ b/library/core/src/prelude/v1.rs @@ -76,7 +76,9 @@ pub use crate::macros::builtin::{RustcDecodable, RustcEncodable}; // Do not `doc(no_inline)` so that they become doc items on their own // (no public module for them to be re-exported from). #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] -pub use crate::macros::builtin::{bench, derive, global_allocator, test, test_case}; +pub use crate::macros::builtin::{ + alloc_error_handler, bench, derive, global_allocator, test, test_case, +}; #[unstable(feature = "derive_const", issue = "none")] pub use crate::macros::builtin::derive_const; diff --git a/library/core/src/slice/sort.rs b/library/core/src/slice/sort.rs index 07fd96f9295..e6e3b55efa9 100644 --- a/library/core/src/slice/sort.rs +++ b/library/core/src/slice/sort.rs @@ -1456,7 +1456,6 @@ pub struct TimSortRun { /// Takes a range as denoted by start and end, that is already sorted and extends it to the right if /// necessary with sorts optimized for smaller ranges such as insertion sort. -#[cfg(not(no_global_oom_handling))] fn provide_sorted_batch<T, F>(v: &mut [T], start: usize, mut end: usize, is_less: &mut F) -> usize where F: FnMut(&T, &T) -> bool, diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 109387b09d0..f2fda64a1ee 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -67,7 +67,7 @@ llvm-libunwind = ["unwind/llvm-libunwind"] system-llvm-libunwind = ["unwind/system-llvm-libunwind"] # Make panics and failed asserts immediately abort without formatting any message -panic_immediate_abort = ["alloc/panic_immediate_abort"] +panic_immediate_abort = ["core/panic_immediate_abort"] # Enable std_detect default features for stdarch/crates/std_detect: # https://github.com/rust-lang/stdarch/blob/master/crates/std_detect/Cargo.toml diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs index 448a8edc291..c5a5991cc81 100644 --- a/library/std/src/alloc.rs +++ b/library/std/src/alloc.rs @@ -57,8 +57,9 @@ #![stable(feature = "alloc_module", since = "1.28.0")] use core::intrinsics; -use core::ptr; use core::ptr::NonNull; +use core::sync::atomic::{AtomicPtr, Ordering}; +use core::{mem, ptr}; #[stable(feature = "alloc_module", since = "1.28.0")] #[doc(inline)] @@ -285,6 +286,76 @@ unsafe impl Allocator for System { } } +static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut()); + +/// Registers a custom allocation error hook, replacing any that was previously registered. +/// +/// The allocation error hook is invoked when an infallible memory allocation fails, before +/// the runtime aborts. The default hook prints a message to standard error, +/// but this behavior can be customized with the [`set_alloc_error_hook`] and +/// [`take_alloc_error_hook`] functions. +/// +/// The hook is provided with a `Layout` struct which contains information +/// about the allocation that failed. +/// +/// The allocation error hook is a global resource. +/// +/// # Examples +/// +/// ``` +/// #![feature(alloc_error_hook)] +/// +/// use std::alloc::{Layout, set_alloc_error_hook}; +/// +/// fn custom_alloc_error_hook(layout: Layout) { +/// panic!("memory allocation of {} bytes failed", layout.size()); +/// } +/// +/// set_alloc_error_hook(custom_alloc_error_hook); +/// ``` +#[unstable(feature = "alloc_error_hook", issue = "51245")] +pub fn set_alloc_error_hook(hook: fn(Layout)) { + HOOK.store(hook as *mut (), Ordering::SeqCst); +} + +/// Unregisters the current allocation error hook, returning it. +/// +/// *See also the function [`set_alloc_error_hook`].* +/// +/// If no custom hook is registered, the default hook will be returned. +#[unstable(feature = "alloc_error_hook", issue = "51245")] +pub fn take_alloc_error_hook() -> fn(Layout) { + let hook = HOOK.swap(ptr::null_mut(), Ordering::SeqCst); + if hook.is_null() { default_alloc_error_hook } else { unsafe { mem::transmute(hook) } } +} + +fn default_alloc_error_hook(layout: Layout) { + extern "Rust" { + // This symbol is emitted by rustc next to __rust_alloc_error_handler. + // Its value depends on the -Zoom={panic,abort} compiler option. + static __rust_alloc_error_handler_should_panic: u8; + } + + #[allow(unused_unsafe)] + if unsafe { __rust_alloc_error_handler_should_panic != 0 } { + panic!("memory allocation of {} bytes failed", layout.size()); + } else { + rtprintpanic!("memory allocation of {} bytes failed\n", layout.size()); + } +} + +#[cfg(not(test))] +#[doc(hidden)] +#[alloc_error_handler] +#[unstable(feature = "alloc_internals", issue = "none")] +pub fn rust_oom(layout: Layout) -> ! { + let hook = HOOK.load(Ordering::SeqCst); + let hook: fn(Layout) = + if hook.is_null() { default_alloc_error_hook } else { unsafe { mem::transmute(hook) } }; + hook(layout); + crate::process::abort() +} + #[cfg(not(test))] #[doc(hidden)] #[allow(unused_attributes)] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 933f75d638b..318a46d1b63 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -236,6 +236,7 @@ // // Language features: // tidy-alphabetical-start +#![feature(alloc_error_handler)] #![feature(allocator_internals)] #![feature(allow_internal_unsafe)] #![feature(allow_internal_unstable)] @@ -319,7 +320,6 @@ #![feature(get_mut_unchecked)] #![feature(map_try_insert)] #![feature(new_uninit)] -#![feature(panic_oom_payload)] #![feature(slice_concat_trait)] #![feature(thin_box)] #![feature(try_reserve_kind)] diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index ca4cf68ad54..a46a29cbad6 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -245,24 +245,19 @@ fn default_hook(info: &PanicInfo<'_>) { // The current implementation always returns `Some`. let location = info.location().unwrap(); + + let msg = match info.payload().downcast_ref::<&'static str>() { + Some(s) => *s, + None => match info.payload().downcast_ref::<String>() { + Some(s) => &s[..], + None => "Box<dyn Any>", + }, + }; let thread = thread_info::current_thread(); let name = thread.as_ref().and_then(|t| t.name()).unwrap_or("<unnamed>"); let write = |err: &mut dyn crate::io::Write| { - // Use the panic message directly if available, otherwise take it from - // the payload. - if let Some(msg) = info.message() { - let _ = writeln!(err, "thread '{name}' panicked at '{msg}', {location}"); - } else { - let msg = if let Some(s) = info.payload().downcast_ref::<&'static str>() { - *s - } else if let Some(s) = info.payload().downcast_ref::<String>() { - &s[..] - } else { - "Box<dyn Any>" - }; - let _ = writeln!(err, "thread '{name}' panicked at '{msg}', {location}"); - } + let _ = writeln!(err, "thread '{name}' panicked at '{msg}', {location}"); static FIRST_PANIC: AtomicBool = AtomicBool::new(true); @@ -529,8 +524,6 @@ pub fn panicking() -> bool { #[cfg(not(test))] #[panic_handler] pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! { - use alloc::alloc::AllocErrorPanicPayload; - struct PanicPayload<'a> { inner: &'a fmt::Arguments<'a>, string: Option<String>, @@ -557,7 +550,8 @@ pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! { unsafe impl<'a> BoxMeUp for PanicPayload<'a> { fn take_box(&mut self) -> *mut (dyn Any + Send) { // We do two allocations here, unfortunately. But (a) they're required with the current - // scheme, and (b) OOM uses its own separate payload type which doesn't allocate. + // scheme, and (b) we don't handle panic + OOM properly anyway (see comment in + // begin_panic below). let contents = mem::take(self.fill()); Box::into_raw(Box::new(contents)) } @@ -582,14 +576,7 @@ pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! { let loc = info.location().unwrap(); // The current implementation always returns Some let msg = info.message().unwrap(); // The current implementation always returns Some crate::sys_common::backtrace::__rust_end_short_backtrace(move || { - if let Some(payload) = info.payload().downcast_ref::<AllocErrorPanicPayload>() { - rust_panic_with_hook( - &mut payload.internal_clone(), - info.message(), - loc, - info.can_unwind(), - ); - } else if let Some(msg) = msg.as_str() { + if let Some(msg) = msg.as_str() { rust_panic_with_hook(&mut StrPanicPayload(msg), info.message(), loc, info.can_unwind()); } else { rust_panic_with_hook( @@ -636,7 +623,11 @@ pub const fn begin_panic<M: Any + Send>(msg: M) -> ! { unsafe impl<A: Send + 'static> BoxMeUp for PanicPayload<A> { fn take_box(&mut self) -> *mut (dyn Any + Send) { - // Note that this should be the only allocation performed in this code path. + // Note that this should be the only allocation performed in this code path. Currently + // this means that panic!() on OOM will invoke this code path, but then again we're not + // really ready for panic on OOM anyway. If we do start doing this, then we should + // propagate this allocation to be performed in the parent of this thread instead of the + // thread that's panicking. let data = match self.inner.take() { Some(a) => Box::new(a) as Box<dyn Any + Send>, None => process::abort(), diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs index 4f325a70b18..2aefd7c513d 100644 --- a/library/std/src/prelude/v1.rs +++ b/library/std/src/prelude/v1.rs @@ -60,7 +60,9 @@ pub use core::prelude::v1::{RustcDecodable, RustcEncodable}; // Do not `doc(no_inline)` so that they become doc items on their own // (no public module for them to be re-exported from). #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] -pub use core::prelude::v1::{bench, derive, global_allocator, test, test_case}; +pub use core::prelude::v1::{ + alloc_error_handler, bench, derive, global_allocator, test, test_case, +}; #[unstable(feature = "derive_const", issue = "none")] pub use core::prelude::v1::derive_const; diff --git a/library/std/src/sync/lazy_lock.rs b/library/std/src/sync/lazy_lock.rs index 8e9ea293ce4..a6bc468b092 100644 --- a/library/std/src/sync/lazy_lock.rs +++ b/library/std/src/sync/lazy_lock.rs @@ -1,9 +1,9 @@ use crate::cell::UnsafeCell; -use crate::fmt; use crate::mem::ManuallyDrop; use crate::ops::Deref; use crate::panic::{RefUnwindSafe, UnwindSafe}; use crate::sync::Once; +use crate::{fmt, ptr}; use super::once::ExclusiveState; @@ -69,6 +69,42 @@ impl<T, F: FnOnce() -> T> LazyLock<T, F> { LazyLock { once: Once::new(), data: UnsafeCell::new(Data { f: ManuallyDrop::new(f) }) } } + /// Consumes this `LazyLock` returning the stored value. + /// + /// Returns `Ok(value)` if `Lazy` is initialized and `Err(f)` otherwise. + /// + /// # Examples + /// + /// ``` + /// #![feature(lazy_cell)] + /// #![feature(lazy_cell_consume)] + /// + /// use std::sync::LazyLock; + /// + /// let hello = "Hello, World!".to_string(); + /// + /// let lazy = LazyLock::new(|| hello.to_uppercase()); + /// + /// assert_eq!(&*lazy, "HELLO, WORLD!"); + /// assert_eq!(LazyLock::into_inner(lazy).ok(), Some("HELLO, WORLD!".to_string())); + /// ``` + #[unstable(feature = "lazy_cell_consume", issue = "109736")] + pub fn into_inner(mut this: Self) -> Result<T, F> { + let state = this.once.state(); + match state { + ExclusiveState::Poisoned => panic!("LazyLock instance has previously been poisoned"), + state => { + let this = ManuallyDrop::new(this); + let data = unsafe { ptr::read(&this.data) }.into_inner(); + match state { + ExclusiveState::Incomplete => Err(ManuallyDrop::into_inner(unsafe { data.f })), + ExclusiveState::Complete => Ok(ManuallyDrop::into_inner(unsafe { data.value })), + ExclusiveState::Poisoned => unreachable!(), + } + } + } + } + /// Forces the evaluation of this lazy value and /// returns a reference to result. This is equivalent /// to the `Deref` impl, but is explicit. diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index f95a97518c5..dd1851e29a9 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -139,6 +139,10 @@ v("musl-root-mips64", "target.mips64-unknown-linux-muslabi64.musl-root", "mips64-unknown-linux-muslabi64 install directory") v("musl-root-mips64el", "target.mips64el-unknown-linux-muslabi64.musl-root", "mips64el-unknown-linux-muslabi64 install directory") +v("musl-root-riscv32gc", "target.riscv32gc-unknown-linux-musl.musl-root", + "riscv32gc-unknown-linux-musl install directory") +v("musl-root-riscv64gc", "target.riscv64gc-unknown-linux-musl.musl-root", + "riscv64gc-unknown-linux-musl install directory") v("qemu-armhf-rootfs", "target.arm-unknown-linux-gnueabihf.qemu-rootfs", "rootfs in qemu testing, you probably don't want to use this") v("qemu-aarch64-rootfs", "target.aarch64-unknown-linux-gnu.qemu-rootfs", diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14-stage1/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14-stage1/Dockerfile index 21dcf29b4a9..d45ef0a7d07 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14-stage1/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14-stage1/Dockerfile @@ -32,6 +32,10 @@ RUN sh /scripts/sccache.sh # LLVM, rather than the typical src/llvm-project LLVM. ENV NO_DOWNLOAD_CI_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/docker/host-x86_64/x86_64-gnu-llvm-14/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/Dockerfile index cfb638e8b07..1f28b939778 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-14/Dockerfile @@ -38,6 +38,10 @@ RUN sh /scripts/sccache.sh # LLVM, rather than the typical src/llvm-project LLVM. ENV NO_DOWNLOAD_CI_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/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile index c471843b853..960683b92bd 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile @@ -38,6 +38,10 @@ RUN sh /scripts/sccache.sh # LLVM, rather than the typical src/llvm-project LLVM. ENV NO_DOWNLOAD_CI_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/run.sh b/src/ci/run.sh index 3056d9fc054..966af3abc6f 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -143,7 +143,11 @@ if [ "$RUST_RELEASE_CHANNEL" = "nightly" ] || [ "$DIST_REQUIRE_ALL_TOOLS" = "" ] RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-missing-tools" fi -export COMPILETEST_NEEDS_ALL_LLVM_COMPONENTS=1 +# 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 # Print the date from the local machine and the date from an external source to # check for clock drifts. An HTTP URL is used instead of HTTPS since on Azure diff --git a/src/doc/book b/src/doc/book -Subproject c06006157b14b3d47b5c716fc392b77f3b2e21c +Subproject 8fa6b854d515506d825390fe0d817f5ef0c8935 diff --git a/src/doc/embedded-book b/src/doc/embedded-book -Subproject 701d1551429da4cb609082c0ac99df569e33671 +Subproject 897fcf566f16bf87bf37199bdddec1801fd0053 diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide -Subproject 6337ed17fb8dcd918d78b7d97d213e923530337 +Subproject 2a5eb92197e9cf8fe91164dcbf4f9b88c0d7e73 diff --git a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md index 1f52ab75010..1874baa0c38 100644 --- a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md +++ b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md @@ -17,6 +17,7 @@ This feature tracks `asm!` and `global_asm!` support for the following architect - AVR - MSP430 - M68k +- LoongArch ## Register classes @@ -45,6 +46,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | M68k | `reg` | `d[0-7]`, `a[0-7]` | `r` | | M68k | `reg_data` | `d[0-7]` | `d` | | M68k | `reg_addr` | `a[0-3]` | `a` | +| LoongArch | `reg` | `$r1`, `$r[4-20]`, `$r[23,30]` | `r` | +| LoongArch | `freg` | `$f[0-31]` | `f` | > **Notes**: > - NVPTX doesn't have a fixed register set, so named registers are not supported. @@ -76,6 +79,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | MSP430 | `reg` | None | `i8`, `i16` | | M68k | `reg`, `reg_addr` | None | `i16`, `i32` | | M68k | `reg_data` | None | `i8`, `i16`, `i32` | +| LoongArch64 | `reg` | None | `i8`, `i16`, `i32`, `i64`, `f32`, `f64` | +| LoongArch64 | `freg` | None | `f32`, `f64` | ## Register aliases @@ -97,6 +102,10 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | M68k | `a5` | `bp` | | M68k | `a6` | `fp` | | M68k | `a7` | `sp`, `usp`, `ssp`, `isp` | +| LoongArch | `$r0` | `zero` | +| LoongArch | `$r2` | `tp` | +| LoongArch | `$r3` | `sp` | +| LoongArch | `$r22` | `fp` | > **Notes**: > - TI does not mandate a frame pointer for MSP430, but toolchains are allowed @@ -107,7 +116,7 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | Architecture | Unsupported register | Reason | | ------------ | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | All | `sp` | The stack pointer must be restored to its original value at the end of an asm code block. | -| All | `fr` (Hexagon), `$fp` (MIPS), `Y` (AVR), `r4` (MSP430), `a6` (M68k) | The frame pointer cannot be used as an input or output. | +| All | `fr` (Hexagon), `$fp` (MIPS), `Y` (AVR), `r4` (MSP430), `a6` (M68k), `$fp` (LoongArch) | The frame pointer cannot be used as an input or output. | | All | `r19` (Hexagon) | This is used internally by LLVM as a "base pointer" for functions with complex stack frames. | | MIPS | `$0` or `$zero` | This is a constant zero register which can't be modified. | | MIPS | `$1` or `$at` | Reserved for assembler. | @@ -118,6 +127,10 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | AVR | `r0`, `r1`, `r1r0` | Due to an issue in LLVM, the `r0` and `r1` registers cannot be used as inputs or outputs. If modified, they must be restored to their original values before the end of the block. | |MSP430 | `r0`, `r2`, `r3` | These are the program counter, status register, and constant generator respectively. Neither the status register nor constant generator can be written to. | | M68k | `a4`, `a5` | Used internally by LLVM for the base pointer and global base pointer. | +| LoongArch | `$r0` or `$zero` | This is a constant zero register which can't be modified. | +| LoongArch | `$r2` or `$tp` | This is reserved for TLS. | +| LoongArch | `$r21` | This is reserved by the ABI. | +| LoongArch | `$r31` or `$s8` | This is used internally by LLVM. | ## Template modifiers @@ -132,6 +145,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | PowerPC | `reg` | None | `0` | None | | PowerPC | `reg_nonzero` | None | `3` | `b` | | PowerPC | `freg` | None | `0` | None | +| LoongArch | `reg` | None | `$r2` | None | +| LoongArch | `freg` | None | `$f0` | None | # Flags covered by `preserves_flags` diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 04379c2bca9..c992a5388d1 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -422,8 +422,8 @@ fn clean_projection<'tcx>( let bounds = cx .tcx .explicit_item_bounds(ty.skip_binder().def_id) - .iter() - .map(|(bound, _)| EarlyBinder(*bound).subst(cx.tcx, ty.skip_binder().substs)) + .subst_iter_copied(cx.tcx, ty.skip_binder().substs) + .map(|(pred, _)| pred) .collect::<Vec<_>>(); return clean_middle_opaque_bounds(cx, bounds); } @@ -1315,10 +1315,11 @@ pub(crate) fn clean_middle_assoc_item<'tcx>( } if let ty::TraitContainer = assoc_item.container { - let bounds = tcx.explicit_item_bounds(assoc_item.def_id); + let bounds = + tcx.explicit_item_bounds(assoc_item.def_id).subst_identity_iter_copied(); let predicates = tcx.explicit_predicates_of(assoc_item.def_id).predicates; let predicates = - tcx.arena.alloc_from_iter(bounds.into_iter().chain(predicates).copied()); + tcx.arena.alloc_from_iter(bounds.chain(predicates.iter().copied())); let mut generics = clean_ty_generics( cx, tcx.generics_of(assoc_item.def_id), @@ -1845,8 +1846,8 @@ pub(crate) fn clean_middle_ty<'tcx>( let bounds = cx .tcx .explicit_item_bounds(def_id) - .iter() - .map(|(bound, _)| EarlyBinder(*bound).subst(cx.tcx, substs)) + .subst_iter_copied(cx.tcx, substs) + .map(|(bound, _)| bound) .collect::<Vec<_>>(); clean_middle_opaque_bounds(cx, bounds) } diff --git a/src/tools/cargo b/src/tools/cargo -Subproject de80432f04da61d98dcbbc1572598071718ccfd +Subproject 9e586fbd8b931494067144623b76c37d213b1ab diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs index ed0bd58c770..ff838c2d56e 100644 --- a/src/tools/clippy/clippy_lints/src/future_not_send.rs +++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs @@ -4,7 +4,7 @@ use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::{self, AliasTy, Clause, EarlyBinder, PredicateKind}; +use rustc_middle::ty::{self, AliasTy, Clause, PredicateKind}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, Span}; @@ -66,8 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { if let ty::Alias(ty::Opaque, AliasTy { def_id, substs, .. }) = *ret_ty.kind() { let preds = cx.tcx.explicit_item_bounds(def_id); let mut is_future = false; - for &(p, _span) in preds { - let p = EarlyBinder(p).subst(cx.tcx, substs); + for (p, _span) in preds.subst_iter_copied(cx.tcx, substs) { if let Some(trait_pred) = p.to_opt_poly_trait_pred() { if Some(trait_pred.skip_binder().trait_ref.def_id) == cx.tcx.lang_items().future_trait() { is_future = true; diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index 8b996c18816..cb700126c2b 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -90,7 +90,7 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<' return false; } - for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) { + for (predicate, _span) in cx.tcx.explicit_item_bounds(def_id).subst_identity_iter_copied() { match predicate.kind().skip_binder() { // For `impl Trait<U>`, it will register a predicate of `T: Trait<U>`, so we go through // and check substituions to find `U`. @@ -267,7 +267,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { }, ty::Tuple(substs) => substs.iter().any(|ty| is_must_use_ty(cx, ty)), ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => { - for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) { + for (predicate, _) in cx.tcx.explicit_item_bounds(def_id).skip_binder() { if let ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) = predicate.kind().skip_binder() { if cx.tcx.has_attr(trait_predicate.trait_ref.def_id, sym::must_use) { return true; @@ -743,7 +743,7 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: AliasTy<'tcx>) -> Option for (pred, _) in cx .tcx - .bound_explicit_item_bounds(ty.def_id) + .explicit_item_bounds(ty.def_id) .subst_iter_copied(cx.tcx, ty.substs) { match pred.kind().skip_binder() { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/builtin_attr.rs b/src/tools/rust-analyzer/crates/hir-def/src/builtin_attr.rs index e3e5fac98c0..f7c1e683d0d 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/builtin_attr.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/builtin_attr.rs @@ -382,6 +382,10 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_attr!(rustc_allocator, Normal, template!(Word), WarnFollowing, IMPL_DETAIL), rustc_attr!(rustc_nounwind, Normal, template!(Word), WarnFollowing, IMPL_DETAIL), gated!( + alloc_error_handler, Normal, template!(Word), WarnFollowing, + experimental!(alloc_error_handler) + ), + gated!( default_lib_allocator, Normal, template!(Word), WarnFollowing, allocator_internals, experimental!(default_lib_allocator), ), diff --git a/tests/assembly/asm/loongarch-type.rs b/tests/assembly/asm/loongarch-type.rs new file mode 100644 index 00000000000..4e296f3ade5 --- /dev/null +++ b/tests/assembly/asm/loongarch-type.rs @@ -0,0 +1,196 @@ +// min-llvm-version: 16.0 +// assembly-output: emit-asm +// compile-flags: --target loongarch64-unknown-linux-gnu +// needs-llvm-components: loongarch + +#![feature(no_core, lang_items, rustc_attrs, asm_experimental_arch)] +#![crate_type = "rlib"] +#![no_core] +#![allow(asm_sub_register, non_camel_case_types)] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! concat { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! stringify { + () => {}; +} + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +type ptr = *const i32; + +impl Copy for i8 {} +impl Copy for i16 {} +impl Copy for i32 {} +impl Copy for i64 {} +impl Copy for f32 {} +impl Copy for f64 {} +impl Copy for ptr {} +extern "C" { + fn extern_func(); + static extern_static: u8; +} + +// Hack to avoid function merging +extern "Rust" { + fn dont_merge(s: &str); +} + +// CHECK-LABEL: sym_fn: +// CHECK: #APP +// CHECK: pcalau12i $t0, %got_pc_hi20(extern_func) +// CHECK: ld.d $t0, $t0, %got_pc_lo12(extern_func) +// CHECK: #NO_APP +#[no_mangle] +pub unsafe fn sym_fn() { + asm!("la.got $r12, {}", sym extern_func); +} + +// CHECK-LABEL: sym_static: +// CHECK: #APP +// CHECK: pcalau12i $t0, %got_pc_hi20(extern_static) +// CHECK: ld.d $t0, $t0, %got_pc_lo12(extern_static) +// CHECK: #NO_APP +#[no_mangle] +pub unsafe fn sym_static() { + asm!("la.got $r12, {}", sym extern_static); +} + +macro_rules! check { ($func:ident, $ty:ty, $class:ident, $mov:literal) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + dont_merge(stringify!($func)); + + let y; + asm!(concat!($mov," {}, {}"), out($class) y, in($class) x); + y + } +};} + +macro_rules! check_reg { ($func:ident, $ty:ty, $reg:tt, $mov:literal) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + dont_merge(stringify!($func)); + + let y; + asm!(concat!($mov, " ", $reg, ", ", $reg), lateout($reg) y, in($reg) x); + y + } +};} + +// CHECK-LABEL: reg_i8: +// CHECK: #APP +// CHECK: move ${{[a-z0-9]+}}, ${{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_i8, i8, reg, "move"); + +// CHECK-LABEL: reg_i16: +// CHECK: #APP +// CHECK: move ${{[a-z0-9]+}}, ${{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_i16, i16, reg, "move"); + +// CHECK-LABEL: reg_i32: +// CHECK: #APP +// CHECK: move ${{[a-z0-9]+}}, ${{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_i32, i32, reg, "move"); + +// CHECK-LABEL: reg_f32: +// CHECK: #APP +// CHECK: move ${{[a-z0-9]+}}, ${{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_f32, f32, reg, "move"); + +// CHECK-LABEL: reg_i64: +// CHECK: #APP +// CHECK: move ${{[a-z0-9]+}}, ${{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_i64, i64, reg, "move"); + +// CHECK-LABEL: reg_f64: +// CHECK: #APP +// CHECK: move ${{[a-z0-9]+}}, ${{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_f64, f64, reg, "move"); + +// CHECK-LABEL: reg_ptr: +// CHECK: #APP +// CHECK: move ${{[a-z0-9]+}}, ${{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_ptr, ptr, reg, "move"); + +// CHECK-LABEL: freg_f32: +// CHECK: #APP +// CHECK: fmov.s $f{{[a-z0-9]+}}, $f{{[a-z0-9]+}} +// CHECK: #NO_APP +check!(freg_f32, f32, freg, "fmov.s"); + +// CHECK-LABEL: freg_f64: +// CHECK: #APP +// CHECK: fmov.d $f{{[a-z0-9]+}}, $f{{[a-z0-9]+}} +// CHECK: #NO_APP +check!(freg_f64, f64, freg, "fmov.d"); + +// CHECK-LABEL: r4_i8: +// CHECK: #APP +// CHECK: move $a0, $a0 +// CHECK: #NO_APP +check_reg!(r4_i8, i8, "$r4", "move"); + +// CHECK-LABEL: r4_i16: +// CHECK: #APP +// CHECK: move $a0, $a0 +// CHECK: #NO_APP +check_reg!(r4_i16, i16, "$r4", "move"); + +// CHECK-LABEL: r4_i32: +// CHECK: #APP +// CHECK: move $a0, $a0 +// CHECK: #NO_APP +check_reg!(r4_i32, i32, "$r4", "move"); + +// CHECK-LABEL: r4_f32: +// CHECK: #APP +// CHECK: move $a0, $a0 +// CHECK: #NO_APP +check_reg!(r4_f32, f32, "$r4", "move"); + +// CHECK-LABEL: r4_i64: +// CHECK: #APP +// CHECK: move $a0, $a0 +// CHECK: #NO_APP +check_reg!(r4_i64, i64, "$r4", "move"); + +// CHECK-LABEL: r4_f64: +// CHECK: #APP +// CHECK: move $a0, $a0 +// CHECK: #NO_APP +check_reg!(r4_f64, f64, "$r4", "move"); + +// CHECK-LABEL: r4_ptr: +// CHECK: #APP +// CHECK: move $a0, $a0 +// CHECK: #NO_APP +check_reg!(r4_ptr, ptr, "$r4", "move"); + +// CHECK-LABEL: f0_f32: +// CHECK: #APP +// CHECK: fmov.s $f{{[a-z0-9]+}}, $f{{[a-z0-9]+}} +// CHECK: #NO_APP +check_reg!(f0_f32, f32, "$f0", "fmov.s"); + +// CHECK-LABEL: f0_f64: +// CHECK: #APP +// CHECK: fmov.d $f{{[a-z0-9]+}}, $f{{[a-z0-9]+}} +// CHECK: #NO_APP +check_reg!(f0_f64, f64, "$f0", "fmov.d"); diff --git a/tests/debuginfo/pretty-std.rs b/tests/debuginfo/pretty-std.rs index 7bb2810c2b2..c7df7dc3cb3 100644 --- a/tests/debuginfo/pretty-std.rs +++ b/tests/debuginfo/pretty-std.rs @@ -130,8 +130,8 @@ // cdb-check: [+0x000] __0 : "IAMA optional string!" [Type: alloc::string::String] // cdb-command: dx linkedlist -// cdb-check:linkedlist : { len=0x2 } [Type: alloc::collections::linked_list::LinkedList<i32>] -// cdb-check: [<Raw View>] [Type: alloc::collections::linked_list::LinkedList<i32>] +// cdb-check:linkedlist : { len=0x2 } [Type: alloc::collections::linked_list::LinkedList<i32,alloc::alloc::Global>] +// cdb-check: [<Raw View>] [Type: alloc::collections::linked_list::LinkedList<i32,alloc::alloc::Global>] // cdb-check: [0x0] : 128 [Type: int] // cdb-check: [0x1] : 42 [Type: int] diff --git a/tests/mir-opt/nll/named_lifetimes_basic.use_x.nll.0.mir b/tests/mir-opt/nll/named_lifetimes_basic.use_x.nll.0.mir index 6cd6d8b7795..be5baf6ee39 100644 --- a/tests/mir-opt/nll/named_lifetimes_basic.use_x.nll.0.mir +++ b/tests/mir-opt/nll/named_lifetimes_basic.use_x.nll.0.mir @@ -1,39 +1,39 @@ // MIR for `use_x` 0 nll | Free Region Mapping -| '_#0r | Global | ['_#2r, '_#1r, '_#0r, '_#4r, '_#3r] -| '_#1r | Local | ['_#1r, '_#4r] -| '_#2r | Local | ['_#2r, '_#1r, '_#4r] -| '_#3r | Local | ['_#4r, '_#3r] -| '_#4r | Local | ['_#4r] +| '?0 | Global | ['?2, '?1, '?0, '?4, '?3] +| '?1 | Local | ['?1, '?4] +| '?2 | Local | ['?2, '?1, '?4] +| '?3 | Local | ['?4, '?3] +| '?4 | Local | ['?4] | | Inferred Region Values -| '_#0r | U0 | {bb0[0..=1], '_#0r, '_#1r, '_#2r, '_#3r, '_#4r} -| '_#1r | U0 | {bb0[0..=1], '_#1r} -| '_#2r | U0 | {bb0[0..=1], '_#2r} -| '_#3r | U0 | {bb0[0..=1], '_#3r} -| '_#4r | U0 | {bb0[0..=1], '_#4r} -| '_#5r | U0 | {bb0[0..=1], '_#1r} -| '_#6r | U0 | {bb0[0..=1], '_#2r} -| '_#7r | U0 | {bb0[0..=1], '_#1r} -| '_#8r | U0 | {bb0[0..=1], '_#3r} +| '?0 | U0 | {bb0[0..=1], '?0, '?1, '?2, '?3, '?4} +| '?1 | U0 | {bb0[0..=1], '?1} +| '?2 | U0 | {bb0[0..=1], '?2} +| '?3 | U0 | {bb0[0..=1], '?3} +| '?4 | U0 | {bb0[0..=1], '?4} +| '?5 | U0 | {bb0[0..=1], '?1} +| '?6 | U0 | {bb0[0..=1], '?2} +| '?7 | U0 | {bb0[0..=1], '?1} +| '?8 | U0 | {bb0[0..=1], '?3} | | Inference Constraints -| '_#0r live at {bb0[0..=1]} -| '_#1r live at {bb0[0..=1]} -| '_#2r live at {bb0[0..=1]} -| '_#3r live at {bb0[0..=1]} -| '_#4r live at {bb0[0..=1]} -| '_#1r: '_#5r due to BoringNoLocation at All($DIR/named_lifetimes_basic.rs:12:26: 12:27) ($DIR/named_lifetimes_basic.rs:12:26: 12:27 (#0) -| '_#1r: '_#7r due to BoringNoLocation at All($DIR/named_lifetimes_basic.rs:12:54: 12:55) ($DIR/named_lifetimes_basic.rs:12:54: 12:55 (#0) -| '_#2r: '_#6r due to BoringNoLocation at All($DIR/named_lifetimes_basic.rs:12:42: 12:43) ($DIR/named_lifetimes_basic.rs:12:42: 12:43 (#0) -| '_#3r: '_#8r due to BoringNoLocation at All($DIR/named_lifetimes_basic.rs:12:66: 12:67) ($DIR/named_lifetimes_basic.rs:12:66: 12:67 (#0) -| '_#5r: '_#1r due to BoringNoLocation at All($DIR/named_lifetimes_basic.rs:12:26: 12:27) ($DIR/named_lifetimes_basic.rs:12:26: 12:27 (#0) -| '_#6r: '_#2r due to BoringNoLocation at All($DIR/named_lifetimes_basic.rs:12:42: 12:43) ($DIR/named_lifetimes_basic.rs:12:42: 12:43 (#0) -| '_#7r: '_#1r due to BoringNoLocation at All($DIR/named_lifetimes_basic.rs:12:54: 12:55) ($DIR/named_lifetimes_basic.rs:12:54: 12:55 (#0) -| '_#8r: '_#3r due to BoringNoLocation at All($DIR/named_lifetimes_basic.rs:12:66: 12:67) ($DIR/named_lifetimes_basic.rs:12:66: 12:67 (#0) +| '?0 live at {bb0[0..=1]} +| '?1 live at {bb0[0..=1]} +| '?2 live at {bb0[0..=1]} +| '?3 live at {bb0[0..=1]} +| '?4 live at {bb0[0..=1]} +| '?1: '?5 due to BoringNoLocation at All($DIR/named_lifetimes_basic.rs:12:26: 12:27) ($DIR/named_lifetimes_basic.rs:12:26: 12:27 (#0) +| '?1: '?7 due to BoringNoLocation at All($DIR/named_lifetimes_basic.rs:12:54: 12:55) ($DIR/named_lifetimes_basic.rs:12:54: 12:55 (#0) +| '?2: '?6 due to BoringNoLocation at All($DIR/named_lifetimes_basic.rs:12:42: 12:43) ($DIR/named_lifetimes_basic.rs:12:42: 12:43 (#0) +| '?3: '?8 due to BoringNoLocation at All($DIR/named_lifetimes_basic.rs:12:66: 12:67) ($DIR/named_lifetimes_basic.rs:12:66: 12:67 (#0) +| '?5: '?1 due to BoringNoLocation at All($DIR/named_lifetimes_basic.rs:12:26: 12:27) ($DIR/named_lifetimes_basic.rs:12:26: 12:27 (#0) +| '?6: '?2 due to BoringNoLocation at All($DIR/named_lifetimes_basic.rs:12:42: 12:43) ($DIR/named_lifetimes_basic.rs:12:42: 12:43 (#0) +| '?7: '?1 due to BoringNoLocation at All($DIR/named_lifetimes_basic.rs:12:54: 12:55) ($DIR/named_lifetimes_basic.rs:12:54: 12:55 (#0) +| '?8: '?3 due to BoringNoLocation at All($DIR/named_lifetimes_basic.rs:12:66: 12:67) ($DIR/named_lifetimes_basic.rs:12:66: 12:67 (#0) | -fn use_x(_1: &'_#5r mut i32, _2: &'_#6r u32, _3: &'_#7r u32, _4: &'_#8r u32) -> bool { +fn use_x(_1: &'?5 mut i32, _2: &'?6 u32, _3: &'?7 u32, _4: &'?8 u32) -> bool { debug w => _1; // in scope 0 at $DIR/named_lifetimes_basic.rs:+0:26: +0:27 debug x => _2; // in scope 0 at $DIR/named_lifetimes_basic.rs:+0:42: +0:43 debug y => _3; // in scope 0 at $DIR/named_lifetimes_basic.rs:+0:54: +0:55 diff --git a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir index 798e45df8ca..71bdfcc5c49 100644 --- a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir +++ b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir @@ -1,24 +1,24 @@ // MIR for `main` 0 nll | Free Region Mapping -| '_#0r | Global | ['_#0r, '_#1r] -| '_#1r | Local | ['_#1r] +| '?0 | Global | ['?0, '?1] +| '?1 | Local | ['?1] | | Inferred Region Values -| '_#0r | U0 | {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0], '_#0r, '_#1r} -| '_#1r | U0 | {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0], '_#1r} -| '_#2r | U0 | {bb1[0..=7], bb2[0..=2]} -| '_#3r | U0 | {bb1[1..=7], bb2[0..=2]} -| '_#4r | U0 | {bb1[4..=7], bb2[0..=2]} +| '?0 | U0 | {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0], '?0, '?1} +| '?1 | U0 | {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0], '?1} +| '?2 | U0 | {bb1[0..=7], bb2[0..=2]} +| '?3 | U0 | {bb1[1..=7], bb2[0..=2]} +| '?4 | U0 | {bb1[4..=7], bb2[0..=2]} | | Inference Constraints -| '_#0r live at {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0]} -| '_#1r live at {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0]} -| '_#2r live at {bb1[0]} -| '_#3r live at {bb1[1..=3]} -| '_#4r live at {bb1[4..=7], bb2[0..=2]} -| '_#2r: '_#3r due to Assignment at Single(bb1[0]) ($DIR/region_subtyping_basic.rs:18:13: 18:18 (#0) -| '_#3r: '_#4r due to Assignment at Single(bb1[3]) ($DIR/region_subtyping_basic.rs:19:13: 19:14 (#0) +| '?0 live at {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0]} +| '?1 live at {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0]} +| '?2 live at {bb1[0]} +| '?3 live at {bb1[1..=3]} +| '?4 live at {bb1[4..=7], bb2[0..=2]} +| '?2: '?3 due to Assignment at Single(bb1[0]) ($DIR/region_subtyping_basic.rs:18:13: 18:18 (#0) +| '?3: '?4 due to Assignment at Single(bb1[3]) ($DIR/region_subtyping_basic.rs:19:13: 19:14 (#0) | fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/region_subtyping_basic.rs:+0:11: +0:11 @@ -32,10 +32,10 @@ fn main() -> () { let _10: bool; // in scope 0 at $DIR/region_subtyping_basic.rs:+7:9: +7:18 scope 1 { debug v => _1; // in scope 1 at $DIR/region_subtyping_basic.rs:+1:9: +1:14 - let _2: &'_#3r usize; // in scope 1 at $DIR/region_subtyping_basic.rs:+2:9: +2:10 + let _2: &'?3 usize; // in scope 1 at $DIR/region_subtyping_basic.rs:+2:9: +2:10 scope 2 { debug p => _2; // in scope 2 at $DIR/region_subtyping_basic.rs:+2:9: +2:10 - let _6: &'_#4r usize; // in scope 2 at $DIR/region_subtyping_basic.rs:+3:9: +3:10 + let _6: &'?4 usize; // in scope 2 at $DIR/region_subtyping_basic.rs:+3:9: +3:10 scope 3 { debug q => _6; // in scope 3 at $DIR/region_subtyping_basic.rs:+3:9: +3:10 } @@ -55,7 +55,7 @@ fn main() -> () { } bb1: { - _2 = &'_#2r _1[_3]; // bb1[0]: scope 1 at $DIR/region_subtyping_basic.rs:+2:13: +2:18 + _2 = &'?2 _1[_3]; // bb1[0]: scope 1 at $DIR/region_subtyping_basic.rs:+2:13: +2:18 FakeRead(ForLet(None), _2); // bb1[1]: scope 1 at $DIR/region_subtyping_basic.rs:+2:9: +2:10 StorageLive(_6); // bb1[2]: scope 2 at $DIR/region_subtyping_basic.rs:+3:9: +3:10 _6 = _2; // bb1[3]: scope 2 at $DIR/region_subtyping_basic.rs:+3:13: +3:14 diff --git a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir index 4767bfc76ed..9fa8609b751 100644 --- a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir +++ b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir @@ -1,24 +1,24 @@ // MIR for `main` 0 nll | Free Region Mapping -| '_#0r | Global | ['_#0r, '_#1r] -| '_#1r | Local | ['_#1r] +| '?0 | Global | ['?0, '?1] +| '?1 | Local | ['?1] | | Inferred Region Values -| '_#0r | U0 | {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0], '_#0r, '_#1r} -| '_#1r | U0 | {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0], '_#1r} -| '_#2r | U0 | {bb1[0..=7], bb2[0..=2]} -| '_#3r | U0 | {bb1[1..=7], bb2[0..=2]} -| '_#4r | U0 | {bb1[4..=7], bb2[0..=2]} +| '?0 | U0 | {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0], '?0, '?1} +| '?1 | U0 | {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0], '?1} +| '?2 | U0 | {bb1[0..=7], bb2[0..=2]} +| '?3 | U0 | {bb1[1..=7], bb2[0..=2]} +| '?4 | U0 | {bb1[4..=7], bb2[0..=2]} | | Inference Constraints -| '_#0r live at {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0]} -| '_#1r live at {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0]} -| '_#2r live at {bb1[0]} -| '_#3r live at {bb1[1..=3]} -| '_#4r live at {bb1[4..=7], bb2[0..=2]} -| '_#2r: '_#3r due to Assignment at Single(bb1[0]) ($DIR/region_subtyping_basic.rs:18:13: 18:18 (#0) -| '_#3r: '_#4r due to Assignment at Single(bb1[3]) ($DIR/region_subtyping_basic.rs:19:13: 19:14 (#0) +| '?0 live at {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0]} +| '?1 live at {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0]} +| '?2 live at {bb1[0]} +| '?3 live at {bb1[1..=3]} +| '?4 live at {bb1[4..=7], bb2[0..=2]} +| '?2: '?3 due to Assignment at Single(bb1[0]) ($DIR/region_subtyping_basic.rs:18:13: 18:18 (#0) +| '?3: '?4 due to Assignment at Single(bb1[3]) ($DIR/region_subtyping_basic.rs:19:13: 19:14 (#0) | fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/region_subtyping_basic.rs:+0:11: +0:11 @@ -32,10 +32,10 @@ fn main() -> () { let _10: bool; // in scope 0 at $DIR/region_subtyping_basic.rs:+7:9: +7:18 scope 1 { debug v => _1; // in scope 1 at $DIR/region_subtyping_basic.rs:+1:9: +1:14 - let _2: &'_#3r usize; // in scope 1 at $DIR/region_subtyping_basic.rs:+2:9: +2:10 + let _2: &'?3 usize; // in scope 1 at $DIR/region_subtyping_basic.rs:+2:9: +2:10 scope 2 { debug p => _2; // in scope 2 at $DIR/region_subtyping_basic.rs:+2:9: +2:10 - let _6: &'_#4r usize; // in scope 2 at $DIR/region_subtyping_basic.rs:+3:9: +3:10 + let _6: &'?4 usize; // in scope 2 at $DIR/region_subtyping_basic.rs:+3:9: +3:10 scope 3 { debug q => _6; // in scope 3 at $DIR/region_subtyping_basic.rs:+3:9: +3:10 } @@ -55,7 +55,7 @@ fn main() -> () { } bb1: { - _2 = &'_#2r _1[_3]; // bb1[0]: scope 1 at $DIR/region_subtyping_basic.rs:+2:13: +2:18 + _2 = &'?2 _1[_3]; // bb1[0]: scope 1 at $DIR/region_subtyping_basic.rs:+2:13: +2:18 FakeRead(ForLet(None), _2); // bb1[1]: scope 1 at $DIR/region_subtyping_basic.rs:+2:9: +2:10 StorageLive(_6); // bb1[2]: scope 2 at $DIR/region_subtyping_basic.rs:+3:9: +3:10 _6 = _2; // bb1[3]: scope 2 at $DIR/region_subtyping_basic.rs:+3:13: +3:14 diff --git a/tests/mir-opt/storage_ranges.main.nll.0.mir b/tests/mir-opt/storage_ranges.main.nll.0.mir index 8e10e70f192..5bb1a7bf0c9 100644 --- a/tests/mir-opt/storage_ranges.main.nll.0.mir +++ b/tests/mir-opt/storage_ranges.main.nll.0.mir @@ -1,21 +1,21 @@ // MIR for `main` 0 nll | Free Region Mapping -| '_#0r | Global | ['_#0r, '_#1r] -| '_#1r | Local | ['_#1r] +| '?0 | Global | ['?0, '?1] +| '?1 | Local | ['?1] | | Inferred Region Values -| '_#0r | U0 | {bb0[0..=22], '_#0r, '_#1r} -| '_#1r | U0 | {bb0[0..=22], '_#1r} -| '_#2r | U0 | {bb0[10..=11]} -| '_#3r | U0 | {bb0[11]} +| '?0 | U0 | {bb0[0..=22], '?0, '?1} +| '?1 | U0 | {bb0[0..=22], '?1} +| '?2 | U0 | {bb0[10..=11]} +| '?3 | U0 | {bb0[11]} | | Inference Constraints -| '_#0r live at {bb0[0..=22]} -| '_#1r live at {bb0[0..=22]} -| '_#2r live at {bb0[10]} -| '_#3r live at {bb0[11]} -| '_#2r: '_#3r due to Assignment at Single(bb0[10]) ($DIR/storage_ranges.rs:6:17: 6:25 (#0) +| '?0 live at {bb0[0..=22]} +| '?1 live at {bb0[0..=22]} +| '?2 live at {bb0[10]} +| '?3 live at {bb0[11]} +| '?2: '?3 due to Assignment at Single(bb0[10]) ($DIR/storage_ranges.rs:6:17: 6:25 (#0) | fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/storage_ranges.rs:+0:11: +0:11 diff --git a/tests/run-make/coverage-reports/expected_show_coverage.issue-84561.txt b/tests/run-make/coverage-reports/expected_show_coverage.issue-84561.txt index 9c3192c008c..4a60432c14c 100644 --- a/tests/run-make/coverage-reports/expected_show_coverage.issue-84561.txt +++ b/tests/run-make/coverage-reports/expected_show_coverage.issue-84561.txt @@ -136,10 +136,10 @@ 134| | 135| |impl std::fmt::Debug for Foo { 136| | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - 137| 9| write!(f, "try and succeed")?; + 137| 7| write!(f, "try and succeed")?; ^0 - 138| 9| Ok(()) - 139| 9| } + 138| 7| Ok(()) + 139| 7| } 140| |} 141| | 142| |static mut DEBUG_LEVEL_ENABLED: bool = false; diff --git a/tests/run-make/issue-51671/Makefile b/tests/run-make/issue-51671/Makefile index 00cf9134662..c9364536992 100644 --- a/tests/run-make/issue-51671/Makefile +++ b/tests/run-make/issue-51671/Makefile @@ -6,3 +6,4 @@ all: $(RUSTC) --emit=obj app.rs nm $(TMPDIR)/app.o | $(CGREP) rust_begin_unwind nm $(TMPDIR)/app.o | $(CGREP) rust_eh_personality + nm $(TMPDIR)/app.o | $(CGREP) __rg_oom diff --git a/tests/run-make/issue-51671/app.rs b/tests/run-make/issue-51671/app.rs index a9d3457bf90..e9dc1e9744f 100644 --- a/tests/run-make/issue-51671/app.rs +++ b/tests/run-make/issue-51671/app.rs @@ -1,5 +1,5 @@ #![crate_type = "bin"] -#![feature(lang_items)] +#![feature(lang_items, alloc_error_handler)] #![no_main] #![no_std] @@ -13,3 +13,8 @@ fn panic(_: &PanicInfo) -> ! { #[lang = "eh_personality"] fn eh() {} + +#[alloc_error_handler] +fn oom(_: Layout) -> ! { + loop {} +} diff --git a/tests/run-make/issue-69368/Makefile b/tests/run-make/issue-69368/Makefile new file mode 100644 index 00000000000..b1229d1b07f --- /dev/null +++ b/tests/run-make/issue-69368/Makefile @@ -0,0 +1,19 @@ +# ignore-cross-compile +include ../tools.mk + +# Test that previously triggered a linker failure with root cause +# similar to one found in the issue #69368. +# +# The crate that provides oom lang item is missing some other lang +# items. Necessary to prevent the use of start-group / end-group. +# +# The weak lang items are defined in a separate compilation units, +# so that linker could omit them if not used. +# +# The crates that need those weak lang items are dependencies of +# crates that provide them. + +all: + $(RUSTC) a.rs + $(RUSTC) b.rs + $(RUSTC) c.rs diff --git a/tests/run-make/issue-69368/a.rs b/tests/run-make/issue-69368/a.rs new file mode 100644 index 00000000000..a54f429550e --- /dev/null +++ b/tests/run-make/issue-69368/a.rs @@ -0,0 +1,26 @@ +#![crate_type = "rlib"] +#![feature(lang_items)] +#![feature(panic_unwind)] +#![no_std] + +extern crate panic_unwind; + +#[panic_handler] +pub fn panic_handler(_: &core::panic::PanicInfo) -> ! { + loop {} +} + +#[no_mangle] +extern "C" fn __rust_drop_panic() -> ! { + loop {} +} + +#[no_mangle] +extern "C" fn __rust_foreign_exception() -> ! { + loop {} +} + +#[lang = "eh_personality"] +fn eh_personality() { + loop {} +} diff --git a/tests/run-make/issue-69368/b.rs b/tests/run-make/issue-69368/b.rs new file mode 100644 index 00000000000..4d6af026656 --- /dev/null +++ b/tests/run-make/issue-69368/b.rs @@ -0,0 +1,8 @@ +#![crate_type = "rlib"] +#![feature(alloc_error_handler)] +#![no_std] + +#[alloc_error_handler] +pub fn error_handler(_: core::alloc::Layout) -> ! { + panic!(); +} diff --git a/tests/run-make/issue-69368/c.rs b/tests/run-make/issue-69368/c.rs new file mode 100644 index 00000000000..729c4249a05 --- /dev/null +++ b/tests/run-make/issue-69368/c.rs @@ -0,0 +1,34 @@ +#![crate_type = "bin"] +#![feature(start)] +#![no_std] + +extern crate alloc; +extern crate a; +extern crate b; + +use alloc::vec::Vec; +use core::alloc::*; + +struct Allocator; + +unsafe impl GlobalAlloc for Allocator { + unsafe fn alloc(&self, _: Layout) -> *mut u8 { + loop {} + } + + unsafe fn dealloc(&self, _: *mut u8, _: Layout) { + loop {} + } +} + +#[global_allocator] +static ALLOCATOR: Allocator = Allocator; + +#[start] +fn main(argc: isize, _argv: *const *const u8) -> isize { + let mut v = Vec::new(); + for i in 0..argc { + v.push(i); + } + v.iter().sum() +} diff --git a/tests/run-make/wasm-symbols-not-exported/bar.rs b/tests/run-make/wasm-symbols-not-exported/bar.rs index eb768446b4b..6ffbd3ec690 100644 --- a/tests/run-make/wasm-symbols-not-exported/bar.rs +++ b/tests/run-make/wasm-symbols-not-exported/bar.rs @@ -1,4 +1,4 @@ -#![feature(panic_handler)] +#![feature(panic_handler, alloc_error_handler)] #![crate_type = "cdylib"] #![no_std] @@ -24,6 +24,11 @@ pub extern fn foo(a: u32) -> u32 { a * 2 } +#[alloc_error_handler] +fn a(_: core::alloc::Layout) -> ! { + loop {} +} + #[panic_handler] fn b(_: &core::panic::PanicInfo) -> ! { loop {} diff --git a/tests/ui/alloc-error/alloc-error-handler-bad-signature-1.rs b/tests/ui/alloc-error/alloc-error-handler-bad-signature-1.rs new file mode 100644 index 00000000000..cd06423e3a5 --- /dev/null +++ b/tests/ui/alloc-error/alloc-error-handler-bad-signature-1.rs @@ -0,0 +1,18 @@ +// compile-flags:-C panic=abort + +#![feature(alloc_error_handler)] +#![no_std] +#![no_main] + +use core::alloc::Layout; + +#[alloc_error_handler] +fn oom( + info: &Layout, //~^ ERROR mismatched types +) -> () //~^^ ERROR mismatched types +{ + loop {} +} + +#[panic_handler] +fn panic(_: &core::panic::PanicInfo) -> ! { loop {} } diff --git a/tests/ui/alloc-error/alloc-error-handler-bad-signature-1.stderr b/tests/ui/alloc-error/alloc-error-handler-bad-signature-1.stderr new file mode 100644 index 00000000000..de92841d7f1 --- /dev/null +++ b/tests/ui/alloc-error/alloc-error-handler-bad-signature-1.stderr @@ -0,0 +1,44 @@ +error[E0308]: mismatched types + --> $DIR/alloc-error-handler-bad-signature-1.rs:10:1 + | +LL | #[alloc_error_handler] + | ---------------------- in this procedural macro expansion +LL | // fn oom( +LL | || info: &Layout, +LL | || ) -> () + | ||_______- arguments to this function are incorrect +LL | | { +LL | | loop {} +LL | | } + | |__^ expected `&Layout`, found `Layout` + | +note: function defined here + --> $DIR/alloc-error-handler-bad-signature-1.rs:10:4 + | +LL | fn oom( + | ^^^ +LL | info: &Layout, + | ------------- + = note: this error originates in the attribute macro `alloc_error_handler` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> $DIR/alloc-error-handler-bad-signature-1.rs:10:1 + | +LL | #[alloc_error_handler] + | ---------------------- in this procedural macro expansion +LL | // fn oom( +LL | || info: &Layout, +LL | || ) -> () + | ||_______^ expected `!`, found `()` +LL | | { +LL | | loop {} +LL | | } + | |__- expected `!` because of return type + | + = note: expected type `!` + found unit type `()` + = note: this error originates in the attribute macro `alloc_error_handler` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/alloc-error/alloc-error-handler-bad-signature-2.rs b/tests/ui/alloc-error/alloc-error-handler-bad-signature-2.rs new file mode 100644 index 00000000000..4f76257fc72 --- /dev/null +++ b/tests/ui/alloc-error/alloc-error-handler-bad-signature-2.rs @@ -0,0 +1,17 @@ +// compile-flags:-C panic=abort + +#![feature(alloc_error_handler)] +#![no_std] +#![no_main] + +struct Layout; + +#[alloc_error_handler] +fn oom( + info: Layout, //~^ ERROR mismatched types +) { //~^^ ERROR mismatched types + loop {} +} + +#[panic_handler] +fn panic(_: &core::panic::PanicInfo) -> ! { loop {} } diff --git a/tests/ui/alloc-error/alloc-error-handler-bad-signature-2.stderr b/tests/ui/alloc-error/alloc-error-handler-bad-signature-2.stderr new file mode 100644 index 00000000000..7a495380f2b --- /dev/null +++ b/tests/ui/alloc-error/alloc-error-handler-bad-signature-2.stderr @@ -0,0 +1,50 @@ +error[E0308]: mismatched types + --> $DIR/alloc-error-handler-bad-signature-2.rs:10:1 + | +LL | #[alloc_error_handler] + | ---------------------- in this procedural macro expansion +LL | // fn oom( +LL | || info: Layout, +LL | || ) { + | ||_- arguments to this function are incorrect +LL | | loop {} +LL | | } + | |__^ expected `Layout`, found `core::alloc::Layout` + | + = note: `core::alloc::Layout` and `Layout` have similar names, but are actually distinct types +note: `core::alloc::Layout` is defined in crate `core` + --> $SRC_DIR/core/src/alloc/layout.rs:LL:COL +note: `Layout` is defined in the current crate + --> $DIR/alloc-error-handler-bad-signature-2.rs:7:1 + | +LL | struct Layout; + | ^^^^^^^^^^^^^ +note: function defined here + --> $DIR/alloc-error-handler-bad-signature-2.rs:10:4 + | +LL | fn oom( + | ^^^ +LL | info: Layout, + | ------------ + = note: this error originates in the attribute macro `alloc_error_handler` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> $DIR/alloc-error-handler-bad-signature-2.rs:10:1 + | +LL | #[alloc_error_handler] + | ---------------------- in this procedural macro expansion +LL | // fn oom( +LL | || info: Layout, +LL | || ) { + | ||_^ expected `!`, found `()` +LL | | loop {} +LL | | } + | |__- expected `!` because of return type + | + = note: expected type `!` + found unit type `()` + = note: this error originates in the attribute macro `alloc_error_handler` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/alloc-error/alloc-error-handler-bad-signature-3.rs b/tests/ui/alloc-error/alloc-error-handler-bad-signature-3.rs new file mode 100644 index 00000000000..ea9ad39a70d --- /dev/null +++ b/tests/ui/alloc-error/alloc-error-handler-bad-signature-3.rs @@ -0,0 +1,15 @@ +// compile-flags:-C panic=abort + +#![feature(alloc_error_handler)] +#![no_std] +#![no_main] + +struct Layout; + +#[alloc_error_handler] +fn oom() -> ! { //~ ERROR function takes 0 arguments but 1 argument was supplied + loop {} +} + +#[panic_handler] +fn panic(_: &core::panic::PanicInfo) -> ! { loop {} } diff --git a/tests/ui/alloc-error/alloc-error-handler-bad-signature-3.stderr b/tests/ui/alloc-error/alloc-error-handler-bad-signature-3.stderr new file mode 100644 index 00000000000..eb739b149a1 --- /dev/null +++ b/tests/ui/alloc-error/alloc-error-handler-bad-signature-3.stderr @@ -0,0 +1,21 @@ +error[E0061]: this function takes 0 arguments but 1 argument was supplied + --> $DIR/alloc-error-handler-bad-signature-3.rs:10:1 + | +LL | #[alloc_error_handler] + | ---------------------- in this procedural macro expansion +LL | fn oom() -> ! { + | _-^^^^^^^^^^^^ +LL | | loop {} +LL | | } + | |_- unexpected argument of type `core::alloc::Layout` + | +note: function defined here + --> $DIR/alloc-error-handler-bad-signature-3.rs:10:4 + | +LL | fn oom() -> ! { + | ^^^ + = note: this error originates in the attribute macro `alloc_error_handler` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0061`. diff --git a/tests/ui/alloc-error/default-alloc-error-hook.rs b/tests/ui/alloc-error/default-alloc-error-hook.rs index 919d4b714a1..8be09500f4e 100644 --- a/tests/ui/alloc-error/default-alloc-error-hook.rs +++ b/tests/ui/alloc-error/default-alloc-error-hook.rs @@ -2,7 +2,7 @@ // ignore-emscripten no processes // ignore-sgx no processes -use std::alloc::{handle_alloc_error, Layout}; +use std::alloc::{Layout, handle_alloc_error}; use std::env; use std::process::Command; use std::str; @@ -24,5 +24,5 @@ fn main() { .strip_suffix("qemu: uncaught target signal 6 (Aborted) - core dumped\n") .unwrap_or(stderr); - assert!(stderr.contains("memory allocation of 42 bytes failed")); + assert_eq!(stderr, "memory allocation of 42 bytes failed\n"); } diff --git a/tests/ui/allocator/no_std-alloc-error-handler-custom.rs b/tests/ui/allocator/no_std-alloc-error-handler-custom.rs new file mode 100644 index 00000000000..28926243390 --- /dev/null +++ b/tests/ui/allocator/no_std-alloc-error-handler-custom.rs @@ -0,0 +1,84 @@ +// run-pass +// ignore-android no libc +// ignore-emscripten no libc +// ignore-sgx no libc +// ignore-wasm32 no libc +// only-linux +// compile-flags:-C panic=abort +// aux-build:helper.rs + +#![feature(rustc_private, lang_items)] +#![feature(alloc_error_handler)] +#![no_std] +#![no_main] + +extern crate alloc; +extern crate libc; + +// ARM targets need these symbols +#[no_mangle] +pub fn __aeabi_unwind_cpp_pr0() {} + +#[no_mangle] +pub fn __aeabi_unwind_cpp_pr1() {} + +use alloc::boxed::Box; +use alloc::string::ToString; +use core::alloc::{GlobalAlloc, Layout}; +use core::ptr::null_mut; + +extern crate helper; + +struct MyAllocator; + +#[alloc_error_handler] +fn my_oom(layout: Layout) -> ! { + use alloc::fmt::write; + unsafe { + let size = layout.size(); + let mut s = alloc::string::String::new(); + write(&mut s, format_args!("My OOM: failed to allocate {} bytes!\n", size)).unwrap(); + libc::write(libc::STDERR_FILENO, s.as_ptr() as *const _, s.len()); + libc::exit(0) + } +} + +unsafe impl GlobalAlloc for MyAllocator { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + if layout.size() < 4096 { libc::malloc(layout.size()) as _ } else { null_mut() } + } + unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {} +} + +#[global_allocator] +static A: MyAllocator = MyAllocator; + +#[panic_handler] +fn panic(panic_info: &core::panic::PanicInfo) -> ! { + unsafe { + let s = panic_info.to_string(); + const PSTR: &str = "panic occurred: "; + const CR: &str = "\n"; + libc::write(libc::STDERR_FILENO, PSTR.as_ptr() as *const _, PSTR.len()); + libc::write(libc::STDERR_FILENO, s.as_ptr() as *const _, s.len()); + libc::write(libc::STDERR_FILENO, CR.as_ptr() as *const _, CR.len()); + libc::exit(1) + } +} + +// Because we are compiling this code with `-C panic=abort`, this wouldn't normally be needed. +// However, `core` and `alloc` are both compiled with `-C panic=unwind`, which means that functions +// in these libraries will refer to `rust_eh_personality` if LLVM can not *prove* the contents won't +// unwind. So, for this test case we will define the symbol. +#[lang = "eh_personality"] +extern "C" fn rust_eh_personality() {} + +#[derive(Default, Debug)] +struct Page(#[allow(unused_tuple_struct_fields)] [[u64; 32]; 16]); + +#[no_mangle] +fn main(_argc: i32, _argv: *const *const u8) -> isize { + let zero = Box::<Page>::new(Default::default()); + helper::work_with(&zero); + 1 +} diff --git a/tests/ui/associated-types/substs-ppaux.verbose.stderr b/tests/ui/associated-types/substs-ppaux.verbose.stderr index e4f6ba573ca..ad67899e6da 100644 --- a/tests/ui/associated-types/substs-ppaux.verbose.stderr +++ b/tests/ui/associated-types/substs-ppaux.verbose.stderr @@ -77,7 +77,7 @@ LL | <str as Foo<u8>>::bar; | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `str` -note: required for `str` to implement `Foo<'_#0r, '_#1r, u8>` +note: required for `str` to implement `Foo<'?0, '?1, u8>` --> $DIR/substs-ppaux.rs:11:17 | LL | impl<'a,'b,T,S> Foo<'a, 'b, S> for T {} diff --git a/tests/ui/closures/binder/nested-closures-regions.stderr b/tests/ui/closures/binder/nested-closures-regions.stderr index b385e0ed6e0..381aadb1564 100644 --- a/tests/ui/closures/binder/nested-closures-regions.stderr +++ b/tests/ui/closures/binder/nested-closures-regions.stderr @@ -9,11 +9,11 @@ LL | for<'a> || -> () { for<'c> |_: &'a ()| -> () {}; }; extern "rust-call" fn((&(),)), (), ] - = note: late-bound region is '_#4r - = note: late-bound region is '_#2r + = note: late-bound region is '?4 + = note: late-bound region is '?2 = note: number of external vids: 3 - = note: where '_#1r: '_#2r - = note: where '_#2r: '_#1r + = note: where '?1: '?2 + = note: where '?2: '?1 note: no external requirements --> $DIR/nested-closures-regions.rs:8:5 @@ -26,7 +26,7 @@ LL | for<'a> || -> () { for<'c> |_: &'a ()| -> () {}; }; extern "rust-call" fn(()), (), ] - = note: late-bound region is '_#2r + = note: late-bound region is '?2 note: no external requirements --> $DIR/nested-closures-regions.rs:7:1 diff --git a/tests/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr b/tests/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr index ff89dd34034..381bb0c084a 100644 --- a/tests/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr +++ b/tests/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr @@ -9,7 +9,7 @@ LL | let c1 : () = c; | expected due to this | = note: expected unit type `()` - found closure `[mod1::f<T>::{closure#0} closure_substs=(unavailable) substs=[T, _#16t, extern "rust-call" fn(()), _#15t]]` + found closure `[mod1::f<T>::{closure#0} closure_substs=(unavailable) substs=[T, ?16t, extern "rust-call" fn(()), ?15t]]` help: use parentheses to call this closure | LL | let c1 : () = c(); diff --git a/tests/ui/closures/print/closure-print-generic-verbose-1.stderr b/tests/ui/closures/print/closure-print-generic-verbose-1.stderr index 3ab7c66d11f..9a1f18fa855 100644 --- a/tests/ui/closures/print/closure-print-generic-verbose-1.stderr +++ b/tests/ui/closures/print/closure-print-generic-verbose-1.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value: `c` --> $DIR/closure-print-generic-verbose-1.rs:17:5 | LL | let c = to_fn_once(move|| { - | - move occurs because `c` has type `[f<T>::{closure#0} closure_kind_ty=i32 closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=(Foo<&'_#9r str>, T)]`, which does not implement the `Copy` trait + | - move occurs because `c` has type `[f<T>::{closure#0} closure_kind_ty=i32 closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=(Foo<&'?9 str>, T)]`, which does not implement the `Copy` trait ... LL | c(); | --- `c` moved due to this call diff --git a/tests/ui/closures/print/closure-print-generic-verbose-2.stderr b/tests/ui/closures/print/closure-print-generic-verbose-2.stderr index 5bbf84f963d..2a4d16c48dc 100644 --- a/tests/ui/closures/print/closure-print-generic-verbose-2.stderr +++ b/tests/ui/closures/print/closure-print-generic-verbose-2.stderr @@ -9,7 +9,7 @@ LL | let c1 : () = c; | expected due to this | = note: expected unit type `()` - found closure `[f<T>::{closure#0} closure_substs=(unavailable) substs=[T, _#16t, extern "rust-call" fn(()), _#15t]]` + found closure `[f<T>::{closure#0} closure_substs=(unavailable) substs=[T, ?16t, extern "rust-call" fn(()), ?15t]]` help: use parentheses to call this closure | LL | let c1 : () = c(); diff --git a/tests/ui/closures/print/closure-print-verbose.stderr b/tests/ui/closures/print/closure-print-verbose.stderr index 083717b3334..9e219435e5c 100644 --- a/tests/ui/closures/print/closure-print-verbose.stderr +++ b/tests/ui/closures/print/closure-print-verbose.stderr @@ -7,7 +7,7 @@ LL | let foo: fn(u8) -> u8 = |v: u8| { a += v; a }; | expected due to this | = note: expected fn pointer `fn(u8) -> u8` - found closure `[main::{closure#0} closure_substs=(unavailable) substs=[i8, extern "rust-call" fn((u8,)) -> u8, _#6t]]` + found closure `[main::{closure#0} closure_substs=(unavailable) substs=[i8, extern "rust-call" fn((u8,)) -> u8, ?6t]]` note: closures can only be coerced to `fn` types if they do not capture any variables --> $DIR/closure-print-verbose.rs:10:39 | diff --git a/tests/ui/const-generics/occurs-check/unused-substs-2.rs b/tests/ui/const-generics/occurs-check/unused-substs-2.rs index 9b1212694f5..84e24d1a3f5 100644 --- a/tests/ui/const-generics/occurs-check/unused-substs-2.rs +++ b/tests/ui/const-generics/occurs-check/unused-substs-2.rs @@ -1,9 +1,9 @@ #![feature(generic_const_exprs)] #![allow(incomplete_features)] -// The goal is to get an unevaluated const `ct` with a `Ty::Infer(TyVar(_#1t)` subst. +// The goal is to get an unevaluated const `ct` with a `Ty::Infer(TyVar(?1t)` subst. // -// If we are then able to infer `ty::Infer(TyVar(_#1t) := Ty<ct>` we introduced an +// If we are then able to infer `ty::Infer(TyVar(?1t) := Ty<ct>` we introduced an // artificial inference cycle. struct Foo<const N: usize>; @@ -20,8 +20,8 @@ impl<T> Bind<T> for Foo<{ 6 + 1 }> { fn main() { let (mut t, foo) = Foo::bind(); - // `t` is `ty::Infer(TyVar(_#1t))` - // `foo` contains `ty::Infer(TyVar(_#1t))` in its substs + // `t` is `ty::Infer(TyVar(?1t))` + // `foo` contains `ty::Infer(TyVar(?1t))` in its substs t = foo; //~^ ERROR mismatched types //~| NOTE cyclic type diff --git a/tests/ui/const-generics/occurs-check/unused-substs-3.rs b/tests/ui/const-generics/occurs-check/unused-substs-3.rs index d5aeab47e62..6db18d587d3 100644 --- a/tests/ui/const-generics/occurs-check/unused-substs-3.rs +++ b/tests/ui/const-generics/occurs-check/unused-substs-3.rs @@ -1,9 +1,9 @@ #![feature(generic_const_exprs)] #![allow(incomplete_features)] -// The goal is to get an unevaluated const `ct` with a `Ty::Infer(TyVar(_#1t)` subst. +// The goal is to get an unevaluated const `ct` with a `Ty::Infer(TyVar(?1t)` subst. // -// If we are then able to infer `ty::Infer(TyVar(_#1t) := Ty<ct>` we introduced an +// If we are then able to infer `ty::Infer(TyVar(?1t) := Ty<ct>` we introduced an // artificial inference cycle. fn bind<T>() -> (T, [u8; 6 + 1]) { todo!() @@ -11,8 +11,8 @@ fn bind<T>() -> (T, [u8; 6 + 1]) { fn main() { let (mut t, foo) = bind(); - // `t` is `ty::Infer(TyVar(_#1t))` - // `foo` contains `ty::Infer(TyVar(_#1t))` in its substs + // `t` is `ty::Infer(TyVar(?1t))` + // `foo` contains `ty::Infer(TyVar(?1t))` in its substs t = foo; //~^ ERROR mismatched types //~| NOTE cyclic type diff --git a/tests/ui/feature-gates/feature-gate-alloc-error-handler.rs b/tests/ui/feature-gates/feature-gate-alloc-error-handler.rs new file mode 100644 index 00000000000..78d189d20b6 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-alloc-error-handler.rs @@ -0,0 +1,16 @@ +// compile-flags:-C panic=abort + +#![no_std] +#![no_main] + +use core::alloc::Layout; + +#[alloc_error_handler] //~ ERROR use of unstable library feature 'alloc_error_handler' +fn oom(info: Layout) -> ! { + loop {} +} + +#[panic_handler] +fn panic(_: &core::panic::PanicInfo) -> ! { + loop {} +} diff --git a/tests/ui/feature-gates/feature-gate-alloc-error-handler.stderr b/tests/ui/feature-gates/feature-gate-alloc-error-handler.stderr new file mode 100644 index 00000000000..f414eb463df --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-alloc-error-handler.stderr @@ -0,0 +1,12 @@ +error[E0658]: use of unstable library feature 'alloc_error_handler' + --> $DIR/feature-gate-alloc-error-handler.rs:8:3 + | +LL | #[alloc_error_handler] + | ^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #51540 <https://github.com/rust-lang/rust/issues/51540> for more information + = help: add `#![feature(alloc_error_handler)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/generator/issue-57084.rs b/tests/ui/generator/issue-57084.rs index 2a5c3dd0570..fbed78ff280 100644 --- a/tests/ui/generator/issue-57084.rs +++ b/tests/ui/generator/issue-57084.rs @@ -1,5 +1,5 @@ // This issue reproduces an ICE on compile (E.g. fails on 2018-12-19 nightly). -// "cannot relate bound region: ReLateBound(DebruijnIndex(1), BrAnon(1)) <= '_#1r" +// "cannot relate bound region: ReLateBound(DebruijnIndex(1), BrAnon(1)) <= '?1" // run-pass // edition:2018 #![feature(generators,generator_trait)] diff --git a/tests/ui/impl-trait/wf-eval-order.rs b/tests/ui/impl-trait/wf-eval-order.rs index c7d6bb87096..8638fc2e775 100644 --- a/tests/ui/impl-trait/wf-eval-order.rs +++ b/tests/ui/impl-trait/wf-eval-order.rs @@ -31,9 +31,9 @@ fn main() { // // - `wf(typeof(x))` because we use a projection candidate. // - `<i32 as B>::V: Clone` because that's a bound on the trait. - // - `<i32 as B>::V` normalizes to `_#1` where `<i32 as A>::U == _#1` + // - `<i32 as B>::V` normalizes to `?1t` where `<i32 as A>::U == ?1t` // - // This all works if we evaluate `<i32 as A>::U == _#1` before + // This all works if we evaluate `<i32 as A>::U == ?1t` before // `<i32 as B>::V`, but we previously had the opposite order. let x = hide(X(0)); } diff --git a/tests/ui/missing/missing-allocator.rs b/tests/ui/missing/missing-allocator.rs index e06e603e3bf..2dc509f2c63 100644 --- a/tests/ui/missing/missing-allocator.rs +++ b/tests/ui/missing/missing-allocator.rs @@ -3,10 +3,16 @@ #![no_std] #![crate_type = "staticlib"] +#![feature(alloc_error_handler)] #[panic_handler] fn panic(_: &core::panic::PanicInfo) -> ! { loop {} } +#[alloc_error_handler] +fn oom(_: core::alloc::Layout) -> ! { + loop {} +} + extern crate alloc; diff --git a/tests/ui/nll/closure-requirements/escape-argument-callee.stderr b/tests/ui/nll/closure-requirements/escape-argument-callee.stderr index c0d95ddaa07..61233fd8407 100644 --- a/tests/ui/nll/closure-requirements/escape-argument-callee.stderr +++ b/tests/ui/nll/closure-requirements/escape-argument-callee.stderr @@ -17,7 +17,7 @@ LL | let mut closure = expect_sig(|p, y| *p = y); | - - ^^^^^^ assignment requires that `'1` must outlive `'2` | | | | | has type `&'1 i32` - | has type `&'_#2r mut &'2 i32` + | has type `&'?2 mut &'2 i32` note: no external requirements --> $DIR/escape-argument-callee.rs:20:1 diff --git a/tests/ui/nll/closure-requirements/escape-upvar-nested.stderr b/tests/ui/nll/closure-requirements/escape-upvar-nested.stderr index 4fbd5eb19a5..c00a31ef8e1 100644 --- a/tests/ui/nll/closure-requirements/escape-upvar-nested.stderr +++ b/tests/ui/nll/closure-requirements/escape-upvar-nested.stderr @@ -7,10 +7,10 @@ LL | let mut closure1 = || p = &y; = note: defining type: test::{closure#0}::{closure#0} with closure substs [ i16, extern "rust-call" fn(()), - (&'_#1r mut &'_#2r i32, &'_#3r i32), + (&'?1 mut &'?2 i32, &'?3 i32), ] = note: number of external vids: 4 - = note: where '_#3r: '_#2r + = note: where '?3: '?2 note: external requirements --> $DIR/escape-upvar-nested.rs:20:27 @@ -21,10 +21,10 @@ LL | let mut closure = || { = note: defining type: test::{closure#0} with closure substs [ i16, extern "rust-call" fn(()), - (&'_#1r mut &'_#2r i32, &'_#3r i32), + (&'?1 mut &'?2 i32, &'?3 i32), ] = note: number of external vids: 4 - = note: where '_#3r: '_#2r + = note: where '?3: '?2 note: no external requirements --> $DIR/escape-upvar-nested.rs:13:1 diff --git a/tests/ui/nll/closure-requirements/escape-upvar-ref.stderr b/tests/ui/nll/closure-requirements/escape-upvar-ref.stderr index bc1ceac5bf0..2d67e6e7d72 100644 --- a/tests/ui/nll/closure-requirements/escape-upvar-ref.stderr +++ b/tests/ui/nll/closure-requirements/escape-upvar-ref.stderr @@ -7,10 +7,10 @@ LL | let mut closure = || p = &y; = note: defining type: test::{closure#0} with closure substs [ i16, extern "rust-call" fn(()), - (&'_#1r mut &'_#2r i32, &'_#3r i32), + (&'?1 mut &'?2 i32, &'?3 i32), ] = note: number of external vids: 4 - = note: where '_#3r: '_#2r + = note: where '?3: '?2 note: no external requirements --> $DIR/escape-upvar-ref.rs:17:1 diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr index 5a7b12732df..ba42576d403 100644 --- a/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr +++ b/tests/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr @@ -6,20 +6,20 @@ LL | |_outlives1, _outlives2, _outlives3, x, y| { | = note: defining type: supply::{closure#0} with closure substs [ i16, - for<Region(BrAnon(None)), Region(BrAnon(None))> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) u32>, std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) &'_#3r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>)), + for<Region(BrAnon(None)), Region(BrAnon(None))> extern "rust-call" fn((std::cell::Cell<&'?1 &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) u32>, std::cell::Cell<&'?2 &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) &'?3 u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>)), (), ] - = note: late-bound region is '_#4r - = note: late-bound region is '_#5r - = note: late-bound region is '_#6r + = note: late-bound region is '?4 + = note: late-bound region is '?5 + = note: late-bound region is '?6 error: lifetime may not live long enough --> $DIR/propagate-approximated-fail-no-postdom.rs:46:13 | LL | |_outlives1, _outlives2, _outlives3, x, y| { - | ---------- ---------- has type `Cell<&'2 &'_#3r u32>` + | ---------- ---------- has type `Cell<&'2 &'?3 u32>` | | - | has type `Cell<&'_#1r &'1 u32>` + | has type `Cell<&'?1 &'1 u32>` ... LL | demand_y(x, y, p) | ^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2` diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-ref.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-ref.stderr index db2ecc779ef..9dd6e02081f 100644 --- a/tests/ui/nll/closure-requirements/propagate-approximated-ref.stderr +++ b/tests/ui/nll/closure-requirements/propagate-approximated-ref.stderr @@ -6,13 +6,13 @@ LL | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y | = note: defining type: supply::{closure#0} with closure substs [ i16, - for<Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None))> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(None) }) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 5, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(None) }) u32>)), + for<Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None))> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) std::cell::Cell<&'?1 &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(None) }) &'?2 u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 5, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(None) }) u32>)), (), ] - = note: late-bound region is '_#3r - = note: late-bound region is '_#4r + = note: late-bound region is '?3 + = note: late-bound region is '?4 = note: number of external vids: 5 - = note: where '_#1r: '_#2r + = note: where '?1: '?2 note: no external requirements --> $DIR/propagate-approximated-ref.rs:42:1 diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr index 1d9dafbe55f..e2f5576d395 100644 --- a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr +++ b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr @@ -6,7 +6,7 @@ LL | foo(cell, |cell_a, cell_x| { | = note: defining type: case1::{closure#0} with closure substs [ i32, - for<Region(BrAnon(None))> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) u32>)), + for<Region(BrAnon(None))> extern "rust-call" fn((std::cell::Cell<&'?1 u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) u32>)), (), ] @@ -36,11 +36,11 @@ LL | foo(cell, |cell_a, cell_x| { | = note: defining type: case2::{closure#0} with closure substs [ i32, - for<Region(BrAnon(None))> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) u32>)), + for<Region(BrAnon(None))> extern "rust-call" fn((std::cell::Cell<&'?1 u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) u32>)), (), ] = note: number of external vids: 2 - = note: where '_#1r: '_#0r + = note: where '?1: '?0 note: no external requirements --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:28:1 diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr index 85f7fe35c0a..383fb471ad3 100644 --- a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr +++ b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr @@ -6,13 +6,13 @@ LL | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| { | = note: defining type: supply::{closure#0} with closure substs [ i16, - for<Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None))> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrAnon(None) }) u32>)), + for<Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None))> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) std::cell::Cell<&'?1 &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrAnon(None) }) u32>)), (), ] - = note: late-bound region is '_#2r - = note: late-bound region is '_#3r + = note: late-bound region is '?2 + = note: late-bound region is '?3 = note: number of external vids: 4 - = note: where '_#1r: '_#0r + = note: where '?1: '?0 note: no external requirements --> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:31:1 @@ -40,7 +40,7 @@ LL | | }); | |______`cell_a` escapes the function body here | argument requires that `'a` must outlive `'static` | - = note: requirement occurs because of the type `Cell<&'_#9r u32>`, which makes the generic argument `&'_#9r u32` invariant + = note: requirement occurs because of the type `Cell<&'?9 u32>`, which makes the generic argument `&'?9 u32` invariant = note: the struct `Cell<T>` is invariant over the parameter `T` = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr index 7194843e203..ac346c0b110 100644 --- a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr +++ b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr @@ -6,13 +6,13 @@ LL | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y | = note: defining type: supply::{closure#0} with closure substs [ i16, - for<Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None))> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(None) }) std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 5, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(None) }) u32>)), + for<Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None))> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) std::cell::Cell<&'?1 &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(None) }) std::cell::Cell<&'?2 &ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 5, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(None) }) u32>)), (), ] - = note: late-bound region is '_#3r - = note: late-bound region is '_#4r + = note: late-bound region is '?3 + = note: late-bound region is '?4 = note: number of external vids: 5 - = note: where '_#1r: '_#0r + = note: where '?1: '?0 note: no external requirements --> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:34:1 @@ -40,7 +40,7 @@ LL | | }); | |______`cell_a` escapes the function body here | argument requires that `'a` must outlive `'static` | - = note: requirement occurs because of the type `Cell<&'_#10r u32>`, which makes the generic argument `&'_#10r u32` invariant + = note: requirement occurs because of the type `Cell<&'?10 u32>`, which makes the generic argument `&'?10 u32` invariant = note: the struct `Cell<T>` is invariant over the parameter `T` = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-val.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-val.stderr index 71f8a1c67c6..b217ae19773 100644 --- a/tests/ui/nll/closure-requirements/propagate-approximated-val.stderr +++ b/tests/ui/nll/closure-requirements/propagate-approximated-val.stderr @@ -6,13 +6,13 @@ LL | establish_relationships(cell_a, cell_b, |outlives1, outlives2, x, y| { | = note: defining type: test::{closure#0} with closure substs [ i16, - for<Region(BrAnon(None)), Region(BrAnon(None))> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>)), + for<Region(BrAnon(None)), Region(BrAnon(None))> extern "rust-call" fn((std::cell::Cell<&'?1 &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) &'?2 u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>)), (), ] - = note: late-bound region is '_#3r - = note: late-bound region is '_#4r + = note: late-bound region is '?3 + = note: late-bound region is '?4 = note: number of external vids: 5 - = note: where '_#1r: '_#2r + = note: where '?1: '?2 note: no external requirements --> $DIR/propagate-approximated-val.rs:35:1 diff --git a/tests/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr b/tests/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr index e1cb97b1c7d..f31478b6d1c 100644 --- a/tests/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr +++ b/tests/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr @@ -6,12 +6,12 @@ LL | |_outlives1, _outlives2, x, y| { | = note: defining type: supply::{closure#0} with closure substs [ i16, - for<Region(BrAnon(None)), Region(BrAnon(None))> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>)), + for<Region(BrAnon(None)), Region(BrAnon(None))> extern "rust-call" fn((std::cell::Cell<&'?1 &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) &'?2 u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>)), (), ] - = note: late-bound region is '_#3r + = note: late-bound region is '?3 = note: number of external vids: 4 - = note: where '_#1r: '_#2r + = note: where '?1: '?2 note: no external requirements --> $DIR/propagate-despite-same-free-region.rs:39:1 diff --git a/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr index b66e8391c01..1509ade87fa 100644 --- a/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr +++ b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr @@ -6,19 +6,19 @@ LL | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| { | = note: defining type: supply::{closure#0} with closure substs [ i16, - for<Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None))> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>)), + for<Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None))> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) &'?1 u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>)), (), ] - = note: late-bound region is '_#2r - = note: late-bound region is '_#3r + = note: late-bound region is '?2 + = note: late-bound region is '?3 error: lifetime may not live long enough --> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:37:9 | LL | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| { - | --------- - has type `&'_#7r Cell<&'1 u32>` + | --------- - has type `&'?7 Cell<&'1 u32>` | | - | has type `&'_#5r Cell<&'2 &'_#1r u32>` + | has type `&'?5 Cell<&'2 &'?1 u32>` LL | // Only works if 'x: 'y: LL | demand_y(x, y, x.get()) | ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2` diff --git a/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr index 49641fd06fd..c85a9872e21 100644 --- a/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr +++ b/tests/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr @@ -6,19 +6,19 @@ LL | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y | = note: defining type: supply::{closure#0} with closure substs [ i16, - for<Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None))> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(None) }) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 5, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(None) }) u32>)), + for<Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None)), Region(BrAnon(None))> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) &'?1 u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 2, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(None) }) &'?2 u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 4, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) u32>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 5, kind: BrAnon(None) }) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BoundRegion { var: 3, kind: BrAnon(None) }) u32>)), (), ] - = note: late-bound region is '_#3r - = note: late-bound region is '_#4r + = note: late-bound region is '?3 + = note: late-bound region is '?4 error: lifetime may not live long enough --> $DIR/propagate-fail-to-approximate-longer-wrong-bounds.rs:41:9 | LL | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| { - | ---------- ---------- has type `&'_#8r Cell<&'2 &'_#2r u32>` + | ---------- ---------- has type `&'?8 Cell<&'2 &'?2 u32>` | | - | has type `&'_#6r Cell<&'1 &'_#1r u32>` + | has type `&'?6 Cell<&'1 &'?1 u32>` LL | // Only works if 'x: 'y: LL | demand_y(x, y, x.get()) | ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2` diff --git a/tests/ui/nll/closure-requirements/propagate-from-trait-match.stderr b/tests/ui/nll/closure-requirements/propagate-from-trait-match.stderr index 038a5e11f88..05e274ab220 100644 --- a/tests/ui/nll/closure-requirements/propagate-from-trait-match.stderr +++ b/tests/ui/nll/closure-requirements/propagate-from-trait-match.stderr @@ -4,13 +4,13 @@ note: external requirements LL | establish_relationships(value, |value| { | ^^^^^^^ | - = note: defining type: supply::<'_#1r, T>::{closure#0} with closure substs [ + = note: defining type: supply::<'?1, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((T,)), (), ] = note: number of external vids: 2 - = note: where T: '_#1r + = note: where T: '?1 note: no external requirements --> $DIR/propagate-from-trait-match.rs:28:1 @@ -20,7 +20,7 @@ LL | | where LL | | T: Trait<'a>, | |_________________^ | - = note: defining type: supply::<'_#1r, T> + = note: defining type: supply::<'?1, T> error[E0309]: the parameter type `T` may not live long enough --> $DIR/propagate-from-trait-match.rs:43:9 diff --git a/tests/ui/nll/member-constraints/min-choice.rs b/tests/ui/nll/member-constraints/min-choice.rs index 14b4dae7abf..f4aca69e19f 100644 --- a/tests/ui/nll/member-constraints/min-choice.rs +++ b/tests/ui/nll/member-constraints/min-choice.rs @@ -1,5 +1,5 @@ -// Assuming that the hidden type in these tests is `&'_#15r u8`, -// we have a member constraint: `'_#15r member ['static, 'a, 'b, 'c]`. +// Assuming that the hidden type in these tests is `&'?15 u8`, +// we have a member constraint: `'?15 member ['static, 'a, 'b, 'c]`. // // Make sure we pick up the minimum non-ambiguous region among them. // We will have to exclude `['b, 'c]` because they're incomparable, diff --git a/tests/ui/nll/member-constraints/nested-impl-trait-fail.rs b/tests/ui/nll/member-constraints/nested-impl-trait-fail.rs index 66ff828a84f..ceb417f84f3 100644 --- a/tests/ui/nll/member-constraints/nested-impl-trait-fail.rs +++ b/tests/ui/nll/member-constraints/nested-impl-trait-fail.rs @@ -5,9 +5,9 @@ trait Cap<'a> {} impl<T> Cap<'_> for T {} -// Assuming the hidden type is `[&'_#15r u8; 1]`, we have two distinct member constraints: -// - '_#15r member ['static, 'a, 'b] // from outer impl-trait -// - '_#15r member ['static, 'a, 'b] // from inner impl-trait +// Assuming the hidden type is `[&'?15 u8; 1]`, we have two distinct member constraints: +// - '?15 member ['static, 'a, 'b] // from outer impl-trait +// - '?15 member ['static, 'a, 'b] // from inner impl-trait // To satisfy both we can choose 'a or 'b, so it's a failure due to ambiguity. fn fail_early_bound<'s, 'a, 'b>(a: &'s u8) -> impl IntoIterator<Item = impl Cap<'a> + Cap<'b>> where diff --git a/tests/ui/nll/member-constraints/nested-impl-trait-pass.rs b/tests/ui/nll/member-constraints/nested-impl-trait-pass.rs index 15540cb460e..4be0f02acf2 100644 --- a/tests/ui/nll/member-constraints/nested-impl-trait-pass.rs +++ b/tests/ui/nll/member-constraints/nested-impl-trait-pass.rs @@ -5,9 +5,9 @@ trait Cap<'a> {} impl<T> Cap<'_> for T {} -// Assuming the hidden type is `[&'_#15r u8; 1]`, we have two distinct member constraints: -// - '_#15r member ['static, 'a, 'b] // from outer impl-trait -// - '_#15r member ['static, 'a] // from inner impl-trait +// Assuming the hidden type is `[&'?15 u8; 1]`, we have two distinct member constraints: +// - '?15 member ['static, 'a, 'b] // from outer impl-trait +// - '?15 member ['static, 'a] // from inner impl-trait // To satisfy both we can only choose 'a. fn pass_early_bound<'s, 'a, 'b>(a: &'s u8) -> impl IntoIterator<Item = impl Cap<'a>> + Cap<'b> where diff --git a/tests/ui/nll/ty-outlives/projection-no-regions-closure.stderr b/tests/ui/nll/ty-outlives/projection-no-regions-closure.stderr index 4933b934868..4eefb180ee5 100644 --- a/tests/ui/nll/ty-outlives/projection-no-regions-closure.stderr +++ b/tests/ui/nll/ty-outlives/projection-no-regions-closure.stderr @@ -4,13 +4,13 @@ note: external requirements LL | with_signature(x, |mut y| Box::new(y.next())) | ^^^^^^^ | - = note: defining type: no_region::<'_#1r, T>::{closure#0} with closure substs [ + = note: defining type: no_region::<'?1, T>::{closure#0} with closure substs [ i32, - extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#2r)>, + extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '?2)>, (), ] = note: number of external vids: 3 - = note: where <T as std::iter::Iterator>::Item: '_#2r + = note: where <T as std::iter::Iterator>::Item: '?2 note: no external requirements --> $DIR/projection-no-regions-closure.rs:21:1 @@ -20,7 +20,7 @@ LL | | where LL | | T: Iterator, | |________________^ | - = note: defining type: no_region::<'_#1r, T> + = note: defining type: no_region::<'?1, T> error[E0309]: the associated type `<T as Iterator>::Item` may not live long enough --> $DIR/projection-no-regions-closure.rs:25:31 @@ -37,13 +37,13 @@ note: external requirements LL | with_signature(x, |mut y| Box::new(y.next())) | ^^^^^^^ | - = note: defining type: correct_region::<'_#1r, T>::{closure#0} with closure substs [ + = note: defining type: correct_region::<'?1, T>::{closure#0} with closure substs [ i32, - extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#2r)>, + extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '?2)>, (), ] = note: number of external vids: 3 - = note: where <T as std::iter::Iterator>::Item: '_#2r + = note: where <T as std::iter::Iterator>::Item: '?2 note: no external requirements --> $DIR/projection-no-regions-closure.rs:30:1 @@ -53,7 +53,7 @@ LL | | where LL | | T: 'a + Iterator, | |_____________________^ | - = note: defining type: correct_region::<'_#1r, T> + = note: defining type: correct_region::<'?1, T> note: external requirements --> $DIR/projection-no-regions-closure.rs:42:23 @@ -61,13 +61,13 @@ note: external requirements LL | with_signature(x, |mut y| Box::new(y.next())) | ^^^^^^^ | - = note: defining type: wrong_region::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ + = note: defining type: wrong_region::<'?1, '?2, T>::{closure#0} with closure substs [ i32, - extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#3r)>, + extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '?3)>, (), ] = note: number of external vids: 4 - = note: where <T as std::iter::Iterator>::Item: '_#3r + = note: where <T as std::iter::Iterator>::Item: '?3 note: no external requirements --> $DIR/projection-no-regions-closure.rs:38:1 @@ -77,7 +77,7 @@ LL | | where LL | | T: 'b + Iterator, | |_____________________^ | - = note: defining type: wrong_region::<'_#1r, '_#2r, T> + = note: defining type: wrong_region::<'?1, '?2, T> error[E0309]: the associated type `<T as Iterator>::Item` may not live long enough --> $DIR/projection-no-regions-closure.rs:42:31 @@ -94,13 +94,13 @@ note: external requirements LL | with_signature(x, |mut y| Box::new(y.next())) | ^^^^^^^ | - = note: defining type: outlives_region::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ + = note: defining type: outlives_region::<'?1, '?2, T>::{closure#0} with closure substs [ i32, - extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#3r)>, + extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '?3)>, (), ] = note: number of external vids: 4 - = note: where <T as std::iter::Iterator>::Item: '_#3r + = note: where <T as std::iter::Iterator>::Item: '?3 note: no external requirements --> $DIR/projection-no-regions-closure.rs:47:1 @@ -111,7 +111,7 @@ LL | | T: 'b + Iterator, LL | | 'b: 'a, | |___________^ | - = note: defining type: outlives_region::<'_#1r, '_#2r, T> + = note: defining type: outlives_region::<'?1, '?2, T> error: aborting due to 2 previous errors diff --git a/tests/ui/nll/ty-outlives/projection-one-region-closure.stderr b/tests/ui/nll/ty-outlives/projection-one-region-closure.stderr index 11ada59c066..986c2bd2182 100644 --- a/tests/ui/nll/ty-outlives/projection-one-region-closure.stderr +++ b/tests/ui/nll/ty-outlives/projection-one-region-closure.stderr @@ -4,15 +4,15 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^ | - = note: defining type: no_relationships_late::<'_#1r, T>::{closure#0} with closure substs [ + = note: defining type: no_relationships_late::<'?1, T>::{closure#0} with closure substs [ i32, - extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), + extern "rust-call" fn((std::cell::Cell<&'?2 ()>, T)), (), ] - = note: late-bound region is '_#3r + = note: late-bound region is '?3 = note: number of external vids: 4 - = note: where T: '_#2r - = note: where '_#1r: '_#2r + = note: where T: '?2 + = note: where '?1: '?2 note: no external requirements --> $DIR/projection-one-region-closure.rs:41:1 @@ -22,7 +22,7 @@ LL | | where LL | | T: Anything<'b>, | |____________________^ | - = note: defining type: no_relationships_late::<'_#1r, T> + = note: defining type: no_relationships_late::<'?1, T> error[E0309]: the parameter type `T` may not live long enough --> $DIR/projection-one-region-closure.rs:45:39 @@ -54,14 +54,14 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^ | - = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ + = note: defining type: no_relationships_early::<'?1, '?2, T>::{closure#0} with closure substs [ i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), + extern "rust-call" fn((std::cell::Cell<&'?3 ()>, T)), (), ] = note: number of external vids: 4 - = note: where T: '_#3r - = note: where '_#2r: '_#3r + = note: where T: '?3 + = note: where '?2: '?3 note: no external requirements --> $DIR/projection-one-region-closure.rs:51:1 @@ -72,7 +72,7 @@ LL | | T: Anything<'b>, LL | | 'a: 'a, | |___________^ | - = note: defining type: no_relationships_early::<'_#1r, '_#2r, T> + = note: defining type: no_relationships_early::<'?1, '?2, T> error[E0309]: the parameter type `T` may not live long enough --> $DIR/projection-one-region-closure.rs:56:39 @@ -104,13 +104,13 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^ | - = note: defining type: projection_outlives::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ + = note: defining type: projection_outlives::<'?1, '?2, T>::{closure#0} with closure substs [ i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), + extern "rust-call" fn((std::cell::Cell<&'?3 ()>, T)), (), ] = note: number of external vids: 4 - = note: where <T as Anything<'_#2r>>::AssocType: '_#3r + = note: where <T as Anything<'?2>>::AssocType: '?3 note: no external requirements --> $DIR/projection-one-region-closure.rs:62:1 @@ -121,7 +121,7 @@ LL | | T: Anything<'b>, LL | | T::AssocType: 'a, | |_____________________^ | - = note: defining type: projection_outlives::<'_#1r, '_#2r, T> + = note: defining type: projection_outlives::<'?1, '?2, T> note: external requirements --> $DIR/projection-one-region-closure.rs:80:29 @@ -129,14 +129,14 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^ | - = note: defining type: elements_outlive::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ + = note: defining type: elements_outlive::<'?1, '?2, T>::{closure#0} with closure substs [ i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), + extern "rust-call" fn((std::cell::Cell<&'?3 ()>, T)), (), ] = note: number of external vids: 4 - = note: where T: '_#3r - = note: where '_#2r: '_#3r + = note: where T: '?3 + = note: where '?2: '?3 note: no external requirements --> $DIR/projection-one-region-closure.rs:74:1 @@ -148,7 +148,7 @@ LL | | T: 'a, LL | | 'b: 'a, | |___________^ | - = note: defining type: elements_outlive::<'_#1r, '_#2r, T> + = note: defining type: elements_outlive::<'?1, '?2, T> error: aborting due to 4 previous errors diff --git a/tests/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr b/tests/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr index 47d4f2e46c6..25cc60d8141 100644 --- a/tests/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr +++ b/tests/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr @@ -4,14 +4,14 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^ | - = note: defining type: no_relationships_late::<'_#1r, T>::{closure#0} with closure substs [ + = note: defining type: no_relationships_late::<'?1, T>::{closure#0} with closure substs [ i32, - extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), + extern "rust-call" fn((std::cell::Cell<&'?2 ()>, T)), (), ] - = note: late-bound region is '_#3r + = note: late-bound region is '?3 = note: number of external vids: 4 - = note: where '_#1r: '_#2r + = note: where '?1: '?2 note: no external requirements --> $DIR/projection-one-region-trait-bound-closure.rs:33:1 @@ -21,7 +21,7 @@ LL | | where LL | | T: Anything<'b>, | |____________________^ | - = note: defining type: no_relationships_late::<'_#1r, T> + = note: defining type: no_relationships_late::<'?1, T> error: lifetime may not live long enough --> $DIR/projection-one-region-trait-bound-closure.rs:37:39 @@ -42,13 +42,13 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^ | - = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ + = note: defining type: no_relationships_early::<'?1, '?2, T>::{closure#0} with closure substs [ i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), + extern "rust-call" fn((std::cell::Cell<&'?3 ()>, T)), (), ] = note: number of external vids: 4 - = note: where '_#2r: '_#3r + = note: where '?2: '?3 note: no external requirements --> $DIR/projection-one-region-trait-bound-closure.rs:42:1 @@ -59,7 +59,7 @@ LL | | T: Anything<'b>, LL | | 'a: 'a, | |___________^ | - = note: defining type: no_relationships_early::<'_#1r, '_#2r, T> + = note: defining type: no_relationships_early::<'?1, '?2, T> error: lifetime may not live long enough --> $DIR/projection-one-region-trait-bound-closure.rs:47:39 @@ -80,13 +80,13 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^ | - = note: defining type: projection_outlives::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ + = note: defining type: projection_outlives::<'?1, '?2, T>::{closure#0} with closure substs [ i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), + extern "rust-call" fn((std::cell::Cell<&'?3 ()>, T)), (), ] = note: number of external vids: 4 - = note: where <T as Anything<'_#2r>>::AssocType: '_#3r + = note: where <T as Anything<'?2>>::AssocType: '?3 note: no external requirements --> $DIR/projection-one-region-trait-bound-closure.rs:52:1 @@ -97,7 +97,7 @@ LL | | T: Anything<'b>, LL | | T::AssocType: 'a, | |_____________________^ | - = note: defining type: projection_outlives::<'_#1r, '_#2r, T> + = note: defining type: projection_outlives::<'?1, '?2, T> note: external requirements --> $DIR/projection-one-region-trait-bound-closure.rs:69:29 @@ -105,13 +105,13 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^ | - = note: defining type: elements_outlive::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ + = note: defining type: elements_outlive::<'?1, '?2, T>::{closure#0} with closure substs [ i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), + extern "rust-call" fn((std::cell::Cell<&'?3 ()>, T)), (), ] = note: number of external vids: 4 - = note: where '_#2r: '_#3r + = note: where '?2: '?3 note: no external requirements --> $DIR/projection-one-region-trait-bound-closure.rs:64:1 @@ -122,7 +122,7 @@ LL | | T: Anything<'b>, LL | | 'b: 'a, | |___________^ | - = note: defining type: elements_outlive::<'_#1r, '_#2r, T> + = note: defining type: elements_outlive::<'?1, '?2, T> note: external requirements --> $DIR/projection-one-region-trait-bound-closure.rs:81:29 @@ -130,13 +130,13 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^ | - = note: defining type: one_region::<'_#1r, T>::{closure#0} with closure substs [ + = note: defining type: one_region::<'?1, T>::{closure#0} with closure substs [ i32, - extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), + extern "rust-call" fn((std::cell::Cell<&'?2 ()>, T)), (), ] = note: number of external vids: 3 - = note: where '_#1r: '_#2r + = note: where '?1: '?2 note: no external requirements --> $DIR/projection-one-region-trait-bound-closure.rs:73:1 @@ -146,7 +146,7 @@ LL | | where LL | | T: Anything<'a>, | |____________________^ | - = note: defining type: one_region::<'_#1r, T> + = note: defining type: one_region::<'?1, T> error: aborting due to 2 previous errors diff --git a/tests/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr b/tests/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr index b27186b0537..5a092d7b849 100644 --- a/tests/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr +++ b/tests/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr @@ -4,12 +4,12 @@ note: no external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^ | - = note: defining type: no_relationships_late::<'_#1r, T>::{closure#0} with closure substs [ + = note: defining type: no_relationships_late::<'?1, T>::{closure#0} with closure substs [ i32, - extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), + extern "rust-call" fn((std::cell::Cell<&'?2 ()>, T)), (), ] - = note: late-bound region is '_#3r + = note: late-bound region is '?3 note: no external requirements --> $DIR/projection-one-region-trait-bound-static-closure.rs:32:1 @@ -19,7 +19,7 @@ LL | | where LL | | T: Anything<'b>, | |____________________^ | - = note: defining type: no_relationships_late::<'_#1r, T> + = note: defining type: no_relationships_late::<'?1, T> note: no external requirements --> $DIR/projection-one-region-trait-bound-static-closure.rs:45:29 @@ -27,9 +27,9 @@ note: no external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^ | - = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ + = note: defining type: no_relationships_early::<'?1, '?2, T>::{closure#0} with closure substs [ i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), + extern "rust-call" fn((std::cell::Cell<&'?3 ()>, T)), (), ] @@ -42,7 +42,7 @@ LL | | T: Anything<'b>, LL | | 'a: 'a, | |___________^ | - = note: defining type: no_relationships_early::<'_#1r, '_#2r, T> + = note: defining type: no_relationships_early::<'?1, '?2, T> note: no external requirements --> $DIR/projection-one-region-trait-bound-static-closure.rs:64:29 @@ -50,9 +50,9 @@ note: no external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^ | - = note: defining type: projection_outlives::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ + = note: defining type: projection_outlives::<'?1, '?2, T>::{closure#0} with closure substs [ i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), + extern "rust-call" fn((std::cell::Cell<&'?3 ()>, T)), (), ] @@ -65,7 +65,7 @@ LL | | T: Anything<'b>, LL | | T::AssocType: 'a, | |_____________________^ | - = note: defining type: projection_outlives::<'_#1r, '_#2r, T> + = note: defining type: projection_outlives::<'?1, '?2, T> note: no external requirements --> $DIR/projection-one-region-trait-bound-static-closure.rs:73:29 @@ -73,9 +73,9 @@ note: no external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^ | - = note: defining type: elements_outlive::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ + = note: defining type: elements_outlive::<'?1, '?2, T>::{closure#0} with closure substs [ i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), + extern "rust-call" fn((std::cell::Cell<&'?3 ()>, T)), (), ] @@ -88,7 +88,7 @@ LL | | T: Anything<'b>, LL | | 'b: 'a, | |___________^ | - = note: defining type: elements_outlive::<'_#1r, '_#2r, T> + = note: defining type: elements_outlive::<'?1, '?2, T> note: no external requirements --> $DIR/projection-one-region-trait-bound-static-closure.rs:85:29 @@ -96,9 +96,9 @@ note: no external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^ | - = note: defining type: one_region::<'_#1r, T>::{closure#0} with closure substs [ + = note: defining type: one_region::<'?1, T>::{closure#0} with closure substs [ i32, - extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), + extern "rust-call" fn((std::cell::Cell<&'?2 ()>, T)), (), ] @@ -110,5 +110,5 @@ LL | | where LL | | T: Anything<'a>, | |____________________^ | - = note: defining type: one_region::<'_#1r, T> + = note: defining type: one_region::<'?1, T> diff --git a/tests/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr b/tests/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr index 530dd86819d..51283aa8828 100644 --- a/tests/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr +++ b/tests/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr @@ -4,14 +4,14 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^ | - = note: defining type: no_relationships_late::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ + = note: defining type: no_relationships_late::<'?1, '?2, T>::{closure#0} with closure substs [ i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), + extern "rust-call" fn((std::cell::Cell<&'?3 ()>, T)), (), ] - = note: late-bound region is '_#4r + = note: late-bound region is '?4 = note: number of external vids: 5 - = note: where <T as Anything<'_#1r, '_#2r>>::AssocType: '_#3r + = note: where <T as Anything<'?1, '?2>>::AssocType: '?3 note: no external requirements --> $DIR/projection-two-region-trait-bound-closure.rs:34:1 @@ -21,16 +21,16 @@ LL | | where LL | | T: Anything<'b, 'c>, | |________________________^ | - = note: defining type: no_relationships_late::<'_#1r, '_#2r, T> + = note: defining type: no_relationships_late::<'?1, '?2, T> -error[E0309]: the associated type `<T as Anything<'_#5r, '_#6r>>::AssocType` may not live long enough +error[E0309]: the associated type `<T as Anything<'?5, '?6>>::AssocType` may not live long enough --> $DIR/projection-two-region-trait-bound-closure.rs:38:39 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^ | - = help: consider adding an explicit lifetime bound `<T as Anything<'_#5r, '_#6r>>::AssocType: 'a`... - = note: ...so that the type `<T as Anything<'_#5r, '_#6r>>::AssocType` will meet its required lifetime bounds + = help: consider adding an explicit lifetime bound `<T as Anything<'?5, '?6>>::AssocType: 'a`... + = note: ...so that the type `<T as Anything<'?5, '?6>>::AssocType` will meet its required lifetime bounds note: external requirements --> $DIR/projection-two-region-trait-bound-closure.rs:48:29 @@ -38,13 +38,13 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^ | - = note: defining type: no_relationships_early::<'_#1r, '_#2r, '_#3r, T>::{closure#0} with closure substs [ + = note: defining type: no_relationships_early::<'?1, '?2, '?3, T>::{closure#0} with closure substs [ i32, - extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)), + extern "rust-call" fn((std::cell::Cell<&'?4 ()>, T)), (), ] = note: number of external vids: 5 - = note: where <T as Anything<'_#2r, '_#3r>>::AssocType: '_#4r + = note: where <T as Anything<'?2, '?3>>::AssocType: '?4 note: no external requirements --> $DIR/projection-two-region-trait-bound-closure.rs:43:1 @@ -55,16 +55,16 @@ LL | | T: Anything<'b, 'c>, LL | | 'a: 'a, | |___________^ | - = note: defining type: no_relationships_early::<'_#1r, '_#2r, '_#3r, T> + = note: defining type: no_relationships_early::<'?1, '?2, '?3, T> -error[E0309]: the associated type `<T as Anything<'_#6r, '_#7r>>::AssocType` may not live long enough +error[E0309]: the associated type `<T as Anything<'?6, '?7>>::AssocType` may not live long enough --> $DIR/projection-two-region-trait-bound-closure.rs:48:39 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^ | - = help: consider adding an explicit lifetime bound `<T as Anything<'_#6r, '_#7r>>::AssocType: 'a`... - = note: ...so that the type `<T as Anything<'_#6r, '_#7r>>::AssocType` will meet its required lifetime bounds + = help: consider adding an explicit lifetime bound `<T as Anything<'?6, '?7>>::AssocType: 'a`... + = note: ...so that the type `<T as Anything<'?6, '?7>>::AssocType` will meet its required lifetime bounds note: external requirements --> $DIR/projection-two-region-trait-bound-closure.rs:61:29 @@ -72,13 +72,13 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^ | - = note: defining type: projection_outlives::<'_#1r, '_#2r, '_#3r, T>::{closure#0} with closure substs [ + = note: defining type: projection_outlives::<'?1, '?2, '?3, T>::{closure#0} with closure substs [ i32, - extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)), + extern "rust-call" fn((std::cell::Cell<&'?4 ()>, T)), (), ] = note: number of external vids: 5 - = note: where <T as Anything<'_#2r, '_#3r>>::AssocType: '_#4r + = note: where <T as Anything<'?2, '?3>>::AssocType: '?4 note: no external requirements --> $DIR/projection-two-region-trait-bound-closure.rs:53:1 @@ -89,7 +89,7 @@ LL | | T: Anything<'b, 'c>, LL | | T::AssocType: 'a, | |_____________________^ | - = note: defining type: projection_outlives::<'_#1r, '_#2r, '_#3r, T> + = note: defining type: projection_outlives::<'?1, '?2, '?3, T> note: external requirements --> $DIR/projection-two-region-trait-bound-closure.rs:70:29 @@ -97,13 +97,13 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^ | - = note: defining type: elements_outlive1::<'_#1r, '_#2r, '_#3r, T>::{closure#0} with closure substs [ + = note: defining type: elements_outlive1::<'?1, '?2, '?3, T>::{closure#0} with closure substs [ i32, - extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)), + extern "rust-call" fn((std::cell::Cell<&'?4 ()>, T)), (), ] = note: number of external vids: 5 - = note: where <T as Anything<'_#2r, '_#3r>>::AssocType: '_#4r + = note: where <T as Anything<'?2, '?3>>::AssocType: '?4 note: no external requirements --> $DIR/projection-two-region-trait-bound-closure.rs:65:1 @@ -114,7 +114,7 @@ LL | | T: Anything<'b, 'c>, LL | | 'b: 'a, | |___________^ | - = note: defining type: elements_outlive1::<'_#1r, '_#2r, '_#3r, T> + = note: defining type: elements_outlive1::<'?1, '?2, '?3, T> note: external requirements --> $DIR/projection-two-region-trait-bound-closure.rs:79:29 @@ -122,13 +122,13 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^ | - = note: defining type: elements_outlive2::<'_#1r, '_#2r, '_#3r, T>::{closure#0} with closure substs [ + = note: defining type: elements_outlive2::<'?1, '?2, '?3, T>::{closure#0} with closure substs [ i32, - extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)), + extern "rust-call" fn((std::cell::Cell<&'?4 ()>, T)), (), ] = note: number of external vids: 5 - = note: where <T as Anything<'_#2r, '_#3r>>::AssocType: '_#4r + = note: where <T as Anything<'?2, '?3>>::AssocType: '?4 note: no external requirements --> $DIR/projection-two-region-trait-bound-closure.rs:74:1 @@ -139,7 +139,7 @@ LL | | T: Anything<'b, 'c>, LL | | 'c: 'a, | |___________^ | - = note: defining type: elements_outlive2::<'_#1r, '_#2r, '_#3r, T> + = note: defining type: elements_outlive2::<'?1, '?2, '?3, T> note: external requirements --> $DIR/projection-two-region-trait-bound-closure.rs:87:29 @@ -147,14 +147,14 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^ | - = note: defining type: two_regions::<'_#1r, T>::{closure#0} with closure substs [ + = note: defining type: two_regions::<'?1, T>::{closure#0} with closure substs [ i32, - extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), + extern "rust-call" fn((std::cell::Cell<&'?2 ()>, T)), (), ] - = note: late-bound region is '_#3r + = note: late-bound region is '?3 = note: number of external vids: 4 - = note: where <T as Anything<'_#1r, '_#1r>>::AssocType: '_#2r + = note: where <T as Anything<'?1, '?1>>::AssocType: '?2 note: no external requirements --> $DIR/projection-two-region-trait-bound-closure.rs:83:1 @@ -164,7 +164,7 @@ LL | | where LL | | T: Anything<'b, 'b>, | |________________________^ | - = note: defining type: two_regions::<'_#1r, T> + = note: defining type: two_regions::<'?1, T> error: lifetime may not live long enough --> $DIR/projection-two-region-trait-bound-closure.rs:87:5 @@ -178,7 +178,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a` | = help: consider adding the following bound: `'b: 'a` - = note: requirement occurs because of the type `Cell<&'_#8r ()>`, which makes the generic argument `&'_#8r ()` invariant + = note: requirement occurs because of the type `Cell<&'?8 ()>`, which makes the generic argument `&'?8 ()` invariant = note: the struct `Cell<T>` is invariant over the parameter `T` = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance @@ -188,13 +188,13 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^ | - = note: defining type: two_regions_outlive::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ + = note: defining type: two_regions_outlive::<'?1, '?2, T>::{closure#0} with closure substs [ i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), + extern "rust-call" fn((std::cell::Cell<&'?3 ()>, T)), (), ] = note: number of external vids: 4 - = note: where <T as Anything<'_#2r, '_#2r>>::AssocType: '_#3r + = note: where <T as Anything<'?2, '?2>>::AssocType: '?3 note: no external requirements --> $DIR/projection-two-region-trait-bound-closure.rs:92:1 @@ -205,7 +205,7 @@ LL | | T: Anything<'b, 'b>, LL | | 'b: 'a, | |___________^ | - = note: defining type: two_regions_outlive::<'_#1r, '_#2r, T> + = note: defining type: two_regions_outlive::<'?1, '?2, T> note: external requirements --> $DIR/projection-two-region-trait-bound-closure.rs:109:29 @@ -213,13 +213,13 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^ | - = note: defining type: one_region::<'_#1r, T>::{closure#0} with closure substs [ + = note: defining type: one_region::<'?1, T>::{closure#0} with closure substs [ i32, - extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), + extern "rust-call" fn((std::cell::Cell<&'?2 ()>, T)), (), ] = note: number of external vids: 3 - = note: where <T as Anything<'_#1r, '_#1r>>::AssocType: '_#2r + = note: where <T as Anything<'?1, '?1>>::AssocType: '?2 note: no external requirements --> $DIR/projection-two-region-trait-bound-closure.rs:101:1 @@ -229,7 +229,7 @@ LL | | where LL | | T: Anything<'a, 'a>, | |________________________^ | - = note: defining type: one_region::<'_#1r, T> + = note: defining type: one_region::<'?1, T> error: aborting due to 3 previous errors diff --git a/tests/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr b/tests/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr index 2c4a0597554..04616f9b702 100644 --- a/tests/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr +++ b/tests/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr @@ -6,11 +6,11 @@ LL | twice(cell, value, |a, b| invoke(a, b)); | = note: defining type: generic::<T>::{closure#0} with closure substs [ i16, - for<Region(BrAnon(None)), Region(BrAnon(None))> extern "rust-call" fn((std::option::Option<std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) ()>>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) T)), + for<Region(BrAnon(None)), Region(BrAnon(None))> extern "rust-call" fn((std::option::Option<std::cell::Cell<&'?1 &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) ()>>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) T)), (), ] = note: number of external vids: 2 - = note: where T: '_#1r + = note: where T: '?1 note: no external requirements --> $DIR/ty-param-closure-approximate-lower-bound.rs:22:1 @@ -28,12 +28,12 @@ LL | twice(cell, value, |a, b| invoke(a, b)); | = note: defining type: generic_fail::<T>::{closure#0} with closure substs [ i16, - for<Region(BrAnon(None)), Region(BrAnon(None))> extern "rust-call" fn((std::option::Option<std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) ()>>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) T)), + for<Region(BrAnon(None)), Region(BrAnon(None))> extern "rust-call" fn((std::option::Option<std::cell::Cell<&'?1 &ReLateBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrAnon(None) }) ()>>, &ReLateBound(DebruijnIndex(0), BoundRegion { var: 1, kind: BrAnon(None) }) T)), (), ] - = note: late-bound region is '_#2r + = note: late-bound region is '?2 = note: number of external vids: 3 - = note: where T: '_#1r + = note: where T: '?1 note: no external requirements --> $DIR/ty-param-closure-approximate-lower-bound.rs:28:1 diff --git a/tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.rs b/tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.rs index 4343c3aee53..72b18c16732 100644 --- a/tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.rs +++ b/tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.rs @@ -19,8 +19,8 @@ where // Here, the closure winds up being required to prove that `T: // 'a`. In principle, it could know that, except that it is // type-checked in a fully generic way, and hence it winds up with - // a propagated requirement that `T: '_#2`, where `'_#2` appears - // in the return type. The caller makes the mapping from `'_#2` to + // a propagated requirement that `T: '?2`, where `'?2` appears + // in the return type. The caller makes the mapping from `'?2` to // `'a` (and subsequently reports an error). with_signature(x, |y| y) diff --git a/tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr b/tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr index 35979c8bf51..d580774ff8c 100644 --- a/tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr +++ b/tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr @@ -4,13 +4,13 @@ note: external requirements LL | with_signature(x, |y| y) | ^^^ | - = note: defining type: no_region::<'_#1r, T>::{closure#0} with closure substs [ + = note: defining type: no_region::<'?1, T>::{closure#0} with closure substs [ i32, - extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn std::fmt::Debug + '_#2r)>, + extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn std::fmt::Debug + '?2)>, (), ] = note: number of external vids: 3 - = note: where T: '_#2r + = note: where T: '?2 note: no external requirements --> $DIR/ty-param-closure-outlives-from-return-type.rs:15:1 @@ -20,7 +20,7 @@ LL | | where LL | | T: Debug, | |_____________^ | - = note: defining type: no_region::<'_#1r, T> + = note: defining type: no_region::<'?1, T> error[E0309]: the parameter type `T` may not live long enough --> $DIR/ty-param-closure-outlives-from-return-type.rs:26:27 diff --git a/tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr b/tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr index 4c97db58c6c..3d4c11a3c54 100644 --- a/tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr +++ b/tests/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr @@ -6,12 +6,12 @@ LL | with_signature(a, b, |x, y| { | = note: defining type: no_region::<T>::{closure#0} with closure substs [ i32, - extern "rust-call" fn((std::cell::Cell<&'_#1r ()>, T)), + extern "rust-call" fn((std::cell::Cell<&'?1 ()>, T)), (), ] - = note: late-bound region is '_#2r + = note: late-bound region is '?2 = note: number of external vids: 3 - = note: where T: '_#1r + = note: where T: '?1 note: no external requirements --> $DIR/ty-param-closure-outlives-from-where-clause.rs:26:1 @@ -38,13 +38,13 @@ note: external requirements LL | with_signature(a, b, |x, y| { | ^^^^^^ | - = note: defining type: correct_region::<'_#1r, T>::{closure#0} with closure substs [ + = note: defining type: correct_region::<'?1, T>::{closure#0} with closure substs [ i32, - extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), + extern "rust-call" fn((std::cell::Cell<&'?2 ()>, T)), (), ] = note: number of external vids: 3 - = note: where T: '_#2r + = note: where T: '?2 note: no external requirements --> $DIR/ty-param-closure-outlives-from-where-clause.rs:38:1 @@ -54,7 +54,7 @@ LL | | where LL | | T: 'a, | |__________^ | - = note: defining type: correct_region::<'_#1r, T> + = note: defining type: correct_region::<'?1, T> note: external requirements --> $DIR/ty-param-closure-outlives-from-where-clause.rs:63:26 @@ -62,14 +62,14 @@ note: external requirements LL | with_signature(a, b, |x, y| { | ^^^^^^ | - = note: defining type: wrong_region::<'_#1r, T>::{closure#0} with closure substs [ + = note: defining type: wrong_region::<'?1, T>::{closure#0} with closure substs [ i32, - extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), + extern "rust-call" fn((std::cell::Cell<&'?2 ()>, T)), (), ] - = note: late-bound region is '_#3r + = note: late-bound region is '?3 = note: number of external vids: 4 - = note: where T: '_#2r + = note: where T: '?2 note: no external requirements --> $DIR/ty-param-closure-outlives-from-where-clause.rs:59:1 @@ -79,7 +79,7 @@ LL | | where LL | | T: 'b, | |__________^ | - = note: defining type: wrong_region::<'_#1r, T> + = note: defining type: wrong_region::<'?1, T> error[E0309]: the parameter type `T` may not live long enough --> $DIR/ty-param-closure-outlives-from-where-clause.rs:65:9 @@ -98,13 +98,13 @@ note: external requirements LL | with_signature(a, b, |x, y| { | ^^^^^^ | - = note: defining type: outlives_region::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ + = note: defining type: outlives_region::<'?1, '?2, T>::{closure#0} with closure substs [ i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), + extern "rust-call" fn((std::cell::Cell<&'?3 ()>, T)), (), ] = note: number of external vids: 4 - = note: where T: '_#3r + = note: where T: '?3 note: no external requirements --> $DIR/ty-param-closure-outlives-from-where-clause.rs:71:1 @@ -115,7 +115,7 @@ LL | | T: 'b, LL | | 'b: 'a, | |___________^ | - = note: defining type: outlives_region::<'_#1r, '_#2r, T> + = note: defining type: outlives_region::<'?1, '?2, T> error: aborting due to 2 previous errors diff --git a/tests/ui/oom_unwind.rs b/tests/ui/oom_unwind.rs index 704d6f8b810..21a8fb2b22b 100644 --- a/tests/ui/oom_unwind.rs +++ b/tests/ui/oom_unwind.rs @@ -1,4 +1,4 @@ -// compile-flags: -Z oom=unwind +// compile-flags: -Z oom=panic // run-pass // no-prefer-dynamic // needs-unwind diff --git a/tests/ui/repr/repr-transparent.stderr b/tests/ui/repr/repr-transparent.stderr index f1c570b9523..cb1e2337776 100644 --- a/tests/ui/repr/repr-transparent.stderr +++ b/tests/ui/repr/repr-transparent.stderr @@ -58,7 +58,7 @@ error[E0731]: transparent enum needs exactly one variant, but has 2 LL | enum MultipleVariants { | ^^^^^^^^^^^^^^^^^^^^^ needs exactly one variant, but has 2 LL | Foo(String), - | --- + | --- variant here LL | Bar, | --- too many variants in `MultipleVariants` diff --git a/tests/ui/repr/transparent-enum-too-many-variants.stderr b/tests/ui/repr/transparent-enum-too-many-variants.stderr index fb44757efaf..1a500257f48 100644 --- a/tests/ui/repr/transparent-enum-too-many-variants.stderr +++ b/tests/ui/repr/transparent-enum-too-many-variants.stderr @@ -5,6 +5,8 @@ LL | enum Foo { | ^^^^^^^^ needs exactly one variant, but has 2 LL | A(u8), B(u8), | - - too many variants in `Foo` + | | + | variant here error: aborting due to previous error diff --git a/tests/ui/traits/infer-from-object-issue-26952.rs b/tests/ui/traits/infer-from-object-issue-26952.rs index ed258dbb24c..9544b4f2088 100644 --- a/tests/ui/traits/infer-from-object-issue-26952.rs +++ b/tests/ui/traits/infer-from-object-issue-26952.rs @@ -1,8 +1,8 @@ // run-pass #![allow(dead_code)] #![allow(unused_variables)] -// Test that when we match a trait reference like `Foo<A>: Foo<_#0t>`, -// we unify with `_#0t` with `A`. In this code, if we failed to do +// Test that when we match a trait reference like `Foo<A>: Foo<?0t>`, +// we unify with `?0t` with `A`. In this code, if we failed to do // that, then you get an unconstrained type-variable in `call`. // // Also serves as a regression test for issue #26952, though the test diff --git a/tests/ui/traits/new-solver/int-var-alias-eq.rs b/tests/ui/traits/new-solver/int-var-alias-eq.rs index 2da387db4a9..790197e2d97 100644 --- a/tests/ui/traits/new-solver/int-var-alias-eq.rs +++ b/tests/ui/traits/new-solver/int-var-alias-eq.rs @@ -1,7 +1,7 @@ // check-pass // compile-flags: -Ztrait-solver=next -// HIR typeck ends up equating `<_#0i as Add>::Output == _#0i`. +// HIR typeck ends up equating `<?0i as Add>::Output == ?0i`. // Want to make sure that we emit an alias-eq goal for this, // instead of treating it as a type error and bailing. diff --git a/tests/ui/traits/new-solver/negative-coherence-bounds.rs b/tests/ui/traits/new-solver/negative-coherence-bounds.rs new file mode 100644 index 00000000000..5436b02c3de --- /dev/null +++ b/tests/ui/traits/new-solver/negative-coherence-bounds.rs @@ -0,0 +1,40 @@ +// check-pass + +// This test verifies that negative trait predicate cannot be satisfied from a +// positive param-env candidate. + +// Negative coherence is one of the only places where we actually construct and +// evaluate negative predicates. Specifically, when verifying whether the first +// and second impls below overlap, we do not want to consider them disjoint, +// otherwise the second impl would be missing an associated type `type Item` +// which is provided by the first impl that it is specializing. + +#![feature(specialization)] +//~^ WARN the feature `specialization` is incomplete +#![feature(with_negative_coherence)] + +trait BoxIter { + type Item; + + fn last(self) -> Option<Self::Item>; +} + +impl<I: Iterator + ?Sized> BoxIter for Box<I> { + type Item = I::Item; + + default fn last(self) -> Option<I::Item> { + todo!() + } +} + +// When checking that this impl does/doesn't overlap the one above, we evaluate +// a negative version of all of the where-clause predicates of the impl below. +// For `I: !Iterator`, we should make sure that the param-env clause `I: Iterator` +// from above doesn't satisfy this predicate. +impl<I: Iterator> BoxIter for Box<I> { + fn last(self) -> Option<I::Item> { + (*self).last() + } +} + +fn main() {} diff --git a/tests/ui/traits/new-solver/negative-coherence-bounds.stderr b/tests/ui/traits/new-solver/negative-coherence-bounds.stderr new file mode 100644 index 00000000000..4127f51f56d --- /dev/null +++ b/tests/ui/traits/new-solver/negative-coherence-bounds.stderr @@ -0,0 +1,12 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/negative-coherence-bounds.rs:12:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/traits/new-solver/two-projection-param-candidates-are-ambiguous.rs b/tests/ui/traits/new-solver/two-projection-param-candidates-are-ambiguous.rs index cde2059ca9b..3c7fc0d813d 100644 --- a/tests/ui/traits/new-solver/two-projection-param-candidates-are-ambiguous.rs +++ b/tests/ui/traits/new-solver/two-projection-param-candidates-are-ambiguous.rs @@ -1,7 +1,7 @@ // compile-flags: -Ztrait-solver=next // When we're solving `<T as Foo>::Assoc = i32`, we actually first solve -// `<T as Foo>::Assoc = _#1t`, then unify `_#1t` with `i32`. That goal +// `<T as Foo>::Assoc = ?1t`, then unify `?1t` with `i32`. That goal // with the inference variable is ambiguous when there are >1 param-env // candidates. diff --git a/tests/ui/type-alias-impl-trait/closure_parent_substs.rs b/tests/ui/type-alias-impl-trait/closure_parent_substs.rs index 475f4724ff2..3ff20d99ad8 100644 --- a/tests/ui/type-alias-impl-trait/closure_parent_substs.rs +++ b/tests/ui/type-alias-impl-trait/closure_parent_substs.rs @@ -12,7 +12,7 @@ // Basic test mod test1 { - // Hidden type = Closure['_#0r] + // Hidden type = Closure['?0] type Opaque = impl Sized; fn define<'a: 'a>() -> Opaque { @@ -24,8 +24,8 @@ mod test1 { mod test2 { trait Trait {} - // Hidden type = Closure['a, '_#0r, '_#1r] - // Constraints = [('_#0r: 'a), ('a: '_#1r)] + // Hidden type = Closure['a, '?0, '?1] + // Constraints = [('?0: 'a), ('a: '?1)] type Opaque<'a> where &'a (): Trait, @@ -45,8 +45,8 @@ mod test2 { mod test3 { trait Trait {} - // Hidden type = Closure['a, 'b, '_#0r] - // Constraints = [('_#0r: 'a), ('_#0r: 'b)] + // Hidden type = Closure['a, 'b, '?0] + // Constraints = [('?0: 'a), ('?0: 'b)] type Opaque<'a, 'b> where (&'a (), &'b ()): Trait, |
