diff options
59 files changed, 782 insertions, 682 deletions
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index c1b3f34e5a6..e2a592d851a 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -176,15 +176,14 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>( return_if_di_node_created_in_meantime!(cx, unique_type_id); - let (thin_pointer_size, thin_pointer_align) = - cx.size_and_align_of(cx.tcx.mk_imm_ptr(cx.tcx.types.unit)); + let data_layout = &cx.tcx.data_layout; let ptr_type_debuginfo_name = compute_debuginfo_type_name(cx.tcx, ptr_type, true); match fat_pointer_kind(cx, pointee_type) { None => { // This is a thin pointer. Create a regular pointer type and give it the correct name. debug_assert_eq!( - (thin_pointer_size, thin_pointer_align), + (data_layout.pointer_size, data_layout.pointer_align.abi), cx.size_and_align_of(ptr_type), "ptr_type={}, pointee_type={}", ptr_type, @@ -195,8 +194,8 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>( llvm::LLVMRustDIBuilderCreatePointerType( DIB(cx), pointee_type_di_node, - thin_pointer_size.bits(), - thin_pointer_align.bits() as u32, + data_layout.pointer_size.bits(), + data_layout.pointer_align.abi.bits() as u32, 0, // Ignore DWARF address space. ptr_type_debuginfo_name.as_ptr().cast(), ptr_type_debuginfo_name.len(), diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 037b07dec62..57856b4ddb1 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -10,6 +10,7 @@ use rustc_middle::mir::mono::Linkage; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self as ty, TyCtxt}; use rustc_session::{lint, parse::feature_err}; +use rustc_span::symbol::Ident; use rustc_span::{sym, Span}; use rustc_target::spec::{abi, SanitizerSet}; @@ -83,336 +84,368 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } }; - if attr.has_name(sym::cold) { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD; - } else if attr.has_name(sym::rustc_allocator) { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR; - } else if attr.has_name(sym::ffi_returns_twice) { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_RETURNS_TWICE; - } else if attr.has_name(sym::ffi_pure) { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_PURE; - } else if attr.has_name(sym::ffi_const) { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_CONST; - } else if attr.has_name(sym::rustc_nounwind) { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND; - } else if attr.has_name(sym::rustc_reallocator) { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::REALLOCATOR; - } else if attr.has_name(sym::rustc_deallocator) { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::DEALLOCATOR; - } else if attr.has_name(sym::rustc_allocator_zeroed) { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED; - } else if attr.has_name(sym::naked) { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED; - } else if attr.has_name(sym::no_mangle) { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE; - } else if attr.has_name(sym::no_coverage) { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_COVERAGE; - } else if attr.has_name(sym::rustc_std_internal_symbol) { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL; - } else if attr.has_name(sym::used) { - let inner = attr.meta_item_list(); - match inner.as_deref() { - Some([item]) if item.has_name(sym::linker) => { - if !tcx.features().used_with_arg { - feature_err( - &tcx.sess.parse_sess, - sym::used_with_arg, - attr.span, - "`#[used(linker)]` is currently unstable", - ) - .emit(); - } - codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER; - } - Some([item]) if item.has_name(sym::compiler) => { - if !tcx.features().used_with_arg { - feature_err( - &tcx.sess.parse_sess, - sym::used_with_arg, - attr.span, - "`#[used(compiler)]` is currently unstable", - ) - .emit(); - } - codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED; - } - Some(_) => { - tcx.sess.emit_err(ExpectedUsedSymbol { span: attr.span }); - } - None => { - // Unfortunately, unconditionally using `llvm.used` causes - // issues in handling `.init_array` with the gold linker, - // but using `llvm.compiler.used` caused a nontrival amount - // of unintentional ecosystem breakage -- particularly on - // Mach-O targets. - // - // As a result, we emit `llvm.compiler.used` only on ELF - // targets. This is somewhat ad-hoc, but actually follows - // our pre-LLVM 13 behavior (prior to the ecosystem - // breakage), and seems to match `clang`'s behavior as well - // (both before and after LLVM 13), possibly because they - // have similar compatibility concerns to us. See - // https://github.com/rust-lang/rust/issues/47384#issuecomment-1019080146 - // and following comments for some discussion of this, as - // well as the comments in `rustc_codegen_llvm` where these - // flags are handled. - // - // Anyway, to be clear: this is still up in the air - // somewhat, and is subject to change in the future (which - // is a good thing, because this would ideally be a bit - // more firmed up). - let is_like_elf = !(tcx.sess.target.is_like_osx - || tcx.sess.target.is_like_windows - || tcx.sess.target.is_like_wasm); - codegen_fn_attrs.flags |= if is_like_elf { - CodegenFnAttrFlags::USED - } else { - CodegenFnAttrFlags::USED_LINKER - }; - } + let Some(Ident { name, .. }) = attr.ident() else { + continue; + }; + + match name { + sym::cold => { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD; } - } else if attr.has_name(sym::cmse_nonsecure_entry) { - if let Some(fn_sig) = fn_sig() - && !matches!(fn_sig.skip_binder().abi(), abi::Abi::C { .. }) - { - struct_span_err!( - tcx.sess, - attr.span, - E0776, - "`#[cmse_nonsecure_entry]` requires C ABI" - ) - .emit(); + sym::rustc_allocator => { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR; } - if !tcx.sess.target.llvm_target.contains("thumbv8m") { - struct_span_err!(tcx.sess, attr.span, E0775, "`#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension") - .emit(); + sym::ffi_returns_twice => { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_RETURNS_TWICE; } - codegen_fn_attrs.flags |= CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY; - } else if attr.has_name(sym::thread_local) { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL; - } else if attr.has_name(sym::track_caller) { - if !tcx.is_closure(did.to_def_id()) - && let Some(fn_sig) = fn_sig() - && fn_sig.skip_binder().abi() != abi::Abi::Rust - { - struct_span_err!(tcx.sess, attr.span, E0737, "`#[track_caller]` requires Rust ABI") - .emit(); + sym::ffi_pure => { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_PURE; } - if tcx.is_closure(did.to_def_id()) && !tcx.features().closure_track_caller { - feature_err( - &tcx.sess.parse_sess, - sym::closure_track_caller, - attr.span, - "`#[track_caller]` on closures is currently unstable", - ) - .emit(); + sym::ffi_const => { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_CONST; + } + sym::rustc_nounwind => { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND; + } + sym::rustc_reallocator => { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::REALLOCATOR; + } + sym::rustc_deallocator => { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::DEALLOCATOR; + } + sym::rustc_allocator_zeroed => { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED; + } + sym::naked => { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED; + } + sym::no_mangle => { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE; + } + sym::no_coverage => { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_COVERAGE; + } + sym::rustc_std_internal_symbol => { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL; + } + sym::used => { + let inner = attr.meta_item_list(); + match inner.as_deref() { + Some([item]) if item.has_name(sym::linker) => { + if !tcx.features().used_with_arg { + feature_err( + &tcx.sess.parse_sess, + sym::used_with_arg, + attr.span, + "`#[used(linker)]` is currently unstable", + ) + .emit(); + } + codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER; + } + Some([item]) if item.has_name(sym::compiler) => { + if !tcx.features().used_with_arg { + feature_err( + &tcx.sess.parse_sess, + sym::used_with_arg, + attr.span, + "`#[used(compiler)]` is currently unstable", + ) + .emit(); + } + codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED; + } + Some(_) => { + tcx.sess.emit_err(ExpectedUsedSymbol { span: attr.span }); + } + None => { + // Unfortunately, unconditionally using `llvm.used` causes + // issues in handling `.init_array` with the gold linker, + // but using `llvm.compiler.used` caused a nontrival amount + // of unintentional ecosystem breakage -- particularly on + // Mach-O targets. + // + // As a result, we emit `llvm.compiler.used` only on ELF + // targets. This is somewhat ad-hoc, but actually follows + // our pre-LLVM 13 behavior (prior to the ecosystem + // breakage), and seems to match `clang`'s behavior as well + // (both before and after LLVM 13), possibly because they + // have similar compatibility concerns to us. See + // https://github.com/rust-lang/rust/issues/47384#issuecomment-1019080146 + // and following comments for some discussion of this, as + // well as the comments in `rustc_codegen_llvm` where these + // flags are handled. + // + // Anyway, to be clear: this is still up in the air + // somewhat, and is subject to change in the future (which + // is a good thing, because this would ideally be a bit + // more firmed up). + let is_like_elf = !(tcx.sess.target.is_like_osx + || tcx.sess.target.is_like_windows + || tcx.sess.target.is_like_wasm); + codegen_fn_attrs.flags |= if is_like_elf { + CodegenFnAttrFlags::USED + } else { + CodegenFnAttrFlags::USED_LINKER + }; + } + } } - codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER; - } else if attr.has_name(sym::export_name) { - if let Some(s) = attr.value_str() { - if s.as_str().contains('\0') { - // `#[export_name = ...]` will be converted to a null-terminated string, - // so it may not contain any null characters. + sym::cmse_nonsecure_entry => { + if let Some(fn_sig) = fn_sig() + && !matches!(fn_sig.skip_binder().abi(), abi::Abi::C { .. }) + { struct_span_err!( tcx.sess, attr.span, - E0648, - "`export_name` may not contain null characters" + E0776, + "`#[cmse_nonsecure_entry]` requires C ABI" ) .emit(); } - codegen_fn_attrs.export_name = Some(s); - } - } else if attr.has_name(sym::target_feature) { - if !tcx.is_closure(did.to_def_id()) - && let Some(fn_sig) = fn_sig() - && fn_sig.skip_binder().unsafety() == hir::Unsafety::Normal - { - if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc { - // The `#[target_feature]` attribute is allowed on - // WebAssembly targets on all functions, including safe - // ones. Other targets require that `#[target_feature]` is - // only applied to unsafe functions (pending the - // `target_feature_11` feature) because on most targets - // execution of instructions that are not supported is - // considered undefined behavior. For WebAssembly which is a - // 100% safe target at execution time it's not possible to - // execute undefined instructions, and even if a future - // feature was added in some form for this it would be a - // deterministic trap. There is no undefined behavior when - // executing WebAssembly so `#[target_feature]` is allowed - // on safe functions (but again, only for WebAssembly) - // - // Note that this is also allowed if `actually_rustdoc` so - // if a target is documenting some wasm-specific code then - // it's not spuriously denied. - // - // This exception needs to be kept in sync with allowing - // `#[target_feature]` on `main` and `start`. - } else if !tcx.features().target_feature_11 { - let mut err = feature_err( + if !tcx.sess.target.llvm_target.contains("thumbv8m") { + struct_span_err!(tcx.sess, attr.span, E0775, "`#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension") + .emit(); + } + codegen_fn_attrs.flags |= CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY; + } + sym::thread_local => { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL; + } + sym::track_caller => { + if !tcx.is_closure(did.to_def_id()) + && let Some(fn_sig) = fn_sig() + && fn_sig.skip_binder().abi() != abi::Abi::Rust + { + struct_span_err!(tcx.sess, attr.span, E0737, "`#[track_caller]` requires Rust ABI") + .emit(); + } + if tcx.is_closure(did.to_def_id()) && !tcx.features().closure_track_caller { + feature_err( &tcx.sess.parse_sess, - sym::target_feature_11, + sym::closure_track_caller, attr.span, - "`#[target_feature(..)]` can only be applied to `unsafe` functions", - ); - err.span_label(tcx.def_span(did), "not an `unsafe` function"); - err.emit(); - } else { - check_target_feature_trait_unsafe(tcx, did, attr.span); + "`#[track_caller]` on closures is currently unstable", + ) + .emit(); } + codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER; } - from_target_feature( - tcx, - attr, - supported_target_features, - &mut codegen_fn_attrs.target_features, - ); - } else if attr.has_name(sym::linkage) { - if let Some(val) = attr.value_str() { - let linkage = Some(linkage_by_name(tcx, did, val.as_str())); - if tcx.is_foreign_item(did) { - codegen_fn_attrs.import_linkage = linkage; - } else { - codegen_fn_attrs.linkage = linkage; + sym::export_name => { + if let Some(s) = attr.value_str() { + if s.as_str().contains('\0') { + // `#[export_name = ...]` will be converted to a null-terminated string, + // so it may not contain any null characters. + struct_span_err!( + tcx.sess, + attr.span, + E0648, + "`export_name` may not contain null characters" + ) + .emit(); + } + codegen_fn_attrs.export_name = Some(s); } } - } else if attr.has_name(sym::link_section) { - if let Some(val) = attr.value_str() { - if val.as_str().bytes().any(|b| b == 0) { - let msg = format!( - "illegal null byte in link_section \ - value: `{}`", - &val - ); - tcx.sess.span_err(attr.span, &msg); - } else { - codegen_fn_attrs.link_section = Some(val); + sym::target_feature => { + if !tcx.is_closure(did.to_def_id()) + && let Some(fn_sig) = fn_sig() + && fn_sig.skip_binder().unsafety() == hir::Unsafety::Normal + { + if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc { + // The `#[target_feature]` attribute is allowed on + // WebAssembly targets on all functions, including safe + // ones. Other targets require that `#[target_feature]` is + // only applied to unsafe functions (pending the + // `target_feature_11` feature) because on most targets + // execution of instructions that are not supported is + // considered undefined behavior. For WebAssembly which is a + // 100% safe target at execution time it's not possible to + // execute undefined instructions, and even if a future + // feature was added in some form for this it would be a + // deterministic trap. There is no undefined behavior when + // executing WebAssembly so `#[target_feature]` is allowed + // on safe functions (but again, only for WebAssembly) + // + // Note that this is also allowed if `actually_rustdoc` so + // if a target is documenting some wasm-specific code then + // it's not spuriously denied. + // + // This exception needs to be kept in sync with allowing + // `#[target_feature]` on `main` and `start`. + } else if !tcx.features().target_feature_11 { + let mut err = feature_err( + &tcx.sess.parse_sess, + sym::target_feature_11, + attr.span, + "`#[target_feature(..)]` can only be applied to `unsafe` functions", + ); + err.span_label(tcx.def_span(did), "not an `unsafe` function"); + err.emit(); + } else { + check_target_feature_trait_unsafe(tcx, did, attr.span); + } + } + from_target_feature( + tcx, + attr, + supported_target_features, + &mut codegen_fn_attrs.target_features, + ); + } + sym::linkage => { + if let Some(val) = attr.value_str() { + let linkage = Some(linkage_by_name(tcx, did, val.as_str())); + if tcx.is_foreign_item(did) { + codegen_fn_attrs.import_linkage = linkage; + } else { + codegen_fn_attrs.linkage = linkage; + } } } - } else if attr.has_name(sym::link_name) { - codegen_fn_attrs.link_name = attr.value_str(); - } else if attr.has_name(sym::link_ordinal) { - link_ordinal_span = Some(attr.span); - if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) { - codegen_fn_attrs.link_ordinal = ordinal; - } - } else if attr.has_name(sym::no_sanitize) { - no_sanitize_span = Some(attr.span); - if let Some(list) = attr.meta_item_list() { - for item in list.iter() { - if item.has_name(sym::address) { - codegen_fn_attrs.no_sanitize |= - SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS; - } else if item.has_name(sym::cfi) { - codegen_fn_attrs.no_sanitize |= SanitizerSet::CFI; - } else if item.has_name(sym::kcfi) { - codegen_fn_attrs.no_sanitize |= SanitizerSet::KCFI; - } else if item.has_name(sym::memory) { - codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY; - } else if item.has_name(sym::memtag) { - codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMTAG; - } else if item.has_name(sym::shadow_call_stack) { - codegen_fn_attrs.no_sanitize |= SanitizerSet::SHADOWCALLSTACK; - } else if item.has_name(sym::thread) { - codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD; - } else if item.has_name(sym::hwaddress) { - codegen_fn_attrs.no_sanitize |= SanitizerSet::HWADDRESS; + sym::link_section => { + if let Some(val) = attr.value_str() { + if val.as_str().bytes().any(|b| b == 0) { + let msg = format!( + "illegal null byte in link_section \ + value: `{}`", + &val + ); + tcx.sess.span_err(attr.span, &msg); } else { - tcx.sess - .struct_span_err(item.span(), "invalid argument for `no_sanitize`") - .note("expected one of: `address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow-call-stack`, or `thread`") - .emit(); + codegen_fn_attrs.link_section = Some(val); } } } - } else if attr.has_name(sym::instruction_set) { - codegen_fn_attrs.instruction_set = attr.meta_item_list().and_then(|l| match &l[..] { - [NestedMetaItem::MetaItem(set)] => { - let segments = - set.path.segments.iter().map(|x| x.ident.name).collect::<Vec<_>>(); - match segments.as_slice() { - [sym::arm, sym::a32] | [sym::arm, sym::t32] => { - if !tcx.sess.target.has_thumb_interworking { - struct_span_err!( - tcx.sess.diagnostic(), - attr.span, - E0779, - "target does not support `#[instruction_set]`" - ) + sym::link_name => { + codegen_fn_attrs.link_name = attr.value_str(); + } + sym::link_ordinal => { + link_ordinal_span = Some(attr.span); + if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) { + codegen_fn_attrs.link_ordinal = ordinal; + } + } + sym::no_sanitize => { + no_sanitize_span = Some(attr.span); + if let Some(list) = attr.meta_item_list() { + for item in list.iter() { + match item.ident().map(|ident| ident.name) { + Some(sym::address) => { + codegen_fn_attrs.no_sanitize |= + SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS; + } + Some(sym::cfi) => { + codegen_fn_attrs.no_sanitize |= SanitizerSet::CFI; + } + Some(sym::kcfi) => { + codegen_fn_attrs.no_sanitize |= SanitizerSet::KCFI; + } + Some(sym::memory) => { + codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY; + } + Some(sym::memtag) => { + codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMTAG; + } + Some(sym::shadow_call_stack) => { + codegen_fn_attrs.no_sanitize |= SanitizerSet::SHADOWCALLSTACK; + } + Some(sym::thread) => { + codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD; + } + Some(sym::hwaddress) => { + codegen_fn_attrs.no_sanitize |= SanitizerSet::HWADDRESS; + } + _ => { + tcx.sess + .struct_span_err(item.span(), "invalid argument for `no_sanitize`") + .note("expected one of: `address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow-call-stack`, or `thread`") .emit(); - None - } else if segments[1] == sym::a32 { - Some(InstructionSetAttr::ArmA32) - } else if segments[1] == sym::t32 { - Some(InstructionSetAttr::ArmT32) - } else { - unreachable!() } } - _ => { - struct_span_err!( - tcx.sess.diagnostic(), - attr.span, - E0779, - "invalid instruction set specified", - ) - .emit(); - None - } } } - [] => { - struct_span_err!( - tcx.sess.diagnostic(), - attr.span, - E0778, - "`#[instruction_set]` requires an argument" - ) - .emit(); - None - } - _ => { - struct_span_err!( - tcx.sess.diagnostic(), - attr.span, - E0779, - "cannot specify more than one instruction set" - ) - .emit(); - None - } - }) - } else if attr.has_name(sym::repr) { - codegen_fn_attrs.alignment = match attr.meta_item_list() { - Some(items) => match items.as_slice() { - [item] => match item.name_value_literal() { - Some((sym::align, literal)) => { - let alignment = rustc_attr::parse_alignment(&literal.kind); - - match alignment { - Ok(align) => Some(align), - Err(msg) => { + } + sym::instruction_set => { + codegen_fn_attrs.instruction_set = + attr.meta_item_list().and_then(|l| match &l[..] { + [NestedMetaItem::MetaItem(set)] => { + let segments = + set.path.segments.iter().map(|x| x.ident.name).collect::<Vec<_>>(); + match segments.as_slice() { + [sym::arm, sym::a32] | [sym::arm, sym::t32] => { + if !tcx.sess.target.has_thumb_interworking { + struct_span_err!( + tcx.sess.diagnostic(), + attr.span, + E0779, + "target does not support `#[instruction_set]`" + ) + .emit(); + None + } else if segments[1] == sym::a32 { + Some(InstructionSetAttr::ArmA32) + } else if segments[1] == sym::t32 { + Some(InstructionSetAttr::ArmT32) + } else { + unreachable!() + } + } + _ => { struct_span_err!( tcx.sess.diagnostic(), attr.span, - E0589, - "invalid `repr(align)` attribute: {}", - msg + E0779, + "invalid instruction set specified", ) .emit(); - None } } } - _ => None, - }, - [] => None, - _ => None, - }, - None => None, - }; + [] => { + struct_span_err!( + tcx.sess.diagnostic(), + attr.span, + E0778, + "`#[instruction_set]` requires an argument" + ) + .emit(); + None + } + _ => { + struct_span_err!( + tcx.sess.diagnostic(), + attr.span, + E0779, + "cannot specify more than one instruction set" + ) + .emit(); + None + } + }) + } + sym::repr => { + codegen_fn_attrs.alignment = if let Some(items) = attr.meta_item_list() + && let [item] = items.as_slice() + && let Some((sym::align, literal)) = item.name_value_literal() + { + rustc_attr::parse_alignment(&literal.kind).map_err(|msg| { + struct_span_err!( + tcx.sess.diagnostic(), + attr.span, + E0589, + "invalid `repr(align)` attribute: {}", + msg + ) + .emit(); + }) + .ok() + } else { + None + }; + } + _ => {} } } diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 5da0e826c56..2d647f5d7f2 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -397,8 +397,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { PassMode::Cast(cast_ty, _) => { let op = match self.locals[mir::RETURN_PLACE] { - LocalRef::Operand(Some(op)) => op, - LocalRef::Operand(None) => bug!("use of return before def"), + LocalRef::Operand(op) => op, + LocalRef::PendingOperand => bug!("use of return before def"), LocalRef::Place(cg_place) => OperandRef { val: Ref(cg_place.llval, None, cg_place.align), layout: cg_place.layout, @@ -1673,7 +1673,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { match self.locals[index] { LocalRef::Place(dest) => dest, LocalRef::UnsizedPlace(_) => bug!("return type must be sized"), - LocalRef::Operand(None) => { + LocalRef::PendingOperand => { // Handle temporary places, specifically `Operand` ones, as // they don't have `alloca`s. return if fn_ret.is_indirect() { @@ -1694,7 +1694,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ReturnDest::DirectOperand(index) }; } - LocalRef::Operand(Some(_)) => { + LocalRef::Operand(_) => { bug!("place local already assigned to"); } } @@ -1737,7 +1737,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { IndirectOperand(tmp, index) => { let op = bx.load_operand(tmp); tmp.storage_dead(bx); - self.locals[index] = LocalRef::Operand(Some(op)); + self.locals[index] = LocalRef::Operand(op); self.debug_introduce_local(bx, index); } DirectOperand(index) => { @@ -1752,7 +1752,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } else { OperandRef::from_immediate_or_packed_pair(bx, llval, ret_abi.layout) }; - self.locals[index] = LocalRef::Operand(Some(op)); + self.locals[index] = LocalRef::Operand(op); self.debug_introduce_local(bx, index); } } diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 6e32c28a42c..d15774696a5 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -312,7 +312,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { LocalRef::Place(place) | LocalRef::UnsizedPlace(place) => { bx.set_var_name(place.llval, name); } - LocalRef::Operand(Some(operand)) => match operand.val { + LocalRef::Operand(operand) => match operand.val { OperandValue::Ref(x, ..) | OperandValue::Immediate(x) => { bx.set_var_name(x, name); } @@ -323,7 +323,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.set_var_name(b, &(name.clone() + ".1")); } }, - LocalRef::Operand(None) => {} + LocalRef::PendingOperand => {} } } @@ -332,9 +332,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } let base = match local_ref { - LocalRef::Operand(None) => return, + LocalRef::PendingOperand => return, - LocalRef::Operand(Some(operand)) => { + LocalRef::Operand(operand) => { // Don't spill operands onto the stack in naked functions. // See: https://github.com/rust-lang/rust/issues/42779 let attrs = bx.tcx().codegen_fn_attrs(self.instance.def_id()); diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 5cffca5230a..189549953d9 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -123,7 +123,10 @@ enum LocalRef<'tcx, V> { /// Every time it is initialized, we have to reallocate the place /// and update the fat pointer. That's the reason why it is indirect. UnsizedPlace(PlaceRef<'tcx, V>), - Operand(Option<OperandRef<'tcx, V>>), + /// The backend [`OperandValue`] has already been generated. + Operand(OperandRef<'tcx, V>), + /// Will be a `Self::Operand` once we get to its definition. + PendingOperand, } impl<'a, 'tcx, V: CodegenObject> LocalRef<'tcx, V> { @@ -135,9 +138,9 @@ impl<'a, 'tcx, V: CodegenObject> LocalRef<'tcx, V> { // Zero-size temporaries aren't always initialized, which // doesn't matter because they don't contain data, but // we need something in the operand. - LocalRef::Operand(Some(OperandRef::new_zst(bx, layout))) + LocalRef::Operand(OperandRef::new_zst(bx, layout)) } else { - LocalRef::Operand(None) + LocalRef::PendingOperand } } } @@ -337,7 +340,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // We don't have to cast or keep the argument in the alloca. // FIXME(eddyb): We should figure out how to use llvm.dbg.value instead // of putting everything in allocas just so we can use llvm.dbg.declare. - let local = |op| LocalRef::Operand(Some(op)); + let local = |op| LocalRef::Operand(op); match arg.mode { PassMode::Ignore => { return local(OperandRef::new_zst(bx, arg.layout)); diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 25721f75583..b45e7c834e7 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -370,7 +370,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { debug!("maybe_codegen_consume_direct(place_ref={:?})", place_ref); match self.locals[place_ref.local] { - LocalRef::Operand(Some(mut o)) => { + LocalRef::Operand(mut o) => { // Moves out of scalar and scalar pair fields are trivial. for elem in place_ref.projection.iter() { match elem { @@ -395,7 +395,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { Some(o) } - LocalRef::Operand(None) => { + LocalRef::PendingOperand => { bug!("use of {:?} before def", place_ref); } LocalRef::Place(..) | LocalRef::UnsizedPlace(..) => { diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index f6523a448e3..1633cfef19d 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -558,6 +558,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bug!("using operand local {:?} as place", place_ref); } } + LocalRef::PendingOperand => { + bug!("using still-pending operand local {:?} as place", place_ref); + } }; for elem in place_ref.projection[base..].iter() { cg_base = match *elem { diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 4bc4fdab59e..d867d6b0cd4 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -545,7 +545,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // ZST are passed as operands and require special handling // because codegen_place() panics if Local is operand. if let Some(index) = place.as_local() { - if let LocalRef::Operand(Some(op)) = self.locals[index] { + if let LocalRef::Operand(op) = self.locals[index] { if let ty::Array(_, n) = op.layout.ty.kind() { let n = n.eval_target_usize(bx.cx().tcx(), ty::ParamEnv::reveal_all()); return bx.cx().const_usize(n); diff --git a/compiler/rustc_codegen_ssa/src/mir/statement.rs b/compiler/rustc_codegen_ssa/src/mir/statement.rs index 41f585f7fcc..3fd7397ad38 100644 --- a/compiler/rustc_codegen_ssa/src/mir/statement.rs +++ b/compiler/rustc_codegen_ssa/src/mir/statement.rs @@ -18,12 +18,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { LocalRef::UnsizedPlace(cg_indirect_dest) => { self.codegen_rvalue_unsized(bx, cg_indirect_dest, rvalue) } - LocalRef::Operand(None) => { + LocalRef::PendingOperand => { let operand = self.codegen_rvalue_operand(bx, rvalue); - self.locals[index] = LocalRef::Operand(Some(operand)); + self.locals[index] = LocalRef::Operand(operand); self.debug_introduce_local(bx, index); } - LocalRef::Operand(Some(op)) => { + LocalRef::Operand(op) => { if !op.layout.is_zst() { span_bug!( statement.source_info.span, diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 6d9dfe9697c..4ab6bb5908b 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -1427,13 +1427,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { for (base_trait_ref, span, constness) in regular_traits_refs_spans { assert_eq!(constness, ty::BoundConstness::NotConst); - for obligation in traits::elaborate_trait_ref(tcx, base_trait_ref) { - debug!( - "conv_object_ty_poly_trait_ref: observing object predicate `{:?}`", - obligation.predicate - ); + for pred in traits::elaborate_trait_ref(tcx, base_trait_ref) { + debug!("conv_object_ty_poly_trait_ref: observing object predicate `{:?}`", pred); - let bound_predicate = obligation.predicate.kind(); + let bound_predicate = pred.kind(); match bound_predicate.skip_binder() { ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => { let pred = bound_predicate.rebind(pred); diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 491bd04f346..c912a8a640d 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1912,14 +1912,13 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { // Check elaborated bounds. let implied_obligations = traits::elaborate_predicates_with_span(tcx, predicates_with_span); - for obligation in implied_obligations { + for (pred, obligation_span) in implied_obligations { // We lower empty bounds like `Vec<dyn Copy>:` as // `WellFormed(Vec<dyn Copy>)`, which will later get checked by // regular WF checking - if let ty::PredicateKind::WellFormed(..) = obligation.predicate.kind().skip_binder() { + if let ty::PredicateKind::WellFormed(..) = pred.kind().skip_binder() { continue; } - let pred = obligation.predicate; // Match the existing behavior. if pred.is_global() && !pred.has_late_bound_vars() { let pred = self.normalize(span, None, pred); @@ -1930,8 +1929,6 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { if let Some(hir::Generics { predicates, .. }) = hir_node.and_then(|node| node.generics()) { - let obligation_span = obligation.cause.span(); - span = predicates .iter() // There seems to be no better way to find out which predicate we are in diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index aa66d7bb5ef..d2e45c28658 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -130,12 +130,9 @@ 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_predicates( - tcx, - tcx.explicit_item_bounds(def_id).iter().map(|&(bound, _span)| bound), - ) - .map(|obligation| obligation.predicate), - ); + let bounds = tcx.mk_predicates_from_iter(util::elaborate_predicates( + tcx, + tcx.explicit_item_bounds(def_id).iter().map(|&(bound, _span)| bound), + )); ty::EarlyBinder(bounds) } diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index 7f1e4ccc964..dfa9e6148aa 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -318,16 +318,8 @@ fn check_predicates<'tcx>( span: Span, ) { let instantiated = tcx.predicates_of(impl1_def_id).instantiate(tcx, impl1_substs); - let impl1_predicates: Vec<_> = traits::elaborate_predicates_with_span( - tcx, - std::iter::zip( - instantiated.predicates, - // Don't drop predicates (unsound!) because `spans` is too short - instantiated.spans.into_iter().chain(std::iter::repeat(span)), - ), - ) - .map(|obligation| (obligation.predicate, obligation.cause.span)) - .collect(); + let impl1_predicates: Vec<_> = + traits::elaborate_predicates_with_span(tcx, instantiated.into_iter()).collect(); let mut impl2_predicates = if impl2_node.is_from_trait() { // Always applicable traits have to be always applicable without any @@ -341,7 +333,6 @@ fn check_predicates<'tcx>( .predicates .into_iter(), ) - .map(|obligation| obligation.predicate) .collect() }; debug!(?impl1_predicates, ?impl2_predicates); @@ -361,12 +352,16 @@ fn check_predicates<'tcx>( // which is sound because we forbid impls like the following // // impl<D: Debug> AlwaysApplicable for D { } - let always_applicable_traits = impl1_predicates.iter().copied().filter(|&(predicate, _)| { - matches!( - trait_predicate_kind(tcx, predicate), - Some(TraitSpecializationKind::AlwaysApplicable) - ) - }); + let always_applicable_traits = impl1_predicates + .iter() + .copied() + .filter(|&(predicate, _)| { + matches!( + trait_predicate_kind(tcx, predicate), + Some(TraitSpecializationKind::AlwaysApplicable) + ) + }) + .map(|(pred, _span)| pred); // Include the well-formed predicates of the type parameters of the impl. for arg in tcx.impl_trait_ref(impl1_def_id).unwrap().subst_identity().substs { @@ -380,10 +375,7 @@ fn check_predicates<'tcx>( traits::elaborate_obligations(tcx, obligations).map(|obligation| obligation.predicate), ) } - impl2_predicates.extend( - traits::elaborate_predicates_with_span(tcx, always_applicable_traits) - .map(|obligation| obligation.predicate), - ); + impl2_predicates.extend(traits::elaborate_predicates(tcx, always_applicable_traits)); for (predicate, span) in impl1_predicates { if !impl2_predicates.iter().any(|pred2| trait_predicates_eq(tcx, predicate, *pred2, span)) { diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index ec391ea80f4..47a8b080166 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -204,15 +204,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut expected_sig = None; let mut expected_kind = None; - for obligation in traits::elaborate_predicates_with_span( + for (pred, span) in traits::elaborate_predicates_with_span( self.tcx, // Reverse the obligations here, since `elaborate_*` uses a stack, // and we want to keep inference generally in the same order of // the registered obligations. predicates.rev(), ) { - debug!(?obligation.predicate); - let bound_predicate = obligation.predicate.kind(); + debug!(?pred); + let bound_predicate = pred.kind(); // Given a Projection predicate, we can potentially infer // the complete signature. @@ -220,9 +220,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && let ty::PredicateKind::Clause(ty::Clause::Projection(proj_predicate)) = bound_predicate.skip_binder() { let inferred_sig = self.normalize( - obligation.cause.span, + span, self.deduce_sig_from_projection( - Some(obligation.cause.span), + Some(span), bound_predicate.rebind(proj_predicate), ), ); diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index a0aa43deadc..2762e778591 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -576,17 +576,13 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { traits::elaborate_predicates(self.tcx, predicates.predicates.iter().copied()) // We don't care about regions here. - .filter_map(|obligation| match obligation.predicate.kind().skip_binder() { + .filter_map(|pred| match pred.kind().skip_binder() { ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) if trait_pred.def_id() == sized_def_id => { let span = predicates .iter() - .find_map( - |(p, span)| { - if p == obligation.predicate { Some(span) } else { None } - }, - ) + .find_map(|(p, span)| if p == pred { Some(span) } else { None }) .unwrap_or(rustc_span::DUMMY_SP); Some((trait_pred, span)) } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index fd16363a1db..75c3d9f641d 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1942,7 +1942,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { escaped } let mut err = struct_span_err!(self.tcx.sess, span, E0308, "{}", failure_str); - if let Some((expected, found)) = trace.values.ty() { + let values = self.resolve_vars_if_possible(trace.values); + if let Some((expected, found)) = values.ty() { match (expected.kind(), found.kind()) { (ty::Tuple(_), ty::Tuple(_)) => {} // If a tuple of length one was expected and the found expression has diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 0d2faeba5fc..f3797499866 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -74,44 +74,58 @@ pub struct Elaborator<'tcx> { pub fn elaborate_trait_ref<'tcx>( tcx: TyCtxt<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>, -) -> Elaborator<'tcx> { +) -> impl Iterator<Item = ty::Predicate<'tcx>> { elaborate_predicates(tcx, std::iter::once(trait_ref.without_const().to_predicate(tcx))) } pub fn elaborate_trait_refs<'tcx>( tcx: TyCtxt<'tcx>, trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>, -) -> Elaborator<'tcx> { - let predicates = trait_refs.map(|trait_ref| trait_ref.without_const().to_predicate(tcx)); +) -> impl Iterator<Item = ty::Predicate<'tcx>> { + let predicates = trait_refs.map(move |trait_ref| trait_ref.without_const().to_predicate(tcx)); elaborate_predicates(tcx, predicates) } pub fn elaborate_predicates<'tcx>( tcx: TyCtxt<'tcx>, predicates: impl Iterator<Item = ty::Predicate<'tcx>>, -) -> Elaborator<'tcx> { - let obligations = predicates - .map(|predicate| { - predicate_obligation(predicate, ty::ParamEnv::empty(), ObligationCause::dummy()) - }) - .collect(); - elaborate_obligations(tcx, obligations) +) -> impl Iterator<Item = ty::Predicate<'tcx>> { + elaborate_obligations( + tcx, + predicates + .map(|predicate| { + Obligation::new( + tcx, + // We'll dump the cause/param-env later + ObligationCause::dummy(), + ty::ParamEnv::empty(), + predicate, + ) + }) + .collect(), + ) + .map(|obl| obl.predicate) } pub fn elaborate_predicates_with_span<'tcx>( tcx: TyCtxt<'tcx>, predicates: impl Iterator<Item = (ty::Predicate<'tcx>, Span)>, -) -> Elaborator<'tcx> { - let obligations = predicates - .map(|(predicate, span)| { - predicate_obligation( - predicate, - ty::ParamEnv::empty(), - ObligationCause::dummy_with_span(span), - ) - }) - .collect(); - elaborate_obligations(tcx, obligations) +) -> impl Iterator<Item = (ty::Predicate<'tcx>, Span)> { + elaborate_obligations( + tcx, + predicates + .map(|(predicate, span)| { + Obligation::new( + tcx, + // We'll dump the cause/param-env later + ObligationCause::dummy_with_span(span), + ty::ParamEnv::empty(), + predicate, + ) + }) + .collect(), + ) + .map(|obl| (obl.predicate, obl.cause.span)) } pub fn elaborate_obligations<'tcx>( @@ -141,10 +155,6 @@ impl<'tcx> Elaborator<'tcx> { self.stack.extend(obligations.into_iter().filter(|o| self.visited.insert(o.predicate))); } - pub fn filter_to_traits(self) -> FilterToTraits<Self> { - FilterToTraits::new(self) - } - fn elaborate(&mut self, obligation: &PredicateObligation<'tcx>) { let tcx = self.visited.tcx; @@ -325,20 +335,18 @@ impl<'tcx> Iterator for Elaborator<'tcx> { // Supertrait iterator /////////////////////////////////////////////////////////////////////////// -pub type Supertraits<'tcx> = FilterToTraits<Elaborator<'tcx>>; - pub fn supertraits<'tcx>( tcx: TyCtxt<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>, -) -> Supertraits<'tcx> { - elaborate_trait_ref(tcx, trait_ref).filter_to_traits() +) -> impl Iterator<Item = ty::PolyTraitRef<'tcx>> { + FilterToTraits::new(elaborate_trait_ref(tcx, trait_ref)) } pub fn transitive_bounds<'tcx>( tcx: TyCtxt<'tcx>, - bounds: impl Iterator<Item = ty::PolyTraitRef<'tcx>>, -) -> Supertraits<'tcx> { - elaborate_trait_refs(tcx, bounds).filter_to_traits() + trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>, +) -> impl Iterator<Item = ty::PolyTraitRef<'tcx>> { + FilterToTraits::new(elaborate_trait_refs(tcx, trait_refs)) } /// A specialized variant of `elaborate_trait_refs` that only elaborates trait references that may @@ -393,12 +401,12 @@ impl<I> FilterToTraits<I> { } } -impl<'tcx, I: Iterator<Item = PredicateObligation<'tcx>>> Iterator for FilterToTraits<I> { +impl<'tcx, I: Iterator<Item = ty::Predicate<'tcx>>> Iterator for FilterToTraits<I> { type Item = ty::PolyTraitRef<'tcx>; fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> { - while let Some(obligation) = self.base_iterator.next() { - if let Some(data) = obligation.predicate.to_opt_poly_trait_pred() { + while let Some(pred) = self.base_iterator.next() { + if let Some(data) = pred.to_opt_poly_trait_pred() { return Some(data.map_bound(|t| t.trait_ref)); } } diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index faca61fc29b..42e59f92840 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -258,11 +258,11 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { cx.tcx, cx.tcx.explicit_item_bounds(def).iter().cloned(), ) - .find_map(|obligation| { + .find_map(|(pred, _span)| { // 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, - )) = obligation.predicate.kind().skip_binder() + )) = pred.kind().skip_binder() { let def_id = poly_trait_predicate.trait_ref.def_id; diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index c1cf6ee0f9e..e7075d5e791 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -117,7 +117,7 @@ impl<'tcx> MirPass<'tcx> for ConstProp { .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None }); if traits::impossible_predicates( tcx, - traits::elaborate_predicates(tcx, predicates).map(|o| o.predicate).collect(), + traits::elaborate_predicates(tcx, predicates).collect(), ) { trace!("ConstProp skipped for {:?}: found unsatisfiable predicates", def_id); return; diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs index 45bd98f39d2..60401b05492 100644 --- a/compiler/rustc_mir_transform/src/const_prop_lint.rs +++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs @@ -93,7 +93,7 @@ impl<'tcx> MirLint<'tcx> for ConstProp { .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None }); if traits::impossible_predicates( tcx, - traits::elaborate_predicates(tcx, predicates).map(|o| o.predicate).collect(), + traits::elaborate_predicates(tcx, predicates).collect(), ) { trace!("ConstProp skipped for {:?}: found unsatisfiable predicates", def_id); return; diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 80618fd1abe..2ff7de8cb9e 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -1065,7 +1065,7 @@ pub(super) struct CurrentDepGraph<K: DepKind> { /// This is used to verify that fingerprints do not change between the creation of a node /// and its recomputation. #[cfg(debug_assertions)] - fingerprints: Lock<FxHashMap<DepNode<K>, Fingerprint>>, + fingerprints: Lock<IndexVec<DepNodeIndex, Option<Fingerprint>>>, /// Used to trap when a specific edge is added to the graph. /// This is used for debug purposes and is only active with `debug_assertions`. @@ -1151,7 +1151,7 @@ impl<K: DepKind> CurrentDepGraph<K> { #[cfg(debug_assertions)] forbidden_edge, #[cfg(debug_assertions)] - fingerprints: Lock::new(Default::default()), + fingerprints: Lock::new(IndexVec::from_elem_n(None, new_node_count_estimate)), total_read_count: AtomicU64::new(0), total_duplicate_read_count: AtomicU64::new(0), node_intern_event_id, @@ -1163,14 +1163,8 @@ impl<K: DepKind> CurrentDepGraph<K> { if let Some(forbidden_edge) = &self.forbidden_edge { forbidden_edge.index_to_node.lock().insert(dep_node_index, key); } - match self.fingerprints.lock().entry(key) { - Entry::Vacant(v) => { - v.insert(fingerprint); - } - Entry::Occupied(o) => { - assert_eq!(*o.get(), fingerprint, "Unstable fingerprints for {:?}", key); - } - } + let previous = *self.fingerprints.lock().get_or_insert_with(dep_node_index, || fingerprint); + assert_eq!(previous, fingerprint, "Unstable fingerprints for {:?}", key); } /// Writes the node to the current dep-graph and allocates a `DepNodeIndex` for it. diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs index 995fec78c40..b2658614fd3 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly.rs @@ -470,7 +470,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { for assumption in elaborate_predicates(tcx, bounds.iter().map(|bound| bound.with_self_ty(tcx, self_ty))) { - match G::consider_object_bound_candidate(self, goal, assumption.predicate) { + match G::consider_object_bound_candidate(self, goal, assumption) { Ok(result) => { candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result }) } diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 6a64dfdedd4..65e7bcb7f01 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -9,8 +9,6 @@ //! FIXME(@lcnr): Write that section. If you read this before then ask me //! about it on zulip. -// FIXME: uses of `infcx.at` need to enable deferred projection equality once that's implemented. - use rustc_hir::def_id::DefId; use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues}; use rustc_infer::traits::query::NoSolution; @@ -105,8 +103,6 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { goal: Goal<'tcx, SubtypePredicate<'tcx>>, ) -> QueryResult<'tcx> { if goal.predicate.a.is_ty_var() && goal.predicate.b.is_ty_var() { - // FIXME: Do we want to register a subtype relation between these vars? - // That won't actually reflect in the query response, so it seems moot. self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) } else { self.sub(goal.param_env, goal.predicate.a, goal.predicate.b)?; diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs index 219890b9dc4..9773a3eacd6 100644 --- a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs @@ -78,8 +78,6 @@ impl<'tcx> SearchGraph<'tcx> { tcx: TyCtxt<'tcx>, goal: CanonicalGoal<'tcx>, ) -> Result<(), QueryResult<'tcx>> { - // FIXME: start by checking the global cache - // Look at the provisional cache to check for cycles. let cache = &mut self.provisional_cache; match cache.lookup_table.entry(goal) { diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 6b3a59b1ed5..878c502655c 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -349,8 +349,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { let normalized_preds = elaborate_predicates( tcx, computed_preds.clone().chain(user_computed_preds.iter().cloned()), - ) - .map(|o| o.predicate); + ); new_env = ty::ParamEnv::new( tcx.mk_predicates_from_iter(normalized_preds), param_env.reveal(), diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 98e00e8223b..03ba125cf2b 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -367,8 +367,8 @@ fn negative_impl_exists<'tcx>( } // Try to prove a negative obligation exists for super predicates - for o in util::elaborate_predicates(infcx.tcx, iter::once(o.predicate)) { - if resolve_negative_obligation(infcx.fork(), &o, body_def_id) { + for pred in util::elaborate_predicates(infcx.tcx, iter::once(o.predicate)) { + if resolve_negative_obligation(infcx.fork(), &o.with(infcx.tcx, pred), body_def_id) { return true; } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs index 84045c4d0ed..672b3365ff4 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs @@ -82,15 +82,15 @@ pub fn recompute_applicable_impls<'tcx>( let predicates = tcx.predicates_of(obligation.cause.body_id.to_def_id()).instantiate_identity(tcx); - for obligation in elaborate_predicates_with_span(tcx, predicates.into_iter()) { - let kind = obligation.predicate.kind(); + for (pred, span) in elaborate_predicates_with_span(tcx, predicates.into_iter()) { + let kind = pred.kind(); if let ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) = kind.skip_binder() && param_env_candidate_may_apply(kind.rebind(trait_pred)) { if kind.rebind(trait_pred.trait_ref) == ty::TraitRef::identity(tcx, trait_pred.def_id()) { ambiguities.push(Ambiguity::ParamEnv(tcx.def_span(trait_pred.def_id()))) } else { - ambiguities.push(Ambiguity::ParamEnv(obligation.cause.span)) + ambiguities.push(Ambiguity::ParamEnv(span)) } } } 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 296fd1ed524..c19798213b7 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1624,8 +1624,8 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } }; - for obligation in super::elaborate_predicates(self.tcx, std::iter::once(cond)) { - let bound_predicate = obligation.predicate.kind(); + for pred in super::elaborate_predicates(self.tcx, std::iter::once(cond)) { + let bound_predicate = pred.kind(); if let ty::PredicateKind::Clause(ty::Clause::Trait(implication)) = bound_predicate.skip_binder() { diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index e8970606704..8d831dca6e3 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -66,7 +66,7 @@ pub use self::util::{expand_trait_aliases, TraitAliasExpander}; pub use self::util::{get_vtable_index_of_object_method, impl_item_is_final, upcast_choices}; pub use self::util::{ supertrait_def_ids, supertraits, transitive_bounds, transitive_bounds_that_define_assoc_type, - SupertraitDefIds, Supertraits, + SupertraitDefIds, }; pub use self::chalk_fulfill::FulfillmentContext as ChalkFulfillmentContext; @@ -267,9 +267,7 @@ pub fn normalize_param_env_or_error<'tcx>( // and errors will get reported then; so outside of type inference we // can be sure that no errors should occur. let mut predicates: Vec<_> = - util::elaborate_predicates(tcx, unnormalized_env.caller_bounds().into_iter()) - .map(|obligation| obligation.predicate) - .collect(); + util::elaborate_predicates(tcx, unnormalized_env.caller_bounds().into_iter()).collect(); debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates); diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 5d2af5ff33c..dbf6b78572a 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -379,26 +379,24 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { // Search for a predicate like `Self : Sized` amongst the trait bounds. let predicates = tcx.predicates_of(def_id); let predicates = predicates.instantiate_identity(tcx).predicates; - elaborate_predicates(tcx, predicates.into_iter()).any(|obligation| { - match obligation.predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::Clause::Trait(ref trait_pred)) => { - trait_pred.def_id() == sized_def_id && trait_pred.self_ty().is_param(0) - } - ty::PredicateKind::Clause(ty::Clause::Projection(..)) - | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) - | ty::PredicateKind::Subtype(..) - | ty::PredicateKind::Coerce(..) - | ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..)) - | ty::PredicateKind::WellFormed(..) - | ty::PredicateKind::ObjectSafe(..) - | ty::PredicateKind::ClosureKind(..) - | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..)) - | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::AliasRelate(..) - | ty::PredicateKind::Ambiguous - | ty::PredicateKind::TypeWellFormedFromEnv(..) => false, + elaborate_predicates(tcx, predicates.into_iter()).any(|pred| match pred.kind().skip_binder() { + ty::PredicateKind::Clause(ty::Clause::Trait(ref trait_pred)) => { + trait_pred.def_id() == sized_def_id && trait_pred.self_ty().is_param(0) } + ty::PredicateKind::Clause(ty::Clause::Projection(..)) + | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) + | ty::PredicateKind::Subtype(..) + | ty::PredicateKind::Coerce(..) + | ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..)) + | ty::PredicateKind::WellFormed(..) + | ty::PredicateKind::ObjectSafe(..) + | ty::PredicateKind::ClosureKind(..) + | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..)) + | ty::PredicateKind::ConstEvaluatable(..) + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::AliasRelate(..) + | ty::PredicateKind::Ambiguous + | ty::PredicateKind::TypeWellFormedFromEnv(..) => false, }) } @@ -669,9 +667,9 @@ fn object_ty_for_trait<'tcx>( debug!(?trait_predicate); let mut elaborated_predicates: Vec<_> = elaborate_trait_ref(tcx, trait_ref) - .filter_map(|obligation| { - debug!(?obligation); - let pred = obligation.predicate.to_opt_poly_projection_pred()?; + .filter_map(|pred| { + debug!(?pred); + let pred = pred.to_opt_poly_projection_pred()?; Some(pred.map_bound(|p| { ty::ExistentialPredicate::Projection(ty::ExistentialProjection::erase_self_ty( tcx, p, diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index ec5bd982a3c..156674e33c3 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -921,9 +921,9 @@ pub(crate) fn required_region_bounds<'tcx>( assert!(!erased_self_ty.has_escaping_bound_vars()); traits::elaborate_predicates(tcx, predicates) - .filter_map(|obligation| { - debug!(?obligation); - match obligation.predicate.kind().skip_binder() { + .filter_map(|pred| { + debug!(?pred); + match pred.kind().skip_binder() { ty::PredicateKind::Clause(ty::Clause::Projection(..)) | ty::PredicateKind::Clause(ty::Clause::Trait(..)) | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) diff --git a/config.example.toml b/config.example.toml index 32eab76b369..5ef83760aed 100644 --- a/config.example.toml +++ b/config.example.toml @@ -1,7 +1,7 @@ # Sample TOML configuration file for building Rust. # -# To configure rustbuild, copy this file to the directory from which you will be -# running the build, and name it config.toml. +# To configure rustbuild, run `./configure` or `./x.py setup`. +# See https://rustc-dev-guide.rust-lang.org/building/how-to-build-and-run.html#create-a-configtoml for more information. # # All options are commented out by default in this file, and they're commented # out with their default values. The build system by default looks for @@ -9,12 +9,6 @@ # a custom configuration file can also be specified with `--config` to the build # system. -# Keeps track of the last version of `x.py` used. -# If it does not match the version that is currently running, -# `x.py` will prompt you to update it and read the changelog. -# See `src/bootstrap/CHANGELOG.md` for more information. -changelog-seen = 2 - # ============================================================================= # Global Settings # ============================================================================= @@ -25,6 +19,12 @@ changelog-seen = 2 # Note that this has no default value (x.py uses the defaults in `config.toml.example`). #profile = <none> +# Keeps track of the last version of `x.py` used. +# If `changelog-seen` does not match the version that is currently running, +# `x.py` will prompt you to update it and to read the changelog. +# See `src/bootstrap/CHANGELOG.md` for more information. +changelog-seen = 2 + # ============================================================================= # Tweaking how LLVM is compiled # ============================================================================= @@ -33,7 +33,7 @@ changelog-seen = 2 # Whether to use Rust CI built LLVM instead of locally building it. # # Unless you're developing for a target where Rust CI doesn't build a compiler -# toolchain or changing LLVM locally, you probably want to set this to true. +# toolchain or changing LLVM locally, you probably want to leave this enabled. # # All tier 1 targets are currently supported; set this to `"if-available"` if # you are not sure whether you're on a tier 1 target. @@ -42,9 +42,7 @@ changelog-seen = 2 # # Note that many of the LLVM options are not currently supported for # downloading. Currently only the "assertions" option can be toggled. -# -# Defaults to "if-available" when `channel = "dev"` and "false" otherwise. -#download-ci-llvm = "if-available" +#download-ci-llvm = if rust.channel == "dev" { "if-available" } else { false } # Indicates whether the LLVM build is a Release or Debug build #optimize = true @@ -59,6 +57,8 @@ changelog-seen = 2 #release-debuginfo = false # Indicates whether the LLVM assertions are enabled or not +# NOTE: When assertions are disabled, bugs in the integration between rustc and LLVM can lead to +# unsoundness (segfaults, etc.) in the rustc process itself, not just in the generated code. #assertions = false # Indicates whether the LLVM testsuite is enabled in the build or not. Does @@ -70,10 +70,9 @@ changelog-seen = 2 # Indicates whether the LLVM plugin is enabled or not #plugins = false -# Indicates whether ccache is used when building LLVM +# Indicates whether ccache is used when building LLVM. Set to `true` to use the first `ccache` in +# PATH, or set an absolute path to use a specific version. #ccache = false -# or alternatively ... -#ccache = "/path/to/ccache" # When true, link libstdc++ statically into the rustc_llvm. # This is useful if you don't want to use the dynamic version of that @@ -87,11 +86,8 @@ changelog-seen = 2 # Note: this is NOT related to Rust compilation targets. However, as Rust is # dependent on LLVM for code generation, turning targets off here WILL lead to # the resulting rustc being unable to compile for the disabled architectures. -# Also worth pointing out is that, in case support for new targets are added to -# LLVM, enabling them here doesn't mean Rust is automatically gaining said -# support. You'll need to write a target specification at least, and most -# likely, teach rustc about the C ABI of the target. Get in touch with the -# Rust team and file an issue if you need assistance in porting! +# +# To add support for new targets, see https://rustc-dev-guide.rust-lang.org/building/new-target.html. #targets = "AArch64;ARM;BPF;Hexagon;MSP430;Mips;NVPTX;PowerPC;RISCV;Sparc;SystemZ;WebAssembly;X86" # LLVM experimental targets to build support for. These targets are specified in @@ -104,19 +100,18 @@ changelog-seen = 2 # This can be useful when building LLVM with debug info, which significantly # increases the size of binaries and consequently the memory required by # each linker process. -# If absent or 0, linker invocations are treated like any other job and +# If set to 0, linker invocations are treated like any other job and # controlled by rustbuild's -j parameter. #link-jobs = 0 -# When invoking `llvm-config` this configures whether the `--shared` argument is -# passed to prefer linking to shared libraries. -# NOTE: `thin-lto = true` requires this to be `true` and will give an error otherwise. -#link-shared = false +# Whether to build LLVM as a dynamically linked library (as opposed to statically linked). +# Under the hood, this passes `--shared` to llvm-config. +# NOTE: To avoid performing LTO multiple times, we suggest setting this to `true` when `thin-lto` is enabled. +#link-shared = llvm.thin-lto # When building llvm, this configures what is being appended to the version. -# The default is "-rust-$version-$channel", except for dev channel where rustc -# version number is omitted. To use LLVM version as is, provide an empty string. -#version-suffix = "-rust-dev" +# To use LLVM version as is, provide an empty string. +#version-suffix = if rust.channel == "dev" { "-rust-dev" } else { "-rust-$version-$channel" } # On MSVC you can compile LLVM with clang-cl, but the test suite doesn't pass # with clang-cl, so this is special in that it only compiles LLVM with clang-cl. @@ -178,47 +173,58 @@ changelog-seen = 2 # The default stage to use for the `bench` subcommand #bench-stage = 2 -# Build triple for the original snapshot compiler. This must be a compiler that -# nightlies are already produced for. The current platform must be able to run -# binaries of this build triple and the nightly will be used to bootstrap the -# first compiler. +# Build triple for the pre-compiled snapshot compiler. If `rustc` is set, this must match its host +# triple (see `rustc --version --verbose`; cross-compiling the rust build system itself is NOT +# supported). If `rustc` is unset, this must be a platform with pre-compiled host tools +# (https://doc.rust-lang.org/nightly/rustc/platform-support.html). The current platform must be +# able to run binaries of this build triple. # -# Defaults to platform where `x.py` is run. +# If `rustc` is present in path, this defaults to the host it was compiled for. +# Otherwise, `x.py` will try to infer it from the output of `uname`. +# If `uname` is not found in PATH, we assume this is `x86_64-pc-windows-msvc`. +# This may be changed in the future. #build = "x86_64-unknown-linux-gnu" (as an example) -# Which triples to produce a compiler toolchain for. Each of these triples will -# be bootstrapped from the build triple themselves. +# Which triples to produce a compiler toolchain for. Each of these triples will be bootstrapped from +# the build triple themselves. In other words, this is the list of triples for which to build a +# compiler that can RUN on that triple. # -# Defaults to just the build triple. -#host = ["x86_64-unknown-linux-gnu"] (as an example) +# Defaults to just the `build` triple. +#host = [build.build] (list of triples) -# Which triples to build libraries (core/alloc/std/test/proc_macro) for. Each of -# these triples will be bootstrapped from the build triple themselves. +# Which triples to build libraries (core/alloc/std/test/proc_macro) for. Each of these triples will +# be bootstrapped from the build triple themselves. In other words, this is the list of triples for +# which to build a library that can CROSS-COMPILE to that triple. # # Defaults to `host`. If you set this explicitly, you likely want to add all # host triples to this list as well in order for those host toolchains to be # able to compile programs for their native target. -#target = ["x86_64-unknown-linux-gnu"] (as an example) +#target = build.host (list of triples) -# Use this directory to store build artifacts. -# You can use "$ROOT" to indicate the root of the git repository. +# Use this directory to store build artifacts. Paths are relative to the current directory, not to +# the root of the repository. #build-dir = "build" # Instead of downloading the src/stage0.json version of Cargo specified, use # this Cargo binary instead to build all Rust code +# If you set this, you likely want to set `rustc` as well. #cargo = "/path/to/cargo" # Instead of downloading the src/stage0.json version of the compiler # specified, use this rustc binary instead as the stage0 snapshot compiler. +# If you set this, you likely want to set `cargo` as well. #rustc = "/path/to/rustc" -# Instead of download the src/stage0.json version of rustfmt specified, +# Instead of downloading the src/stage0.json version of rustfmt specified, # use this rustfmt binary instead as the stage0 snapshot rustfmt. #rustfmt = "/path/to/rustfmt" -# Flag to specify whether any documentation is built. If false, rustdoc and +# Whether to build documentation by default. If false, rustdoc and # friends will still be compiled but they will not be used to generate any # documentation. +# +# You can still build documentation when this is disabled by explicitly passing paths, +# e.g. `x doc library`. #docs = true # Flag to specify whether CSS, JavaScript, and HTML are minified when @@ -229,8 +235,8 @@ changelog-seen = 2 # Flag to specify whether private items should be included in the library docs. #library-docs-private-items = false -# Indicate whether the compiler should be documented in addition to the standard -# library and facade crates. +# Indicate whether to build compiler documentation by default. +# You can still build documentation when this is disabled by explicitly passing a path: `x doc compiler`. #compiler-docs = false # Indicate whether git submodules are managed and updated automatically. @@ -247,14 +253,14 @@ changelog-seen = 2 # Python interpreter to use for various tasks throughout the build, notably # rustdoc tests, the lldb python interpreter, and some dist bits and pieces. # -# Defaults to the Python interpreter used to execute x.py +# Defaults to the Python interpreter used to execute x.py. #python = "python" # The path to the REUSE executable to use. Note that REUSE is not required in # most cases, as our tooling relies on a cached (and shrinked) copy of the # REUSE output present in the git repository and in our source tarballs. # -# REUSE is only needed if your changes caused the overral licensing of the +# REUSE is only needed if your changes caused the overall licensing of the # repository to change, and the cached copy has to be regenerated. # # Defaults to the "reuse" command in the system path. @@ -264,14 +270,19 @@ changelog-seen = 2 # set that all the Cargo.toml files create, instead of updating it. #locked-deps = false -# Indicate whether the vendored sources are used for Rust dependencies or not +# Indicate whether the vendored sources are used for Rust dependencies or not. +# +# Vendoring requires additional setup. We recommend using the pre-generated source tarballs if you +# want to use vendoring. See +# https://forge.rust-lang.org/infra/other-installation-methods.html#source-code. #vendor = false # Typically the build system will build the Rust compiler twice. The second # compiler, however, will simply use its own libraries to link against. If you # would rather to perform a full bootstrap, compiling the compiler three times, -# then you can set this option to true. You shouldn't ever need to set this -# option to true. +# then you can set this option to true. +# +# This is only useful for verifying that rustc generates reproducible builds. #full-bootstrap = false # Enable a build of the extended Rust tool set which is not only the compiler @@ -300,7 +311,7 @@ changelog-seen = 2 # "rust-demangler", # if profiler = true #] -# Verbosity level: 0 == not verbose, 1 == verbose, 2 == very verbose +# Verbosity level: 0 == not verbose, 1 == verbose, 2 == very verbose, 3 == print environment variables on each rustc invocation #verbose = 0 # Build the sanitizer runtimes @@ -320,11 +331,12 @@ changelog-seen = 2 # Arguments passed to the `./configure` script, used during distcheck. You # probably won't fill this in but rather it's filled in by the `./configure` -# script. +# script. Useful for debugging. #configure-args = [] # Indicates that a local rebuild is occurring instead of a full bootstrap, # essentially skipping stage0 as the local compiler is recompiling itself again. +# Useful for modifying only the stage2 compiler without having to pass `--keep-stage 0` each time. #local-rebuild = false # Print out how long each rustbuild step took (mostly intended for CI and @@ -354,10 +366,10 @@ changelog-seen = 2 # ============================================================================= [install] -# Instead of installing to /usr/local, install to this path instead. +# Where to install the generated toolchain. Must be an absolute path. #prefix = "/usr/local" -# Where to install system configuration files +# Where to install system configuration files. # If this is a relative path, it will get installed in `prefix` above #sysconfdir = "/etc" @@ -411,9 +423,10 @@ changelog-seen = 2 #debug = false # Whether to download the stage 1 and 2 compilers from CI. -# This is mostly useful for tools; if you have changes to `compiler/` they will be ignored. +# This is mostly useful for tools; if you have changes to `compiler/` or `library/` they will be ignored. # -# You can set this to "if-unchanged" to only download if `compiler/` has not been modified. +# Set this to "if-unchanged" to only download if the compiler and standard library have not been modified. +# Set this to `true` to download unconditionally (useful if e.g. you are only changing doc-comments). #download-rustc = false # Number of codegen units to use for each compiler invocation. A value of 0 @@ -429,10 +442,8 @@ changelog-seen = 2 # See https://github.com/rust-lang/rust/issues/83600. #codegen-units-std = codegen-units -# Whether or not debug assertions are enabled for the compiler and standard -# library. Debug assertions control the maximum log level used by rustc. When -# enabled calls to `trace!` and `debug!` macros are preserved in the compiled -# binary, otherwise they are omitted. +# Whether or not debug assertions are enabled for the compiler and standard library. +# These can help find bugs at the cost of a small runtime slowdown. # # Defaults to rust.debug value #debug-assertions = rust.debug (boolean) @@ -444,13 +455,11 @@ changelog-seen = 2 #debug-assertions-std = rust.debug-assertions (boolean) # Whether or not to leave debug! and trace! calls in the rust binary. -# Overrides the `debug-assertions` option, if defined. # # Defaults to rust.debug-assertions value # -# If you see a message from `tracing` saying -# `max_level_info` is enabled and means logging won't be shown, -# set this value to `true`. +# If you see a message from `tracing` saying "some trace filter directives would enable traces that +# are disabled statically" because `max_level_info` is enabled, set this value to `true`. #debug-logging = rust.debug-assertions (boolean) # Whether or not overflow checks are enabled for the compiler and standard @@ -477,18 +486,16 @@ changelog-seen = 2 # # Note that debuginfo-level = 2 generates several gigabytes of debuginfo # and will slow down the linking process significantly. -# -# Defaults to 1 if debug is true -#debuginfo-level = 0 +#debuginfo-level = if rust.debug { 1 } else { 0 } # Debuginfo level for the compiler. -#debuginfo-level-rustc = debuginfo-level +#debuginfo-level-rustc = rust.debuginfo-level # Debuginfo level for the standard library. -#debuginfo-level-std = debuginfo-level +#debuginfo-level-std = rust.debuginfo-level # Debuginfo level for the tools. -#debuginfo-level-tools = debuginfo-level +#debuginfo-level-tools = rust.debuginfo-level # Debuginfo level for the test suites run with compiletest. # FIXME(#61117): Some tests fail when this option is enabled. @@ -520,6 +527,7 @@ changelog-seen = 2 # Build a multi-threaded rustc # FIXME(#75760): Some UI tests fail when this option is enabled. +# NOTE: This option is NOT SUPPORTED. See #48685. #parallel-compiler = false # The default linker that will be hard-coded into the generated @@ -546,7 +554,7 @@ changelog-seen = 2 # upstream Rust you need to set this to "". However, note that if you are not # actually compatible -- for example if you've backported patches that change # behavior -- this may lead to miscompilations or other bugs. -#description = <none> (string) +#description = "" # The root location of the musl installation directory. The library directory # will also need to contain libunwind.a for an unwinding implementation. Note @@ -575,14 +583,16 @@ changelog-seen = 2 # Flag indicating whether git info will be retrieved from .git automatically. # Having the git information can cause a lot of rebuilds during development. -# Note: If this attribute is not explicitly set (e.g. if left commented out) it -# will default to true if channel = "dev", but will default to false otherwise. -#ignore-git = if channel == "dev" { true } else { false } +# +# FIXME(#76720): this can causes bugs if different compilers reuse the same metadata cache. +#ignore-git = if rust.channel == "dev" { true } else { false } -# When creating source tarballs whether or not to create a source tarball. +# Whether to create a source tarball by default when running `x dist`. +# +# You can still build a source tarball when this is disabled by explicitly passing `x dist rustc-src`. #dist-src = true -# After building or testing extended tools (e.g. clippy and rustfmt), append the +# After building or testing an optional component (e.g. the nomicon or reference), append the # result (broken, compiling, testing) into this JSON file. #save-toolstates = <none> (path) @@ -624,11 +634,12 @@ changelog-seen = 2 # will make code compile faster at the expense of lower runtime performance. #thin-lto-import-instr-limit = if incremental { 10 } else { LLVM default (currently 100) } -# Map debuginfo paths to `/rust/$sha/...`, generally only set for releases +# Map debuginfo paths to `/rust/$sha/...`. +# Useful for reproducible builds. Generally only set for releases #remap-debuginfo = false -# Link the compiler against `jemalloc`, where on Linux and OSX it should -# override the default allocator for rustc and LLVM. +# Link the compiler and LLVM against `jemalloc` instead of the default libc allocator. +# This option is only tested on Linux and OSX. #jemalloc = false # Run tests in various test suites with the "nll compare mode" in addition to diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 5469261ef56..55e18b04956 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -135,7 +135,6 @@ #![feature(maybe_uninit_uninit_array)] #![feature(maybe_uninit_uninit_array_transpose)] #![cfg_attr(test, feature(new_uninit))] -#![feature(nonnull_slice_from_raw_parts)] #![feature(pattern)] #![feature(pointer_byte_offsets)] #![feature(provide_any)] diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index 2a93a242d51..966cf575116 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -8,7 +8,7 @@ #![feature(const_cow_is_borrowed)] #![feature(const_heap)] #![feature(const_mut_refs)] -#![feature(const_nonnull_slice_from_raw_parts)] +#![feature(const_slice_from_raw_parts_mut)] #![feature(const_ptr_write)] #![feature(const_try)] #![feature(core_intrinsics)] @@ -38,7 +38,6 @@ #![feature(const_default_impls)] #![feature(const_trait_impl)] #![feature(const_str_from_utf8)] -#![feature(nonnull_slice_from_raw_parts)] #![feature(panic_update_hook)] #![feature(pointer_is_aligned)] #![feature(slice_flatten)] diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 8c1a6488605..a46804c186c 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -462,8 +462,6 @@ impl<T> NonNull<[T]> { /// # Examples /// /// ```rust - /// #![feature(nonnull_slice_from_raw_parts)] - /// /// use std::ptr::NonNull; /// /// // create a slice pointer when starting out with a pointer to the first element @@ -475,8 +473,8 @@ impl<T> NonNull<[T]> { /// /// (Note that this example artificially demonstrates a use of this method, /// but `let slice = NonNull::from(&x[..]);` would be a better way to write code like this.) - #[unstable(feature = "nonnull_slice_from_raw_parts", issue = "71941")] - #[rustc_const_unstable(feature = "const_nonnull_slice_from_raw_parts", issue = "71941")] + #[stable(feature = "nonnull_slice_from_raw_parts", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_unstable(feature = "const_slice_from_raw_parts_mut", issue = "67456")] #[must_use] #[inline] pub const fn slice_from_raw_parts(data: NonNull<T>, len: usize) -> Self { @@ -494,7 +492,6 @@ impl<T> NonNull<[T]> { /// # Examples /// /// ```rust - /// #![feature(nonnull_slice_from_raw_parts)] /// use std::ptr::NonNull; /// /// let slice: NonNull<[i8]> = NonNull::slice_from_raw_parts(NonNull::dangling(), 3); @@ -514,7 +511,7 @@ impl<T> NonNull<[T]> { /// # Examples /// /// ```rust - /// #![feature(slice_ptr_get, nonnull_slice_from_raw_parts)] + /// #![feature(slice_ptr_get)] /// use std::ptr::NonNull; /// /// let slice: NonNull<[i8]> = NonNull::slice_from_raw_parts(NonNull::dangling(), 3); @@ -534,7 +531,7 @@ impl<T> NonNull<[T]> { /// # Examples /// /// ```rust - /// #![feature(slice_ptr_get, nonnull_slice_from_raw_parts)] + /// #![feature(slice_ptr_get)] /// use std::ptr::NonNull; /// /// let slice: NonNull<[i8]> = NonNull::slice_from_raw_parts(NonNull::dangling(), 3); @@ -668,7 +665,7 @@ impl<T> NonNull<[T]> { /// # Examples /// /// ``` - /// #![feature(slice_ptr_get, nonnull_slice_from_raw_parts)] + /// #![feature(slice_ptr_get)] /// use std::ptr::NonNull; /// /// let x = &mut [1, 2, 4]; diff --git a/library/panic_abort/src/android.rs b/library/panic_abort/src/android.rs index 0fd824f8a45..20b5b6b5146 100644 --- a/library/panic_abort/src/android.rs +++ b/library/panic_abort/src/android.rs @@ -15,7 +15,7 @@ type SetAbortMessageType = unsafe extern "C" fn(*const libc::c_char) -> (); // // Weakly resolve the symbol for android_set_abort_message. This function is only available // for API >= 21. -pub(crate) unsafe fn android_set_abort_message(payload: *mut &mut dyn BoxMeUp) { +pub(crate) unsafe fn android_set_abort_message(payload: &mut dyn BoxMeUp) { let func_addr = libc::dlsym(libc::RTLD_DEFAULT, ANDROID_SET_ABORT_MESSAGE.as_ptr() as *const libc::c_char) as usize; @@ -23,7 +23,7 @@ pub(crate) unsafe fn android_set_abort_message(payload: *mut &mut dyn BoxMeUp) { return; } - let payload = (*payload).get(); + let payload = payload.get(); let msg = match payload.downcast_ref::<&'static str>() { Some(msg) => msg.as_bytes(), None => match payload.downcast_ref::<String>() { diff --git a/library/panic_abort/src/lib.rs b/library/panic_abort/src/lib.rs index a3cebf99c53..b193d79b0e1 100644 --- a/library/panic_abort/src/lib.rs +++ b/library/panic_abort/src/lib.rs @@ -29,7 +29,7 @@ pub unsafe extern "C" fn __rust_panic_cleanup(_: *mut u8) -> *mut (dyn Any + Sen // "Leak" the payload and shim to the relevant abort on the platform in question. #[rustc_std_internal_symbol] -pub unsafe fn __rust_start_panic(_payload: *mut &mut dyn BoxMeUp) -> u32 { +pub unsafe fn __rust_start_panic(_payload: &mut dyn BoxMeUp) -> u32 { // Android has the ability to attach a message as part of the abort. #[cfg(target_os = "android")] android::android_set_abort_message(_payload); diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs index ea3c9a7a663..ce78ab82ef9 100644 --- a/library/panic_unwind/src/lib.rs +++ b/library/panic_unwind/src/lib.rs @@ -99,8 +99,8 @@ pub unsafe extern "C" fn __rust_panic_cleanup(payload: *mut u8) -> *mut (dyn Any // Entry point for raising an exception, just delegates to the platform-specific // implementation. #[rustc_std_internal_symbol] -pub unsafe fn __rust_start_panic(payload: *mut &mut dyn BoxMeUp) -> u32 { - let payload = Box::from_raw((*payload).take_box()); +pub unsafe fn __rust_start_panic(payload: &mut dyn BoxMeUp) -> u32 { + let payload = Box::from_raw(payload.take_box()); imp::panic(payload) } diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs index d98ab021cad..25c64240e74 100644 --- a/library/std/src/io/cursor.rs +++ b/library/std/src/io/cursor.rs @@ -34,7 +34,7 @@ use crate::io::{self, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut, SeekFrom}; /// use std::fs::File; /// /// // a library function we've written -/// fn write_ten_bytes_at_end<W: Write + Seek>(writer: &mut W) -> io::Result<()> { +/// fn write_ten_bytes_at_end<W: Write + Seek>(mut writer: W) -> io::Result<()> { /// writer.seek(SeekFrom::End(-10))?; /// /// for i in 0..10 { diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 4e7b6080835..baad6de707b 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -292,7 +292,6 @@ #![feature(is_some_and)] #![feature(maybe_uninit_slice)] #![feature(maybe_uninit_write_slice)] -#![feature(nonnull_slice_from_raw_parts)] #![feature(panic_can_unwind)] #![feature(panic_info_message)] #![feature(panic_internals)] diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index e59f32af77d..e505466e535 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -46,12 +46,10 @@ extern "C" { fn __rust_panic_cleanup(payload: *mut u8) -> *mut (dyn Any + Send + 'static); } -#[allow(improper_ctypes)] extern "Rust" { - /// `payload` is passed through another layer of raw pointers as `&mut dyn Trait` is not - /// FFI-safe. `BoxMeUp` lazily performs allocation only when needed (this avoids allocations - /// when using the "abort" panic runtime). - fn __rust_start_panic(payload: *mut &mut dyn BoxMeUp) -> u32; + /// `BoxMeUp` lazily performs allocation only when needed (this avoids + /// allocations when using the "abort" panic runtime). + fn __rust_start_panic(payload: &mut dyn BoxMeUp) -> u32; } /// This function is called by the panic runtime if FFI code catches a Rust @@ -738,10 +736,7 @@ pub fn rust_panic_without_hook(payload: Box<dyn Any + Send>) -> ! { /// yer breakpoints. #[inline(never)] #[cfg_attr(not(test), rustc_std_internal_symbol)] -fn rust_panic(mut msg: &mut dyn BoxMeUp) -> ! { - let code = unsafe { - let obj = &mut msg as *mut &mut dyn BoxMeUp; - __rust_start_panic(obj) - }; +fn rust_panic(msg: &mut dyn BoxMeUp) -> ! { + let code = unsafe { __rust_start_panic(msg) }; rtabort!("failed to initiate panic, error {code}") } diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 838e33aca04..4d528a767e4 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -16,7 +16,7 @@ use crate::config::{SplitDebuginfo, TargetSelection}; use crate::doc; use crate::flags::{Color, Subcommand}; use crate::install; -use crate::native; +use crate::llvm; use crate::run; use crate::setup; use crate::test; @@ -636,13 +636,13 @@ impl<'a> Builder<'a> { tool::Rustdoc, tool::Clippy, tool::CargoClippy, - native::Llvm, - native::Sanitizers, + llvm::Llvm, + llvm::Sanitizers, tool::Rustfmt, tool::Miri, tool::CargoMiri, - native::Lld, - native::CrtBeginEnd + llvm::Lld, + llvm::CrtBeginEnd ), Kind::Check | Kind::Clippy | Kind::Fix => describe!( check::Std, @@ -1101,7 +1101,7 @@ impl<'a> Builder<'a> { /// check build or dry-run, where there's no need to build all of LLVM. fn llvm_config(&self, target: TargetSelection) -> Option<PathBuf> { if self.config.llvm_enabled() && self.kind != Kind::Check && !self.config.dry_run() { - let native::LlvmResult { llvm_config, .. } = self.ensure(native::Llvm { target }); + let llvm::LlvmResult { llvm_config, .. } = self.ensure(llvm::Llvm { target }); if llvm_config.is_file() { return Some(llvm_config); } @@ -1227,7 +1227,7 @@ impl<'a> Builder<'a> { // rustc_llvm. But if LLVM is stale, that'll be a tiny amount // of work comparatively, and we'd likely need to rebuild it anyway, // so that's okay. - if crate::native::prebuilt_llvm_config(self, target).is_err() { + if crate::llvm::prebuilt_llvm_config(self, target).is_err() { cargo.env("RUST_CHECK", "1"); } } diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 54971af644c..67bd573a855 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -24,7 +24,7 @@ use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step}; use crate::cache::{Interned, INTERNER}; use crate::config::{LlvmLibunwind, RustcLto, TargetSelection}; use crate::dist; -use crate::native; +use crate::llvm; use crate::tool::SourceType; use crate::util::get_clang_cl_resource_dir; use crate::util::{exe, is_debug_info, is_dylib, output, symlink_dir, t, up_to_date}; @@ -191,7 +191,7 @@ fn copy_and_stamp( } fn copy_llvm_libunwind(builder: &Builder<'_>, target: TargetSelection, libdir: &Path) -> PathBuf { - let libunwind_path = builder.ensure(native::Libunwind { target }); + let libunwind_path = builder.ensure(llvm::Libunwind { target }); let libunwind_source = libunwind_path.join("libunwind.a"); let libunwind_target = libdir.join("libunwind.a"); builder.copy(&libunwind_source, &libunwind_target); @@ -266,7 +266,7 @@ fn copy_self_contained_objects( DependencyType::TargetSelfContained, ); } - let crt_path = builder.ensure(native::CrtBeginEnd { target }); + let crt_path = builder.ensure(llvm::CrtBeginEnd { target }); for &obj in &["crtbegin.o", "crtbeginS.o", "crtend.o", "crtendS.o"] { let src = crt_path.join(obj); let target = libdir_self_contained.join(obj); @@ -474,7 +474,7 @@ fn copy_sanitizers( compiler: &Compiler, target: TargetSelection, ) -> Vec<PathBuf> { - let runtimes: Vec<native::SanitizerRuntime> = builder.ensure(native::Sanitizers { target }); + let runtimes: Vec<llvm::SanitizerRuntime> = builder.ensure(llvm::Sanitizers { target }); if builder.config.dry_run() { return Vec::new(); @@ -876,12 +876,12 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetS // busting caches (e.g. like #71152). if builder.config.llvm_enabled() && (builder.kind != Kind::Check - || crate::native::prebuilt_llvm_config(builder, target).is_ok()) + || crate::llvm::prebuilt_llvm_config(builder, target).is_ok()) { if builder.is_rust_llvm(target) { cargo.env("LLVM_RUSTLLVM", "1"); } - let native::LlvmResult { llvm_config, .. } = builder.ensure(native::Llvm { target }); + let llvm::LlvmResult { llvm_config, .. } = builder.ensure(llvm::Llvm { target }); cargo.env("LLVM_CONFIG", &llvm_config); if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) { cargo.env("CFG_LLVM_ROOT", s); @@ -1359,7 +1359,7 @@ impl Step for Assemble { } let lld_install = if builder.config.lld_enabled { - Some(builder.ensure(native::Lld { target: target_compiler.host })) + Some(builder.ensure(llvm::Lld { target: target_compiler.host })) } else { None }; @@ -1423,8 +1423,8 @@ impl Step for Assemble { } if builder.config.rust_codegen_backends.contains(&INTERNER.intern_str("llvm")) { - let native::LlvmResult { llvm_config, .. } = - builder.ensure(native::Llvm { target: target_compiler.host }); + let llvm::LlvmResult { llvm_config, .. } = + builder.ensure(llvm::Llvm { target: target_compiler.host }); if !builder.config.dry_run() { let llvm_bin_dir = output(Command::new(llvm_config).arg("--bindir")); let llvm_bin_dir = Path::new(llvm_bin_dir.trim()); diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 95625170478..0eba18c3a63 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -1207,11 +1207,11 @@ impl Config { config.llvm_from_ci = match llvm.download_ci_llvm { Some(StringOrBool::String(s)) => { assert!(s == "if-available", "unknown option `{}` for download-ci-llvm", s); - crate::native::is_ci_llvm_available(&config, asserts) + crate::llvm::is_ci_llvm_available(&config, asserts) } Some(StringOrBool::Bool(b)) => b, None => { - config.channel == "dev" && crate::native::is_ci_llvm_available(&config, asserts) + config.channel == "dev" && crate::llvm::is_ci_llvm_available(&config, asserts) } }; @@ -1254,7 +1254,7 @@ impl Config { } } else { config.llvm_from_ci = - config.channel == "dev" && crate::native::is_ci_llvm_available(&config, false); + config.channel == "dev" && crate::llvm::is_ci_llvm_available(&config, false); } if let Some(t) = toml.target { diff --git a/src/bootstrap/config/tests.rs b/src/bootstrap/config/tests.rs index 16dc8c63abc..5cea143e0a7 100644 --- a/src/bootstrap/config/tests.rs +++ b/src/bootstrap/config/tests.rs @@ -11,7 +11,7 @@ fn parse(config: &str) -> Config { #[test] fn download_ci_llvm() { - if crate::native::is_ci_llvm_modified(&parse("")) { + if crate::llvm::is_ci_llvm_modified(&parse("")) { eprintln!("Detected LLVM as non-available: running in CI and modified LLVM in this change"); return; } diff --git a/src/bootstrap/defaults/config.user.toml b/src/bootstrap/defaults/config.user.toml index ee271c3fb51..25d9e649f23 100644 --- a/src/bootstrap/defaults/config.user.toml +++ b/src/bootstrap/defaults/config.user.toml @@ -8,9 +8,11 @@ doc-stage = 2 # When compiling from source, you usually want all tools. extended = true +# Most users installing from source want to build all parts of the project from source. [llvm] -# Most users installing from source want to build all parts of the project from source, not just rustc itself. download-ci-llvm = false +[rust] +download-rustc = false [dist] # Use better compression when preparing tarballs. diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index dceb4bd1b89..2ce54d9a3b4 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -27,7 +27,7 @@ use crate::channel; use crate::compile; use crate::config::TargetSelection; use crate::doc::DocumentationFormat; -use crate::native; +use crate::llvm; use crate::tarball::{GeneratedTarball, OverlayKind, Tarball}; use crate::tool::{self, Tool}; use crate::util::{exe, is_dylib, output, t, timeit}; @@ -1965,8 +1965,8 @@ fn maybe_install_llvm(builder: &Builder<'_>, target: TargetSelection, dst_libdir builder.install(&llvm_dylib_path, dst_libdir, 0o644); } !builder.config.dry_run() - } else if let Ok(native::LlvmResult { llvm_config, .. }) = - native::prebuilt_llvm_config(builder, target) + } else if let Ok(llvm::LlvmResult { llvm_config, .. }) = + llvm::prebuilt_llvm_config(builder, target) { let mut cmd = Command::new(llvm_config); cmd.arg("--libfiles"); @@ -2154,7 +2154,7 @@ impl Step for LlvmTools { } } - builder.ensure(crate::native::Llvm { target }); + builder.ensure(crate::llvm::Llvm { target }); let mut tarball = Tarball::new(builder, "llvm-tools", &target.triple); tarball.set_overlay(OverlayKind::LLVM); @@ -2213,10 +2213,10 @@ impl Step for RustDev { let mut tarball = Tarball::new(builder, "rust-dev", &target.triple); tarball.set_overlay(OverlayKind::LLVM); - builder.ensure(crate::native::Llvm { target }); + builder.ensure(crate::llvm::Llvm { target }); // We want to package `lld` to use it with `download-ci-llvm`. - builder.ensure(crate::native::Lld { target }); + builder.ensure(crate::llvm::Lld { target }); let src_bindir = builder.llvm_out(target).join("bin"); // If updating this list, you likely want to change diff --git a/src/bootstrap/download.rs b/src/bootstrap/download.rs index d1e2149d3f9..8fbc034965a 100644 --- a/src/bootstrap/download.rs +++ b/src/bootstrap/download.rs @@ -12,7 +12,7 @@ use xz2::bufread::XzDecoder; use crate::{ config::RustfmtMetadata, - native::detect_llvm_sha, + llvm::detect_llvm_sha, t, util::{check_run, exe, program_out_of_date, try_run}, Config, diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 54aa5a585bb..20b92b294fe 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -53,8 +53,8 @@ mod download; mod flags; mod format; mod install; +mod llvm; mod metadata; -mod native; mod render_tests; mod run; mod sanity; diff --git a/src/bootstrap/native.rs b/src/bootstrap/llvm.rs index f27db5c91e2..de06f8ca8c0 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/llvm.rs @@ -870,71 +870,6 @@ impl Step for Lld { } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct TestHelpers { - pub target: TargetSelection, -} - -impl Step for TestHelpers { - type Output = (); - - fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.path("tests/auxiliary/rust_test_helpers.c") - } - - fn make_run(run: RunConfig<'_>) { - run.builder.ensure(TestHelpers { target: run.target }) - } - - /// Compiles the `rust_test_helpers.c` library which we used in various - /// `run-pass` tests for ABI testing. - fn run(self, builder: &Builder<'_>) { - if builder.config.dry_run() { - return; - } - // The x86_64-fortanix-unknown-sgx target doesn't have a working C - // toolchain. However, some x86_64 ELF objects can be linked - // without issues. Use this hack to compile the test helpers. - let target = if self.target == "x86_64-fortanix-unknown-sgx" { - TargetSelection::from_user("x86_64-unknown-linux-gnu") - } else { - self.target - }; - let dst = builder.test_helpers_out(target); - let src = builder.src.join("tests/auxiliary/rust_test_helpers.c"); - if up_to_date(&src, &dst.join("librust_test_helpers.a")) { - return; - } - - builder.info("Building test helpers"); - t!(fs::create_dir_all(&dst)); - let mut cfg = cc::Build::new(); - // FIXME: Workaround for https://github.com/emscripten-core/emscripten/issues/9013 - if target.contains("emscripten") { - cfg.pic(false); - } - - // We may have found various cross-compilers a little differently due to our - // extra configuration, so inform cc of these compilers. Note, though, that - // on MSVC we still need cc's detection of env vars (ugh). - if !target.contains("msvc") { - if let Some(ar) = builder.ar(target) { - cfg.archiver(ar); - } - cfg.compiler(builder.cc(target)); - } - cfg.cargo_metadata(false) - .out_dir(&dst) - .target(&target.triple) - .host(&builder.config.build.triple) - .opt_level(0) - .warnings(false) - .debug(false) - .file(builder.src.join("tests/auxiliary/rust_test_helpers.c")) - .compile("rust_test_helpers"); - } -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct Sanitizers { pub target: TargetSelection, } diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 29d37c09d88..92a7603a9df 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -19,11 +19,11 @@ use crate::config::TargetSelection; use crate::dist; use crate::doc::DocumentationFormat; use crate::flags::Subcommand; -use crate::native; +use crate::llvm; use crate::render_tests::add_flags_and_try_run_tests; use crate::tool::{self, SourceType, Tool}; use crate::toolstate::ToolState; -use crate::util::{self, add_link_lib_path, dylib_path, dylib_path_var, output, t}; +use crate::util::{self, add_link_lib_path, dylib_path, dylib_path_var, output, t, up_to_date}; use crate::{envify, CLang, DocTests, GitRepo, Mode}; const ADB_TEST_DIR: &str = "/data/local/tmp/work"; @@ -1434,11 +1434,11 @@ note: if you're sure you want to do this, please open an issue as to why. In the builder.ensure(compile::Std::new(compiler, compiler.host)); // Also provide `rust_test_helpers` for the host. - builder.ensure(native::TestHelpers { target: compiler.host }); + builder.ensure(TestHelpers { target: compiler.host }); // As well as the target, except for plain wasm32, which can't build it if !target.contains("wasm") || target.contains("emscripten") { - builder.ensure(native::TestHelpers { target }); + builder.ensure(TestHelpers { target }); } builder.ensure(RemoteCopyLibs { compiler, target }); @@ -1625,8 +1625,8 @@ note: if you're sure you want to do this, please open an issue as to why. In the let mut llvm_components_passed = false; let mut copts_passed = false; if builder.config.llvm_enabled() { - let native::LlvmResult { llvm_config, .. } = - builder.ensure(native::Llvm { target: builder.config.build }); + let llvm::LlvmResult { llvm_config, .. } = + builder.ensure(llvm::Llvm { target: builder.config.build }); if !builder.config.dry_run() { let llvm_version = output(Command::new(&llvm_config).arg("--version")); let llvm_components = output(Command::new(&llvm_config).arg("--components")); @@ -1664,7 +1664,7 @@ note: if you're sure you want to do this, please open an issue as to why. In the // If LLD is available, add it to the PATH if builder.config.lld_enabled { let lld_install_root = - builder.ensure(native::Lld { target: builder.config.build }); + builder.ensure(llvm::Lld { target: builder.config.build }); let lld_bin_path = lld_install_root.join("bin"); @@ -2747,3 +2747,68 @@ impl Step for RustInstaller { run.builder.ensure(Self); } } + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct TestHelpers { + pub target: TargetSelection, +} + +impl Step for TestHelpers { + type Output = (); + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("tests/auxiliary/rust_test_helpers.c") + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(TestHelpers { target: run.target }) + } + + /// Compiles the `rust_test_helpers.c` library which we used in various + /// `run-pass` tests for ABI testing. + fn run(self, builder: &Builder<'_>) { + if builder.config.dry_run() { + return; + } + // The x86_64-fortanix-unknown-sgx target doesn't have a working C + // toolchain. However, some x86_64 ELF objects can be linked + // without issues. Use this hack to compile the test helpers. + let target = if self.target == "x86_64-fortanix-unknown-sgx" { + TargetSelection::from_user("x86_64-unknown-linux-gnu") + } else { + self.target + }; + let dst = builder.test_helpers_out(target); + let src = builder.src.join("tests/auxiliary/rust_test_helpers.c"); + if up_to_date(&src, &dst.join("librust_test_helpers.a")) { + return; + } + + builder.info("Building test helpers"); + t!(fs::create_dir_all(&dst)); + let mut cfg = cc::Build::new(); + // FIXME: Workaround for https://github.com/emscripten-core/emscripten/issues/9013 + if target.contains("emscripten") { + cfg.pic(false); + } + + // We may have found various cross-compilers a little differently due to our + // extra configuration, so inform cc of these compilers. Note, though, that + // on MSVC we still need cc's detection of env vars (ugh). + if !target.contains("msvc") { + if let Some(ar) = builder.ar(target) { + cfg.archiver(ar); + } + cfg.compiler(builder.cc(target)); + } + cfg.cargo_metadata(false) + .out_dir(&dst) + .target(&target.triple) + .host(&builder.config.build.triple) + .opt_level(0) + .warnings(false) + .debug(false) + .file(builder.src.join("tests/auxiliary/rust_test_helpers.c")) + .compile("rust_test_helpers"); + } +} diff --git a/src/ci/stage-build.py b/src/ci/stage-build.py index d4d80e8f77c..7cd5e88f6a2 100644 --- a/src/ci/stage-build.py +++ b/src/ci/stage-build.py @@ -727,7 +727,7 @@ def record_metrics(pipeline: Pipeline, timer: Timer): metrics = load_last_metrics(pipeline.metrics_path()) if metrics is None: return - llvm_steps = tuple(metrics.find_all_by_type("bootstrap::native::Llvm")) + llvm_steps = tuple(metrics.find_all_by_type("bootstrap::llvm::Llvm")) assert len(llvm_steps) > 0 llvm_duration = sum(step.duration for step in llvm_steps) diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 840ed8e1080..c081578b8d4 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -1946,11 +1946,7 @@ function initSearch(rawSearchIndex) { function showResults(results, go_to_first, filterCrates) { const search = searchState.outputElement(); if (go_to_first || (results.others.length === 1 - && getSettingValue("go-to-only-result") === "true" - // By default, the search DOM element is "empty" (meaning it has no children not - // text content). Once a search has been run, it won't be empty, even if you press - // ESC or empty the search input (which also "cancels" the search). - && (!search.firstChild || search.firstChild.innerText !== searchState.loadingText)) + && getSettingValue("go-to-only-result") === "true") ) { const elem = document.createElement("a"); elem.href = results.others[0].href; diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index 1ab81aee7b8..327e090d38b 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -124,9 +124,9 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { let preds = traits::elaborate_predicates(cx.tcx, cx.param_env.caller_bounds().iter()) .filter(|p| !p.is_global()) - .filter_map(|obligation| { + .filter_map(|pred| { // Note that we do not want to deal with qualified predicates here. - match obligation.predicate.kind().no_bound_vars() { + match pred.kind().no_bound_vars() { Some(ty::PredicateKind::Clause(ty::Clause::Trait(pred))) if pred.def_id() != sized_trait => { Some(pred) }, diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 29830557a44..fd06c0b8677 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -2106,7 +2106,6 @@ pub fn fn_has_unsatisfiable_preds(cx: &LateContext<'_>, did: DefId) -> bool { traits::impossible_predicates( cx.tcx, traits::elaborate_predicates(cx.tcx, predicates) - .map(|o| o.predicate) .collect::<Vec<_>>(), ) } diff --git a/tests/rustdoc-gui/setting-go-to-only-result.goml b/tests/rustdoc-gui/setting-go-to-only-result.goml new file mode 100644 index 00000000000..3811011a64e --- /dev/null +++ b/tests/rustdoc-gui/setting-go-to-only-result.goml @@ -0,0 +1,63 @@ +// Checks that the setting "Directly go to item in search if there is only one result " is working as expected. + +define-function: ( + "check-setting", + (storage_value, setting_attribute_value), + block { + assert-local-storage: {"rustdoc-go-to-only-result": |storage_value|} + click: "#settings-menu" + wait-for: "#settings" + assert-property: ("#go-to-only-result", {"checked": |setting_attribute_value|}) + } +) + +goto: "file://" + |DOC_PATH| + "/lib2/index.html" + +call-function: ("check-setting", { + "storage_value": null, + "setting_attribute_value": "false", +}) + +// By default, the search doesn't automatically go to the page if there is only one result. +goto: "file://" + |DOC_PATH| + "/lib2/index.html?search=HasALongTraitWithParams" +// It will timeout if the setting isn't working. +wait-for: "#search" +assert-document-property: ({"URL": "/lib2/index.html"}, CONTAINS) + +// Now we change its value. +click: "#settings-menu" +wait-for: "#settings" +click: "#go-to-only-result" +assert-local-storage: {"rustdoc-go-to-only-result": "true"} + +goto: "file://" + |DOC_PATH| + "/lib2/index.html" +// We enter it into the search. +write: (".search-input", "HasALongTraitWithParams") +wait-for-document-property: {"title": "HasALongTraitWithParams in lib2 - Rust"} +assert-document-property: ({"URL": "/lib2/struct.HasALongTraitWithParams.html"}, ENDS_WITH) + +// We try again to see if it goes to the only result +goto: "file://" + |DOC_PATH| + "/lib2/index.html?search=HasALongTraitWithParams" +wait-for-document-property: {"title": "HasALongTraitWithParams in lib2 - Rust"} +assert-document-property: ({"URL": "/lib2/struct.HasALongTraitWithParams.html"}, ENDS_WITH) + +// We check the settings +call-function: ("check-setting", { + "storage_value": "true", + "setting_attribute_value": "true", +}) + +// And now we re-disable the setting. +click: "#go-to-only-result" +assert-local-storage: {"rustdoc-go-to-only-result": "false"} + +goto: "file://" + |DOC_PATH| + "/lib2/index.html?search=HasALongTraitWithParams" +// It will timeout if the setting isn't working. +wait-for: "#search" +assert-document-property: ({"URL": "/lib2/index.html"}, CONTAINS) + +// And we check everything is back the way it was before. +call-function: ("check-setting", { + "storage_value": "false", + "setting_attribute_value": "false", +}) diff --git a/tests/ui/inference/char-as-str-single.fixed b/tests/ui/inference/char-as-str-single.fixed index bab1854dc51..1621a279f03 100644 --- a/tests/ui/inference/char-as-str-single.fixed +++ b/tests/ui/inference/char-as-str-single.fixed @@ -10,3 +10,12 @@ fn main() { let _: char = '人'; //~ ERROR mismatched types let _: char = '\''; //~ ERROR mismatched types } + +// regression test for https://github.com/rust-lang/rust/issues/109586 +#[allow(dead_code)] +fn convert_c_to_str(c: char) { + match c { + 'A' => {} //~ ERROR mismatched types + _ => {} + } +} diff --git a/tests/ui/inference/char-as-str-single.rs b/tests/ui/inference/char-as-str-single.rs index 736920643b2..2903142f159 100644 --- a/tests/ui/inference/char-as-str-single.rs +++ b/tests/ui/inference/char-as-str-single.rs @@ -10,3 +10,12 @@ fn main() { let _: char = "人"; //~ ERROR mismatched types let _: char = "'"; //~ ERROR mismatched types } + +// regression test for https://github.com/rust-lang/rust/issues/109586 +#[allow(dead_code)] +fn convert_c_to_str(c: char) { + match c { + "A" => {} //~ ERROR mismatched types + _ => {} + } +} diff --git a/tests/ui/inference/char-as-str-single.stderr b/tests/ui/inference/char-as-str-single.stderr index 3375ec6ac32..9149efe3240 100644 --- a/tests/ui/inference/char-as-str-single.stderr +++ b/tests/ui/inference/char-as-str-single.stderr @@ -37,6 +37,19 @@ help: if you meant to write a `char` literal, use single quotes LL | let _: char = '\''; | ~~~~ -error: aborting due to 3 previous errors +error[E0308]: mismatched types + --> $DIR/char-as-str-single.rs:18:9 + | +LL | match c { + | - this expression has type `char` +LL | "A" => {} + | ^^^ expected `char`, found `&str` + | +help: if you meant to write a `char` literal, use single quotes + | +LL | 'A' => {} + | ~~~ + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0308`. |
