diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs index 23aeb1e06463c..ee0cef350b42f 100644 --- a/compiler/rustc_codegen_gcc/src/asm.rs +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -22,7 +22,7 @@ use rustc_target::asm::*; use crate::builder::Builder; use crate::callee::get_fn; use crate::context::CodegenCx; -use crate::errors::{NulBytesInAsm, UnwindingInlineAsm}; +use crate::diagnostics::{NulBytesInAsm, UnwindingInlineAsm}; use crate::type_of::LayoutGccExt; // Rust asm! and GCC Extended Asm semantics differ substantially. diff --git a/compiler/rustc_codegen_gcc/src/back/lto.rs b/compiler/rustc_codegen_gcc/src/back/lto.rs index 7166ad8b1f17f..98f9abdb05c4c 100644 --- a/compiler/rustc_codegen_gcc/src/back/lto.rs +++ b/compiler/rustc_codegen_gcc/src/back/lto.rs @@ -35,7 +35,7 @@ use rustc_log::tracing::info; use tempfile::{TempDir, tempdir}; use crate::back::write::{codegen, save_temp_bitcode}; -use crate::errors::LtoBitcodeFromRlib; +use crate::diagnostics::LtoBitcodeFromRlib; use crate::{GccCodegenBackend, GccContext, LtoMode, to_gcc_opt_level}; struct LtoData { diff --git a/compiler/rustc_codegen_gcc/src/back/write.rs b/compiler/rustc_codegen_gcc/src/back/write.rs index 8fd38a2efd600..cf5514412f745 100644 --- a/compiler/rustc_codegen_gcc/src/back/write.rs +++ b/compiler/rustc_codegen_gcc/src/back/write.rs @@ -12,7 +12,7 @@ use rustc_session::config::OutputType; use rustc_target::spec::SplitDebuginfo; use crate::base::add_pic_option; -use crate::errors::CopyBitcode; +use crate::diagnostics::CopyBitcode; use crate::{GccContext, LtoMode}; pub(crate) fn codegen( diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index 7671d2e026b03..a407362638f10 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -36,7 +36,7 @@ use rustc_target::spec::{HasTargetSpec, HasX86AbiOpt, Target, X86Abi}; use crate::abi::FnAbiGccExt; use crate::common::{SignType, TypeReflection, type_is_pointer}; use crate::context::CodegenCx; -use crate::errors; +use crate::diagnostics; use crate::intrinsic::llvm; use crate::type_of::LayoutGccExt; @@ -1803,7 +1803,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { _instance: Option>, ) { // FIXME: implement support for explicit tail calls like rustc_codegen_llvm. - self.tcx.dcx().emit_fatal(errors::ExplicitTailCallsUnsupported); + self.tcx.dcx().emit_fatal(diagnostics::ExplicitTailCallsUnsupported); } fn zext(&mut self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc> { diff --git a/compiler/rustc_codegen_gcc/src/errors.rs b/compiler/rustc_codegen_gcc/src/diagnostics.rs similarity index 100% rename from compiler/rustc_codegen_gcc/src/errors.rs rename to compiler/rustc_codegen_gcc/src/diagnostics.rs diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index 4cc4a2d258d14..55c721a9706a6 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -59,7 +59,7 @@ mod context; mod coverageinfo; mod debuginfo; mod declare; -mod errors; +mod diagnostics; mod gcc_util; mod int; mod intrinsic; diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 1f00e47a89927..a4176a8feb0f9 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -16,7 +16,7 @@ use rustc_target::spec::{Arch, FramePointer, SanitizerSet, StackProbeType, Stack use smallvec::SmallVec; use crate::context::SimpleCx; -use crate::errors::{PackedStackBackchainNeedsSoftfloat, SanitizerMemtagRequiresMte}; +use crate::diagnostics::{PackedStackBackchainNeedsSoftfloat, SanitizerMemtagRequiresMte}; use crate::llvm::AttributePlace::Function; use crate::llvm::{ self, AllocKindFlags, Attribute, AttributeKind, AttributePlace, MemoryEffects, Value, diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 70d48def59e91..4883eb1087be3 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -28,7 +28,7 @@ use crate::back::write::{ self, CodegenDiagnosticsStage, DiagnosticHandlers, bitcode_section_name, codegen, save_temp_bitcode, }; -use crate::errors::{LlvmError, LtoBitcodeFromRlib}; +use crate::diagnostics::{LlvmError, LtoBitcodeFromRlib}; use crate::llvm::{self, build_string}; use crate::{LlvmCodegenBackend, ModuleLlvm}; diff --git a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs index 65cf4cad24bd6..350d4ce9ee331 100644 --- a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs +++ b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs @@ -4,7 +4,7 @@ use std::ptr::NonNull; use rustc_data_structures::small_c_str::SmallCStr; -use crate::errors::LlvmError; +use crate::diagnostics::LlvmError; use crate::llvm; /// Responsible for safely creating and disposing llvm::TargetMachine via ffi functions. diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 6a0f4fa6d54d2..94883a94f089a 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -34,7 +34,7 @@ use crate::back::profiling::{ use crate::builder::SBuilder; use crate::builder::gpu_offload::scalar_width; use crate::common::AsCCharPtr; -use crate::errors::{ +use crate::diagnostics::{ CopyBitcode, FromLlvmDiag, FromLlvmOptimizationDiag, LlvmError, ParseTargetMachineConfig, UnsupportedCompression, WithLlvmError, WriteBytecode, }; @@ -819,7 +819,7 @@ pub(crate) unsafe fn llvm_optimize( device_out_c.as_ptr(), ); if !ok || !device_out.exists() { - dcx.emit_err(crate::errors::OffloadBundleImagesFailed); + dcx.emit_err(crate::diagnostics::OffloadBundleImagesFailed); } } } @@ -837,15 +837,15 @@ pub(crate) unsafe fn llvm_optimize( { let device_pathbuf = PathBuf::from(device_path); if device_pathbuf.is_relative() { - dcx.emit_err(crate::errors::OffloadWithoutAbsPath); + dcx.emit_err(crate::diagnostics::OffloadWithoutAbsPath); } else if device_pathbuf .file_name() .and_then(|n| n.to_str()) .is_some_and(|n| n != "device.bin") { - dcx.emit_err(crate::errors::OffloadWrongFileName); + dcx.emit_err(crate::diagnostics::OffloadWrongFileName); } else if !device_pathbuf.exists() { - dcx.emit_err(crate::errors::OffloadNonexistingPath); + dcx.emit_err(crate::diagnostics::OffloadNonexistingPath); } let host_path = cgcx.output_filenames.path(OutputType::Object); let host_dir = host_path.parent().unwrap(); @@ -859,7 +859,7 @@ pub(crate) unsafe fn llvm_optimize( let ok = unsafe { llvm::LLVMRustOffloadEmbedBufferInModule(llmod2, device_bin_c.as_ptr()) }; if !ok { - dcx.emit_err(crate::errors::OffloadEmbedFailed); + dcx.emit_err(crate::diagnostics::OffloadEmbedFailed); } write_output_file( dcx, diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 8f87acaf675a4..ee752373ceca4 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -21,7 +21,7 @@ use rustc_target::spec::Arch; use tracing::{debug, instrument, trace}; use crate::common::CodegenCx; -use crate::errors::SymbolAlreadyDefined; +use crate::diagnostics::SymbolAlreadyDefined; use crate::llvm::{self, Type, Value, const_ptr_auth}; use crate::type_of::LayoutLlvmExt; use crate::{base, debuginfo}; diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 8f1910eaced13..89d9be451ebf4 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -238,7 +238,7 @@ pub(crate) unsafe fn create_module<'ll>( .expect("got a non-UTF8 data-layout from LLVM"); if target_data_layout != llvm_data_layout { - tcx.dcx().emit_err(crate::errors::MismatchedDataLayout { + tcx.dcx().emit_err(crate::diagnostics::MismatchedDataLayout { rustc_target: sess.opts.target_triple.to_string().as_str(), rustc_layout: target_data_layout.as_str(), llvm_target: sess.target.llvm_target.borrow(), diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/diagnostics.rs similarity index 100% rename from compiler/rustc_codegen_llvm/src/errors.rs rename to compiler/rustc_codegen_llvm/src/diagnostics.rs diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index edf943c81a755..4ae85af897527 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -39,7 +39,7 @@ use crate::builder::gpu_offload::{ }; use crate::context::CodegenCx; use crate::declare::declare_raw_fn; -use crate::errors::{ +use crate::diagnostics::{ AutoDiffWithoutEnable, AutoDiffWithoutLto, IntrinsicSignatureMismatch, IntrinsicWrongArch, OffloadWithoutEnable, OffloadWithoutFatLTO, UnknownIntrinsic, }; diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 1dd460c409737..3ec0495956c4c 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -59,7 +59,7 @@ mod context; mod coverageinfo; mod debuginfo; mod declare; -mod errors; +mod diagnostics; mod intrinsic; mod llvm; mod llvm_util; @@ -233,10 +233,11 @@ impl CodegenBackend for LlvmCodegenBackend { match llvm::EnzymeWrapper::get_or_init(&sess.opts.sysroot) { Ok(_) => {} Err(llvm::EnzymeLibraryError::NotFound { err }) => { - sess.dcx().emit_fatal(crate::errors::AutoDiffComponentMissing { err }); + sess.dcx().emit_fatal(crate::diagnostics::AutoDiffComponentMissing { err }); } Err(llvm::EnzymeLibraryError::LoadFailed { err }) => { - sess.dcx().emit_fatal(crate::errors::AutoDiffComponentUnavailable { err }); + sess.dcx() + .emit_fatal(crate::diagnostics::AutoDiffComponentUnavailable { err }); } } enable_autodiff_settings(&sess.opts.unstable_opts.autodiff); diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 87d8676cd8018..9ad14925afb14 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -21,7 +21,7 @@ use rustc_target::spec::{ use smallvec::{SmallVec, smallvec}; use crate::back::write::create_informational_target_machine; -use crate::{errors, llvm}; +use crate::{diagnostics, llvm}; static INIT: Once = Once::new(); @@ -636,7 +636,8 @@ fn llvm_features_by_flags(sess: &Session, features: &mut Vec) { // -Zfixed-x18 if sess.opts.unstable_opts.fixed_x18 { if sess.target.arch != Arch::AArch64 { - sess.dcx().emit_fatal(errors::FixedX18InvalidArch { arch: sess.target.arch.desc() }); + sess.dcx() + .emit_fatal(diagnostics::FixedX18InvalidArch { arch: sess.target.arch.desc() }); } else { features.push("+reserve-x18".into()); } diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index b746bab643a34..19d43797a875d 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -19,7 +19,7 @@ use tracing::debug; use crate::abi::FnAbiLlvmExt; use crate::builder::Builder; use crate::context::CodegenCx; -use crate::errors::SymbolAlreadyDefined; +use crate::diagnostics::SymbolAlreadyDefined; use crate::type_of::LayoutLlvmExt; use crate::{base, llvm}; diff --git a/compiler/rustc_hir_analysis/src/check/always_applicable.rs b/compiler/rustc_hir_analysis/src/check/always_applicable.rs index b9c0011d1a4ff..2d56f2f1542ab 100644 --- a/compiler/rustc_hir_analysis/src/check/always_applicable.rs +++ b/compiler/rustc_hir_analysis/src/check/always_applicable.rs @@ -16,6 +16,7 @@ use rustc_span::sym; use rustc_trait_selection::regions::InferCtxtRegionExt; use rustc_trait_selection::traits::{self, ObligationCtxt}; +use crate::check::missing_items_must_implement_one_of_err; use crate::diagnostics; use crate::hir::def_id::{DefId, LocalDefId}; @@ -394,11 +395,12 @@ fn check_drop_xor_pin_drop<'tcx>( match (drop_span, pin_drop_span) { (None, None) => { if tcx.features().pin_ergonomics() { - return Err(tcx.dcx().emit_err(crate::diagnostics::MissingOneOfTraitItem { - span: tcx.def_span(drop_impl_did), - note: None, - missing_items_msg: "drop`, `pin_drop".to_string(), - })); + return Err(missing_items_must_implement_one_of_err( + tcx, + drop_impl_did, + [sym::drop, sym::pin_drop].into_iter(), + None, + )); } else { return Err(tcx .dcx() diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 26d289a0fc70c..1b2e496d6a23c 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1436,19 +1436,13 @@ fn check_impl_items_against_trait<'tcx>( } if !missing_items.is_empty() { - let full_impl_span = tcx.hir_span_with_body(tcx.local_def_id_to_hir_id(impl_id)); - missing_items_err(tcx, impl_id, &missing_items, full_impl_span); + missing_items_err(tcx, impl_id, &missing_items); } if let Some(missing_items) = must_implement_one_of { let attr_span = find_attr!(tcx, trait_ref.def_id, RustcMustImplementOneOf {attr_span, ..} => *attr_span); - - missing_items_must_implement_one_of_err( - tcx, - tcx.def_span(impl_id), - missing_items, - attr_span, - ); + let missing_items = missing_items.into_iter().map(|i| i.name); + missing_items_must_implement_one_of_err(tcx, impl_id, missing_items, attr_span); } } } diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 451db9fd64aca..0d45703e17fbd 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -103,6 +103,9 @@ use tracing::debug; use self::compare_impl_item::collect_return_position_impl_trait_in_trait_tys; use self::region::region_scope_tree; +use crate::diagnostics::{ + MissingTraitItemLabel, MissingTraitItemSuggestion, MissingTraitItemSuggestionNone, +}; use crate::{check_c_variadic_abi, diagnostics}; /// Adds query implementations to the [Providers] vtable, see [`rustc_middle::query`] @@ -203,11 +206,30 @@ pub(super) fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDef } } -fn missing_items_err( +fn impl_suggestion_span(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) -> Span { + let full_impl_span = tcx.hir_span_with_body(tcx.local_def_id_to_hir_id(impl_def_id)); + if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(full_impl_span) + && snippet.ends_with("}") + { + // `Span` before impl block closing brace. + let hi = full_impl_span.hi() - BytePos(1); + // Point at the place right before the closing brace of the relevant `impl` to suggest + // adding the associated item at the end of its body. + full_impl_span.with_lo(hi).with_hi(hi) + } else { + full_impl_span.shrink_to_hi() + } +} + +fn missing_items_suggestions( tcx: TyCtxt<'_>, impl_def_id: LocalDefId, missing_items: &[ty::AssocItem], - full_impl_span: Span, +) -> ( + String, + Vec, + Vec, + Vec, ) { let missing_items = missing_items.iter().filter(|trait_item| !trait_item.is_impl_trait_in_trait()); @@ -218,17 +240,7 @@ fn missing_items_err( .collect::>() .join("`, `"); - let sugg_sp = if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(full_impl_span) - && snippet.ends_with("}") - { - // `Span` before impl block closing brace. - let hi = full_impl_span.hi() - BytePos(1); - // Point at the place right before the closing brace of the relevant `impl` to suggest - // adding the associated item at the end of its body. - full_impl_span.with_lo(hi).with_hi(hi) - } else { - full_impl_span.shrink_to_hi() - }; + let sugg_sp = impl_suggestion_span(tcx, impl_def_id); // Obtain the level of indentation ending in `sugg_sp`. let padding = tcx.sess.source_map().indentation_before(sugg_sp).unwrap_or_else(String::new); @@ -259,6 +271,13 @@ fn missing_items_err( } } + (missing_items_msg, missing_trait_item, missing_trait_item_none, missing_trait_item_label) +} + +fn missing_items_err(tcx: TyCtxt<'_>, impl_def_id: LocalDefId, missing_items: &[ty::AssocItem]) { + let (missing_items_msg, missing_trait_item, missing_trait_item_none, missing_trait_item_label) = + missing_items_suggestions(tcx, impl_def_id, missing_items); + tcx.dcx().emit_err(diagnostics::MissingTraitItem { span: tcx.span_of_impl(impl_def_id.to_def_id()).unwrap(), missing_items_msg, @@ -270,18 +289,29 @@ fn missing_items_err( fn missing_items_must_implement_one_of_err( tcx: TyCtxt<'_>, - impl_span: Span, - missing_items: &[Ident], + impl_def_id: LocalDefId, + missing_items: impl Iterator, annotation_span: Option, -) { - let missing_items_msg = - missing_items.iter().map(Ident::to_string).collect::>().join("`, `"); +) -> ErrorGuaranteed { + // Look up the associated items so we can use them to emit better errors. + let trait_def_id = tcx.impl_trait_id(impl_def_id); + let assoc_items = tcx.associated_items(trait_def_id); + let missing_items = missing_items + .flat_map(|s| assoc_items.filter_by_name_unhygienic_and_kind(s, ty::AssocTag::Fn)) + .cloned() + .collect::>(); + + let (missing_items_msg, missing_trait_item, missing_trait_item_none, missing_trait_item_label) = + missing_items_suggestions(tcx, impl_def_id, &missing_items); tcx.dcx().emit_err(diagnostics::MissingOneOfTraitItem { - span: impl_span, + span: tcx.def_span(impl_def_id), note: annotation_span, missing_items_msg, - }); + missing_trait_item_label, + missing_trait_item, + missing_trait_item_none, + }) } fn default_body_is_unstable( diff --git a/compiler/rustc_hir_analysis/src/diagnostics.rs b/compiler/rustc_hir_analysis/src/diagnostics.rs index 0ea353cf14cee..eb0dcb3a346b2 100644 --- a/compiler/rustc_hir_analysis/src/diagnostics.rs +++ b/compiler/rustc_hir_analysis/src/diagnostics.rs @@ -966,6 +966,12 @@ pub(crate) struct MissingOneOfTraitItem { pub span: Span, #[note("required because of this annotation")] pub note: Option, + #[subdiagnostic] + pub missing_trait_item_label: Vec, + #[subdiagnostic] + pub missing_trait_item: Vec, + #[subdiagnostic] + pub missing_trait_item_none: Vec, pub missing_items_msg: String, } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 4ce07ffe45ed7..ad00003af9482 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -41,7 +41,8 @@ use crate::ref_mut::CmCell; use crate::{ BindingKey, Decl, DeclData, DeclKind, DelayedVisResolutionError, ExternModule, ExternPreludeEntry, Finalize, IdentKey, LocalModule, Module, ModuleKind, ModuleOrUniformRoot, - ParentScope, PathResult, Res, Resolver, Segment, Used, VisResolutionError, diagnostics, + ParentScope, PathResult, Res, ResolutionTable, Resolver, Segment, Used, VisResolutionError, + diagnostics, }; impl<'ra, 'tcx> Resolver<'ra, 'tcx> { @@ -279,7 +280,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { res, )) }; - match self.cm().resolve_path( + match self.cm_mut().resolve_path( &segments, None, parent_scope, @@ -336,7 +337,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { pub(crate) fn build_reduced_graph_external( &self, module: ExternModule<'ra>, - ) -> FxIndexMap> { + ) -> ResolutionTable<'ra> { let mut resolutions = FxIndexMap::default(); let def_id = module.def_id(); let children = self.tcx.module_children(def_id); diff --git a/compiler/rustc_resolve/src/diagnostics/impls.rs b/compiler/rustc_resolve/src/diagnostics/impls.rs index cbc84540fcdef..212629395c98b 100644 --- a/compiler/rustc_resolve/src/diagnostics/impls.rs +++ b/compiler/rustc_resolve/src/diagnostics/impls.rs @@ -782,7 +782,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// This takes the error provided, combines it with the span and any additional spans inside the /// error and emits it. pub(crate) fn report_error( - &mut self, + &self, span: Span, resolution_error: ResolutionError<'ra>, ) -> ErrorGuaranteed { @@ -790,7 +790,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } pub(crate) fn into_struct_error( - &mut self, + &self, span: Span, resolution_error: ResolutionError<'ra>, ) -> Diag<'_> { @@ -1459,7 +1459,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } pub(crate) fn add_scope_set_candidates( - &mut self, + &self, suggestions: &mut Vec, scope_set: ScopeSet<'ra>, ps: &ParentScope<'ra>, @@ -1560,7 +1560,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// Lookup typo candidate in scope for a macro or import. fn early_lookup_typo_candidate( - &mut self, + &self, scope_set: ScopeSet<'ra>, parent_scope: &ParentScope<'ra>, ident: Ident, @@ -1828,7 +1828,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// N.B., the method does not look into imports, but this is not a problem, /// since we report the definitions (thus, the de-aliased imports). pub(crate) fn lookup_import_candidates( - &mut self, + &self, lookup_ident: Ident, namespace: Namespace, parent_scope: &ParentScope<'ra>, @@ -3310,7 +3310,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// ``` #[instrument(level = "debug", skip(self, parent_scope))] fn make_missing_self_suggestion( - &mut self, + &self, mut path: Vec, parent_scope: &ParentScope<'ra>, ) -> Option<(Vec, Option)> { @@ -3330,7 +3330,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// ``` #[instrument(level = "debug", skip(self, parent_scope))] fn make_missing_crate_suggestion( - &mut self, + &self, mut path: Vec, parent_scope: &ParentScope<'ra>, ) -> Option<(Vec, Option)> { @@ -3362,7 +3362,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// ``` #[instrument(level = "debug", skip(self, parent_scope))] fn make_missing_super_suggestion( - &mut self, + &self, mut path: Vec, parent_scope: &ParentScope<'ra>, ) -> Option<(Vec, Option)> { @@ -3385,7 +3385,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// name as the first part of path. #[instrument(level = "debug", skip(self, parent_scope))] fn make_external_crate_suggestion( - &mut self, + &self, mut path: Vec, parent_scope: &ParentScope<'ra>, ) -> Option<(Vec, Option)> { diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 1c94779a6009a..3f34af1d01d83 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -346,7 +346,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { diag_metadata, ))); } else if let RibKind::Block(Some(module)) = rib.kind - && let Ok(binding) = self.cm().resolve_ident_in_scope_set( + && let Ok(binding) = self.cm_mut().resolve_ident_in_scope_set( ident, ScopeSet::Module(ns, module.to_module()), parent_scope, @@ -362,7 +362,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let parent_scope = &ParentScope { module: module.to_module(), ..*parent_scope }; let finalize = finalize.map(|f| Finalize { stage: Stage::Late, ..f }); return self - .cm() + .cm_mut() .resolve_ident_in_scope_set( orig_ident, ScopeSet::All(ns), @@ -1457,7 +1457,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// Validate a local resolution (from ribs). #[instrument(level = "debug", skip(self, all_ribs))] fn validate_res_from_ribs( - &mut self, + &self, rib_index: usize, rib_ident: Ident, res: Res, diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 3f2e24995deab..c00eb97f4c3d6 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -34,9 +34,9 @@ use crate::diagnostics::{ }; use crate::ref_mut::{CmCell, CmRefCell}; use crate::{ - AmbiguityError, BindingKey, CmResolver, Decl, DeclData, DeclKind, Determinacy, Finalize, - IdentKey, ImportSuggestion, ImportSummary, LocalModule, ModuleOrUniformRoot, ParentScope, - PathResult, PerNS, Res, ResolutionError, Resolver, ScopeSet, Segment, Used, module_to_string, + AmbiguityError, BindingKey, Decl, DeclData, DeclKind, Determinacy, Finalize, IdentKey, + ImportSuggestion, ImportSummary, LocalModule, ModuleOrUniformRoot, ParentScope, PathResult, + PerNS, Res, ResolutionError, Resolver, ScopeSet, Segment, Used, module_to_string, names_to_string, }; @@ -735,7 +735,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } let dummy_decl = self.dummy_decl; let dummy_decl = self.new_import_decl(dummy_decl, import); - self.per_ns(|this, ns| { + self.per_ns_mut(|this, ns| { let ident = IdentKey::new(target); // This can fail, dummies are inserted only in non-occupied slots. let _ = this.try_plant_decl_into_local_module(ident, target.span, ns, dummy_decl); @@ -782,13 +782,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut imports_to_resolve = mem::take(&mut self.indeterminate_imports); self.assert_speculative = true; - let cm_resolver = self.cm(); - rustc_data_structures::sync::par_for_each_slice( &mut imports_to_resolve, |(import, resolution, indeterminate_count)| { - (*resolution, *indeterminate_count) = - cm_resolver.reborrow_ref().resolve_import(*import); + (*resolution, *indeterminate_count) = self.resolve_import(*import); }, ); self.assert_speculative = false; @@ -835,7 +832,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ImportKind::Single { target, decls, .. }, ImportResolutionKind::Single(import_decls), ) => { - self.per_ns(|this, ns| { + self.per_ns_mut(|this, ns| { match import_decls[ns] { PendingDecl::Ready(Some(decl)) => { // We need the `target`, `source` can be extracted. @@ -1116,10 +1113,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// - Other values mean that indeterminate exists under certain namespaces. /// /// Meanwhile, if resolution is successful, its result is returned. - fn resolve_import<'r>( - mut self: CmResolver<'r, 'ra, 'tcx>, - import: Import<'ra>, - ) -> (Option>, usize) { + fn resolve_import(&self, import: Import<'ra>) -> (Option>, usize) { debug!( "(resolving import for module) resolving import `{}::{}` in `{}`", Segment::names_to_string(&import.module_path), @@ -1129,7 +1123,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let module = if let Some(module) = import.imported_module.get() { module } else { - let path_res = self.reborrow().maybe_resolve_path( + let path_res = self.cm().maybe_resolve_path( &import.module_path, None, &import.parent_scope, @@ -1157,11 +1151,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut decls = PerNS::default(); let mut indeterminate_count = 0; - self.per_ns_cm(|mut this, ns| { + self.per_ns(|this, ns| { if bindings[ns].get() != PendingDecl::Pending { return; }; - let binding_result = this.reborrow().maybe_resolve_ident_in_module( + let binding_result = this.cm().maybe_resolve_ident_in_module( module, source, ns, @@ -1202,7 +1196,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // We'll provide more context to the privacy errors later, up to `len`. let privacy_errors_len = self.privacy_errors.len(); - let path_res = self.cm().resolve_path( + let path_res = self.cm_mut().resolve_path( &import.module_path, None, &import.parent_scope, @@ -1370,14 +1364,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // importing it if available. let mut path = import.module_path.clone(); path.push(Segment::from_ident(ident)); - if let PathResult::Module(ModuleOrUniformRoot::Module(module)) = self.cm().resolve_path( - &path, - None, - &import.parent_scope, - Some(finalize), - ignore_decl, - None, - ) { + if let PathResult::Module(ModuleOrUniformRoot::Module(module)) = self + .cm_mut() + .resolve_path(&path, None, &import.parent_scope, Some(finalize), ignore_decl, None) + { let res = module.res().map(|r| (r, ident)); for error in &mut self.privacy_errors[privacy_errors_len..] { error.outermost_res = res; @@ -1407,8 +1397,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } let mut all_ns_err = true; - self.per_ns(|this, ns| { - let binding = this.cm().resolve_ident_in_module( + self.per_ns_mut(|this, ns| { + let binding = this.cm_mut().resolve_ident_in_module( module, ident, ns, @@ -1472,8 +1462,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if all_ns_err { let mut all_ns_failed = true; - self.per_ns(|this, ns| { - let binding = this.cm().resolve_ident_in_module( + self.per_ns_mut(|this, ns| { + let binding = this.cm_mut().resolve_ident_in_module( module, ident, ns, @@ -1632,7 +1622,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // 2 segments, so the `resolve_path` above won't trigger it. let mut full_path = import.module_path.clone(); full_path.push(Segment::from_ident(ident)); - self.per_ns(|this, ns| { + self.per_ns_mut(|this, ns| { if let Some(binding) = bindings[ns].get().decl().map(|b| b.import_source()) { this.lint_if_path_starts_with_module(finalize, &full_path, Some(binding)); } @@ -1642,7 +1632,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Record what this import resolves to for later uses in documentation, // this may resolve to either a value or a type, but for documentation // purposes it's good enough to just favor one over the other. - self.per_ns(|this, ns| { + self.per_ns_mut(|this, ns| { if let Some(binding) = bindings[ns].get().decl().map(|b| b.import_source()) { this.owners.get_mut(&import_id).unwrap().import_res[ns] = Some(binding.res()); } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 535d11d00d718..f30e6844c861c 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1581,7 +1581,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { finalize: Option, source: PathSource<'_, 'ast, 'ra>, ) -> PathResult<'ra> { - self.r.cm().resolve_path_with_ribs( + self.r.cm_mut().resolve_path_with_ribs( path, opt_ns, &self.parent_scope, diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index e26bfa6b96d51..f2ce21377acce 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -2067,7 +2067,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } fn update_err_for_private_tuple_struct_fields( - &mut self, + &self, err: &mut Diag<'_>, source: &PathSource<'_, '_, '_>, def_id: DefId, @@ -2177,7 +2177,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } }; - let bad_struct_syntax_suggestion = |this: &mut Self, err: &mut Diag<'_>, def_id: DefId| { + let bad_struct_syntax_suggestion = |this: &Self, err: &mut Diag<'_>, def_id: DefId| { let (followed_by_brace, closing_brace) = this.followed_by_brace(span); match source { @@ -2629,7 +2629,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } fn suggest_alternative_construction_methods( - &mut self, + &self, def_id: DefId, err: &mut Diag<'_>, path_span: Span, @@ -2784,7 +2784,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } fn lookup_assoc_candidate( - &mut self, + &self, ident: Ident, ns: Namespace, filter_fn: FilterFn, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 2dbf32dc20288..af62b136f60c5 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -24,7 +24,7 @@ use std::cell::Ref; use std::collections::BTreeSet; use std::ops::ControlFlow; -use std::sync::{Arc, Once}; +use std::sync::{Arc, OnceLock}; use std::{fmt, mem}; use diagnostics::{ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst}; @@ -633,7 +633,22 @@ impl BindingKey { } } -type Resolutions<'ra> = CmRefCell>>; +type ResolutionTable<'ra> = FxIndexMap>; + +enum Resolutions<'ra> { + Local(CmRefCell>), + Extern(OnceLock>>), +} + +impl<'ra> Resolutions<'ra> { + fn new(local: bool) -> Self { + if local { + Resolutions::Local(Default::default()) + } else { + Resolutions::Extern(Default::default()) + } + } +} /// One node in the tree of modules. /// @@ -655,8 +670,6 @@ struct ModuleData<'ra> { /// Mapping between names and their (possibly in-progress) resolutions in this module. /// Resolutions in modules from other crates are not populated until accessed. lazy_resolutions: Resolutions<'ra>, - /// True if this is a module from other crate that needs to be populated on access. - populate_on_access: Once, /// Used to disambiguate underscore items (`const _: T = ...`) in the module. underscore_disambiguator: CmCell, @@ -710,6 +723,7 @@ impl<'ra> ModuleData<'ra> { vis: Visibility, arenas: &'ra ResolverArenas<'ra>, ) -> Self { + let lazy_resolutions = Resolutions::new(kind.is_local()); let self_decl = match kind { ModuleKind::Def(def_kind, def_id, ..) => { let expn_id = expansion.as_local().unwrap_or(LocalExpnId::ROOT); @@ -720,8 +734,7 @@ impl<'ra> ModuleData<'ra> { ModuleData { parent, kind, - lazy_resolutions: Default::default(), - populate_on_access: Once::new(), + lazy_resolutions, underscore_disambiguator: CmCell::new(0), unexpanded_invocations: Default::default(), no_implicit_prelude, @@ -1990,27 +2003,28 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - /// Returns a conditionally mutable resolver. - /// - /// Currently only dependent on `assert_speculative`, if `assert_speculative` is false, - /// the resolver will allow mutation; otherwise, it will be immutable. - fn cm(&mut self) -> CmResolver<'_, 'ra, 'tcx> { - CmResolver::new(self, !self.assert_speculative) + /// Returns a conditionally mutable resolver that cannot be mutated. + fn cm(&self) -> CmResolver<'_, 'ra, 'tcx> { + CmResolver::Ref(self) + } + + /// Returns a conditionally mutable resolver that can be mutated. + /// Will panic if the `assert_speculative` field is true. + fn cm_mut(&mut self) -> CmResolver<'_, 'ra, 'tcx> { + assert!(!self.assert_speculative, "can't mutably borrow speculative resolver"); + CmResolver::Mut(self) } /// Runs the function on each namespace. - fn per_ns(&mut self, mut f: F) { + fn per_ns(&self, mut f: F) { f(self, TypeNS); f(self, ValueNS); f(self, MacroNS); } - fn per_ns_cm<'r, F: FnMut(CmResolver<'_, 'ra, 'tcx>, Namespace)>( - mut self: CmResolver<'r, 'ra, 'tcx>, - mut f: F, - ) { - f(self.reborrow(), TypeNS); - f(self.reborrow(), ValueNS); + fn per_ns_mut(&mut self, mut f: F) { + f(self, TypeNS); + f(self, ValueNS); f(self, MacroNS); } @@ -2080,7 +2094,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let scope_set = ScopeSet::All(TypeNS); let ctxt = Macros20NormalizedSyntaxContext::new(sp.ctxt()); - self.cm().visit_scopes(scope_set, parent_scope, ctxt, sp, None, |mut this, scope, _, _| { + let cmr = self.cm_mut(); + cmr.visit_scopes(scope_set, parent_scope, ctxt, sp, None, |mut this, scope, _, _| { match scope { Scope::ModuleNonGlobs(module, _) => { this.get_mut().traits_in_module(module, assoc_item, &mut found_traits); @@ -2162,15 +2177,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.tcx.hir_arena.alloc_slice(&import_ids) } - fn resolutions(&self, module: Module<'ra>) -> &'ra Resolutions<'ra> { - if !module.is_local() { - // as long as 1 thread is building this external table, all other threads will wait - module.populate_on_access.call_once(|| { - *module.lazy_resolutions.borrow_mut_unchecked() = - self.build_reduced_graph_external(module.expect_extern()); - }); + fn resolutions(&self, module: Module<'ra>) -> &'ra CmRefCell> { + match &module.0.0.lazy_resolutions { + Resolutions::Local(local_res) => local_res, + Resolutions::Extern(extern_res) => { + // as long as 1 thread is building this external table, all other threads will wait + extern_res.get_or_init(|| { + CmRefCell::new(self.build_reduced_graph_external(module.expect_extern())) + }) + } } - &module.0.0.lazy_resolutions } fn resolution( @@ -2464,7 +2480,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// and also it's a private type. Fortunately rustdoc doesn't need to know the error, /// just that an error occurred. fn resolve_rustdoc_path( - &mut self, + &self, path_str: &str, ns: Namespace, parent_scope: ParentScope<'ra>, @@ -2791,7 +2807,7 @@ pub fn provide(providers: &mut Providers) { /// /// `Cm` stands for "conditionally mutable". /// -/// Prefer constructing it through [`Resolver::cm`] to ensure correctness. +/// Prefer constructing it through `Resolver::cm(_mut)` to ensure correctness. type CmResolver<'r, 'ra, 'tcx> = ref_mut::RefOrMut<'r, Resolver<'ra, 'tcx>>; // FIXME: These are cells for caches that can be populated even during speculative resolution, @@ -2802,68 +2818,52 @@ use std::cell::{Cell as CacheCell, RefCell as CacheRefCell}; mod ref_mut { use std::cell::{BorrowMutError, Cell, Ref, RefCell, RefMut}; use std::fmt; - use std::marker::PhantomData; use std::ops::Deref; use crate::Resolver; - /// A wrapper around a mutable reference that conditionally allows mutable access. - pub(crate) struct RefOrMut<'a, T> { - // We keep a raw pointer because it makes `reborrow_ref` possible. It is always safe to - // cast this to a `&T` because `RefOrMut` is only created through `new` which takes - // a `&mut T`. - p: *mut T, - mutable: bool, - _marker: PhantomData<&'a mut T>, + /// A reference type that conditionally allows mutable access. + pub(crate) enum RefOrMut<'a, T> { + Ref(&'a T), + Mut(&'a mut T), } impl<'a, T> Deref for RefOrMut<'a, T> { type Target = T; fn deref(&self) -> &Self::Target { - // SAFETY: `RefOrMUt` is only constructable through a `&mut T`. - unsafe { self.p.as_ref_unchecked() } + match self { + RefOrMut::Ref(r) => r, + RefOrMut::Mut(r) => r, + } } } impl<'a, T> AsRef for RefOrMut<'a, T> { fn as_ref(&self) -> &T { - // SAFETY: `RefOrMUt` is only constructable through a `&mut T`. - unsafe { self.p.as_ref_unchecked() } + &*self } } impl<'a, T> RefOrMut<'a, T> { - pub(crate) fn new(p: &'a mut T, mutable: bool) -> Self { - RefOrMut { p, mutable, _marker: PhantomData } - } - - pub(crate) fn reborrow_ref(&self) -> RefOrMut<'_, T> { - assert!( - !self.mutable, - "Tried to reborrow a mutable `RefOrMut` through shared reference." - ); - RefOrMut { p: self.p, mutable: self.mutable, _marker: PhantomData } - } - - /// This is needed because this wraps a `&mut T` and is therefore not `Copy`. + /// This is needed because the type may allow mutable access and is therefore not `Copy`. pub(crate) fn reborrow(&mut self) -> RefOrMut<'_, T> { - RefOrMut { p: self.p, mutable: self.mutable, _marker: PhantomData } + match self { + RefOrMut::Ref(r) => RefOrMut::Ref(r), + RefOrMut::Mut(r) => RefOrMut::Mut(r), + } } /// Returns a mutable reference to the inner value if allowed. /// /// # Panics /// - /// Panics if the `mutable` flag is false. + /// Panics if the wrapped reference is immutable. #[track_caller] pub(crate) fn get_mut(&mut self) -> &mut T { - match self.mutable { - false => panic!("can't mutably borrow speculative resolver"), - // SAFETY: - // - `RefOrMut` is only constructable through a `&mut T` and we - // have tested that it may indeed be used as a `&mut T` in this match. - true => unsafe { self.p.as_mut_unchecked() }, + match self { + RefOrMut::Ref(_) => panic!("can't mutably borrow an immutable reference"), + RefOrMut::Mut(r) => r, } } } @@ -2924,13 +2924,6 @@ mod ref_mut { CmRefCell(RefCell::new(value)) } - #[track_caller] - // FIXME: this should be eliminated in the process of migration - // to parallel name resolution. - pub(crate) fn borrow_mut_unchecked(&self) -> RefMut<'_, T> { - self.0.borrow_mut() - } - #[track_caller] pub(crate) fn borrow_mut<'ra, 'tcx>(&self, r: &Resolver<'ra, 'tcx>) -> RefMut<'_, T> { if r.assert_speculative { diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 54f9aa8e914ec..1e9d60ca21551 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -613,7 +613,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { invoc_in_mod_inert_attr: Option, suggestion_span: Option, ) -> Result<(&'ra Arc, Res), Indeterminate> { - let (ext, res) = match self.cm().resolve_macro_or_delegation_path( + let (ext, res) = match self.cm_mut().resolve_macro_or_delegation_path( path, kind, parent_scope, @@ -966,7 +966,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { for seg in &mut path { seg.id = None; } - match self.cm().resolve_path( + match self.cm_mut().resolve_path( &path, Some(ns), &parent_scope, @@ -1063,7 +1063,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let macro_resolutions = self.single_segment_macro_resolutions.take(self); for (ident, kind, parent_scope, initial_binding, sugg_span) in macro_resolutions { - match self.cm().resolve_ident_in_scope_set( + match self.cm_mut().resolve_ident_in_scope_set( ident, ScopeSet::Macro(kind), &parent_scope, @@ -1117,7 +1117,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let builtin_attrs = mem::take(&mut self.builtin_attrs); for (ident, parent_scope) in builtin_attrs { - let _ = self.cm().resolve_ident_in_scope_set( + let _ = self.cm_mut().resolve_ident_in_scope_set( ident, ScopeSet::Macro(MacroKind::Attr), &parent_scope, @@ -1295,7 +1295,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } fn path_accessible( - &mut self, + &self, expn_id: LocalExpnId, path: &ast::Path, namespaces: &[Namespace], diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index 0af41423b846a..57f1a9788c20c 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -1366,8 +1366,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if kind1 == kind2 && alias1 == alias2 && !self.tcx.sess.opts.verbose => { let mut strs = (DiagStyledString::new(), DiagStyledString::new()); - strs.0.push_normal(format!("_")); - strs.1.push_normal(format!("_")); + strs.0.push_normal("_"); + strs.1.push_normal("_"); strs } @@ -1376,14 +1376,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { match (alias1.kind, alias2.kind) { (ty::Projection { def_id: def_id1 }, ty::Projection { def_id: def_id2 }) => { // `::Name` - values.0.push_normal(format!("<")); - values.1.push_normal(format!("<")); + values.0.push_normal("<"); + values.1.push_normal("<"); let (trait_ref1, args1) = alias1.trait_ref_and_own_args(self.tcx); let (trait_ref2, args2) = alias2.trait_ref_and_own_args(self.tcx); self.recurse(trait_ref1.self_ty(), trait_ref2.self_ty(), &mut values); - values.0.push_normal(format!(" as ")); - values.1.push_normal(format!(" as ")); + values.0.push_normal(" as "); + values.1.push_normal(" as "); if trait_ref1.def_id == trait_ref2.def_id { if self.tcx.sess.opts.verbose { values @@ -1414,8 +1414,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .1 .push_highlighted(format!("{}", trait_ref2.print_trait_sugared())); } - values.0.push_normal(format!(">::")); - values.1.push_normal(format!(">::")); + values.0.push_normal(">::"); + values.1.push_normal(">::"); let name1 = self.tcx.item_name(def_id1); let name2 = self.tcx.item_name(def_id2); if def_id1 == def_id2 { diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 81f19529418a5..60f4ca6a8759c 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -285,27 +285,21 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { || self.tcx.is_diagnostic_item(sym::TryFrom, trait_def_id)) && (self.tcx.is_diagnostic_item(sym::From, leaf_trait_def_id) || self.tcx.is_diagnostic_item(sym::TryFrom, leaf_trait_def_id)) - { - let trait_ref = leaf_trait_predicate.skip_binder().trait_ref; - - if let Some(found_ty) = + && let Some(trait_ref) = + leaf_trait_predicate.no_bound_vars().map(|pred| pred.trait_ref) + && let Some(found_ty) = trait_ref.args.get(1).and_then(|arg| arg.as_type()) - { - let ty = main_trait_predicate.skip_binder().self_ty(); + && let Some(ty) = + main_trait_predicate.no_bound_vars().map(|pred| pred.self_ty()) + && let Some(cast_ty) = + self.find_explicit_cast_type(obligation.param_env, found_ty, ty) + { + let found_ty_str = self.tcx.short_string(found_ty, &mut long_ty_file); + let cast_ty_str = self.tcx.short_string(cast_ty, &mut long_ty_file); - if let Some(cast_ty) = - self.find_explicit_cast_type(obligation.param_env, found_ty, ty) - { - let found_ty_str = - self.tcx.short_string(found_ty, &mut long_ty_file); - let cast_ty_str = - self.tcx.short_string(cast_ty, &mut long_ty_file); - - err.help(format!( - "consider casting the `{found_ty_str}` value to `{cast_ty_str}`", - )); - } - } + err.help(format!( + "consider casting the `{found_ty_str}` value to `{cast_ty_str}`", + )); } *err.long_ty_path() = long_ty_file; diff --git a/library/alloc/src/io/buffered/bufwriter.rs b/library/alloc/src/io/buffered/bufwriter.rs index 4847c1605ac79..806e71c2772ae 100644 --- a/library/alloc/src/io/buffered/bufwriter.rs +++ b/library/alloc/src/io/buffered/bufwriter.rs @@ -490,6 +490,10 @@ impl BufWriter { /// # Example /// /// ``` +/// # // This test requires unwinding to work. +/// # // Disable it when unwinding isn't available. +/// # #[cfg(panic = "unwind")] +/// # fn main() { /// use std::io::{self, BufWriter, Write}; /// use std::panic::{catch_unwind, AssertUnwindSafe}; /// @@ -508,6 +512,9 @@ impl BufWriter { /// let (recovered_writer, buffered_data) = stream.into_parts(); /// assert!(matches!(recovered_writer, PanickingWriter)); /// assert_eq!(buffered_data.unwrap_err().into_inner(), b"some data"); +/// # } +/// # #[cfg(not(panic = "unwind"))] +/// # fn main() {} /// ``` pub struct WriterPanicked { buf: Vec, diff --git a/library/core/src/convert/num.rs b/library/core/src/convert/num.rs index 1125f437c1538..8a5f72bac8c2f 100644 --- a/library/core/src/convert/num.rs +++ b/library/core/src/convert/num.rs @@ -138,27 +138,27 @@ impl_from!(i16 => isize, #[stable(feature = "lossless_iusize_conv", since = "1.2 // of the `f16`/`f128` impls can be used on stable as the `f16` and `f128` types are unstable). // signed integer -> float -impl_from!(i8 => f16, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(i8 => f16, #[unstable(feature = "f16", issue = "116909")], #[unstable_feature_bound(f16)]); impl_from!(i8 => f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(i8 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); -impl_from!(i8 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(i8 => f128, #[unstable(feature = "f128", issue = "116909")], #[unstable_feature_bound(f128)]); impl_from!(i16 => f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(i16 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); -impl_from!(i16 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(i16 => f128, #[unstable(feature = "f128", issue = "116909")], #[unstable_feature_bound(f128)]); impl_from!(i32 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); -impl_from!(i32 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(i32 => f128, #[unstable(feature = "f128", issue = "116909")], #[unstable_feature_bound(f128)]); impl_from!(i64 => f128, #[unstable(feature = "f128", issue = "116909")], #[unstable_feature_bound(f128)]); // unsigned integer -> float -impl_from!(u8 => f16, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(u8 => f16, #[unstable(feature = "f16", issue = "116909")], #[unstable_feature_bound(f16)]); impl_from!(u8 => f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(u8 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); -impl_from!(u8 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(u8 => f128, #[unstable(feature = "f128", issue = "116909")], #[unstable_feature_bound(f128)]); impl_from!(u16 => f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(u16 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); -impl_from!(u16 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(u16 => f128, #[unstable(feature = "f128", issue = "116909")], #[unstable_feature_bound(f128)]); impl_from!(u32 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); -impl_from!(u32 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(u32 => f128, #[unstable(feature = "f128", issue = "116909")], #[unstable_feature_bound(f128)]); impl_from!(u64 => f128, #[unstable(feature = "f128", issue = "116909")], #[unstable_feature_bound(f128)]); // float -> float @@ -170,20 +170,22 @@ impl_from!(u64 => f128, #[unstable(feature = "f128", issue = "116909")], #[unsta // // See also . impl_from!(f16 => f32, #[unstable(feature = "f32_from_f16", issue = "154005")], #[unstable_feature_bound(f32_from_f16)]); -impl_from!(f16 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); -impl_from!(f16 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(f16 => f64, #[unstable(feature = "f16", issue = "116909")], #[unstable_feature_bound(f16)]); +// Also #[unstable(feature = "f16", issue = "116909")]: +impl_from!(f16 => f128, #[unstable(feature = "f128", issue = "116909")], #[unstable_feature_bound(f16, f128)]); impl_from!(f32 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); -impl_from!(f32 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); -impl_from!(f64 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(f32 => f128, #[unstable(feature = "f128", issue = "116909")], #[unstable_feature_bound(f128)]); +impl_from!(f64 => f128, #[unstable(feature = "f128", issue = "116909")], #[unstable_feature_bound(f128)]); macro_rules! impl_float_from_bool { ( + $(#[$attr:meta])* $float:ty $(; doctest_prefix: $(#[doc = $doctest_prefix:literal])* doctest_suffix: $(#[doc = $doctest_suffix:literal])* )? ) => { - #[stable(feature = "float_from_bool", since = "1.68.0")] + $(#[$attr])* #[rustc_const_unstable(feature = "const_convert", issue = "143773")] const impl From for $float { #[doc = concat!("Converts a [`bool`] to [`", stringify!($float),"`] losslessly.")] @@ -210,6 +212,8 @@ macro_rules! impl_float_from_bool { // boolean -> float impl_float_from_bool!( + #[unstable(feature = "f16", issue = "116909")] + #[unstable_feature_bound(f16)] f16; doctest_prefix: // rustdoc doesn't remove the conventional space after the `///` @@ -220,9 +224,17 @@ impl_float_from_bool!( doctest_suffix: ///# } ); -impl_float_from_bool!(f32); -impl_float_from_bool!(f64); impl_float_from_bool!( + #[stable(feature = "float_from_bool", since = "1.68.0")] + f32 +); +impl_float_from_bool!( + #[stable(feature = "float_from_bool", since = "1.68.0")] + f64 +); +impl_float_from_bool!( + #[unstable(feature = "f128", issue = "116909")] + #[unstable_feature_bound(f128)] f128; doctest_prefix: ///# #![allow(unused_features)] diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index 61c9cd7923e5f..3c3156d5d44d1 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -690,15 +690,14 @@ impl u128 { unsafe { core::hint::assert_unchecked(offset <= buf.len()) } offset -= 4; - // pull two pairs let quad = remain % 1_00_00; remain /= 1_00_00; - let pair1 = (quad / 100) as usize; - let pair2 = (quad % 100) as usize; - buf[offset + 0].write(DECIMAL_PAIRS[pair1 * 2 + 0]); - buf[offset + 1].write(DECIMAL_PAIRS[pair1 * 2 + 1]); - buf[offset + 2].write(DECIMAL_PAIRS[pair2 * 2 + 0]); - buf[offset + 3].write(DECIMAL_PAIRS[pair2 * 2 + 1]); + + // SAFETY: quad is a remainder modulo 10_000. The offset checks + // above reserve exactly four bytes in buf. + unsafe { + write_quad(buf.get_unchecked_mut(offset..offset + 4), quad); + } } // Format per two digits from the lookup table. @@ -814,32 +813,66 @@ impl i128 { } } +/// Writes `quad` as exactly four digits (for example: `42` becomes `"0042"`). +/// +/// # Safety +/// +/// `quad` must be below 10_000 and `buf` must contain exactly four bytes. +#[inline(always)] +unsafe fn write_quad(buf: &mut [MaybeUninit], quad: u64) { + // SAFETY: These are this function's caller-provided invariants. + unsafe { + core::hint::assert_unchecked(quad < 10_000); + core::hint::assert_unchecked(buf.len() == 4); + } + + let quad = quad as u32; + + // Note: this is equivalent to `quad / 100`, but contains no division instructions. + let high = (quad * const { (1 << 19) / 100 + 1 }) >> 19; + let low = quad - high * 100; + let high = high as usize; + let low = low as usize; + + // SAFETY: `high` and `low` are below 100 because `quad` is below 10_000. + unsafe { core::hint::assert_unchecked(high < 100 && low < 100) } + + buf[0..2].write_copy_of_slice(&DECIMAL_PAIRS[high * 2..high * 2 + 2]); + buf[2..4].write_copy_of_slice(&DECIMAL_PAIRS[low * 2..low * 2 + 2]); +} + /// Encodes the 16 least-significant decimals of n into `buf[OFFSET .. OFFSET + /// 16 ]`. fn enc_16lsd(buf: &mut [MaybeUninit], n: u64) { - // Consume the least-significant decimals from a working copy. + // SAFETY: Every caller passes a remainder produced by division by 10^16, + // and every used `OFFSET` specialization reserves sixteen bytes in `buf`. + unsafe { + core::hint::assert_unchecked(n < 10_000_000_000_000_000); + core::hint::assert_unchecked(OFFSET + 16 <= buf.len()); + } + + // Peel four digits at a time from right to left (12345678 -> 1234 | 5678). + // Since 10_000 is constant, LLVM replaces each division with multiply or shift. let mut remain = n; - // Format per four digits from the lookup table. for quad_index in (1..4).rev() { - // pull two pairs let quad = remain % 1_00_00; remain /= 1_00_00; - let pair1 = (quad / 100) as usize; - let pair2 = (quad % 100) as usize; - buf[quad_index * 4 + OFFSET + 0].write(DECIMAL_PAIRS[pair1 * 2 + 0]); - buf[quad_index * 4 + OFFSET + 1].write(DECIMAL_PAIRS[pair1 * 2 + 1]); - buf[quad_index * 4 + OFFSET + 2].write(DECIMAL_PAIRS[pair2 * 2 + 0]); - buf[quad_index * 4 + OFFSET + 3].write(DECIMAL_PAIRS[pair2 * 2 + 1]); + + // SAFETY: `OFFSET + quad_index * 4` starts one of the four + // non-overlapping four-byte regions proven in bounds above. + unsafe { + write_quad( + buf.get_unchecked_mut(OFFSET + quad_index * 4..OFFSET + (quad_index + 1) * 4), + quad, + ); + } } - // final two pairs - let pair1 = (remain / 100) as usize; - let pair2 = (remain % 100) as usize; - buf[OFFSET + 0].write(DECIMAL_PAIRS[pair1 * 2 + 0]); - buf[OFFSET + 1].write(DECIMAL_PAIRS[pair1 * 2 + 1]); - buf[OFFSET + 2].write(DECIMAL_PAIRS[pair2 * 2 + 0]); - buf[OFFSET + 3].write(DECIMAL_PAIRS[pair2 * 2 + 1]); + // SAFETY: OFFSET starts the first four-byte region proven in bounds above. + unsafe { + write_quad(buf.get_unchecked_mut(OFFSET..OFFSET + 4), remain); + } } /// Euclidean division plus remainder with constant 1E16 basically consumes 16 diff --git a/library/core/src/iter/adapters/take.rs b/library/core/src/iter/adapters/take.rs index ecd462c60eda3..3df2c70801644 100644 --- a/library/core/src/iter/adapters/take.rs +++ b/library/core/src/iter/adapters/take.rs @@ -56,6 +56,19 @@ where } } + #[inline] + fn count(mut self) -> usize { + if self.n == 0 { + return 0; + } + // Advancing consumes the same elements `next` would have yielded, + // while benefiting from the inner iterator's `advance_by` fast path. + match self.iter.advance_by(self.n) { + Ok(()) => self.n, + Err(remaining) => self.n - remaining.get(), + } + } + #[inline] fn size_hint(&self) -> (usize, Option) { if self.n == 0 { diff --git a/library/core/src/random.rs b/library/core/src/random.rs index 1123e1949a02d..2fec70ffbee7f 100644 --- a/library/core/src/random.rs +++ b/library/core/src/random.rs @@ -1,6 +1,6 @@ //! Random value generation. -use crate::ops::RangeFull; +use crate::range::{RangeFull, RangeInclusive}; /// A source of randomness. #[unstable(feature = "random", issue = "130703")] @@ -43,7 +43,7 @@ impl Distribution for RangeFull { } } -macro_rules! impl_primitive { +macro_rules! impl_full { ($t:ty) => { impl Distribution<$t> for RangeFull { fn sample(&self, source: &mut (impl Rng + ?Sized)) -> $t { @@ -55,15 +55,205 @@ macro_rules! impl_primitive { }; } -impl_primitive!(u8); -impl_primitive!(i8); -impl_primitive!(u16); -impl_primitive!(i16); -impl_primitive!(u32); -impl_primitive!(i32); -impl_primitive!(u64); -impl_primitive!(i64); -impl_primitive!(u128); -impl_primitive!(i128); -impl_primitive!(usize); -impl_primitive!(isize); +impl_full!(u8); +impl_full!(i8); +impl_full!(u16); +impl_full!(i16); +impl_full!(u32); +impl_full!(i32); +impl_full!(u64); +impl_full!(i64); +impl_full!(u128); +impl_full!(i128); +impl_full!(usize); +impl_full!(isize); + +#[cold] +fn empty_range() -> ! { + panic!("cannot sample from an empty distribution") +} + +macro_rules! lemire_sample { + ($name:ident($ty:ty)) => { + // Unbiased uniform sampling of a number within the range [0, bound). + // + // By performing some clever modular arithmetic, this algorithm manages + // to both reduce divisions and minimize the chance of sample rejections. + // + // Algorithm from: + // spellchecker:off + // Daniel Lemire. 2019. Fast Random Integer Generation in an Interval. + // ACM Trans. Model. Comput. Simul. 29, 1, Article 3 (January 2019), 12 pages. + // https://doi.org/10.1145/3230636 + // spellchecker:on + fn $name(bound: $ty, source: &mut (impl Rng + ?Sized)) -> $ty { + debug_assert_ne!(bound, 0); + + let sample: $ty = (..).sample(source); + + let (mut l, mut res) = sample.carrying_mul(bound, 0); + if l < bound { + let t = bound.wrapping_neg() % bound; + while l < t { + let sample: $ty = (..).sample(source); + (l, res) = sample.carrying_mul(bound, 0); + } + } + + debug_assert!(res < bound); + res + } + }; +} + +lemire_sample!(bounded32(u32)); +lemire_sample!(bounded64(u64)); +lemire_sample!(bounded128(u128)); + +macro_rules! impl_range { + ($unsigned:ty, $signed:ty as $base:ty => $bounded:ident) => { + impl Distribution<$unsigned> for RangeInclusive<$unsigned> { + /// Chooses a random number within the range. + /// + /// Every possible result value is equally likely. In other words, + /// this operation uses unbiased uniform sampling. + /// + /// # Panics + /// + /// Panics if the range is empty. + /// + /// # Side-channels + /// + /// This implementation does not claim to be resistant against side- + /// channel attacks. In particular, the execution time of this operation + /// may leak information about the returned value, and not just the + /// values of the range bounds. While this implementation tries to + /// avoid operations with particularly data-dependent timing (such + /// as divisions), Rust as a language has no facilities for ensuring + /// data-independent timing, voiding all promises about side-channel- + /// freedom. + /// + /// # Examples + /// + /// A D20 dice roll: + /// ``` + /// #![feature(random)] + /// + /// use std::random::{Distribution, SystemRng}; + /// use std::range::RangeInclusive; + /// + /// let roll = RangeInclusive::from(1..=20).sample(&mut SystemRng); + /// assert!(1 <= roll && roll <= 20); + /// if roll == 20 { + /// println!("Wow! You achieve writing a sound linked list."); + /// } else { + /// println!("Miri attacks!"); + /// } + /// ``` + #[inline] + fn sample(&self, source: &mut (impl Rng + ?Sized)) -> $unsigned { + if self.start > self.last { + empty_range(); + } + + if self.start == self.last { + return self.start; + } + + let Some(bound) = (self.last - self.start).checked_add(1) else { + // Overflow can only occur for Self::MIN..=Self::MAX, meaning + // the range is effectively unbounded. + return RangeFull.sample(source); + }; + + let offset = if bound.is_power_of_two() { + let sample: $unsigned = RangeFull.sample(source); + sample & (bound - 1) + } else { + $bounded(bound as $base, source) as $unsigned + }; + + self.start + offset + } + } + + impl Distribution<$signed> for RangeInclusive<$signed> { + /// Chooses a random number within the range. + /// + /// Every possible result value is equally likely. In other words, + /// this operation uses unbiased uniform sampling. + /// + /// # Panics + /// + /// Panics if the range is empty. + /// + /// # Side-channels + /// + /// This implementation does not claim to be resistant against side- + /// channel attacks. In particular, the execution time of this operation + /// may leak information about the returned value, and not just the + /// values of the range bounds. While this implementation tries to + /// avoid operations with particularly data-dependent timing (such + /// as divisions), Rust as a language has no facilities for ensuring + /// data-independent timing, voiding all promises about side-channel- + /// freedom. + /// + /// # Examples + /// + /// A D20 dice roll: + /// ``` + /// #![feature(random)] + /// + /// use std::random::{Distribution, SystemRng}; + /// use std::range::RangeInclusive; + /// + /// let roll = RangeInclusive::from(1..=20).sample(&mut SystemRng); + /// assert!(1 <= roll && roll <= 20); + /// if roll == 20 { + /// println!("Wow! You achieve writing a sound linked list."); + /// } else { + /// println!("Miri attacks!"); + /// } + /// ``` + #[inline] + fn sample(&self, source: &mut (impl Rng + ?Sized)) -> $signed { + if self.start > self.last { + empty_range(); + } + + if self.start == self.last { + return self.start; + } + + let Some(bound) = self.last.wrapping_sub(self.start).cast_unsigned().checked_add(1) + else { + // Overflow can only occur for Self::MIN..=Self::MAX, meaning + // the range is effectively unbounded. + return RangeFull.sample(source); + }; + + let offset = if bound.is_power_of_two() { + let sample: $unsigned = RangeFull.sample(source); + sample & (bound - 1) + } else { + $bounded(bound as $base, source) as $unsigned + }; + + self.start.wrapping_add_unsigned(offset) + } + } + }; +} + +// Use 32-bit integers for small integers since it reduces the likelihood of +// sample rejections. +impl_range!(u8, i8 as u32 => bounded32); +impl_range!(u16, i16 as u32 => bounded32); + +impl_range!(u32, i32 as u32 => bounded32); +impl_range!(u64, i64 as u64 => bounded64); +impl_range!(u128, i128 as u128 => bounded128); +#[cfg(any(target_pointer_width = "16", target_pointer_width = "32",))] +impl_range!(usize, isize as u32 => bounded32); +#[cfg(target_pointer_width = "64")] +impl_range!(usize, isize as u64 => bounded64); diff --git a/library/coretests/tests/iter/adapters/take.rs b/library/coretests/tests/iter/adapters/take.rs index b932059afec8a..700bd3f44a1d1 100644 --- a/library/coretests/tests/iter/adapters/take.rs +++ b/library/coretests/tests/iter/adapters/take.rs @@ -260,3 +260,66 @@ fn test_reverse_on_zip() { assert_eq!((1, 0), (one, zero)); } } + +#[test] +fn test_iterator_take_count() { + let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19]; + + // take shorter than, equal to, and longer than the underlying iterator + assert_eq!(xs.iter().take(0).count(), 0); + assert_eq!(xs.iter().take(5).count(), 5); + assert_eq!(xs.iter().take(10).count(), 10); + assert_eq!(xs.iter().take(11).count(), 10); + assert_eq!(xs.iter().take(usize::MAX).count(), 10); + + // partially consumed + let mut it = xs.iter().take(5); + it.next(); + it.next(); + assert_eq!(it.count(), 3); + + let mut it = xs.iter().take(20); + it.next(); + assert_eq!(it.count(), 9); + + // `count` must observe the same elements `next` would have yielded: + // a side-effecting inner iterator sees exactly min(n, len) closure calls. + let mut calls = 0; + let count = (0..10) + .map(|x| { + calls += 1; + x + }) + .take(3) + .count(); + assert_eq!(count, 3); + assert_eq!(calls, 3); + + // stateful filter: count agrees with the number of elements actually yielded + let mut budget = 7; + let yielded: Vec = (1..100) + .filter(|&x| { + if x <= budget { + budget -= 1; + true + } else { + false + } + }) + .take(10) + .collect(); + + let mut budget = 7; + let counted = (1..100) + .filter(|&x| { + if x <= budget { + budget -= 1; + true + } else { + false + } + }) + .take(10) + .count(); + assert_eq!(counted, yielded.len()); +} diff --git a/library/std/src/sys/fs/hermit.rs b/library/std/src/sys/fs/hermit.rs index d29ea81c67e6d..0d3732a83a9e9 100644 --- a/library/std/src/sys/fs/hermit.rs +++ b/library/std/src/sys/fs/hermit.rs @@ -1,6 +1,7 @@ -use crate::ffi::{CStr, OsStr, OsString, c_char}; +use crate::ffi::{CStr, OsStr, OsString}; use crate::fs::TryLockError; use crate::io::{self, BorrowedCursor, Error, ErrorKind, IoSlice, IoSliceMut, SeekFrom}; +use crate::mem::MaybeUninit; use crate::os::hermit::ffi::OsStringExt; use crate::os::hermit::hermit_abi::{ self, DT_DIR, DT_LNK, DT_REG, DT_UNKNOWN, O_APPEND, O_CREAT, O_DIRECTORY, O_EXCL, O_RDONLY, @@ -12,9 +13,10 @@ use crate::sync::Arc; use crate::sys::fd::FileDesc; pub use crate::sys::fs::common::{Dir, copy, exists}; use crate::sys::helpers::run_path_with_cstr; +use crate::sys::io::DEFAULT_BUF_SIZE; use crate::sys::time::SystemTime; use crate::sys::{AsInner, AsInnerMut, FromInner, IntoInner, cvt, unsupported, unsupported_err}; -use crate::{fmt, mem}; +use crate::{cmp, fmt, mem, slice}; #[derive(Debug)] pub struct File(FileDesc); @@ -33,29 +35,75 @@ impl FileAttr { // all DirEntry's will have a reference to this struct struct InnerReadDir { root: PathBuf, - dir: Vec, -} - -impl InnerReadDir { - pub fn new(root: PathBuf, dir: Vec) -> Self { - Self { root, dir } - } } pub struct ReadDir { inner: Arc, + fd: FileDesc, + buf: GetdentsBuffer, +} + +/// A buffer containing [`dirent64`]s, filled with [`getdents64`]. +/// +/// This struct is roughly modeled after the `BufReader`'s `Buffer`. +struct GetdentsBuffer { + // The buffer. + buf: Box<[MaybeUninit]>, + // The current seek offset into `buf`, must always be <= `filled`. pos: usize, + // Each call to `fill_buf` sets `filled` to indicate how many bytes at the start of `buf` are + // initialized with bytes from a read. + filled: usize, } -impl ReadDir { - fn new(inner: InnerReadDir) -> Self { - Self { inner: Arc::new(inner), pos: 0 } +impl GetdentsBuffer { + /// Creates a new buffer with at least `capacity` bytes for use with dirent. + fn with_capacity(capacity: usize) -> Self { + let buf = Box::new_uninit_slice(capacity.div_ceil(size_of::())); + Self { buf, pos: 0, filled: 0 } + } + + fn buffer(&self) -> &[u8] { + // SAFETY: self.pos and self.filled are valid, and self.filled >= self.pos, and + // that region is initialized because those are all invariants of this type. + unsafe { + let ptr = self.buf.as_ptr().cast::>().add(self.pos); + slice::from_raw_parts(ptr, self.filled - self.pos).assume_init_ref() + } + } + + fn consume(&mut self, amt: usize) { + self.pos = cmp::min(self.pos + amt, self.filled); + } + + fn fill_buf(&mut self, fd: BorrowedFd<'_>) -> io::Result<&[u8]> { + // If we've reached the end of our internal buffer then we need to fetch + // some more data from the reader. + // Branch using `>=` instead of the more correct `==` + // to tell the compiler that the pos..cap slice is always valid. + if self.pos >= self.filled { + debug_assert!(self.pos == self.filled); + + let result = unsafe { + cvt(hermit_abi::getdents64( + fd.as_raw_fd(), + self.buf.as_mut_ptr().cast(), + self.buf.len() * size_of::(), + )) + }; + + self.pos = 0; + self.filled = 0; + + self.filled = result? as usize; + } + + Ok(self.buffer()) } } pub struct DirEntry { - /// path to the entry - root: PathBuf, + dir: Arc, /// 64-bit inode number ino: u64, /// File type @@ -185,48 +233,59 @@ impl Iterator for ReadDir { type Item = io::Result; fn next(&mut self) -> Option> { - let mut counter: usize = 0; - let mut offset: usize = 0; - - // loop over all directory entries and search the entry for the current position loop { - // leave function, if the loop reaches the of the buffer (with all entries) - if offset >= self.inner.dir.len() { + let buf = match self.buf.fill_buf(self.fd.as_fd()) { + Ok(buf) => buf, + Err(err) => return Some(Err(err)), + }; + + if buf.len() == 0 { + // No more entries left. return None; } - let dir = unsafe { &*(self.inner.dir.as_ptr().add(offset) as *const dirent64) }; - - if counter == self.pos { - self.pos += 1; - - // After dirent64, the file name is stored. d_reclen represents the length of the dirent64 - // plus the length of the file name. Consequently, file name has a size of d_reclen minus - // the size of dirent64. The file name is always a C string and terminated by `\0`. - // Consequently, we are able to ignore the last byte. - let name_bytes = - unsafe { CStr::from_ptr(&dir.d_name as *const _ as *const c_char).to_bytes() }; - let entry = DirEntry { - root: self.inner.root.clone(), - ino: dir.d_ino, - type_: dir.d_type, - name: OsString::from_vec(name_bytes.to_vec()), - }; - - return Some(Ok(entry)); + let entry_ptr = buf.as_ptr().cast::(); + + // The dirent64 struct is a weird imaginary thing that isn't ever supposed + // to be worked with by value. Its trailing d_name field is declared + // variously as [c_char; 256] or [c_char; 1] on different systems but + // either way that size is meaningless; only the offset of d_name is + // meaningful. The dirent64 pointers that libc returns from getdents64 are + // allowed to point to allocations smaller _or_ LARGER than implied by the + // definition of the struct. + // + // As such, we need to be even more careful with dirent64 than if its + // contents were "simply" partially initialized data. + // + // Like for uninitialized contents, converting entry_ptr to `&dirent64` + // would not be legal. However, we can use `&raw const (*entry_ptr).d_name` + // to refer the fields individually, because that operation is equivalent + // to `byte_offset` and thus does not require the full extent of `*entry_ptr` + // to be in bounds of the same allocation, only the offset of the field + // being referenced. + + self.buf.consume(usize::from(unsafe { (*entry_ptr).d_reclen })); + + // d_name is guaranteed to be null-terminated. + let name = unsafe { CStr::from_ptr((&raw const (*entry_ptr).d_name).cast()) }; + let name_bytes = name.to_bytes(); + if name_bytes == b"." || name_bytes == b".." { + continue; } - counter += 1; - - // move to the next dirent64, which is directly stored after the previous one - offset = offset + usize::from(dir.d_reclen); + return Some(Ok(DirEntry { + dir: Arc::clone(&self.inner), + ino: unsafe { (*entry_ptr).d_ino }, + type_: unsafe { (*entry_ptr).d_type }, + name: OsString::from_vec(name_bytes.to_vec()), + })); } } } impl DirEntry { pub fn path(&self) -> PathBuf { - self.root.join(self.file_name_os_str()) + self.dir.root.join(self.file_name_os_str()) } pub fn file_name(&self) -> OsString { @@ -342,7 +401,7 @@ impl File { } let fd = unsafe { cvt(hermit_abi::open(path.as_ptr(), flags, mode))? }; - Ok(File(unsafe { FileDesc::from_raw_fd(fd as i32) })) + Ok(File(unsafe { FileDesc::from_raw_fd(fd) })) } pub fn file_attr(&self) -> io::Result { @@ -352,7 +411,7 @@ impl File { } pub fn fsync(&self) -> io::Result<()> { - Err(Error::from_raw_os_error(22)) + unsupported() } pub fn datasync(&self) -> io::Result<()> { @@ -380,7 +439,7 @@ impl File { } pub fn truncate(&self, _size: u64) -> io::Result<()> { - Err(Error::from_raw_os_error(22)) + unsupported() } pub fn read(&self, buf: &mut [u8]) -> io::Result { @@ -431,15 +490,15 @@ impl File { } pub fn duplicate(&self) -> io::Result { - Err(Error::from_raw_os_error(22)) + unsupported() } pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> { - Err(Error::from_raw_os_error(22)) + unsupported() } pub fn set_times(&self, _times: FileTimes) -> io::Result<()> { - Err(Error::from_raw_os_error(22)) + unsupported() } } @@ -516,42 +575,14 @@ pub fn readdir(path: &Path) -> io::Result { let fd_raw = run_path_with_cstr(path, &|path| { cvt(unsafe { hermit_abi::open(path.as_ptr(), O_RDONLY | O_DIRECTORY, 0) }) })?; - let fd = unsafe { FileDesc::from_raw_fd(fd_raw as i32) }; - let root = path.to_path_buf(); - - // read all director entries - let mut vec: Vec = Vec::new(); - let mut sz = 512; - loop { - // reserve memory to receive all directory entries - vec.resize(sz, 0); - - let readlen = unsafe { - hermit_abi::getdents64(fd.as_raw_fd(), vec.as_mut_ptr() as *mut dirent64, sz) - }; - if readlen > 0 { - // shrink down to the minimal size - vec.resize(readlen.try_into().unwrap(), 0); - break; - } - - // if the buffer is too small, getdents64 returns EINVAL - // otherwise, getdents64 returns an error number - if readlen != (-hermit_abi::errno::EINVAL).into() { - return Err(Error::from_raw_os_error(readlen.try_into().unwrap())); - } + let fd = unsafe { FileDesc::from_raw_fd(fd_raw) }; - // we don't have enough memory => try to increase the vector size - sz = sz * 2; - - // 1 MB for directory entries should be enough - // stop here to avoid an endless loop - if sz > 0x100000 { - return Err(Error::from(ErrorKind::Uncategorized)); - } - } + let root = path.to_path_buf(); + let inner = Arc::new(InnerReadDir { root }); + let buf_size = usize::max(DEFAULT_BUF_SIZE, size_of::()); + let buf = GetdentsBuffer::with_capacity(buf_size); - Ok(ReadDir::new(InnerReadDir::new(root, vec))) + Ok(ReadDir { inner, fd, buf }) } pub fn unlink(path: &Path) -> io::Result<()> { @@ -563,7 +594,7 @@ pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> { } pub fn set_perm(_p: &Path, _perm: FilePermissions) -> io::Result<()> { - Err(Error::from_raw_os_error(22)) + unsupported() } pub fn set_perm_nofollow(_p: &Path, _perm: FilePermissions) -> io::Result<()> { @@ -571,11 +602,11 @@ pub fn set_perm_nofollow(_p: &Path, _perm: FilePermissions) -> io::Result<()> { } pub fn set_times(_p: &Path, _times: FileTimes) -> io::Result<()> { - Err(Error::from_raw_os_error(22)) + unsupported() } pub fn set_times_nofollow(_p: &Path, _times: FileTimes) -> io::Result<()> { - Err(Error::from_raw_os_error(22)) + unsupported() } pub fn rmdir(path: &Path) -> io::Result<()> { diff --git a/library/std/src/sys/net/connection/socket/hermit.rs b/library/std/src/sys/net/connection/socket/hermit.rs index ba40da4035b6f..f43395ce8fd80 100644 --- a/library/std/src/sys/net/connection/socket/hermit.rs +++ b/library/std/src/sys/net/connection/socket/hermit.rs @@ -304,8 +304,8 @@ impl Socket { } pub fn take_error(&self) -> io::Result> { - let raw: c_int = unsafe { getsockopt(self, libc::SOL_SOCKET, libc::SO_ERROR)? }; - if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) } + let raw = unsafe { getsockopt(self, libc::SOL_SOCKET, libc::SO_ERROR)? }; + if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw))) } } pub fn as_raw(&self) -> RawFd { diff --git a/library/std/src/sys/pal/windows/winsock.rs b/library/std/src/sys/pal/windows/winsock.rs index b110a43ef3aa8..7b2e7fe59171c 100644 --- a/library/std/src/sys/pal/windows/winsock.rs +++ b/library/std/src/sys/pal/windows/winsock.rs @@ -1,18 +1,17 @@ use super::c; use crate::ffi::c_int; -use crate::sync::atomic::Atomic; -use crate::sync::atomic::Ordering::{AcqRel, Relaxed}; +use crate::sync::Once; use crate::{io, mem}; -static WSA_STARTED: Atomic = Atomic::::new(false); +static WSA_INIT: Once = Once::new(); /// Checks whether the Windows socket interface has been started already, and /// if not, starts it. #[inline] pub fn startup() { - if !WSA_STARTED.load(Relaxed) { - wsa_startup(); - } + // Make sure to only call `WSAStartup` once, because it's not thread-safe + // on Wine: https://bugs.winehq.org/show_bug.cgi?id=60084. + WSA_INIT.call_once_force(|_| wsa_startup()); } #[cold] @@ -24,11 +23,6 @@ fn wsa_startup() { &mut data, ); assert_eq!(ret, 0); - if WSA_STARTED.swap(true, AcqRel) { - // If another thread raced with us and called WSAStartup first then call - // WSACleanup so it's as though WSAStartup was only called once. - c::WSACleanup(); - } } } diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index a2184f75487fe..eed0481bb5255 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -1016,7 +1016,7 @@ impl CommandLineStep for IntrinsicTest { const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.path("library/stdarch/crates/intrinsic-test") + run.alias("intrinsic-test") } fn is_default_step(_builder: &Builder<'_>) -> bool { @@ -1113,7 +1113,7 @@ impl CommandLineStep for IntrinsicTest { for skip in &skip_file { cmd.arg("--skip").arg(skip); } - cmd.arg("--sample-percentage").arg("10"); + cmd.arg("--sample-percentage").arg("100"); cmd.arg("--cc-arg-style").arg("gcc"); cmd.env("CC", builder.cc(host)); cmd.env("CFLAGS", cflags); diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test.snap index aa67ecaceabfd..824440507a89a 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test.snap @@ -214,4 +214,4 @@ expression: test - Suite(test::tests/run-make-cargo) [Test] test::IntrinsicTest targets: [x86_64-unknown-linux-gnu] - - Set({test::library/stdarch/crates/intrinsic-test}) + - Set({test::intrinsic-test}) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_library.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_library.snap index ba1f6b3c940c3..f97bb839c1e73 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_library.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_library.snap @@ -21,6 +21,3 @@ expression: test library [Test] test::StdarchVerify targets: [x86_64-unknown-linux-gnu] - Set({test::library/stdarch/crates/stdarch-verify}) -[Test] test::IntrinsicTest - targets: [x86_64-unknown-linux-gnu] - - Set({test::library/stdarch/crates/intrinsic-test}) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage.snap index ceb1e8c0130d9..98b15298d3dbf 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage.snap @@ -211,4 +211,4 @@ expression: test --skip=coverage - Suite(test::tests/run-make-cargo) [Test] test::IntrinsicTest targets: [x86_64-unknown-linux-gnu] - - Set({test::library/stdarch/crates/intrinsic-test}) + - Set({test::intrinsic-test}) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage_map.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage_map.snap index 2f5ae46107c10..308cc9f079648 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage_map.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage_map.snap @@ -214,4 +214,4 @@ expression: test --skip=coverage-map - Suite(test::tests/run-make-cargo) [Test] test::IntrinsicTest targets: [x86_64-unknown-linux-gnu] - - Set({test::library/stdarch/crates/intrinsic-test}) + - Set({test::intrinsic-test}) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage_run.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage_run.snap index b19db9047540e..c7395e025b773 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage_run.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage_run.snap @@ -214,4 +214,4 @@ expression: test --skip=coverage-run - Suite(test::tests/run-make-cargo) [Test] test::IntrinsicTest targets: [x86_64-unknown-linux-gnu] - - Set({test::library/stdarch/crates/intrinsic-test}) + - Set({test::intrinsic-test}) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests.snap index 79a79462addbb..6885e2cd0fe25 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests.snap @@ -157,4 +157,4 @@ expression: test --skip=tests - Set({test::src/tools/test-float-parse}) [Test] test::IntrinsicTest targets: [x86_64-unknown-linux-gnu] - - Set({test::library/stdarch/crates/intrinsic-test}) + - Set({test::intrinsic-test}) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests_coverage.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests_coverage.snap index d0837ff3ce8a2..0f5f708ea19c0 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests_coverage.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests_coverage.snap @@ -211,4 +211,4 @@ expression: test --skip=tests/coverage - Suite(test::tests/run-make-cargo) [Test] test::IntrinsicTest targets: [x86_64-unknown-linux-gnu] - - Set({test::library/stdarch/crates/intrinsic-test}) + - Set({test::intrinsic-test}) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests_etc.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests_etc.snap index 6aaa2a9592b0e..80dd87e9a5856 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests_etc.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests_etc.snap @@ -135,3 +135,6 @@ expression: test --skip=tests --skip=coverage-map --skip=coverage-run --skip=lib [Test] test::TestFloatParse targets: [x86_64-unknown-linux-gnu] - Set({test::src/tools/test-float-parse}) +[Test] test::IntrinsicTest + targets: [x86_64-unknown-linux-gnu] + - Set({test::intrinsic-test}) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 6cc2811c15f3b..b3ed7d4c6beb7 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -607,7 +607,6 @@ impl Config { stack_protector: rust_stack_protector, strip: rust_strip, bootstrap_override_lld: rust_bootstrap_override_lld, - bootstrap_override_lld_legacy: rust_bootstrap_override_lld_legacy, std_features: rust_std_features, break_on_ice: rust_break_on_ice, rustflags: rust_rustflags, @@ -717,14 +716,7 @@ impl Config { let pgo_rustdoc = init_pgo(pgo_rustdoc, "rustdoc"); let pgo_cargo = init_pgo(pgo_cargo, "cargo"); - if rust_bootstrap_override_lld.is_some() && rust_bootstrap_override_lld_legacy.is_some() { - panic!( - "Cannot use both `rust.use-lld` and `rust.bootstrap-override-lld`. Please use only `rust.bootstrap-override-lld`" - ); - } - - let bootstrap_override_lld = - rust_bootstrap_override_lld.or(rust_bootstrap_override_lld_legacy).unwrap_or_default(); + let bootstrap_override_lld = rust_bootstrap_override_lld.unwrap_or_default(); if rust_optimize.as_ref().is_some_and(|v| matches!(v, RustOptimize::Bool(false))) { eprintln!( diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs index d84315d87e45a..d179d0713fcda 100644 --- a/src/bootstrap/src/core/config/tests.rs +++ b/src/bootstrap/src/core/config/tests.rs @@ -252,16 +252,6 @@ fn rust_lld() { parse("rust.bootstrap-override-lld = false").bootstrap_override_lld, BootstrapOverrideLld::None )); - - // Also check the legacy options - assert!(matches!( - parse("rust.use-lld = true").bootstrap_override_lld, - BootstrapOverrideLld::External - )); - assert!(matches!( - parse("rust.use-lld = false").bootstrap_override_lld, - BootstrapOverrideLld::None - )); } #[test] diff --git a/src/bootstrap/src/core/config/toml/rust.rs b/src/bootstrap/src/core/config/toml/rust.rs index fa4573ef1734f..f8f383ef18e73 100644 --- a/src/bootstrap/src/core/config/toml/rust.rs +++ b/src/bootstrap/src/core/config/toml/rust.rs @@ -51,8 +51,6 @@ define_config! { llvm_bitcode_linker: Option = "llvm-bitcode-linker", lld: Option = "lld", bootstrap_override_lld: Option = "bootstrap-override-lld", - // FIXME: Remove this option in Spring 2026 - bootstrap_override_lld_legacy: Option = "use-lld", llvm_tools: Option = "llvm-tools", deny_warnings: Option = "deny-warnings", backtrace_on_ice: Option = "backtrace-on-ice", @@ -385,7 +383,6 @@ pub fn check_incompatible_options_for_ci_rustc( break_on_ice: _, parallel_frontend_threads: _, bootstrap_override_lld: _, - bootstrap_override_lld_legacy: _, rustflags: _, } = ci_rust_config; diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 062310cc351a7..8892832037ee2 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -661,4 +661,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Warning, summary: "Obsolete option `build.compiletest-use-stage0-libtest` has no effect and has been removed.", }, + ChangeInfo { + change_id: 160142, + severity: ChangeSeverity::Warning, + summary: "The `rust.use-lld` option has been removed. Use `rust.bootstrap-override-lld` instead.", + }, ]; diff --git a/src/ci/docker/scripts/stage_2_test_set1.sh b/src/ci/docker/scripts/stage_2_test_set1.sh index 884e0c9cb0e88..e7930513c0d62 100755 --- a/src/ci/docker/scripts/stage_2_test_set1.sh +++ b/src/ci/docker/scripts/stage_2_test_set1.sh @@ -15,7 +15,7 @@ fi # Skip intrinsic-test on LLVM 21 to avoid CI failures. if [ "$LLVM_VERSION" = "21" ]; then echo "LLVM_VERSION is 21; skipping intrinsic-test" - SKIP_INTRINSICS="--skip library/stdarch/crates/intrinsic-test" + SKIP_INTRINSICS="--skip intrinsic-test" fi ../x.py --stage 2 test \ diff --git a/src/ci/docker/scripts/stage_2_test_set2.sh b/src/ci/docker/scripts/stage_2_test_set2.sh index 6301344f89fc9..5963924cce529 100755 --- a/src/ci/docker/scripts/stage_2_test_set2.sh +++ b/src/ci/docker/scripts/stage_2_test_set2.sh @@ -24,7 +24,7 @@ fi # Skip intrinsic-test on LLVM 21 to avoid CI failures. if [ "$LLVM_VERSION" = "21" ]; then echo "LLVM_VERSION is 21; skipping intrinsic-test" - SKIP_INTRINSICS="--skip library/stdarch/crates/intrinsic-test" + SKIP_INTRINSICS="--skip intrinsic-test" fi ../x.py --stage 2 test \ diff --git a/tests/ui/associated-types/nested-assoc-type-projection-ice-109864.rs b/tests/ui/associated-types/nested-assoc-type-projection-ice-109864.rs new file mode 100644 index 0000000000000..ae55712c50a93 --- /dev/null +++ b/tests/ui/associated-types/nested-assoc-type-projection-ice-109864.rs @@ -0,0 +1,39 @@ +//! Regression test for . +//! +//! Deeply nested associated-type projections used to ICE with "type variables +//! should not be hashed" — but only under incremental compilation. They should now +//! produce ordinary trait-bound errors instead of crashing. + +//@ incremental + +struct S; +struct S2

(); //~ ERROR type parameter `P` is never used + +trait Foo { + type Out; +} + +trait Bar { + type Out; +} + +trait Qux { + type Out; +} + +trait Fuzz { + type Out; +} + +impl, B> Fuzz> for S2 { + type Out = <>::Out as Bar< + //~^ ERROR the trait bound `>::Out: Qux` is not satisfied + //~| ERROR the trait bound `>::Out: Bar, _>` is not satisfied + //~| ERROR the trait bound `>::Out: Bar, _>` is not satisfied + S2, + <<>::Out as Qux>::Out as Fuzz>>::Out, + //~^ ERROR the trait bound `>::Out: Qux` is not satisfied + >>::Out; +} + +fn main() {} diff --git a/tests/ui/associated-types/nested-assoc-type-projection-ice-109864.stderr b/tests/ui/associated-types/nested-assoc-type-projection-ice-109864.stderr new file mode 100644 index 0000000000000..fdf55aa4c2bdb --- /dev/null +++ b/tests/ui/associated-types/nested-assoc-type-projection-ice-109864.stderr @@ -0,0 +1,65 @@ +error[E0392]: type parameter `P` is never used + --> $DIR/nested-assoc-type-projection-ice-109864.rs:10:11 + | +LL | struct S2

(); + | ^ unused type parameter + | + = help: consider removing `P`, referring to it in a field, or using a marker such as `PhantomData` + = help: if you intended `P` to be a const parameter, use `const P: /* Type */` instead + +error[E0277]: the trait bound `>::Out: Qux` is not satisfied + --> $DIR/nested-assoc-type-projection-ice-109864.rs:29:16 + | +LL | type Out = <>::Out as Bar< + | ________________^ +... | +LL | | >>::Out; + | |___________^ the trait `Qux` is not implemented for `>::Out` + | +help: consider further restricting the associated type + | +LL | impl, B> Fuzz> for S2 where >::Out: Qux { + | ++++++++++++++++++++++++++++++++ + +error[E0277]: the trait bound `>::Out: Bar, _>` is not satisfied + --> $DIR/nested-assoc-type-projection-ice-109864.rs:29:16 + | +LL | type Out = <>::Out as Bar< + | ________________^ +... | +LL | | >>::Out; + | |___________^ the trait `Bar, _>` is not implemented for `>::Out` + | +help: this trait has no implementations, consider adding one + --> $DIR/nested-assoc-type-projection-ice-109864.rs:16:1 + | +LL | trait Bar { + | ^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `>::Out: Qux` is not satisfied + --> $DIR/nested-assoc-type-projection-ice-109864.rs:34:10 + | +LL | <<>::Out as Qux>::Out as Fuzz>>::Out, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Qux` is not implemented for `>::Out` + | +help: consider further restricting the associated type + | +LL | impl, B> Fuzz> for S2 where >::Out: Qux { + | ++++++++++++++++++++++++++++++++ + +error[E0277]: the trait bound `>::Out: Bar, _>` is not satisfied + --> $DIR/nested-assoc-type-projection-ice-109864.rs:29:5 + | +LL | type Out = <>::Out as Bar< + | ^^^^^^^^ the trait `Bar, _>` is not implemented for `>::Out` + | +help: this trait has no implementations, consider adding one + --> $DIR/nested-assoc-type-projection-ice-109864.rs:16:1 + | +LL | trait Bar { + | ^^^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0277, E0392. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/feature-gates/feature-gate-f128.e2015.stderr b/tests/ui/feature-gates/feature-gate-f128.e2015.stderr index 627010a935475..2cf3eacf07523 100644 --- a/tests/ui/feature-gates/feature-gate-f128.e2015.stderr +++ b/tests/ui/feature-gates/feature-gate-f128.e2015.stderr @@ -19,27 +19,127 @@ LL | let a: f128 = 100.0; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:13:12 + --> $DIR/feature-gate-f128.rs:13:18 | -LL | let d: f128 = 1i64.into(); - | ^^^^ +LL | let from_i8: f128 = 1_i8.into(); + | ^^^^ | = note: see issue #116909 for more information = help: add `#![feature(f128)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:16:12 + --> $DIR/feature-gate-f128.rs:16:18 | -LL | let e: f128 = 1u64.into(); - | ^^^^ +LL | let from_u8: f128 = 1_u8.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:17:19 + | +LL | let from_i16: f128 = 1_i16.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:18:19 + | +LL | let from_u16: f128 = 1_u16.into(); + | ^^^^ | = note: see issue #116909 for more information = help: add `#![feature(f128)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:21:11 + --> $DIR/feature-gate-f128.rs:19:19 + | +LL | let from_i32: f128 = 1_i32.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:20:19 + | +LL | let from_u32: f128 = 1_u32.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:21:19 + | +LL | let from_i64: f128 = 1_i64.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:22:19 + | +LL | let from_u64: f128 = 1_u64.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:23:19 + | +LL | let from_f16: f128 = 1.0_f16.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:26:19 + | +LL | let from_f32: f128 = 1.0_f32.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:27:19 + | +LL | let from_f64: f128 = 1.0_f64.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:28:20 + | +LL | let from_bool: f128 = true.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:32:11 | LL | fn foo(a: f128) {} | ^^^^ @@ -49,7 +149,7 @@ LL | fn foo(a: f128) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:24:8 + --> $DIR/feature-gate-f128.rs:35:8 | LL | a: f128, | ^^^^ @@ -78,17 +178,27 @@ LL | let c = 0f128; = help: add `#![feature(f128)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +error[E0658]: the type `f16` is unstable + --> $DIR/feature-gate-f128.rs:23:26 + | +LL | let from_f16: f128 = 1.0_f16.into(); + | ^^^^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f16)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + error[E0658]: use of unstable library feature `f128` - --> $DIR/feature-gate-f128.rs:13:24 + --> $DIR/feature-gate-f128.rs:13:30 | -LL | let d: f128 = 1i64.into(); - | ^^^^ +LL | let from_i8: f128 = 1_i8.into(); + | ^^^^ | = help: add `#![feature(f128)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - = note: required for `f128` to implement `From` - = note: required for `i64` to implement `Into` + = note: required for `f128` to implement `From` + = note: required for `i8` to implement `Into` -error: aborting due to 9 previous errors +error: aborting due to 20 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-f128.e2018.stderr b/tests/ui/feature-gates/feature-gate-f128.e2018.stderr index 627010a935475..2cf3eacf07523 100644 --- a/tests/ui/feature-gates/feature-gate-f128.e2018.stderr +++ b/tests/ui/feature-gates/feature-gate-f128.e2018.stderr @@ -19,27 +19,127 @@ LL | let a: f128 = 100.0; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:13:12 + --> $DIR/feature-gate-f128.rs:13:18 | -LL | let d: f128 = 1i64.into(); - | ^^^^ +LL | let from_i8: f128 = 1_i8.into(); + | ^^^^ | = note: see issue #116909 for more information = help: add `#![feature(f128)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:16:12 + --> $DIR/feature-gate-f128.rs:16:18 | -LL | let e: f128 = 1u64.into(); - | ^^^^ +LL | let from_u8: f128 = 1_u8.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:17:19 + | +LL | let from_i16: f128 = 1_i16.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:18:19 + | +LL | let from_u16: f128 = 1_u16.into(); + | ^^^^ | = note: see issue #116909 for more information = help: add `#![feature(f128)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:21:11 + --> $DIR/feature-gate-f128.rs:19:19 + | +LL | let from_i32: f128 = 1_i32.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:20:19 + | +LL | let from_u32: f128 = 1_u32.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:21:19 + | +LL | let from_i64: f128 = 1_i64.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:22:19 + | +LL | let from_u64: f128 = 1_u64.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:23:19 + | +LL | let from_f16: f128 = 1.0_f16.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:26:19 + | +LL | let from_f32: f128 = 1.0_f32.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:27:19 + | +LL | let from_f64: f128 = 1.0_f64.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:28:20 + | +LL | let from_bool: f128 = true.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:32:11 | LL | fn foo(a: f128) {} | ^^^^ @@ -49,7 +149,7 @@ LL | fn foo(a: f128) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:24:8 + --> $DIR/feature-gate-f128.rs:35:8 | LL | a: f128, | ^^^^ @@ -78,17 +178,27 @@ LL | let c = 0f128; = help: add `#![feature(f128)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +error[E0658]: the type `f16` is unstable + --> $DIR/feature-gate-f128.rs:23:26 + | +LL | let from_f16: f128 = 1.0_f16.into(); + | ^^^^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f16)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + error[E0658]: use of unstable library feature `f128` - --> $DIR/feature-gate-f128.rs:13:24 + --> $DIR/feature-gate-f128.rs:13:30 | -LL | let d: f128 = 1i64.into(); - | ^^^^ +LL | let from_i8: f128 = 1_i8.into(); + | ^^^^ | = help: add `#![feature(f128)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - = note: required for `f128` to implement `From` - = note: required for `i64` to implement `Into` + = note: required for `f128` to implement `From` + = note: required for `i8` to implement `Into` -error: aborting due to 9 previous errors +error: aborting due to 20 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-f128.rs b/tests/ui/feature-gates/feature-gate-f128.rs index 13851b72c70f2..3b64c71a23122 100644 --- a/tests/ui/feature-gates/feature-gate-f128.rs +++ b/tests/ui/feature-gates/feature-gate-f128.rs @@ -10,11 +10,22 @@ pub fn main() { let a: f128 = 100.0; //~ ERROR the type `f128` is unstable let b = 0.0f128; //~ ERROR the type `f128` is unstable let c = 0f128; //~ ERROR the type `f128` is unstable - let d: f128 = 1i64.into(); + let from_i8: f128 = 1_i8.into(); //~^ ERROR the type `f128` is unstable //~| ERROR use of unstable library feature `f128` - let e: f128 = 1u64.into(); + let from_u8: f128 = 1_u8.into(); //~ ERROR the type `f128` is unstable + let from_i16: f128 = 1_i16.into(); //~ ERROR the type `f128` is unstable + let from_u16: f128 = 1_u16.into(); //~ ERROR the type `f128` is unstable + let from_i32: f128 = 1_i32.into(); //~ ERROR the type `f128` is unstable + let from_u32: f128 = 1_u32.into(); //~ ERROR the type `f128` is unstable + let from_i64: f128 = 1_i64.into(); //~ ERROR the type `f128` is unstable + let from_u64: f128 = 1_u64.into(); //~ ERROR the type `f128` is unstable + let from_f16: f128 = 1.0_f16.into(); //~^ ERROR the type `f128` is unstable + //~| ERROR the type `f16` is unstable + let from_f32: f128 = 1.0_f32.into(); //~ ERROR the type `f128` is unstable + let from_f64: f128 = 1.0_f64.into(); //~ ERROR the type `f128` is unstable + let from_bool: f128 = true.into(); //~ ERROR the type `f128` is unstable foo(1.23); } diff --git a/tests/ui/feature-gates/feature-gate-f16.e2015.stderr b/tests/ui/feature-gates/feature-gate-f16.e2015.stderr index b53f12af48fc8..3bc77d00e2384 100644 --- a/tests/ui/feature-gates/feature-gate-f16.e2015.stderr +++ b/tests/ui/feature-gates/feature-gate-f16.e2015.stderr @@ -18,8 +18,48 @@ LL | let a: f16 = 100.0; = help: add `#![feature(f16)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f16.rs:17:20 + | +LL | let into_f128: f128 = 1.0_f16.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f16` is unstable + --> $DIR/feature-gate-f16.rs:20:18 + | +LL | let from_i8: f16 = 1_i8.into(); + | ^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f16)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f16` is unstable + --> $DIR/feature-gate-f16.rs:21:18 + | +LL | let from_u8: f16 = 1_u8.into(); + | ^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f16)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f16` is unstable + --> $DIR/feature-gate-f16.rs:22:20 + | +LL | let from_bool: f16 = true.into(); + | ^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f16)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + error[E0658]: the type `f16` is unstable - --> $DIR/feature-gate-f16.rs:19:11 + --> $DIR/feature-gate-f16.rs:26:11 | LL | fn foo(a: f16) {} | ^^^ @@ -29,7 +69,7 @@ LL | fn foo(a: f16) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f16` is unstable - --> $DIR/feature-gate-f16.rs:22:8 + --> $DIR/feature-gate-f16.rs:29:8 | LL | a: f16, | ^^^ @@ -59,26 +99,46 @@ LL | let c = 0f16; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f16` is unstable - --> $DIR/feature-gate-f16.rs:13:18 + --> $DIR/feature-gate-f16.rs:13:25 | -LL | let d: f32 = 1.0f16.into(); - | ^^^^^^ +LL | let into_f32: f32 = 1.0f16.into(); + | ^^^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f16)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f16` is unstable + --> $DIR/feature-gate-f16.rs:16:25 + | +LL | let into_f64: f64 = 1.0_f16.into(); + | ^^^^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f16)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f16` is unstable + --> $DIR/feature-gate-f16.rs:17:27 + | +LL | let into_f128: f128 = 1.0_f16.into(); + | ^^^^^^^ | = note: see issue #116909 for more information = help: add `#![feature(f16)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: use of unstable library feature `f32_from_f16` - --> $DIR/feature-gate-f16.rs:13:25 + --> $DIR/feature-gate-f16.rs:13:32 | -LL | let d: f32 = 1.0f16.into(); - | ^^^^ +LL | let into_f32: f32 = 1.0f16.into(); + | ^^^^ | = help: add `#![feature(f32_from_f16)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = note: required for `f32` to implement `From` = note: required for `f16` to implement `Into` -error: aborting due to 8 previous errors +error: aborting due to 14 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-f16.e2018.stderr b/tests/ui/feature-gates/feature-gate-f16.e2018.stderr index b53f12af48fc8..3bc77d00e2384 100644 --- a/tests/ui/feature-gates/feature-gate-f16.e2018.stderr +++ b/tests/ui/feature-gates/feature-gate-f16.e2018.stderr @@ -18,8 +18,48 @@ LL | let a: f16 = 100.0; = help: add `#![feature(f16)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f16.rs:17:20 + | +LL | let into_f128: f128 = 1.0_f16.into(); + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f16` is unstable + --> $DIR/feature-gate-f16.rs:20:18 + | +LL | let from_i8: f16 = 1_i8.into(); + | ^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f16)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f16` is unstable + --> $DIR/feature-gate-f16.rs:21:18 + | +LL | let from_u8: f16 = 1_u8.into(); + | ^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f16)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f16` is unstable + --> $DIR/feature-gate-f16.rs:22:20 + | +LL | let from_bool: f16 = true.into(); + | ^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f16)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + error[E0658]: the type `f16` is unstable - --> $DIR/feature-gate-f16.rs:19:11 + --> $DIR/feature-gate-f16.rs:26:11 | LL | fn foo(a: f16) {} | ^^^ @@ -29,7 +69,7 @@ LL | fn foo(a: f16) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f16` is unstable - --> $DIR/feature-gate-f16.rs:22:8 + --> $DIR/feature-gate-f16.rs:29:8 | LL | a: f16, | ^^^ @@ -59,26 +99,46 @@ LL | let c = 0f16; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f16` is unstable - --> $DIR/feature-gate-f16.rs:13:18 + --> $DIR/feature-gate-f16.rs:13:25 | -LL | let d: f32 = 1.0f16.into(); - | ^^^^^^ +LL | let into_f32: f32 = 1.0f16.into(); + | ^^^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f16)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f16` is unstable + --> $DIR/feature-gate-f16.rs:16:25 + | +LL | let into_f64: f64 = 1.0_f16.into(); + | ^^^^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f16)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f16` is unstable + --> $DIR/feature-gate-f16.rs:17:27 + | +LL | let into_f128: f128 = 1.0_f16.into(); + | ^^^^^^^ | = note: see issue #116909 for more information = help: add `#![feature(f16)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: use of unstable library feature `f32_from_f16` - --> $DIR/feature-gate-f16.rs:13:25 + --> $DIR/feature-gate-f16.rs:13:32 | -LL | let d: f32 = 1.0f16.into(); - | ^^^^ +LL | let into_f32: f32 = 1.0f16.into(); + | ^^^^ | = help: add `#![feature(f32_from_f16)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = note: required for `f32` to implement `From` = note: required for `f16` to implement `Into` -error: aborting due to 8 previous errors +error: aborting due to 14 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-f16.rs b/tests/ui/feature-gates/feature-gate-f16.rs index 6babc6c5c03ce..6211581db1c7a 100644 --- a/tests/ui/feature-gates/feature-gate-f16.rs +++ b/tests/ui/feature-gates/feature-gate-f16.rs @@ -10,9 +10,16 @@ pub fn main() { let a: f16 = 100.0; //~ ERROR the type `f16` is unstable let b = 0.0f16; //~ ERROR the type `f16` is unstable let c = 0f16; //~ ERROR the type `f16` is unstable - let d: f32 = 1.0f16.into(); + let into_f32: f32 = 1.0f16.into(); //~^ ERROR the type `f16` is unstable //~| ERROR use of unstable library feature `f32_from_f16` + let into_f64: f64 = 1.0_f16.into(); //~ ERROR the type `f16` is unstable + let into_f128: f128 = 1.0_f16.into(); + //~^ ERROR the type `f16` is unstable + //~| ERROR the type `f128` is unstable + let from_i8: f16 = 1_i8.into(); //~ ERROR the type `f16` is unstable + let from_u8: f16 = 1_u8.into(); //~ ERROR the type `f16` is unstable + let from_bool: f16 = true.into(); //~ ERROR the type `f16` is unstable foo(1.23); } diff --git a/tests/ui/pin-ergonomics/pinned-drop-check.stderr b/tests/ui/pin-ergonomics/pinned-drop-check.stderr index 3a848c66578b4..3dc6e18a9178e 100644 --- a/tests/ui/pin-ergonomics/pinned-drop-check.stderr +++ b/tests/ui/pin-ergonomics/pinned-drop-check.stderr @@ -71,12 +71,18 @@ error[E0046]: not all trait items implemented, missing one of: `drop`, `pin_drop | LL | impl Drop for Foo {} | ^^^^^^^^^^^^^^^^^ missing one of `drop`, `pin_drop` in implementation + | + = help: implement the missing item: `fn drop(&mut self) { todo!() }` + = help: implement the missing item: `fn pin_drop(self: Pin<&mut Self>) { todo!() }` error[E0046]: not all trait items implemented, missing one of: `drop`, `pin_drop` --> $DIR/pinned-drop-check.rs:60:5 | LL | impl Drop for Bar {} | ^^^^^^^^^^^^^^^^^ missing one of `drop`, `pin_drop` in implementation + | + = help: implement the missing item: `fn drop(&mut self) { todo!() }` + = help: implement the missing item: `fn pin_drop(self: Pin<&mut Self>) { todo!() }` error: `Bar` must implement `pin_drop` --> $DIR/pinned-drop-check.rs:87:9 diff --git a/tests/ui/traits/bad-error-message-impl-trait-double-ref-issue-85681.rs b/tests/ui/traits/bad-error-message-impl-trait-double-ref-issue-85681.rs new file mode 100644 index 0000000000000..cce714757cc62 --- /dev/null +++ b/tests/ui/traits/bad-error-message-impl-trait-double-ref-issue-85681.rs @@ -0,0 +1,13 @@ +fn foo(_x: u32, a: impl Into, _y: u32, b: impl Into) { + println!("fox: a={}, b={}", a.into(), b.into()); +} + +fn main() { + let bar: String = "bar".to_string(); + let baz: &str = "baz"; + + for (a, b) in &[(&bar, baz)] { + let a: &String = a; + foo(42, a, 43, b); //~ ERROR: the trait bound `String: From<&&str>` is not satisfied [E0277] + } +} diff --git a/tests/ui/traits/bad-error-message-impl-trait-double-ref-issue-85681.stderr b/tests/ui/traits/bad-error-message-impl-trait-double-ref-issue-85681.stderr new file mode 100644 index 0000000000000..422660d580efc --- /dev/null +++ b/tests/ui/traits/bad-error-message-impl-trait-double-ref-issue-85681.stderr @@ -0,0 +1,23 @@ +error[E0277]: the trait bound `String: From<&&str>` is not satisfied + --> $DIR/bad-error-message-impl-trait-double-ref-issue-85681.rs:11:24 + | +LL | foo(42, a, 43, b); + | --- ^ the trait `From<&&str>` is not implemented for `String` + | | + | required by a bound introduced by this call + | + = help: consider casting the `&&str` value to `&str` + = note: required for `&&str` to implement `Into` +note: required by a bound in `foo` + --> $DIR/bad-error-message-impl-trait-double-ref-issue-85681.rs:1:56 + | +LL | fn foo(_x: u32, a: impl Into, _y: u32, b: impl Into) { + | ^^^^^^^^^^^^ required by this bound in `foo` +help: consider dereferencing here + | +LL | foo(42, a, 43, *b); + | + + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/default-method/rustc_must_implement_one_of.stderr b/tests/ui/traits/default-method/rustc_must_implement_one_of.stderr index 7ad10cfce984f..9868cf8faa084 100644 --- a/tests/ui/traits/default-method/rustc_must_implement_one_of.stderr +++ b/tests/ui/traits/default-method/rustc_must_implement_one_of.stderr @@ -1,6 +1,12 @@ error[E0046]: not all trait items implemented, missing one of: `eq`, `neq` --> $DIR/rustc_must_implement_one_of.rs:41:1 | +LL | fn eq(&self, other: &Self) -> bool { + | ---------------------------------- `eq` from trait +... +LL | fn neq(&self, other: &Self) -> bool { + | ----------------------------------- `neq` from trait +... LL | impl Equal for T3 {} | ^^^^^^^^^^^^^^^^^ missing one of `eq`, `neq` in implementation | diff --git a/tests/ui/traits/explicit-reference-cast-hrtb.rs b/tests/ui/traits/explicit-reference-cast-hrtb.rs new file mode 100644 index 0000000000000..8714bff369b82 --- /dev/null +++ b/tests/ui/traits/explicit-reference-cast-hrtb.rs @@ -0,0 +1,14 @@ +//! Regression test for #158967 + +struct Foo; + +fn f() +where + for<'a> Foo: From<&'a String>, +{ +} + +fn main() { + f(); + //~^ ERROR the trait bound `for<'a> Foo: From<&'a String>` is not satisfied [E0277] +} diff --git a/tests/ui/traits/explicit-reference-cast-hrtb.stderr b/tests/ui/traits/explicit-reference-cast-hrtb.stderr new file mode 100644 index 0000000000000..4921a87900051 --- /dev/null +++ b/tests/ui/traits/explicit-reference-cast-hrtb.stderr @@ -0,0 +1,23 @@ +error[E0277]: the trait bound `for<'a> Foo: From<&'a String>` is not satisfied + --> $DIR/explicit-reference-cast-hrtb.rs:12:5 + | +LL | f(); + | ^^^ unsatisfied trait bound + | +help: the trait `for<'a> From<&'a String>` is not implemented for `Foo` + --> $DIR/explicit-reference-cast-hrtb.rs:3:1 + | +LL | struct Foo; + | ^^^^^^^^^^ +note: required by a bound in `f` + --> $DIR/explicit-reference-cast-hrtb.rs:7:18 + | +LL | fn f() + | - required by a bound in this function +LL | where +LL | for<'a> Foo: From<&'a String>, + | ^^^^^^^^^^^^^^^^ required by this bound in `f` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`.