diff options
67 files changed, 1062 insertions, 586 deletions
diff --git a/Cargo.lock b/Cargo.lock index ebb8d114f2a..d00bf4b1292 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -207,9 +207,9 @@ checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "backtrace" @@ -505,7 +505,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -534,7 +534,7 @@ dependencies = [ "rustc_tools_util", "serde", "serde_json", - "syn 2.0.77", + "syn 2.0.79", "tempfile", "termize", "tokio", @@ -643,7 +643,7 @@ dependencies = [ "nom", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -861,7 +861,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -872,7 +872,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -898,7 +898,7 @@ version = "0.1.83" dependencies = [ "itertools", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -918,7 +918,7 @@ checksum = "62d671cc41a825ebabc75757b62d3d168c577f9149b2d49ece1dad1f72119d25" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -939,7 +939,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -949,7 +949,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4abae7035bf79b9877b779505d8cf3749285b80c43941eda66604841889451dc" dependencies = [ "derive_builder_core", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -961,7 +961,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -1039,7 +1039,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -1192,9 +1192,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.33" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253" +checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" dependencies = [ "crc32fast", "miniz_oxide 0.8.0", @@ -1330,7 +1330,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -1554,7 +1554,7 @@ dependencies = [ "markup5ever", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -1686,7 +1686,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -2661,7 +2661,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -2763,9 +2763,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d30538d42559de6b034bc76fd6dd4c38961b1ee5c6c56e3808c50128fdbc22ce" +checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" [[package]] name = "powerfmt" @@ -3073,7 +3073,7 @@ dependencies = [ "rinja_parser", "rustc-hash 2.0.0", "serde", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -3671,7 +3671,7 @@ dependencies = [ "fluent-syntax", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", "unic-langid", ] @@ -3805,7 +3805,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -3954,7 +3954,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", "synstructure", ] @@ -4535,7 +4535,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", "synstructure", ] @@ -4623,7 +4623,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -4760,7 +4760,7 @@ checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -5024,9 +5024,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.77" +version = "2.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" dependencies = [ "proc-macro2", "quote", @@ -5041,7 +5041,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -5078,9 +5078,9 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.12.0" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" +checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" dependencies = [ "cfg-if", "fastrand", @@ -5174,7 +5174,7 @@ checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -5365,7 +5365,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -5536,7 +5536,7 @@ checksum = "1ed7f4237ba393424195053097c1516bd4590dc82b84f2f97c5c69e12704555b" dependencies = [ "proc-macro-hack", "quote", - "syn 2.0.77", + "syn 2.0.79", "unic-langid-impl", ] @@ -5734,7 +5734,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", "wasm-bindgen-shared", ] @@ -5756,7 +5756,7 @@ checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -5923,7 +5923,7 @@ dependencies = [ "rayon", "serde", "serde_json", - "syn 2.0.77", + "syn 2.0.79", "windows-metadata", ] @@ -5956,7 +5956,7 @@ checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -5967,7 +5967,7 @@ checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -6234,7 +6234,7 @@ checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", "synstructure", ] @@ -6256,7 +6256,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -6276,7 +6276,7 @@ checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", "synstructure", ] @@ -6299,5 +6299,5 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] diff --git a/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch b/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch index a3f370af916..646928893e9 100644 --- a/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch +++ b/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch @@ -82,19 +82,6 @@ index d9de37e..8293fce 100644 #[cfg(target_has_atomic_load_store = "ptr")] macro_rules! atomic_int_ptr_sized { ( $($target_pointer_width:literal $align:literal)* ) => { $( -diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs -index 58b9ba4..91bbd0a 100644 ---- a/library/core/src/cell.rs -+++ b/library/core/src/cell.rs -@@ -2246,8 +2246,6 @@ unsafe_cell_primitive_into_inner! { - u32 "32" - i64 "64" - u64 "64" -- i128 "128" -- u128 "128" - isize "ptr" - usize "ptr" - } -- 2.26.2.7.g19db9cfb68 diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index a2a5499597c..201cfbb1918 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -536,6 +536,11 @@ pub(crate) fn global_llvm_features( // -Ctarget-cpu=native match sess.opts.cg.target_cpu { Some(ref s) if s == "native" => { + // We have already figured out the actual CPU name with `LLVMRustGetHostCPUName` and set + // that for LLVM, so the features implied by that CPU name will be available everywhere. + // However, that is not sufficient: e.g. `skylake` alone is not sufficient to tell if + // some of the instructions are available or not. So we have to also explicitly ask for + // the exact set of features available on the host, and enable all of them. let features_string = unsafe { let ptr = llvm::LLVMGetHostCPUFeatures(); let features_string = if !ptr.is_null() { diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index e1fd8bea1f3..4c34ffc5d4e 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -396,11 +396,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { for i in 0..dest_len { let place = self.project_index(&dest, i)?; - let value = if i == index { - elem.clone() - } else { - self.project_index(&input, i)?.into() - }; + let value = + if i == index { elem.clone() } else { self.project_index(&input, i)? }; self.copy_op(&value, &place)?; } } diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index a7b251ab252..0dc35618ff8 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -627,8 +627,7 @@ impl server::TokenStream for Rustc<'_, '_> { base: Option<Self::TokenStream>, trees: Vec<TokenTree<Self::TokenStream, Self::Span, Self::Symbol>>, ) -> Self::TokenStream { - let mut stream = - if let Some(base) = base { base } else { tokenstream::TokenStream::default() }; + let mut stream = base.unwrap_or_default(); for tree in trees { for tt in (tree, &mut *self).to_internal() { stream.push_tree(tt); @@ -642,8 +641,7 @@ impl server::TokenStream for Rustc<'_, '_> { base: Option<Self::TokenStream>, streams: Vec<Self::TokenStream>, ) -> Self::TokenStream { - let mut stream = - if let Some(base) = base { base } else { tokenstream::TokenStream::default() }; + let mut stream = base.unwrap_or_default(); for s in streams { stream.push_stream(s); } diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index c5843b883a1..63cf483aa22 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -1369,13 +1369,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for (&var_hir_id, _) in upvars.iter() { let mut diagnostics_info = Vec::new(); - let auto_trait_diagnostic = if let Some(diagnostics_info) = - self.compute_2229_migrations_for_trait(min_captures, var_hir_id, closure_clause) - { - diagnostics_info - } else { - FxIndexMap::default() - }; + let auto_trait_diagnostic = self + .compute_2229_migrations_for_trait(min_captures, var_hir_id, closure_clause) + .unwrap_or_default(); let drop_reorder_diagnostic = if let Some(diagnostics_info) = self .compute_2229_migrations_for_drop( diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index c2241773c8c..3b8077bb3fc 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -427,7 +427,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se Err(e) => early_dcx.early_fatal(format!("failed to load fluent bundle: {e}")), }; - let mut locale_resources = Vec::from(config.locale_resources); + let mut locale_resources = config.locale_resources; locale_resources.push(codegen_backend.locale_resource()); let mut sess = rustc_session::build_session( diff --git a/compiler/rustc_lint/src/if_let_rescope.rs b/compiler/rustc_lint/src/if_let_rescope.rs index 229d0c36421..c6218fe1e74 100644 --- a/compiler/rustc_lint/src/if_let_rescope.rs +++ b/compiler/rustc_lint/src/if_let_rescope.rs @@ -304,7 +304,7 @@ impl Subdiagnostic for IfLetRescopeRewrite { .chain(repeat('}').take(closing_brackets.count)) .collect(), )); - let msg = f(diag, crate::fluent_generated::lint_suggestion.into()); + let msg = f(diag, crate::fluent_generated::lint_suggestion); diag.multipart_suggestion_with_style( msg, suggestions, diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 4425c93211a..2157324d5cc 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1622,56 +1622,63 @@ impl<'a> CrateMetadataRef<'a> { ); for virtual_dir in virtual_rust_source_base_dir.iter().flatten() { - if let Some(real_dir) = &sess.opts.real_rust_source_base_dir { - if let rustc_span::FileName::Real(old_name) = name { - if let rustc_span::RealFileName::Remapped { local_path: _, virtual_name } = - old_name - { - if let Ok(rest) = virtual_name.strip_prefix(virtual_dir) { - let virtual_name = virtual_name.clone(); - - // The std library crates are in - // `$sysroot/lib/rustlib/src/rust/library`, whereas other crates - // may be in `$sysroot/lib/rustlib/src/rust/` directly. So we - // detect crates from the std libs and handle them specially. - const STD_LIBS: &[&str] = &[ - "core", - "alloc", - "std", - "test", - "term", - "unwind", - "proc_macro", - "panic_abort", - "panic_unwind", - "profiler_builtins", - "rtstartup", - "rustc-std-workspace-core", - "rustc-std-workspace-alloc", - "rustc-std-workspace-std", - "backtrace", - ]; - let is_std_lib = STD_LIBS.iter().any(|l| rest.starts_with(l)); - - let new_path = if is_std_lib { - real_dir.join("library").join(rest) - } else { - real_dir.join(rest) - }; - - debug!( - "try_to_translate_virtual_to_real: `{}` -> `{}`", - virtual_name.display(), - new_path.display(), - ); - let new_name = rustc_span::RealFileName::Remapped { - local_path: Some(new_path), - virtual_name, - }; - *old_name = new_name; - } + if let Some(real_dir) = &sess.opts.real_rust_source_base_dir + && let rustc_span::FileName::Real(old_name) = name + && let rustc_span::RealFileName::Remapped { local_path: _, virtual_name } = + old_name + && let Ok(rest) = virtual_name.strip_prefix(virtual_dir) + { + // The std library crates are in + // `$sysroot/lib/rustlib/src/rust/library`, whereas other crates + // may be in `$sysroot/lib/rustlib/src/rust/` directly. So we + // detect crates from the std libs and handle them specially. + const STD_LIBS: &[&str] = &[ + "core", + "alloc", + "std", + "test", + "term", + "unwind", + "proc_macro", + "panic_abort", + "panic_unwind", + "profiler_builtins", + "rtstartup", + "rustc-std-workspace-core", + "rustc-std-workspace-alloc", + "rustc-std-workspace-std", + "backtrace", + ]; + let is_std_lib = STD_LIBS.iter().any(|l| rest.starts_with(l)); + + let new_path = if is_std_lib { + real_dir.join("library").join(rest) + } else { + real_dir.join(rest) + }; + + debug!( + "try_to_translate_virtual_to_real: `{}` -> `{}`", + virtual_name.display(), + new_path.display(), + ); + + // Check if the translated real path is affected by any user-requested + // remaps via --remap-path-prefix. Apply them if so. + // Note that this is a special case for imported rust-src paths specified by + // https://rust-lang.github.io/rfcs/3127-trim-paths.html#handling-sysroot-paths. + // Other imported paths are not currently remapped (see #66251). + let (user_remapped, applied) = + sess.source_map().path_mapping().map_prefix(&new_path); + let new_name = if applied { + rustc_span::RealFileName::Remapped { + local_path: Some(new_path.clone()), + virtual_name: user_remapped.to_path_buf(), } - } + } else { + rustc_span::RealFileName::LocalPath(new_path) + }; + *old_name = new_name; } } }; diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 54cfd995832..ee34ccd889f 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -217,7 +217,7 @@ pub fn early_report_macro_deprecation( suggestion_span: span, note: depr.note, path, - since_kind: deprecated_since_kind(is_in_effect, depr.since.clone()), + since_kind: deprecated_since_kind(is_in_effect, depr.since), }; lint_buffer.buffer_lint(deprecation_lint(is_in_effect), node_id, span, diag); } diff --git a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs index 65442877d2d..cc4b7689d40 100644 --- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs +++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs @@ -223,14 +223,14 @@ pub(crate) fn coroutine_by_move_body_def_id<'tcx>( // Inherited from the by-ref coroutine. body_def.codegen_fn_attrs(tcx.codegen_fn_attrs(coroutine_def_id).clone()); - body_def.constness(tcx.constness(coroutine_def_id).clone()); - body_def.coroutine_kind(tcx.coroutine_kind(coroutine_def_id).clone()); + body_def.constness(tcx.constness(coroutine_def_id)); + body_def.coroutine_kind(tcx.coroutine_kind(coroutine_def_id)); body_def.def_ident_span(tcx.def_ident_span(coroutine_def_id)); body_def.def_span(tcx.def_span(coroutine_def_id)); - body_def.explicit_predicates_of(tcx.explicit_predicates_of(coroutine_def_id).clone()); + body_def.explicit_predicates_of(tcx.explicit_predicates_of(coroutine_def_id)); body_def.generics_of(tcx.generics_of(coroutine_def_id).clone()); - body_def.param_env(tcx.param_env(coroutine_def_id).clone()); - body_def.predicates_of(tcx.predicates_of(coroutine_def_id).clone()); + body_def.param_env(tcx.param_env(coroutine_def_id)); + body_def.predicates_of(tcx.predicates_of(coroutine_def_id)); // The type of the coroutine is the `by_move_coroutine_ty`. body_def.type_of(ty::EarlyBinder::bind(by_move_coroutine_ty)); diff --git a/compiler/rustc_mir_transform/src/single_use_consts.rs b/compiler/rustc_mir_transform/src/single_use_consts.rs index 9884b6dd1c3..277a33c0311 100644 --- a/compiler/rustc_mir_transform/src/single_use_consts.rs +++ b/compiler/rustc_mir_transform/src/single_use_consts.rs @@ -185,15 +185,14 @@ impl<'tcx> MutVisitor<'tcx> for LocalReplacer<'tcx> { && let Some(local) = place.as_local() && local == self.local { - let const_op = self + let const_op = *self .operand .as_ref() .unwrap_or_else(|| { bug!("the operand was already stolen"); }) .constant() - .unwrap() - .clone(); + .unwrap(); var_debug_info.value = VarDebugInfoContents::Const(const_op); } } diff --git a/compiler/rustc_pattern_analysis/src/constructor.rs b/compiler/rustc_pattern_analysis/src/constructor.rs index 3cb7576154f..8fce4266345 100644 --- a/compiler/rustc_pattern_analysis/src/constructor.rs +++ b/compiler/rustc_pattern_analysis/src/constructor.rs @@ -735,10 +735,10 @@ impl<Cx: PatCx> Clone for Constructor<Cx> { Constructor::UnionField => Constructor::UnionField, Constructor::Bool(b) => Constructor::Bool(*b), Constructor::IntRange(range) => Constructor::IntRange(*range), - Constructor::F16Range(lo, hi, end) => Constructor::F16Range(lo.clone(), *hi, *end), - Constructor::F32Range(lo, hi, end) => Constructor::F32Range(lo.clone(), *hi, *end), - Constructor::F64Range(lo, hi, end) => Constructor::F64Range(lo.clone(), *hi, *end), - Constructor::F128Range(lo, hi, end) => Constructor::F128Range(lo.clone(), *hi, *end), + Constructor::F16Range(lo, hi, end) => Constructor::F16Range(*lo, *hi, *end), + Constructor::F32Range(lo, hi, end) => Constructor::F32Range(*lo, *hi, *end), + Constructor::F64Range(lo, hi, end) => Constructor::F64Range(*lo, *hi, *end), + Constructor::F128Range(lo, hi, end) => Constructor::F128Range(*lo, *hi, *end), Constructor::Str(value) => Constructor::Str(value.clone()), Constructor::Opaque(inner) => Constructor::Opaque(inner.clone()), Constructor::Or => Constructor::Or, diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 46e30c614ab..582db97e1ce 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1469,11 +1469,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } let unused_macro = self.unused_macros.iter().find_map(|(def_id, (_, unused_ident))| { - if unused_ident.name == ident.name { - Some((def_id.clone(), unused_ident.clone())) - } else { - None - } + if unused_ident.name == ident.name { Some((def_id, unused_ident)) } else { None } }); if let Some((def_id, unused_ident)) = unused_macro { diff --git a/library/Cargo.lock b/library/Cargo.lock index e883749730c..877ae0cc1cc 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -61,9 +61,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.126" +version = "0.1.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "758019257ad46e191b587d8f711022a6ac1d1fb6745d75e1d76c587fdcbca770" +checksum = "e64c30475571756801eff60a811520c3d18e0ceb9c56c97bad2047ae601f6709" dependencies = [ "cc", "rustc-std-workspace-core", diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml index 1b76b4c4a50..11db50a0fdf 100644 --- a/library/alloc/Cargo.toml +++ b/library/alloc/Cargo.toml @@ -10,7 +10,7 @@ edition = "2021" [dependencies] core = { path = "../core" } -compiler_builtins = { version = "0.1.126", features = ['rustc-dep-of-std'] } +compiler_builtins = { version = "0.1.130", features = ['rustc-dep-of-std'] } [dev-dependencies] rand = { version = "0.8.5", default-features = false, features = ["alloc"] } diff --git a/library/alloc/benches/str.rs b/library/alloc/benches/str.rs index f020638e992..98c7c5413ca 100644 --- a/library/alloc/benches/str.rs +++ b/library/alloc/benches/str.rs @@ -347,3 +347,5 @@ make_test!(rsplitn_space_char, s, s.rsplitn(10, ' ').count()); make_test!(split_space_str, s, s.split(" ").count()); make_test!(split_ad_str, s, s.split("ad").count()); + +make_test!(to_lowercase, s, s.to_lowercase()); diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index f636f10d5c0..a92d22b1c30 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -180,10 +180,9 @@ impl<T> [T] { /// This sort is stable (i.e., does not reorder equal elements) and *O*(*n* \* log(*n*)) /// worst-case. /// - /// If the implementation of [`Ord`] for `T` does not implement a [total order] the resulting - /// order of elements in the slice is unspecified. All original elements will remain in the - /// slice and any possible modifications via interior mutability are observed in the input. Same - /// is true if the implementation of [`Ord`] for `T` panics. + /// If the implementation of [`Ord`] for `T` does not implement a [total order], the function + /// may panic; even if the function exits normally, the resulting order of elements in the slice + /// is unspecified. See also the note on panicking below. /// /// When applicable, unstable sorting is preferred because it is generally faster than stable /// sorting and it doesn't allocate auxiliary memory. See @@ -212,7 +211,15 @@ impl<T> [T] { /// /// # Panics /// - /// May panic if the implementation of [`Ord`] for `T` does not implement a [total order]. + /// May panic if the implementation of [`Ord`] for `T` does not implement a [total order], or if + /// the [`Ord`] implementation itself panics. + /// + /// All safe functions on slices preserve the invariant that even if the function panics, all + /// original elements will remain in the slice and any possible modifications via interior + /// mutability are observed in the input. This ensures that recovery code (for instance inside + /// of a `Drop` or following a `catch_unwind`) will still have access to all the original + /// elements. For instance, if the slice belongs to a `Vec`, the `Vec::drop` method will be able + /// to dispose of all contained elements. /// /// # Examples /// @@ -241,10 +248,9 @@ impl<T> [T] { /// This sort is stable (i.e., does not reorder equal elements) and *O*(*n* \* log(*n*)) /// worst-case. /// - /// If the comparison function `compare` does not implement a [total order] the resulting order - /// of elements in the slice is unspecified. All original elements will remain in the slice and - /// any possible modifications via interior mutability are observed in the input. Same is true - /// if `compare` panics. + /// If the comparison function `compare` does not implement a [total order], the function may + /// panic; even if the function exits normally, the resulting order of elements in the slice is + /// unspecified. See also the note on panicking below. /// /// For example `|a, b| (a - b).cmp(a)` is a comparison function that is neither transitive nor /// reflexive nor total, `a < b < c < a` with `a = 1, b = 2, c = 3`. For more information and @@ -263,7 +269,14 @@ impl<T> [T] { /// /// # Panics /// - /// May panic if `compare` does not implement a [total order]. + /// May panic if `compare` does not implement a [total order], or if `compare` itself panics. + /// + /// All safe functions on slices preserve the invariant that even if the function panics, all + /// original elements will remain in the slice and any possible modifications via interior + /// mutability are observed in the input. This ensures that recovery code (for instance inside + /// of a `Drop` or following a `catch_unwind`) will still have access to all the original + /// elements. For instance, if the slice belongs to a `Vec`, the `Vec::drop` method will be able + /// to dispose of all contained elements. /// /// # Examples /// @@ -295,10 +308,9 @@ impl<T> [T] { /// This sort is stable (i.e., does not reorder equal elements) and *O*(*m* \* *n* \* log(*n*)) /// worst-case, where the key function is *O*(*m*). /// - /// If the implementation of [`Ord`] for `K` does not implement a [total order] the resulting - /// order of elements in the slice is unspecified. All original elements will remain in the - /// slice and any possible modifications via interior mutability are observed in the input. Same - /// is true if the implementation of [`Ord`] for `K` panics. + /// If the implementation of [`Ord`] for `K` does not implement a [total order], the function + /// may panic; even if the function exits normally, the resulting order of elements in the slice + /// is unspecified. See also the note on panicking below. /// /// # Current implementation /// @@ -313,7 +325,15 @@ impl<T> [T] { /// /// # Panics /// - /// May panic if the implementation of [`Ord`] for `K` does not implement a [total order]. + /// May panic if the implementation of [`Ord`] for `K` does not implement a [total order], or if + /// the [`Ord`] implementation or the key-function `f` panics. + /// + /// All safe functions on slices preserve the invariant that even if the function panics, all + /// original elements will remain in the slice and any possible modifications via interior + /// mutability are observed in the input. This ensures that recovery code (for instance inside + /// of a `Drop` or following a `catch_unwind`) will still have access to all the original + /// elements. For instance, if the slice belongs to a `Vec`, the `Vec::drop` method will be able + /// to dispose of all contained elements. /// /// # Examples /// @@ -347,10 +367,9 @@ impl<T> [T] { /// storage to remember the results of key evaluation. The order of calls to the key function is /// unspecified and may change in future versions of the standard library. /// - /// If the implementation of [`Ord`] for `K` does not implement a [total order] the resulting - /// order of elements in the slice is unspecified. All original elements will remain in the - /// slice and any possible modifications via interior mutability are observed in the input. Same - /// is true if the implementation of [`Ord`] for `K` panics. + /// If the implementation of [`Ord`] for `K` does not implement a [total order], the function + /// may panic; even if the function exits normally, the resulting order of elements in the slice + /// is unspecified. See also the note on panicking below. /// /// For simple key functions (e.g., functions that are property accesses or basic operations), /// [`sort_by_key`](slice::sort_by_key) is likely to be faster. @@ -369,7 +388,15 @@ impl<T> [T] { /// /// # Panics /// - /// May panic if the implementation of [`Ord`] for `K` does not implement a [total order]. + /// May panic if the implementation of [`Ord`] for `K` does not implement a [total order], or if + /// the [`Ord`] implementation panics. + /// + /// All safe functions on slices preserve the invariant that even if the function panics, all + /// original elements will remain in the slice and any possible modifications via interior + /// mutability are observed in the input. This ensures that recovery code (for instance inside + /// of a `Drop` or following a `catch_unwind`) will still have access to all the original + /// elements. For instance, if the slice belongs to a `Vec`, the `Vec::drop` method will be able + /// to dispose of all contained elements. /// /// # Examples /// diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs index 32212b61c6e..42501f9c315 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -9,6 +9,7 @@ use core::borrow::{Borrow, BorrowMut}; use core::iter::FusedIterator; +use core::mem::MaybeUninit; #[stable(feature = "encode_utf16", since = "1.8.0")] pub use core::str::EncodeUtf16; #[stable(feature = "split_ascii_whitespace", since = "1.34.0")] @@ -365,14 +366,9 @@ impl str { without modifying the original"] #[stable(feature = "unicode_case_mapping", since = "1.2.0")] pub fn to_lowercase(&self) -> String { - let out = convert_while_ascii(self.as_bytes(), u8::to_ascii_lowercase); + let (mut s, rest) = convert_while_ascii(self, u8::to_ascii_lowercase); - // Safety: we know this is a valid char boundary since - // out.len() is only progressed if ascii bytes are found - let rest = unsafe { self.get_unchecked(out.len()..) }; - - // Safety: We have written only valid ASCII to our vec - let mut s = unsafe { String::from_utf8_unchecked(out) }; + let prefix_len = s.len(); for (i, c) in rest.char_indices() { if c == 'Σ' { @@ -381,8 +377,7 @@ impl str { // in `SpecialCasing.txt`, // so hard-code it rather than have a generic "condition" mechanism. // See https://github.com/rust-lang/rust/issues/26035 - let out_len = self.len() - rest.len(); - let sigma_lowercase = map_uppercase_sigma(&self, i + out_len); + let sigma_lowercase = map_uppercase_sigma(self, prefix_len + i); s.push(sigma_lowercase); } else { match conversions::to_lower(c) { @@ -458,14 +453,7 @@ impl str { without modifying the original"] #[stable(feature = "unicode_case_mapping", since = "1.2.0")] pub fn to_uppercase(&self) -> String { - let out = convert_while_ascii(self.as_bytes(), u8::to_ascii_uppercase); - - // Safety: we know this is a valid char boundary since - // out.len() is only progressed if ascii bytes are found - let rest = unsafe { self.get_unchecked(out.len()..) }; - - // Safety: We have written only valid ASCII to our vec - let mut s = unsafe { String::from_utf8_unchecked(out) }; + let (mut s, rest) = convert_while_ascii(self, u8::to_ascii_uppercase); for c in rest.chars() { match conversions::to_upper(c) { @@ -614,50 +602,87 @@ pub unsafe fn from_boxed_utf8_unchecked(v: Box<[u8]>) -> Box<str> { unsafe { Box::from_raw(Box::into_raw(v) as *mut str) } } -/// Converts the bytes while the bytes are still ascii. +/// Converts leading ascii bytes in `s` by calling the `convert` function. +/// /// For better average performance, this happens in chunks of `2*size_of::<usize>()`. -/// Returns a vec with the converted bytes. +/// +/// Returns a tuple of the converted prefix and the remainder starting from +/// the first non-ascii character. +/// +/// This function is only public so that it can be verified in a codegen test, +/// see `issue-123712-str-to-lower-autovectorization.rs`. +#[unstable(feature = "str_internals", issue = "none")] +#[doc(hidden)] #[inline] #[cfg(not(test))] #[cfg(not(no_global_oom_handling))] -fn convert_while_ascii(b: &[u8], convert: fn(&u8) -> u8) -> Vec<u8> { - let mut out = Vec::with_capacity(b.len()); +pub fn convert_while_ascii(s: &str, convert: fn(&u8) -> u8) -> (String, &str) { + // Process the input in chunks of 16 bytes to enable auto-vectorization. + // Previously the chunk size depended on the size of `usize`, + // but on 32-bit platforms with sse or neon is also the better choice. + // The only downside on other platforms would be a bit more loop-unrolling. + const N: usize = 16; + + let mut slice = s.as_bytes(); + let mut out = Vec::with_capacity(slice.len()); + let mut out_slice = out.spare_capacity_mut(); + + let mut ascii_prefix_len = 0_usize; + let mut is_ascii = [false; N]; + + while slice.len() >= N { + // SAFETY: checked in loop condition + let chunk = unsafe { slice.get_unchecked(..N) }; + // SAFETY: out_slice has at least same length as input slice and gets sliced with the same offsets + let out_chunk = unsafe { out_slice.get_unchecked_mut(..N) }; + + for j in 0..N { + is_ascii[j] = chunk[j] <= 127; + } - const USIZE_SIZE: usize = mem::size_of::<usize>(); - const MAGIC_UNROLL: usize = 2; - const N: usize = USIZE_SIZE * MAGIC_UNROLL; - const NONASCII_MASK: usize = usize::from_ne_bytes([0x80; USIZE_SIZE]); + // Auto-vectorization for this check is a bit fragile, sum and comparing against the chunk + // size gives the best result, specifically a pmovmsk instruction on x86. + // See https://github.com/llvm/llvm-project/issues/96395 for why llvm currently does not + // currently recognize other similar idioms. + if is_ascii.iter().map(|x| *x as u8).sum::<u8>() as usize != N { + break; + } - let mut i = 0; - unsafe { - while i + N <= b.len() { - // Safety: we have checks the sizes `b` and `out` to know that our - let in_chunk = b.get_unchecked(i..i + N); - let out_chunk = out.spare_capacity_mut().get_unchecked_mut(i..i + N); - - let mut bits = 0; - for j in 0..MAGIC_UNROLL { - // read the bytes 1 usize at a time (unaligned since we haven't checked the alignment) - // safety: in_chunk is valid bytes in the range - bits |= in_chunk.as_ptr().cast::<usize>().add(j).read_unaligned(); - } - // if our chunks aren't ascii, then return only the prior bytes as init - if bits & NONASCII_MASK != 0 { - break; - } + for j in 0..N { + out_chunk[j] = MaybeUninit::new(convert(&chunk[j])); + } - // perform the case conversions on N bytes (gets heavily autovec'd) - for j in 0..N { - // safety: in_chunk and out_chunk is valid bytes in the range - let out = out_chunk.get_unchecked_mut(j); - out.write(convert(in_chunk.get_unchecked(j))); - } + ascii_prefix_len += N; + slice = unsafe { slice.get_unchecked(N..) }; + out_slice = unsafe { out_slice.get_unchecked_mut(N..) }; + } - // mark these bytes as initialised - i += N; + // handle the remainder as individual bytes + while slice.len() > 0 { + let byte = slice[0]; + if byte > 127 { + break; + } + // SAFETY: out_slice has at least same length as input slice + unsafe { + *out_slice.get_unchecked_mut(0) = MaybeUninit::new(convert(&byte)); } - out.set_len(i); + ascii_prefix_len += 1; + slice = unsafe { slice.get_unchecked(1..) }; + out_slice = unsafe { out_slice.get_unchecked_mut(1..) }; } - out + unsafe { + // SAFETY: ascii_prefix_len bytes have been initialized above + out.set_len(ascii_prefix_len); + + // SAFETY: We have written only valid ascii to the output vec + let ascii_string = String::from_utf8_unchecked(out); + + // SAFETY: we know this is a valid char boundary + // since we only skipped over leading ascii bytes + let rest = core::str::from_utf8_unchecked(slice); + + (ascii_string, rest) + } } diff --git a/library/alloc/tests/str.rs b/library/alloc/tests/str.rs index a80e5275dab..6f930ab0853 100644 --- a/library/alloc/tests/str.rs +++ b/library/alloc/tests/str.rs @@ -1854,7 +1854,10 @@ fn to_lowercase() { assert_eq!("ΑΣ''Α".to_lowercase(), "ασ''α"); // https://github.com/rust-lang/rust/issues/124714 + // input lengths around the boundary of the chunk size used by the ascii prefix optimization + assert_eq!("abcdefghijklmnoΣ".to_lowercase(), "abcdefghijklmnoς"); assert_eq!("abcdefghijklmnopΣ".to_lowercase(), "abcdefghijklmnopς"); + assert_eq!("abcdefghijklmnopqΣ".to_lowercase(), "abcdefghijklmnopqς"); // a really long string that has it's lowercase form // even longer. this tests that implementations don't assume diff --git a/library/core/src/alloc/global.rs b/library/core/src/alloc/global.rs index a6f799c4a7d..68f00d07529 100644 --- a/library/core/src/alloc/global.rs +++ b/library/core/src/alloc/global.rs @@ -124,8 +124,8 @@ pub unsafe trait GlobalAlloc { /// /// # Safety /// - /// This function is unsafe because undefined behavior can result - /// if the caller does not ensure that `layout` has non-zero size. + /// `layout` must have non-zero size. Attempting to allocate for a zero-sized `layout` may + /// result in undefined behavior. /// /// (Extension subtraits might provide more specific bounds on /// behavior, e.g., guarantee a sentinel address or a null pointer @@ -156,14 +156,14 @@ pub unsafe trait GlobalAlloc { /// /// # Safety /// - /// This function is unsafe because undefined behavior can result - /// if the caller does not ensure all of the following: + /// The caller must ensure: /// - /// * `ptr` must denote a block of memory currently allocated via - /// this allocator, + /// * `ptr` is a block of memory currently allocated via this allocator and, /// - /// * `layout` must be the same layout that was used - /// to allocate that block of memory. + /// * `layout` is the same layout that was used to allocate that block of + /// memory. + /// + /// Otherwise undefined behavior can result. #[stable(feature = "global_alloc", since = "1.28.0")] unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout); @@ -172,7 +172,8 @@ pub unsafe trait GlobalAlloc { /// /// # Safety /// - /// This function is unsafe for the same reasons that `alloc` is. + /// The caller has to ensure that `layout` has non-zero size. Like `alloc` + /// zero sized `layout` can result in undefined behaviour. /// However the allocated block of memory is guaranteed to be initialized. /// /// # Errors @@ -220,20 +221,21 @@ pub unsafe trait GlobalAlloc { /// /// # Safety /// - /// This function is unsafe because undefined behavior can result - /// if the caller does not ensure all of the following: + /// The caller must ensure that: /// - /// * `ptr` must be currently allocated via this allocator, + /// * `ptr` is allocated via this allocator, /// - /// * `layout` must be the same layout that was used + /// * `layout` is the same layout that was used /// to allocate that block of memory, /// - /// * `new_size` must be greater than zero. + /// * `new_size` is greater than zero. /// /// * `new_size`, when rounded up to the nearest multiple of `layout.align()`, - /// must not overflow `isize` (i.e., the rounded value must be less than or + /// does not overflow `isize` (i.e., the rounded value must be less than or /// equal to `isize::MAX`). /// + /// If these are not followed, undefined behaviour can result. + /// /// (Extension subtraits might provide more specific bounds on /// behavior, e.g., guarantee a sentinel address or a null pointer /// in response to a zero-size allocation request.) diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index c99f1aece4f..de212581e82 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -514,7 +514,8 @@ impl<T> Cell<T> { /// assert_eq!(five, 5); /// ``` #[stable(feature = "move_cell", since = "1.17.0")] - #[rustc_const_unstable(feature = "const_cell_into_inner", issue = "78729")] + #[rustc_const_stable(feature = "const_cell_into_inner", since = "CURRENT_RUSTC_VERSION")] + #[rustc_allow_const_fn_unstable(const_precise_live_drops)] pub const fn into_inner(self) -> T { self.value.into_inner() } @@ -857,7 +858,8 @@ impl<T> RefCell<T> { /// let five = c.into_inner(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_cell_into_inner", issue = "78729")] + #[rustc_const_stable(feature = "const_cell_into_inner", since = "CURRENT_RUSTC_VERSION")] + #[rustc_allow_const_fn_unstable(const_precise_live_drops)] #[inline] pub const fn into_inner(self) -> T { // Since this function takes `self` (the `RefCell`) by value, the @@ -2100,8 +2102,8 @@ impl<T> UnsafeCell<T> { /// ``` #[inline(always)] #[stable(feature = "rust1", since = "1.0.0")] - // When this is const stabilized, please remove `primitive_into_inner` below. - #[rustc_const_unstable(feature = "const_cell_into_inner", issue = "78729")] + #[rustc_const_stable(feature = "const_cell_into_inner", since = "CURRENT_RUSTC_VERSION")] + #[rustc_allow_const_fn_unstable(const_precise_live_drops)] pub const fn into_inner(self) -> T { self.value } @@ -2247,47 +2249,6 @@ impl<T: CoerceUnsized<U>, U> CoerceUnsized<UnsafeCell<U>> for UnsafeCell<T> {} #[unstable(feature = "dispatch_from_dyn", issue = "none")] impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<UnsafeCell<U>> for UnsafeCell<T> {} -// Special cases of UnsafeCell::into_inner where T is a primitive. These are -// used by Atomic*::into_inner. -// -// The real UnsafeCell::into_inner cannot be used yet in a stable const function. -// That is blocked on a "precise drop analysis" unstable const feature. -// https://github.com/rust-lang/rust/issues/73255 -macro_rules! unsafe_cell_primitive_into_inner { - ($($primitive:ident $atomic:literal)*) => { - $( - #[cfg(target_has_atomic_load_store = $atomic)] - impl UnsafeCell<$primitive> { - pub(crate) const fn primitive_into_inner(self) -> $primitive { - self.value - } - } - )* - }; -} - -unsafe_cell_primitive_into_inner! { - i8 "8" - u8 "8" - i16 "16" - u16 "16" - i32 "32" - u32 "32" - i64 "64" - u64 "64" - i128 "128" - u128 "128" - isize "ptr" - usize "ptr" -} - -#[cfg(target_has_atomic_load_store = "ptr")] -impl<T> UnsafeCell<*mut T> { - pub(crate) const fn primitive_into_inner(self) -> *mut T { - self.value - } -} - /// [`UnsafeCell`], but [`Sync`]. /// /// This is just an `UnsafeCell`, except it implements `Sync` diff --git a/library/core/src/cell/once.rs b/library/core/src/cell/once.rs index 87df8a4e272..14c587e0c48 100644 --- a/library/core/src/cell/once.rs +++ b/library/core/src/cell/once.rs @@ -309,7 +309,8 @@ impl<T> OnceCell<T> { /// ``` #[inline] #[stable(feature = "once_cell", since = "1.70.0")] - #[rustc_const_unstable(feature = "const_cell_into_inner", issue = "78729")] + #[rustc_const_stable(feature = "const_cell_into_inner", since = "CURRENT_RUSTC_VERSION")] + #[rustc_allow_const_fn_unstable(const_precise_live_drops)] pub const fn into_inner(self) -> Option<T> { // Because `into_inner` takes `self` by value, the compiler statically verifies // that it is not currently borrowed. So it is safe to move out `Option<T>`. diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 818a36002e7..4377b4993b8 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -275,49 +275,56 @@ pub macro PartialEq($item:item) { /// Trait for comparisons corresponding to [equivalence relations]( /// https://en.wikipedia.org/wiki/Equivalence_relation). /// -/// This means, that in addition to `a == b` and `a != b` being strict inverses, -/// the relation must be (for all `a`, `b` and `c`): +/// The primary difference to [`PartialEq`] is the additional requirement for reflexivity. A type +/// that implements [`PartialEq`] guarantees that for all `a`, `b` and `c`: /// -/// - reflexive: `a == a`; -/// - symmetric: `a == b` implies `b == a` (required by `PartialEq` as well); and -/// - transitive: `a == b` and `b == c` implies `a == c` (required by `PartialEq` as well). +/// - symmetric: `a == b` implies `b == a` and `a != b` implies `!(a == b)` +/// - transitive: `a == b` and `b == c` implies `a == c` /// -/// This property cannot be checked by the compiler, and therefore `Eq` implies -/// [`PartialEq`], and has no extra methods. +/// `Eq`, which builds on top of [`PartialEq`] also implies: +/// +/// - reflexive: `a == a` +/// +/// This property cannot be checked by the compiler, and therefore `Eq` is a trait without methods. /// /// Violating this property is a logic error. The behavior resulting from a logic error is not /// specified, but users of the trait must ensure that such logic errors do *not* result in /// undefined behavior. This means that `unsafe` code **must not** rely on the correctness of these /// methods. /// -/// Implement `Eq` in addition to `PartialEq` if it's guaranteed that -/// `PartialEq::eq(a, a)` always returns `true` (reflexivity), in addition to -/// the symmetric and transitive properties already required by `PartialEq`. +/// Floating point types such as [`f32`] and [`f64`] implement only [`PartialEq`] but *not* `Eq` +/// because `NaN` != `NaN`. /// /// ## Derivable /// -/// This trait can be used with `#[derive]`. When `derive`d, because `Eq` has -/// no extra methods, it is only informing the compiler that this is an -/// equivalence relation rather than a partial equivalence relation. Note that -/// the `derive` strategy requires all fields are `Eq`, which isn't +/// This trait can be used with `#[derive]`. When `derive`d, because `Eq` has no extra methods, it +/// is only informing the compiler that this is an equivalence relation rather than a partial +/// equivalence relation. Note that the `derive` strategy requires all fields are `Eq`, which isn't /// always desired. /// /// ## How can I implement `Eq`? /// -/// If you cannot use the `derive` strategy, specify that your type implements -/// `Eq`, which has no methods: +/// If you cannot use the `derive` strategy, specify that your type implements `Eq`, which has no +/// extra methods: /// /// ``` -/// enum BookFormat { Paperback, Hardback, Ebook } +/// enum BookFormat { +/// Paperback, +/// Hardback, +/// Ebook, +/// } +/// /// struct Book { /// isbn: i32, /// format: BookFormat, /// } +/// /// impl PartialEq for Book { /// fn eq(&self, other: &Self) -> bool { /// self.isbn == other.isbn /// } /// } +/// /// impl Eq for Book {} /// ``` #[doc(alias = "==")] @@ -325,11 +332,9 @@ pub macro PartialEq($item:item) { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "Eq"] pub trait Eq: PartialEq<Self> { - // this method is used solely by #[derive(Eq)] to assert - // that every component of a type implements `Eq` - // itself. The current deriving infrastructure means doing this - // assertion without using a method on this trait is nearly - // impossible. + // this method is used solely by `impl Eq or #[derive(Eq)]` to assert that every component of a + // type implements `Eq` itself. The current deriving infrastructure means doing this assertion + // without using a method on this trait is nearly impossible. // // This should never be implemented by hand. #[doc(hidden)] @@ -693,17 +698,14 @@ impl<T: Clone> Clone for Reverse<T> { /// Trait for types that form a [total order](https://en.wikipedia.org/wiki/Total_order). /// -/// Implementations must be consistent with the [`PartialOrd`] implementation, and ensure -/// `max`, `min`, and `clamp` are consistent with `cmp`: +/// Implementations must be consistent with the [`PartialOrd`] implementation, and ensure `max`, +/// `min`, and `clamp` are consistent with `cmp`: /// /// - `partial_cmp(a, b) == Some(cmp(a, b))`. /// - `max(a, b) == max_by(a, b, cmp)` (ensured by the default implementation). /// - `min(a, b) == min_by(a, b, cmp)` (ensured by the default implementation). -/// - For `a.clamp(min, max)`, see the [method docs](#method.clamp) -/// (ensured by the default implementation). -/// -/// It's easy to accidentally make `cmp` and `partial_cmp` disagree by -/// deriving some of the traits and manually implementing others. +/// - For `a.clamp(min, max)`, see the [method docs](#method.clamp) (ensured by the default +/// implementation). /// /// Violating these requirements is a logic error. The behavior resulting from a logic error is not /// specified, but users of the trait must ensure that such logic errors do *not* result in @@ -712,15 +714,14 @@ impl<T: Clone> Clone for Reverse<T> { /// /// ## Corollaries /// -/// From the above and the requirements of `PartialOrd`, it follows that for -/// all `a`, `b` and `c`: +/// From the above and the requirements of `PartialOrd`, it follows that for all `a`, `b` and `c`: /// /// - exactly one of `a < b`, `a == b` or `a > b` is true; and -/// - `<` is transitive: `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`. +/// - `<` is transitive: `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and +/// `>`. /// -/// Mathematically speaking, the `<` operator defines a strict [weak order]. In -/// cases where `==` conforms to mathematical equality, it also defines a -/// strict [total order]. +/// Mathematically speaking, the `<` operator defines a strict [weak order]. In cases where `==` +/// conforms to mathematical equality, it also defines a strict [total order]. /// /// [weak order]: https://en.wikipedia.org/wiki/Weak_ordering /// [total order]: https://en.wikipedia.org/wiki/Total_order @@ -730,13 +731,12 @@ impl<T: Clone> Clone for Reverse<T> { /// This trait can be used with `#[derive]`. /// /// When `derive`d on structs, it will produce a -/// [lexicographic](https://en.wikipedia.org/wiki/Lexicographic_order) ordering -/// based on the top-to-bottom declaration order of the struct's members. +/// [lexicographic](https://en.wikipedia.org/wiki/Lexicographic_order) ordering based on the +/// top-to-bottom declaration order of the struct's members. /// -/// When `derive`d on enums, variants are ordered primarily by their discriminants. -/// Secondarily, they are ordered by their fields. -/// By default, the discriminant is smallest for variants at the top, and -/// largest for variants at the bottom. Here's an example: +/// When `derive`d on enums, variants are ordered primarily by their discriminants. Secondarily, +/// they are ordered by their fields. By default, the discriminant is smallest for variants at the +/// top, and largest for variants at the bottom. Here's an example: /// /// ``` /// #[derive(PartialEq, Eq, PartialOrd, Ord)] @@ -748,8 +748,7 @@ impl<T: Clone> Clone for Reverse<T> { /// assert!(E::Top < E::Bottom); /// ``` /// -/// However, manually setting the discriminants can override this default -/// behavior: +/// However, manually setting the discriminants can override this default behavior: /// /// ``` /// #[derive(PartialEq, Eq, PartialOrd, Ord)] @@ -765,51 +764,178 @@ impl<T: Clone> Clone for Reverse<T> { /// /// Lexicographical comparison is an operation with the following properties: /// - Two sequences are compared element by element. -/// - The first mismatching element defines which sequence is lexicographically less or greater than the other. -/// - If one sequence is a prefix of another, the shorter sequence is lexicographically less than the other. -/// - If two sequences have equivalent elements and are of the same length, then the sequences are lexicographically equal. +/// - The first mismatching element defines which sequence is lexicographically less or greater +/// than the other. +/// - If one sequence is a prefix of another, the shorter sequence is lexicographically less than +/// the other. +/// - If two sequences have equivalent elements and are of the same length, then the sequences are +/// lexicographically equal. /// - An empty sequence is lexicographically less than any non-empty sequence. /// - Two empty sequences are lexicographically equal. /// /// ## How can I implement `Ord`? /// -/// `Ord` requires that the type also be [`PartialOrd`] and [`Eq`] (which requires [`PartialEq`]). +/// `Ord` requires that the type also be [`PartialOrd`], [`PartialEq`], and [`Eq`]. /// -/// Then you must define an implementation for [`cmp`]. You may find it useful to use -/// [`cmp`] on your type's fields. +/// Because `Ord` implies a stronger ordering relationship than [`PartialOrd`], and both `Ord` and +/// [`PartialOrd`] must agree, you must choose how to implement `Ord` **first**. You can choose to +/// derive it, or implement it manually. If you derive it, you should derive all four traits. If you +/// implement it manually, you should manually implement all four traits, based on the +/// implementation of `Ord`. /// -/// Here's an example where you want to sort people by height only, disregarding `id` -/// and `name`: +/// Here's an example where you want to define the `Character` comparison by `health` and +/// `experience` only, disregarding the field `mana`: /// /// ``` /// use std::cmp::Ordering; /// -/// #[derive(Eq)] -/// struct Person { -/// id: u32, -/// name: String, -/// height: u32, +/// struct Character { +/// health: u32, +/// experience: u32, +/// mana: f32, /// } /// -/// impl Ord for Person { -/// fn cmp(&self, other: &Self) -> Ordering { -/// self.height.cmp(&other.height) +/// impl Ord for Character { +/// fn cmp(&self, other: &Self) -> std::cmp::Ordering { +/// self.experience +/// .cmp(&other.experience) +/// .then(self.health.cmp(&other.health)) /// } /// } /// -/// impl PartialOrd for Person { +/// impl PartialOrd for Character { /// fn partial_cmp(&self, other: &Self) -> Option<Ordering> { /// Some(self.cmp(other)) /// } /// } /// -/// impl PartialEq for Person { +/// impl PartialEq for Character { /// fn eq(&self, other: &Self) -> bool { -/// self.height == other.height +/// self.health == other.health && self.experience == other.experience +/// } +/// } +/// +/// impl Eq for Character {} +/// ``` +/// +/// If all you need is to `slice::sort` a type by a field value, it can be simpler to use +/// `slice::sort_by_key`. +/// +/// ## Examples of incorrect `Ord` implementations +/// +/// ``` +/// use std::cmp::Ordering; +/// +/// #[derive(Debug)] +/// struct Character { +/// health: f32, +/// } +/// +/// impl Ord for Character { +/// fn cmp(&self, other: &Self) -> std::cmp::Ordering { +/// if self.health < other.health { +/// Ordering::Less +/// } else if self.health > other.health { +/// Ordering::Greater +/// } else { +/// Ordering::Equal +/// } +/// } +/// } +/// +/// impl PartialOrd for Character { +/// fn partial_cmp(&self, other: &Self) -> Option<Ordering> { +/// Some(self.cmp(other)) +/// } +/// } +/// +/// impl PartialEq for Character { +/// fn eq(&self, other: &Self) -> bool { +/// self.health == other.health +/// } +/// } +/// +/// impl Eq for Character {} +/// +/// let a = Character { health: 4.5 }; +/// let b = Character { health: f32::NAN }; +/// +/// // Mistake: floating-point values do not form a total order and using the built-in comparison +/// // operands to implement `Ord` irregardless of that reality does not change it. Use +/// // `f32::total_cmp` if you need a total order for floating-point values. +/// +/// // Reflexivity requirement of `Ord` is not given. +/// assert!(a == a); +/// assert!(b != b); +/// +/// // Antisymmetry requirement of `Ord` is not given. Only one of a < c and c < a is allowed to be +/// // true, not both or neither. +/// assert_eq!((a < b) as u8 + (b < a) as u8, 0); +/// ``` +/// +/// ``` +/// use std::cmp::Ordering; +/// +/// #[derive(Debug)] +/// struct Character { +/// health: u32, +/// experience: u32, +/// } +/// +/// impl PartialOrd for Character { +/// fn partial_cmp(&self, other: &Self) -> Option<Ordering> { +/// Some(self.cmp(other)) +/// } +/// } +/// +/// impl Ord for Character { +/// fn cmp(&self, other: &Self) -> std::cmp::Ordering { +/// if self.health < 50 { +/// self.health.cmp(&other.health) +/// } else { +/// self.experience.cmp(&other.experience) +/// } +/// } +/// } +/// +/// // For performance reasons implementing `PartialEq` this way is not the idiomatic way, but it +/// // ensures consistent behavior between `PartialEq`, `PartialOrd` and `Ord` in this example. +/// impl PartialEq for Character { +/// fn eq(&self, other: &Self) -> bool { +/// self.cmp(other) == Ordering::Equal /// } /// } +/// +/// impl Eq for Character {} +/// +/// let a = Character { +/// health: 3, +/// experience: 5, +/// }; +/// let b = Character { +/// health: 10, +/// experience: 77, +/// }; +/// let c = Character { +/// health: 143, +/// experience: 2, +/// }; +/// +/// // Mistake: The implementation of `Ord` compares different fields depending on the value of +/// // `self.health`, the resulting order is not total. +/// +/// // Transitivity requirement of `Ord` is not given. If a is smaller than b and b is smaller than +/// // c, by transitive property a must also be smaller than c. +/// assert!(a < b && b < c && c < a); +/// +/// // Antisymmetry requirement of `Ord` is not given. Only one of a < c and c < a is allowed to be +/// // true, not both or neither. +/// assert_eq!((a < c) as u8 + (c < a) as u8, 2); /// ``` /// +/// The documentation of [`PartialOrd`] contains further examples, for example it's wrong for +/// [`PartialOrd`] and [`PartialEq`] to disagree. +/// /// [`cmp`]: Ord::cmp #[doc(alias = "<")] #[doc(alias = ">")] @@ -924,8 +1050,12 @@ pub macro Ord($item:item) { /// Trait for types that form a [partial order](https://en.wikipedia.org/wiki/Partial_order). /// -/// The `lt`, `le`, `gt`, and `ge` methods of this trait can be called using -/// the `<`, `<=`, `>`, and `>=` operators, respectively. +/// The `lt`, `le`, `gt`, and `ge` methods of this trait can be called using the `<`, `<=`, `>`, and +/// `>=` operators, respectively. +/// +/// This trait should **only** contain the comparison logic for a type **if one plans on only +/// implementing `PartialOrd` but not [`Ord`]**. Otherwise the comparison logic should be in [`Ord`] +/// and this trait implemented with `Some(self.cmp(other))`. /// /// The methods of this trait must be consistent with each other and with those of [`PartialEq`]. /// The following conditions must hold: @@ -937,26 +1067,25 @@ pub macro Ord($item:item) { /// 5. `a >= b` if and only if `a > b || a == b` /// 6. `a != b` if and only if `!(a == b)`. /// -/// Conditions 2–5 above are ensured by the default implementation. -/// Condition 6 is already ensured by [`PartialEq`]. +/// Conditions 2–5 above are ensured by the default implementation. Condition 6 is already ensured +/// by [`PartialEq`]. /// /// If [`Ord`] is also implemented for `Self` and `Rhs`, it must also be consistent with -/// `partial_cmp` (see the documentation of that trait for the exact requirements). It's -/// easy to accidentally make them disagree by deriving some of the traits and manually -/// implementing others. +/// `partial_cmp` (see the documentation of that trait for the exact requirements). It's easy to +/// accidentally make them disagree by deriving some of the traits and manually implementing others. /// -/// The comparison relations must satisfy the following conditions -/// (for all `a`, `b`, `c` of type `A`, `B`, `C`): +/// The comparison relations must satisfy the following conditions (for all `a`, `b`, `c` of type +/// `A`, `B`, `C`): /// -/// - **Transitivity**: if `A: PartialOrd<B>` and `B: PartialOrd<C>` and `A: -/// PartialOrd<C>`, then `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`. -/// This must also work for longer chains, such as when `A: PartialOrd<B>`, `B: PartialOrd<C>`, -/// `C: PartialOrd<D>`, and `A: PartialOrd<D>` all exist. -/// - **Duality**: if `A: PartialOrd<B>` and `B: PartialOrd<A>`, then `a < b` if and only if `b > a`. +/// - **Transitivity**: if `A: PartialOrd<B>` and `B: PartialOrd<C>` and `A: PartialOrd<C>`, then `a +/// < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`. This must also +/// work for longer chains, such as when `A: PartialOrd<B>`, `B: PartialOrd<C>`, `C: +/// PartialOrd<D>`, and `A: PartialOrd<D>` all exist. +/// - **Duality**: if `A: PartialOrd<B>` and `B: PartialOrd<A>`, then `a < b` if and only if `b > +/// a`. /// -/// Note that the `B: PartialOrd<A>` (dual) and `A: PartialOrd<C>` -/// (transitive) impls are not forced to exist, but these requirements apply -/// whenever they do exist. +/// Note that the `B: PartialOrd<A>` (dual) and `A: PartialOrd<C>` (transitive) impls are not forced +/// to exist, but these requirements apply whenever they do exist. /// /// Violating these requirements is a logic error. The behavior resulting from a logic error is not /// specified, but users of the trait must ensure that such logic errors do *not* result in @@ -992,12 +1121,10 @@ pub macro Ord($item:item) { /// /// ## Strict and non-strict partial orders /// -/// The `<` and `>` operators behave according to a *strict* partial order. -/// However, `<=` and `>=` do **not** behave according to a *non-strict* -/// partial order. -/// That is because mathematically, a non-strict partial order would require -/// reflexivity, i.e. `a <= a` would need to be true for every `a`. This isn't -/// always the case for types that implement `PartialOrd`, for example: +/// The `<` and `>` operators behave according to a *strict* partial order. However, `<=` and `>=` +/// do **not** behave according to a *non-strict* partial order. That is because mathematically, a +/// non-strict partial order would require reflexivity, i.e. `a <= a` would need to be true for +/// every `a`. This isn't always the case for types that implement `PartialOrd`, for example: /// /// ``` /// let a = f64::sqrt(-1.0); @@ -1009,13 +1136,12 @@ pub macro Ord($item:item) { /// This trait can be used with `#[derive]`. /// /// When `derive`d on structs, it will produce a -/// [lexicographic](https://en.wikipedia.org/wiki/Lexicographic_order) ordering -/// based on the top-to-bottom declaration order of the struct's members. +/// [lexicographic](https://en.wikipedia.org/wiki/Lexicographic_order) ordering based on the +/// top-to-bottom declaration order of the struct's members. /// -/// When `derive`d on enums, variants are primarily ordered by their discriminants. -/// Secondarily, they are ordered by their fields. -/// By default, the discriminant is smallest for variants at the top, and -/// largest for variants at the bottom. Here's an example: +/// When `derive`d on enums, variants are primarily ordered by their discriminants. Secondarily, +/// they are ordered by their fields. By default, the discriminant is smallest for variants at the +/// top, and largest for variants at the bottom. Here's an example: /// /// ``` /// #[derive(PartialEq, PartialOrd)] @@ -1027,8 +1153,7 @@ pub macro Ord($item:item) { /// assert!(E::Top < E::Bottom); /// ``` /// -/// However, manually setting the discriminants can override this default -/// behavior: +/// However, manually setting the discriminants can override this default behavior: /// /// ``` /// #[derive(PartialEq, PartialOrd)] @@ -1046,8 +1171,8 @@ pub macro Ord($item:item) { /// generated from default implementations. /// /// However it remains possible to implement the others separately for types which do not have a -/// total order. For example, for floating point numbers, `NaN < 0 == false` and `NaN >= 0 == -/// false` (cf. IEEE 754-2008 section 5.11). +/// total order. For example, for floating point numbers, `NaN < 0 == false` and `NaN >= 0 == false` +/// (cf. IEEE 754-2008 section 5.11). /// /// `PartialOrd` requires your type to be [`PartialEq`]. /// @@ -1056,7 +1181,6 @@ pub macro Ord($item:item) { /// ``` /// use std::cmp::Ordering; /// -/// #[derive(Eq)] /// struct Person { /// id: u32, /// name: String, @@ -1080,11 +1204,13 @@ pub macro Ord($item:item) { /// self.height == other.height /// } /// } +/// +/// impl Eq for Person {} /// ``` /// -/// You may also find it useful to use [`partial_cmp`] on your type's fields. Here -/// is an example of `Person` types who have a floating-point `height` field that -/// is the only field to be used for sorting: +/// You may also find it useful to use [`partial_cmp`] on your type's fields. Here is an example of +/// `Person` types who have a floating-point `height` field that is the only field to be used for +/// sorting: /// /// ``` /// use std::cmp::Ordering; @@ -1108,6 +1234,38 @@ pub macro Ord($item:item) { /// } /// ``` /// +/// ## Examples of incorrect `PartialOrd` implementations +/// +/// ``` +/// use std::cmp::Ordering; +/// +/// #[derive(PartialEq, Debug)] +/// struct Character { +/// health: u32, +/// experience: u32, +/// } +/// +/// impl PartialOrd for Character { +/// fn partial_cmp(&self, other: &Self) -> Option<Ordering> { +/// Some(self.health.cmp(&other.health)) +/// } +/// } +/// +/// let a = Character { +/// health: 10, +/// experience: 5, +/// }; +/// let b = Character { +/// health: 10, +/// experience: 77, +/// }; +/// +/// // Mistake: `PartialEq` and `PartialOrd` disagree with each other. +/// +/// assert_eq!(a.partial_cmp(&b).unwrap(), Ordering::Equal); // a == b according to `PartialOrd`. +/// assert_ne!(a, b); // a != b according to `PartialEq`. +/// ``` +/// /// # Examples /// /// ``` diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 881a89f4d10..dec67f9fe51 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -2659,12 +2659,17 @@ extern "rust-intrinsic" { /// /// `catch_fn` must not unwind. /// - /// The third argument is a function called if an unwind occurs (both Rust unwinds and foreign - /// unwinds). This function takes the data pointer and a pointer to the target-specific - /// exception object that was caught. For more information, see the compiler's source as well as - /// std's `catch_unwind` implementation. + /// The third argument is a function called if an unwind occurs (both Rust `panic` and foreign + /// unwinds). This function takes the data pointer and a pointer to the target- and + /// runtime-specific exception object that was caught. /// - /// The stable version of this intrinsic is `std::panic::catch_unwind`. + /// Note that in the case of a foreign unwinding operation, the exception object data may not be + /// safely usable from Rust, and should not be directly exposed via the standard library. To + /// prevent unsafe access, the library implementation may either abort the process or present an + /// opaque error type to the user. + /// + /// For more information, see the compiler's source, as well as the documentation for the stable + /// version of this intrinsic, `std::panic::catch_unwind`. #[rustc_nounwind] pub fn catch_unwind(try_fn: fn(*mut u8), data: *mut u8, catch_fn: fn(*mut u8, *mut u8)) -> i32; diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 01cadd78cc0..817d9e3b962 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -118,7 +118,6 @@ #![feature(const_array_into_iter_constructors)] #![feature(const_bigint_helper_methods)] #![feature(const_black_box)] -#![feature(const_cell_into_inner)] #![feature(const_char_encode_utf16)] #![feature(const_char_encode_utf8)] #![feature(const_eval_select)] diff --git a/library/core/src/panic/location.rs b/library/core/src/panic/location.rs index e2a842046a9..1ad5c07d15c 100644 --- a/library/core/src/panic/location.rs +++ b/library/core/src/panic/location.rs @@ -44,7 +44,7 @@ impl<'a> Location<'a> { /// /// # Examples /// - /// ```standalone + /// ```standalone_crate /// use std::panic::Location; /// /// /// Returns the [`Location`] at which it is called. diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index be85f507129..42b68e28273 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -596,7 +596,7 @@ impl AtomicBool { #[stable(feature = "atomic_access", since = "1.15.0")] #[rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0")] pub const fn into_inner(self) -> bool { - self.v.primitive_into_inner() != 0 + self.v.into_inner() != 0 } /// Loads a value from the bool. @@ -1413,7 +1413,7 @@ impl<T> AtomicPtr<T> { #[stable(feature = "atomic_access", since = "1.15.0")] #[rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0")] pub const fn into_inner(self) -> *mut T { - self.p.primitive_into_inner() + self.p.into_inner() } /// Loads a value from the pointer. @@ -2408,7 +2408,7 @@ macro_rules! atomic_int { #[$stable_access] #[rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0")] pub const fn into_inner(self) -> $int_type { - self.v.primitive_into_inner() + self.v.into_inner() } /// Loads a value from the atomic integer. diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 604c0d48743..4f2190f78bf 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -18,7 +18,6 @@ #![feature(const_align_offset)] #![feature(const_array_from_ref)] #![feature(const_black_box)] -#![feature(const_cell_into_inner)] #![feature(const_hash)] #![feature(const_heap)] #![feature(const_ip)] diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index d55114227af..7d860b49e87 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -17,7 +17,7 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] } panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core", public = true } -compiler_builtins = { version = "0.1.126" } +compiler_builtins = { version = "0.1.130" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } hashbrown = { version = "0.14", default-features = false, features = [ diff --git a/library/std/build.rs b/library/std/build.rs index 359ae4f20ee..c5d0af469a8 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -96,9 +96,6 @@ fn main() { let has_reliable_f16 = match (target_arch.as_str(), target_os.as_str()) { // We can always enable these in Miri as that is not affected by codegen bugs. _ if is_miri => true, - // Selection failure until recent LLVM <https://github.com/llvm/llvm-project/issues/93894> - // FIXME(llvm19): can probably be removed at the version bump - ("loongarch64", _) => false, // Selection failure <https://github.com/llvm/llvm-project/issues/50374> ("s390x", _) => false, // Unsupported <https://github.com/llvm/llvm-project/issues/94434> @@ -108,18 +105,18 @@ fn main() { // Apple has a special ABI for `f16` that we do not yet support // FIXME(builtins): fixed by <https://github.com/rust-lang/compiler-builtins/pull/675> ("x86" | "x86_64", _) if target_vendor == "apple" => false, - // Missing `__gnu_h2f_ieee` and `__gnu_f2h_ieee` + // Infinite recursion <https://github.com/llvm/llvm-project/issues/97981> + ("csky", _) => false, + ("hexagon", _) => false, + ("loongarch64", _) => false, + ("mips" | "mips64" | "mips32r6" | "mips64r6", _) => false, ("powerpc" | "powerpc64", _) => false, - // Missing `__gnu_h2f_ieee` and `__gnu_f2h_ieee` - ("mips" | "mips32r6" | "mips64" | "mips64r6", _) => false, - // Missing `__extendhfsf` and `__truncsfhf` - ("riscv32" | "riscv64", _) => false, - // Most OSs are missing `__extendhfsf` and `__truncsfhf` - (_, "linux" | "macos") => true, - // Almost all OSs besides Linux and MacOS are missing symbols until compiler-builtins can - // be updated. <https://github.com/rust-lang/rust/pull/125016> will get some of these, the - // next CB update should get the rest. - _ => false, + ("sparc" | "sparc64", _) => false, + ("wasm32" | "wasm64", _) => false, + // `f16` support only requires that symbols converting to and from `f32` are available. We + // provide these in `compiler-builtins`, so `f16` should be available on all platforms that + // do not have other ABI issues or LLVM crashes. + _ => true, }; let has_reliable_f128 = match (target_arch.as_str(), target_os.as_str()) { diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs index 06ed4f6a03d..f81a13d4c44 100644 --- a/library/std/src/net/tcp.rs +++ b/library/std/src/net/tcp.rs @@ -561,7 +561,7 @@ impl TcpStream { /// Moves this TCP stream into or out of nonblocking mode. /// - /// This will result in `read`, `write`, `recv` and `send` operations + /// This will result in `read`, `write`, `recv` and `send` system operations /// becoming nonblocking, i.e., immediately returning from their calls. /// If the IO operation is successful, `Ok` is returned and no further /// action is required. If the IO operation could not be completed and needs diff --git a/library/std/src/net/udp.rs b/library/std/src/net/udp.rs index 8c9e31f9c15..b78e52023b3 100644 --- a/library/std/src/net/udp.rs +++ b/library/std/src/net/udp.rs @@ -764,7 +764,7 @@ impl UdpSocket { /// Moves this UDP socket into or out of nonblocking mode. /// - /// This will result in `recv`, `recv_from`, `send`, and `send_to` + /// This will result in `recv`, `recv_from`, `send`, and `send_to` system /// operations becoming nonblocking, i.e., immediately returning from their /// calls. If the IO operation is successful, `Ok` is returned and no /// further action is required. If the IO operation could not be completed diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs index 015cab89485..d649357a56d 100644 --- a/library/std/src/panic.rs +++ b/library/std/src/panic.rs @@ -288,45 +288,55 @@ pub use core::panic::abort_unwind; /// Invokes a closure, capturing the cause of an unwinding panic if one occurs. /// -/// This function will return `Ok` with the closure's result if the closure -/// does not panic, and will return `Err(cause)` if the closure panics. The -/// `cause` returned is the object with which panic was originally invoked. +/// This function will return `Ok` with the closure's result if the closure does +/// not panic, and will return `Err(cause)` if the closure panics. The `cause` +/// returned is the object with which panic was originally invoked. /// -/// It is currently undefined behavior to unwind from Rust code into foreign -/// code, so this function is particularly useful when Rust is called from -/// another language (normally C). This can run arbitrary Rust code, capturing a -/// panic and allowing a graceful handling of the error. +/// Rust functions that are expected to be called from foreign code that does +/// not support unwinding (such as C compiled with `-fno-exceptions`) should be +/// defined using `extern "C"`, which ensures that if the Rust code panics, it +/// is automatically caught and the process is aborted. If this is the desired +/// behavior, it is not necessary to use `catch_unwind` explicitly. This +/// function should instead be used when more graceful error-handling is needed. /// /// It is **not** recommended to use this function for a general try/catch /// mechanism. The [`Result`] type is more appropriate to use for functions that /// can fail on a regular basis. Additionally, this function is not guaranteed /// to catch all panics, see the "Notes" section below. /// -/// The closure provided is required to adhere to the [`UnwindSafe`] trait to ensure -/// that all captured variables are safe to cross this boundary. The purpose of -/// this bound is to encode the concept of [exception safety][rfc] in the type -/// system. Most usage of this function should not need to worry about this -/// bound as programs are naturally unwind safe without `unsafe` code. If it -/// becomes a problem the [`AssertUnwindSafe`] wrapper struct can be used to quickly -/// assert that the usage here is indeed unwind safe. +/// The closure provided is required to adhere to the [`UnwindSafe`] trait to +/// ensure that all captured variables are safe to cross this boundary. The +/// purpose of this bound is to encode the concept of [exception safety][rfc] in +/// the type system. Most usage of this function should not need to worry about +/// this bound as programs are naturally unwind safe without `unsafe` code. If +/// it becomes a problem the [`AssertUnwindSafe`] wrapper struct can be used to +/// quickly assert that the usage here is indeed unwind safe. /// /// [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1236-stabilize-catch-panic.md /// /// # Notes /// -/// Note that this function **might not catch all panics** in Rust. A panic in -/// Rust is not always implemented via unwinding, but can be implemented by -/// aborting the process as well. This function *only* catches unwinding panics, -/// not those that abort the process. +/// This function **might not catch all Rust panics**. A Rust panic is not +/// always implemented via unwinding, but can be implemented by aborting the +/// process as well. This function *only* catches unwinding panics, not those +/// that abort the process. /// -/// Note that if a custom panic hook has been set, it will be invoked before -/// the panic is caught, before unwinding. +/// If a custom panic hook has been set, it will be invoked before the panic is +/// caught, before unwinding. /// -/// Also note that unwinding into Rust code with a foreign exception (e.g. -/// an exception thrown from C++ code) is undefined behavior. +/// Although unwinding into Rust code with a foreign exception (e.g. an +/// exception thrown from C++ code, or a `panic!` in Rust code compiled or +/// linked with a different runtime) via an appropriate ABI (e.g. `"C-unwind"`) +/// is permitted, catching such an exception using this function will have one +/// of two behaviors, and it is unspecified which will occur: /// -/// Finally, be **careful in how you drop the result of this function**. -/// If it is `Err`, it contains the panic payload, and dropping that may in turn panic! +/// * The process aborts, after executing all destructors of `f` and the +/// functions it called. +/// * The function returns a `Result::Err` containing an opaque type. +/// +/// Finally, be **careful in how you drop the result of this function**. If it +/// is `Err`, it contains the panic payload, and dropping that may in turn +/// panic! /// /// # Examples /// diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 41f02af9366..686f5055ac1 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -664,6 +664,19 @@ impl Builder { /// println!("{result}"); /// ``` /// +/// # Notes +/// +/// This function has the same minimal guarantee regarding "foreign" unwinding operations (e.g. +/// an exception thrown from C++ code, or a `panic!` in Rust code compiled or linked with a +/// different runtime) as [`catch_unwind`]; namely, if the thread created with `thread::spawn` +/// unwinds all the way to the root with such an exception, one of two behaviors are possible, +/// and it is unspecified which will occur: +/// +/// * The process aborts. +/// * The process does not abort, and [`join`] will return a `Result::Err` +/// containing an opaque type. +/// +/// [`catch_unwind`]: ../../std/panic/fn.catch_unwind.html /// [`channels`]: crate::sync::mpsc /// [`join`]: JoinHandle::join /// [`Err`]: crate::result::Result::Err @@ -1784,7 +1797,7 @@ impl<T> JoinHandle<T> { /// operations that happen after `join` returns. /// /// If the associated thread panics, [`Err`] is returned with the parameter given - /// to [`panic!`]. + /// to [`panic!`] (though see the Notes below). /// /// [`Err`]: crate::result::Result::Err /// [atomic memory orderings]: crate::sync::atomic @@ -1806,6 +1819,18 @@ impl<T> JoinHandle<T> { /// }).unwrap(); /// join_handle.join().expect("Couldn't join on the associated thread"); /// ``` + /// + /// # Notes + /// + /// If a "foreign" unwinding operation (e.g. an exception thrown from C++ + /// code, or a `panic!` in Rust code compiled or linked with a different + /// runtime) unwinds all the way to the thread root, the process may be + /// aborted; see the Notes on [`thread::spawn`]. If the process is not + /// aborted, this function will return a `Result::Err` containing an opaque + /// type. + /// + /// [`catch_unwind`]: ../../std/panic/fn.catch_unwind.html + /// [`thread::spawn`]: spawn #[stable(feature = "rust1", since = "1.0.0")] pub fn join(self) -> Result<T> { self.0.join() diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index bae7642cffd..e4011221286 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -242,7 +242,7 @@ pub(crate) fn is_ci_llvm_available(config: &Config, asserts: bool) -> bool { /// Returns true if we're running in CI with modified LLVM (and thus can't download it) pub(crate) fn is_ci_llvm_modified(config: &Config) -> bool { - CiEnv::is_ci() && config.rust_info.is_managed_git_subrepository() && { + CiEnv::is_rust_lang_managed_ci_job() && config.rust_info.is_managed_git_subrepository() && { // We assume we have access to git, so it's okay to unconditionally pass // `true` here. let llvm_sha = detect_llvm_sha(config, true); diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 77e0ece3104..3c0afb858f8 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -343,6 +343,15 @@ pub struct Config { pub out: PathBuf, pub rust_info: channel::GitInfo, + pub cargo_info: channel::GitInfo, + pub rust_analyzer_info: channel::GitInfo, + pub clippy_info: channel::GitInfo, + pub miri_info: channel::GitInfo, + pub rustfmt_info: channel::GitInfo, + pub enzyme_info: channel::GitInfo, + pub in_tree_llvm_info: channel::GitInfo, + pub in_tree_gcc_info: channel::GitInfo, + // These are either the stage0 downloaded binaries or the locally installed ones. pub initial_cargo: PathBuf, pub initial_rustc: PathBuf, @@ -1796,6 +1805,19 @@ impl Config { config.omit_git_hash = omit_git_hash.unwrap_or(default); config.rust_info = GitInfo::new(config.omit_git_hash, &config.src); + config.cargo_info = GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/cargo")); + config.rust_analyzer_info = + GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/rust-analyzer")); + config.clippy_info = + GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/clippy")); + config.miri_info = GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/miri")); + config.rustfmt_info = + GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/rustfmt")); + config.enzyme_info = + GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/enzyme")); + config.in_tree_llvm_info = GitInfo::new(false, &config.src.join("src/llvm-project")); + config.in_tree_gcc_info = GitInfo::new(false, &config.src.join("src/gcc")); + // We need to override `rust.channel` if it's manually specified when using the CI rustc. // This is because if the compiler uses a different channel than the one specified in config.toml, // tests may fail due to using a different channel than the one used by the compiler during tests. diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 7bf5b4e23d2..4805e598ce2 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -305,18 +305,15 @@ impl Build { #[cfg(not(unix))] let is_sudo = false; - let omit_git_hash = config.omit_git_hash; - let rust_info = GitInfo::new(omit_git_hash, &src); - let cargo_info = GitInfo::new(omit_git_hash, &src.join("src/tools/cargo")); - let rust_analyzer_info = GitInfo::new(omit_git_hash, &src.join("src/tools/rust-analyzer")); - let clippy_info = GitInfo::new(omit_git_hash, &src.join("src/tools/clippy")); - let miri_info = GitInfo::new(omit_git_hash, &src.join("src/tools/miri")); - let rustfmt_info = GitInfo::new(omit_git_hash, &src.join("src/tools/rustfmt")); - let enzyme_info = GitInfo::new(omit_git_hash, &src.join("src/tools/enzyme")); - - // we always try to use git for LLVM builds - let in_tree_llvm_info = GitInfo::new(false, &src.join("src/llvm-project")); - let in_tree_gcc_info = GitInfo::new(false, &src.join("src/gcc")); + let rust_info = config.rust_info.clone(); + let cargo_info = config.cargo_info.clone(); + let rust_analyzer_info = config.rust_analyzer_info.clone(); + let clippy_info = config.clippy_info.clone(); + let miri_info = config.miri_info.clone(); + let rustfmt_info = config.rustfmt_info.clone(); + let enzyme_info = config.enzyme_info.clone(); + let in_tree_llvm_info = config.in_tree_llvm_info.clone(); + let in_tree_gcc_info = config.in_tree_gcc_info.clone(); let initial_target_libdir_str = if config.dry_run() { "/dummy/lib/path/to/lib/".to_string() diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version index 47d04a52883..6b2d58c8ef3 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version @@ -1 +1 @@ -0.18.0
\ No newline at end of file +0.18.1
\ No newline at end of file diff --git a/src/doc/rustdoc/src/write-documentation/documentation-tests.md b/src/doc/rustdoc/src/write-documentation/documentation-tests.md index 7ed2e9720fe..c93893b5ada 100644 --- a/src/doc/rustdoc/src/write-documentation/documentation-tests.md +++ b/src/doc/rustdoc/src/write-documentation/documentation-tests.md @@ -414,11 +414,11 @@ In some cases, doctests cannot be merged. For example, if you have: The problem with this code is that, if you change any other doctests, it'll likely break when runing `rustdoc --test`, making it tricky to maintain. -This is where the `standalone` attribute comes in: it tells `rustdoc` that a doctest +This is where the `standalone_crate` attribute comes in: it tells `rustdoc` that a doctest should not be merged with the others. So the previous code should use it: ```rust -//! ```standalone +//! ```standalone_crate //! let location = std::panic::Location::caller(); //! assert_eq!(location.line(), 4); //! ``` diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 3ee6b24ac92..bdd6fbe8c0c 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -837,7 +837,7 @@ impl CreateRunnableDocTests { let is_standalone = !doctest.can_be_merged || scraped_test.langstr.compile_fail || scraped_test.langstr.test_harness - || scraped_test.langstr.standalone + || scraped_test.langstr.standalone_crate || self.rustdoc_options.nocapture || self.rustdoc_options.test_args.iter().any(|arg| arg == "--show-output"); if is_standalone { diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs index d560e3a476b..efbb332d12d 100644 --- a/src/librustdoc/doctest/make.rs +++ b/src/librustdoc/doctest/make.rs @@ -48,7 +48,7 @@ impl DocTestBuilder { ) -> Self { let can_merge_doctests = can_merge_doctests && lang_str.is_some_and(|lang_str| { - !lang_str.compile_fail && !lang_str.test_harness && !lang_str.standalone + !lang_str.compile_fail && !lang_str.test_harness && !lang_str.standalone_crate }); let SourceInfo { crate_attrs, maybe_crate_attrs, crates, everything_else } = diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index b18d621478c..8ae5484feda 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -871,7 +871,7 @@ pub(crate) struct LangString { pub(crate) rust: bool, pub(crate) test_harness: bool, pub(crate) compile_fail: bool, - pub(crate) standalone: bool, + pub(crate) standalone_crate: bool, pub(crate) error_codes: Vec<String>, pub(crate) edition: Option<Edition>, pub(crate) added_classes: Vec<String>, @@ -1194,7 +1194,7 @@ impl Default for LangString { rust: true, test_harness: false, compile_fail: false, - standalone: false, + standalone_crate: false, error_codes: Vec::new(), edition: None, added_classes: Vec::new(), @@ -1264,8 +1264,8 @@ impl LangString { seen_rust_tags = !seen_other_tags || seen_rust_tags; data.no_run = true; } - LangStringToken::LangToken("standalone") => { - data.standalone = true; + LangStringToken::LangToken("standalone_crate") => { + data.standalone_crate = true; seen_rust_tags = !seen_other_tags || seen_rust_tags; } LangStringToken::LangToken(x) if x.starts_with("edition") => { @@ -1298,44 +1298,47 @@ impl LangString { } LangStringToken::LangToken(x) if extra.is_some() => { let s = x.to_lowercase(); - if let Some((flag, help)) = if s == "compile-fail" - || s == "compile_fail" - || s == "compilefail" - { - Some(( - "compile_fail", - "the code block will either not be tested if not marked as a rust one \ - or won't fail if it compiles successfully", - )) - } else if s == "should-panic" || s == "should_panic" || s == "shouldpanic" { - Some(( - "should_panic", - "the code block will either not be tested if not marked as a rust one \ - or won't fail if it doesn't panic when running", - )) - } else if s == "no-run" || s == "no_run" || s == "norun" { - Some(( - "no_run", - "the code block will either not be tested if not marked as a rust one \ - or will be run (which you might not want)", - )) - } else if s == "test-harness" || s == "test_harness" || s == "testharness" { - Some(( - "test_harness", - "the code block will either not be tested if not marked as a rust one \ - or the code will be wrapped inside a main function", - )) - } else { - None + if let Some(help) = match s.as_str() { + "compile-fail" | "compile_fail" | "compilefail" => Some( + "use `compile_fail` to invert the results of this test, so that it \ + passes if it cannot be compiled and fails if it can", + ), + "should-panic" | "should_panic" | "shouldpanic" => Some( + "use `should_panic` to invert the results of this test, so that if \ + passes if it panics and fails if it does not", + ), + "no-run" | "no_run" | "norun" => Some( + "use `no_run` to compile, but not run, the code sample during \ + testing", + ), + "test-harness" | "test_harness" | "testharness" => Some( + "use `test_harness` to run functions marked `#[test]` instead of a \ + potentially-implicit `main` function", + ), + "standalone" | "standalone_crate" | "standalone-crate" => { + if let Some(extra) = extra + && extra.sp.at_least_rust_2024() + { + Some( + "use `standalone_crate` to compile this code block \ + separately", + ) + } else { + None + } + } + _ => None, } { if let Some(extra) = extra { extra.error_invalid_codeblock_attr_with_help( format!("unknown attribute `{x}`"), |lint| { - lint.help(format!( - "there is an attribute with a similar name: `{flag}`" - )) - .help(help); + lint.help(help).help( + "this code block may be skipped during testing, \ + because unknown attributes are treated as markers for \ + code samples written in other programming languages, \ + unless it is also explicitly marked as `rust`", + ); }, ); } diff --git a/src/librustdoc/visit.rs b/src/librustdoc/visit.rs index fbc18176ed8..bfa285c57fa 100644 --- a/src/librustdoc/visit.rs +++ b/src/librustdoc/visit.rs @@ -1,11 +1,17 @@ use crate::clean::*; +/// Allows a type to traverse the cleaned ast of a crate. +/// +/// Note that like [`rustc_ast::visit::Visitor`], but +/// unlike [`rustc_lint::EarlyLintPass`], if you override a +/// `visit_*` method, you will need to manually recurse into +/// its contents. pub(crate) trait DocVisitor<'a>: Sized { fn visit_item(&mut self, item: &'a Item) { self.visit_item_recur(item) } - /// don't override! + /// Don't override! fn visit_inner_recur(&mut self, kind: &'a ItemKind) { match kind { StrippedItem(..) => unreachable!(), @@ -46,7 +52,7 @@ pub(crate) trait DocVisitor<'a>: Sized { } } - /// don't override! + /// Don't override! fn visit_item_recur(&mut self, item: &'a Item) { match &item.kind { StrippedItem(i) => self.visit_inner_recur(&*i), @@ -58,6 +64,7 @@ pub(crate) trait DocVisitor<'a>: Sized { m.items.iter().for_each(|i| self.visit_item(i)) } + /// This is the main entrypoint of [`DocVisitor`]. fn visit_crate(&mut self, c: &'a Crate) { self.visit_item(&c.module); diff --git a/src/tools/build_helper/src/ci.rs b/src/tools/build_helper/src/ci.rs index 6d79c7c83ad..60f319129a0 100644 --- a/src/tools/build_helper/src/ci.rs +++ b/src/tools/build_helper/src/ci.rs @@ -19,6 +19,15 @@ impl CiEnv { pub fn is_ci() -> bool { Self::current() != CiEnv::None } + + /// Checks if running in rust-lang/rust managed CI job. + pub fn is_rust_lang_managed_ci_job() -> bool { + Self::is_ci() + // If both are present, we can assume it's an upstream CI job + // as they are always set unconditionally. + && std::env::var_os("CI_JOB_NAME").is_some() + && std::env::var_os("TOOLSTATE_REPO").is_some() + } } pub mod gha { diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index a291ff37112..6a889d27793 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -1115,6 +1115,7 @@ fn expand_variables(mut value: String, config: &Config) -> String { const CWD: &str = "{{cwd}}"; const SRC_BASE: &str = "{{src-base}}"; const BUILD_BASE: &str = "{{build-base}}"; + const RUST_SRC_BASE: &str = "{{rust-src-base}}"; const SYSROOT_BASE: &str = "{{sysroot-base}}"; const TARGET_LINKER: &str = "{{target-linker}}"; const TARGET: &str = "{{target}}"; @@ -1144,6 +1145,13 @@ fn expand_variables(mut value: String, config: &Config) -> String { value = value.replace(TARGET, &config.target); } + if value.contains(RUST_SRC_BASE) { + let src_base = config.sysroot_base.join("lib/rustlib/src/rust"); + src_base.try_exists().expect(&*format!("{} should exists", src_base.display())); + let src_base = src_base.read_link().unwrap_or(src_base); + value = value.replace(RUST_SRC_BASE, &src_base.to_string_lossy()); + } + value } diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index c2e74dffdca..74d86d2b521 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2294,13 +2294,19 @@ impl<'test> TestCx<'test> { } let base_dir = Path::new("/rustc/FAKE_PREFIX"); - // Paths into the libstd/libcore + // Fake paths into the libstd/libcore normalize_path(&base_dir.join("library"), "$SRC_DIR"); // `ui-fulldeps` tests can show paths to the compiler source when testing macros from // `rustc_macros` // eg. /home/user/rust/compiler normalize_path(&base_dir.join("compiler"), "$COMPILER_DIR"); + // Real paths into the libstd/libcore + let rust_src_dir = &self.config.sysroot_base.join("lib/rustlib/src/rust"); + rust_src_dir.try_exists().expect(&*format!("{} should exists", rust_src_dir.display())); + let rust_src_dir = rust_src_dir.read_link().unwrap_or(rust_src_dir.to_path_buf()); + normalize_path(&rust_src_dir.join("library"), "$SRC_DIR_REAL"); + // Paths into the build directory let test_build_dir = &self.config.build_base; let parent_build_dir = test_build_dir.parent().unwrap().parent().unwrap().parent().unwrap(); @@ -2310,9 +2316,6 @@ impl<'test> TestCx<'test> { // eg. /home/user/rust/build normalize_path(parent_build_dir, "$BUILD_DIR"); - // Paths into lib directory. - normalize_path(&parent_build_dir.parent().unwrap().join("lib"), "$LIB_DIR"); - if json { // escaped newlines in json strings should be readable // in the stderr files. There's no point int being correct, diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock index e5f0aabbf7c..060deb18344 100644 --- a/src/tools/rustbook/Cargo.lock +++ b/src/tools/rustbook/Cargo.lock @@ -102,9 +102,9 @@ checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "bincode" @@ -161,9 +161,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cc" -version = "1.1.21" +version = "1.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07b1695e2c7e8fc85310cde85aeaab7e3097f593c91d209d3f9df76c928100f0" +checksum = "9540e661f81799159abee814118cc139a2004b3a3aa3ea37724a1b66530b90e0" dependencies = [ "shlex", ] @@ -376,9 +376,9 @@ checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "flate2" -version = "1.0.33" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253" +checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" dependencies = [ "crc32fast", "miniz_oxide", @@ -572,9 +572,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.158" +version = "0.2.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" [[package]] name = "libdbus-sys" @@ -949,9 +949,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "polib" @@ -1082,9 +1082,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.4" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853" +checksum = "355ae415ccd3a04315d3f8246e86d67689ea74d88d915576e1589a351062a13b" dependencies = [ "bitflags 2.6.0", ] @@ -1205,9 +1205,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.7" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" dependencies = [ "serde", ] @@ -1275,9 +1275,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.77" +version = "2.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" dependencies = [ "proc-macro2", "quote", @@ -1306,9 +1306,9 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.12.0" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" +checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" dependencies = [ "cfg-if", "fastrand", @@ -1346,18 +1346,18 @@ checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" [[package]] name = "thiserror" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ "proc-macro2", "quote", @@ -1411,9 +1411,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.21" +version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b072cee73c449a636ffd6f32bd8de3a9f7119139aff882f44943ce2986dc5cf" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ "indexmap", "serde", @@ -1766,9 +1766,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.6.18" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" dependencies = [ "memchr", ] diff --git a/tests/codegen/issues/issue-123712-str-to-lower-autovectorization.rs b/tests/codegen/issues/issue-123712-str-to-lower-autovectorization.rs new file mode 100644 index 00000000000..11ee10e8cc3 --- /dev/null +++ b/tests/codegen/issues/issue-123712-str-to-lower-autovectorization.rs @@ -0,0 +1,23 @@ +//@ only-x86_64 +//@ compile-flags: -C opt-level=3 +#![crate_type = "lib"] +#![no_std] +#![feature(str_internals)] + +extern crate alloc; + +/// Ensure that the ascii-prefix loop for `str::to_lowercase` and `str::to_uppercase` uses vector +/// instructions. +/// +/// The llvm ir should be the same for all targets that support some form of simd. Only targets +/// without any simd instructions would see scalarized ir. +/// Unfortunately, there is no `only-simd` directive to only run this test on only such platforms, +/// and using test revisions would still require the core libraries for all platforms. +// CHECK-LABEL: @lower_while_ascii +// CHECK: [[A:%[0-9]]] = load <16 x i8> +// CHECK-NEXT: [[B:%[0-9]]] = icmp slt <16 x i8> [[A]], zeroinitializer +// CHECK-NEXT: [[C:%[0-9]]] = bitcast <16 x i1> [[B]] to i16 +#[no_mangle] +pub fn lower_while_ascii(s: &str) -> (alloc::string::String, &str) { + alloc::str::convert_while_ascii(s, u8::to_ascii_lowercase) +} diff --git a/tests/crashes/130521.rs b/tests/crashes/130521.rs new file mode 100644 index 00000000000..2d30b658024 --- /dev/null +++ b/tests/crashes/130521.rs @@ -0,0 +1,13 @@ +//@ known-bug: #130521 + +#![feature(object_safe_for_dispatch)] +struct Vtable(dyn Cap); + +trait Cap<'a> {} + +union Transmute { + t: u64, + u: &'static Vtable, +} + +const G: &Copy = unsafe { Transmute { t: 1 }.u }; diff --git a/tests/crashes/130524.rs b/tests/crashes/130524.rs new file mode 100644 index 00000000000..14d2269de59 --- /dev/null +++ b/tests/crashes/130524.rs @@ -0,0 +1,22 @@ +//@ known-bug: #130524 + +trait Transform { + type Output<'a>; +} + +trait Propagate<Input> {} + +fn new_node<T: Transform>(_c: Vec<Box<dyn for<'a> Propagate<<T as Transform>::Output<'a>>>>) -> T { + todo!() +} + +impl<Input, T> Propagate<Input> for T {} +struct Noop; + +impl Transform for Noop { + type Output<'a> = (); +} + +fn main() { + let _node: Noop = new_node(vec![Box::new(Noop)]); +} diff --git a/tests/crashes/130627.rs b/tests/crashes/130627.rs new file mode 100644 index 00000000000..59d3606592b --- /dev/null +++ b/tests/crashes/130627.rs @@ -0,0 +1,20 @@ +//@ known-bug: #130627 + +#![feature(trait_alias)] + +trait Test {} + +#[diagnostic::on_unimplemented( + message="message", + label="label", + note="note" +)] +trait Alias = Test; + +// Use trait alias as bound on type parameter. +fn foo<T: Alias>(v: &T) { +} + +pub fn main() { + foo(&1); +} diff --git a/tests/crashes/130687.rs b/tests/crashes/130687.rs new file mode 100644 index 00000000000..361be0905df --- /dev/null +++ b/tests/crashes/130687.rs @@ -0,0 +1,4 @@ +//@ known-bug: #130687 +//@ only-x86_64 +pub struct Data([u8; usize::MAX >> 16]); +const _: &'static Data = &Data([0; usize::MAX >> 16]); diff --git a/tests/crashes/130779.rs b/tests/crashes/130779.rs new file mode 100644 index 00000000000..f0fd81fff44 --- /dev/null +++ b/tests/crashes/130779.rs @@ -0,0 +1,11 @@ +//@ known-bug: #130779 +#![feature(never_patterns)] + +enum E { A } + +fn main() { + match E::A { + ! | + if true => {} + } +} diff --git a/tests/crashes/130921.rs b/tests/crashes/130921.rs new file mode 100644 index 00000000000..b7cb1303937 --- /dev/null +++ b/tests/crashes/130921.rs @@ -0,0 +1,10 @@ +//@ known-bug: #130921 +//@ compile-flags: -Zvalidate-mir -Copt-level=0 --crate-type lib + +pub fn hello() -> [impl Sized; 2] { + if false { + let x = hello(); + let _: &[i32] = &x; + } + todo!() +} diff --git a/tests/crashes/130970.rs b/tests/crashes/130970.rs new file mode 100644 index 00000000000..e1f59c155a5 --- /dev/null +++ b/tests/crashes/130970.rs @@ -0,0 +1,9 @@ +//@ known-bug: #130970 +//@ compile-flags: -Zmir-opt-level=5 -Zvalidate-mir + +fn main() { + extern "C" { + static symbol: [usize]; + } + println!("{}", symbol[0]); +} diff --git a/tests/run-make/doctests-merge/doctest-standalone.rs b/tests/run-make/doctests-merge/doctest-standalone.rs index 134ffb58285..ac9f8f9272a 100644 --- a/tests/run-make/doctests-merge/doctest-standalone.rs +++ b/tests/run-make/doctests-merge/doctest-standalone.rs @@ -1,11 +1,11 @@ #![crate_name = "foo"] #![crate_type = "lib"] -//! ```standalone +//! ```standalone_crate //! foo::init(); //! ``` -/// ```standalone +/// ```standalone_crate /// foo::init(); /// ``` pub fn init() { diff --git a/tests/rustdoc-gui/docblock-code-block-line-number.goml b/tests/rustdoc-gui/docblock-code-block-line-number.goml index 53f756dfcd6..3c16626336e 100644 --- a/tests/rustdoc-gui/docblock-code-block-line-number.goml +++ b/tests/rustdoc-gui/docblock-code-block-line-number.goml @@ -87,8 +87,7 @@ assert-css: ("#settings", {"display": "block"}) // Then, click the toggle button. click: "input#line-numbers" -wait-for: 100 // FIXME: `wait-for-false` does not exist -assert-false: "pre.example-line-numbers" +wait-for-false: "pre.example-line-numbers" assert-local-storage: {"rustdoc-line-numbers": "false" } // Check that the rounded corners are back. @@ -107,8 +106,7 @@ assert-css: ( click: "input#line-numbers" wait-for: "pre.example-line-numbers" assert-local-storage: {"rustdoc-line-numbers": "true" } -wait-for: 100 // FIXME: `wait-for-false` does not exist -assert: "pre.example-line-numbers" +wait-for: "pre.example-line-numbers" // Same check with scraped examples line numbers. go-to: "file://" + |DOC_PATH| + "/scrape_examples/fn.test_many.html" @@ -195,15 +193,13 @@ define-function: ("check-line-numbers-existence", [], block { // Then, click the toggle button. click: "input#line-numbers" - wait-for: 100 // FIXME: `wait-for-false` does not exist - assert-local-storage-false: {"rustdoc-line-numbers": "true" } + wait-for-local-storage-false: {"rustdoc-line-numbers": "true" } assert-false: ".example-line-numbers" // Line numbers should still be there. assert: ".src-line-numbers" // Now disabling the setting. click: "input#line-numbers" - wait-for: 100 // FIXME: `wait-for-false` does not exist - assert-local-storage: {"rustdoc-line-numbers": "true" } + wait-for-local-storage: {"rustdoc-line-numbers": "true" } assert-false: ".example-line-numbers" // Line numbers should still be there. assert: ".src-line-numbers" @@ -246,12 +242,10 @@ wait-for: "#settings" // Then, click the toggle button. click: "input#line-numbers" -wait-for: 100 // FIXME: `wait-for-false` does not exist +wait-for-count: (".example-wrap > pre.example-line-numbers", 0) assert-local-storage-false: {"rustdoc-line-numbers": "true" } -assert-count: (".example-wrap > pre.example-line-numbers", 0) // Now turning off the setting. click: "input#line-numbers" -wait-for: 100 // FIXME: `wait-for-false` does not exist +wait-for-count: (".example-wrap > pre.example-line-numbers", 2) assert-local-storage: {"rustdoc-line-numbers": "true" } -assert-count: (".example-wrap > pre.example-line-numbers", 2) diff --git a/tests/rustdoc-ui/doctest/check-attr-test.stderr b/tests/rustdoc-ui/doctest/check-attr-test.stderr index 10f763a6f9d..257136d1633 100644 --- a/tests/rustdoc-ui/doctest/check-attr-test.stderr +++ b/tests/rustdoc-ui/doctest/check-attr-test.stderr @@ -8,8 +8,8 @@ error: unknown attribute `compile-fail` 9 | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `compile_fail` - = help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully + = help: use `compile_fail` to invert the results of this test, so that it passes if it cannot be compiled and fails if it can + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` note: the lint level is defined here --> $DIR/check-attr-test.rs:3:9 | @@ -26,8 +26,8 @@ error: unknown attribute `compilefail` 9 | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `compile_fail` - = help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully + = help: use `compile_fail` to invert the results of this test, so that it passes if it cannot be compiled and fails if it can + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `comPile_fail` --> $DIR/check-attr-test.rs:5:1 @@ -39,8 +39,8 @@ error: unknown attribute `comPile_fail` 9 | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `compile_fail` - = help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully + = help: use `compile_fail` to invert the results of this test, so that it passes if it cannot be compiled and fails if it can + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `should-panic` --> $DIR/check-attr-test.rs:12:1 @@ -52,8 +52,8 @@ error: unknown attribute `should-panic` 16 | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `should_panic` - = help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running + = help: use `should_panic` to invert the results of this test, so that if passes if it panics and fails if it does not + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `shouldpanic` --> $DIR/check-attr-test.rs:12:1 @@ -65,8 +65,8 @@ error: unknown attribute `shouldpanic` 16 | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `should_panic` - = help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running + = help: use `should_panic` to invert the results of this test, so that if passes if it panics and fails if it does not + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `shOuld_panic` --> $DIR/check-attr-test.rs:12:1 @@ -78,8 +78,8 @@ error: unknown attribute `shOuld_panic` 16 | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `should_panic` - = help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running + = help: use `should_panic` to invert the results of this test, so that if passes if it panics and fails if it does not + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `no-run` --> $DIR/check-attr-test.rs:19:1 @@ -91,8 +91,8 @@ error: unknown attribute `no-run` 23 | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `no_run` - = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want) + = help: use `no_run` to compile, but not run, the code sample during testing + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `norun` --> $DIR/check-attr-test.rs:19:1 @@ -104,8 +104,8 @@ error: unknown attribute `norun` 23 | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `no_run` - = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want) + = help: use `no_run` to compile, but not run, the code sample during testing + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `nO_run` --> $DIR/check-attr-test.rs:19:1 @@ -117,8 +117,8 @@ error: unknown attribute `nO_run` 23 | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `no_run` - = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want) + = help: use `no_run` to compile, but not run, the code sample during testing + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `test-harness` --> $DIR/check-attr-test.rs:26:1 @@ -130,8 +130,8 @@ error: unknown attribute `test-harness` 30 | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `test_harness` - = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function + = help: use `test_harness` to run functions marked `#[test]` instead of a potentially-implicit `main` function + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `testharness` --> $DIR/check-attr-test.rs:26:1 @@ -143,8 +143,8 @@ error: unknown attribute `testharness` 30 | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `test_harness` - = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function + = help: use `test_harness` to run functions marked `#[test]` instead of a potentially-implicit `main` function + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `tesT_harness` --> $DIR/check-attr-test.rs:26:1 @@ -156,8 +156,8 @@ error: unknown attribute `tesT_harness` 30 | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `test_harness` - = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function + = help: use `test_harness` to run functions marked `#[test]` instead of a potentially-implicit `main` function + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: aborting due to 12 previous errors diff --git a/tests/rustdoc-ui/doctest/standalone-warning-2024.rs b/tests/rustdoc-ui/doctest/standalone-warning-2024.rs new file mode 100644 index 00000000000..aac43031546 --- /dev/null +++ b/tests/rustdoc-ui/doctest/standalone-warning-2024.rs @@ -0,0 +1,16 @@ +// This test checks that it will output warnings for usage of `standalone` or `standalone_crate`. + +//@ compile-flags:--test -Zunstable-options --edition 2024 +//@ normalize-stdout-test: "tests/rustdoc-ui/doctest" -> "$$DIR" +//@ normalize-stdout-test: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ normalize-stdout-test: ".rs:\d+:\d+" -> ".rs:$$LINE:$$COL" + +#![deny(warnings)] + +//! ```standalone +//! bla +//! ``` +//! +//! ```standalone-crate +//! bla +//! ``` diff --git a/tests/rustdoc-ui/doctest/standalone-warning-2024.stderr b/tests/rustdoc-ui/doctest/standalone-warning-2024.stderr new file mode 100644 index 00000000000..d69d03d8657 --- /dev/null +++ b/tests/rustdoc-ui/doctest/standalone-warning-2024.stderr @@ -0,0 +1,38 @@ +error: unknown attribute `standalone` + --> $DIR/standalone-warning-2024.rs:10:1 + | +10 | / //! ```standalone +11 | | //! bla +12 | | //! ``` +13 | | //! +14 | | //! ```standalone-crate +15 | | //! bla +16 | | //! ``` + | |_______^ + | + = help: use `standalone_crate` to compile this code block separately + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` +note: the lint level is defined here + --> $DIR/standalone-warning-2024.rs:8:9 + | +8 | #![deny(warnings)] + | ^^^^^^^^ + = note: `#[deny(rustdoc::invalid_codeblock_attributes)]` implied by `#[deny(warnings)]` + +error: unknown attribute `standalone-crate` + --> $DIR/standalone-warning-2024.rs:10:1 + | +10 | / //! ```standalone +11 | | //! bla +12 | | //! ``` +13 | | //! +14 | | //! ```standalone-crate +15 | | //! bla +16 | | //! ``` + | |_______^ + | + = help: use `standalone_crate` to compile this code block separately + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` + +error: aborting due to 2 previous errors + diff --git a/tests/rustdoc-ui/doctest/standalone-warning.rs b/tests/rustdoc-ui/doctest/standalone-warning.rs new file mode 100644 index 00000000000..ce081c7641c --- /dev/null +++ b/tests/rustdoc-ui/doctest/standalone-warning.rs @@ -0,0 +1,10 @@ +// This test checks that it will not output warning for usage of `standalone` or `standalone_crate`. +//@ check-pass + +//! ```standalone +//! bla +//! ``` +//! +//! ```standalone-crate +//! bla +//! ``` diff --git a/tests/rustdoc-ui/lints/check-attr.stderr b/tests/rustdoc-ui/lints/check-attr.stderr index d640125ab51..e23806e0bab 100644 --- a/tests/rustdoc-ui/lints/check-attr.stderr +++ b/tests/rustdoc-ui/lints/check-attr.stderr @@ -10,8 +10,8 @@ LL | | /// boo LL | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `compile_fail` - = help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully + = help: use `compile_fail` to invert the results of this test, so that it passes if it cannot be compiled and fails if it can + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` note: the lint level is defined here --> $DIR/check-attr.rs:1:9 | @@ -30,8 +30,8 @@ LL | | /// boo LL | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `compile_fail` - = help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully + = help: use `compile_fail` to invert the results of this test, so that it passes if it cannot be compiled and fails if it can + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `comPile_fail` --> $DIR/check-attr.rs:3:1 @@ -45,8 +45,8 @@ LL | | /// boo LL | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `compile_fail` - = help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully + = help: use `compile_fail` to invert the results of this test, so that it passes if it cannot be compiled and fails if it can + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `should-panic` --> $DIR/check-attr.rs:13:1 @@ -60,8 +60,8 @@ LL | | /// boo LL | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `should_panic` - = help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running + = help: use `should_panic` to invert the results of this test, so that if passes if it panics and fails if it does not + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `shouldpanic` --> $DIR/check-attr.rs:13:1 @@ -75,8 +75,8 @@ LL | | /// boo LL | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `should_panic` - = help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running + = help: use `should_panic` to invert the results of this test, so that if passes if it panics and fails if it does not + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `sHould_panic` --> $DIR/check-attr.rs:13:1 @@ -90,8 +90,8 @@ LL | | /// boo LL | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `should_panic` - = help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running + = help: use `should_panic` to invert the results of this test, so that if passes if it panics and fails if it does not + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `no-run` --> $DIR/check-attr.rs:23:1 @@ -105,8 +105,8 @@ LL | | /// boo LL | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `no_run` - = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want) + = help: use `no_run` to compile, but not run, the code sample during testing + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `norun` --> $DIR/check-attr.rs:23:1 @@ -120,8 +120,8 @@ LL | | /// boo LL | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `no_run` - = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want) + = help: use `no_run` to compile, but not run, the code sample during testing + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `no_Run` --> $DIR/check-attr.rs:23:1 @@ -135,8 +135,8 @@ LL | | /// boo LL | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `no_run` - = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want) + = help: use `no_run` to compile, but not run, the code sample during testing + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `test-harness` --> $DIR/check-attr.rs:33:1 @@ -150,8 +150,8 @@ LL | | /// boo LL | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `test_harness` - = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function + = help: use `test_harness` to run functions marked `#[test]` instead of a potentially-implicit `main` function + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `testharness` --> $DIR/check-attr.rs:33:1 @@ -165,8 +165,8 @@ LL | | /// boo LL | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `test_harness` - = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function + = help: use `test_harness` to run functions marked `#[test]` instead of a potentially-implicit `main` function + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `teSt_harness` --> $DIR/check-attr.rs:33:1 @@ -180,8 +180,8 @@ LL | | /// boo LL | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `test_harness` - = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function + = help: use `test_harness` to run functions marked `#[test]` instead of a potentially-implicit `main` function + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: unknown attribute `rust2018` --> $DIR/check-attr.rs:43:1 @@ -222,8 +222,8 @@ LL | | /// boo LL | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `should_panic` - = help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running + = help: use `should_panic` to invert the results of this test, so that if passes if it panics and fails if it does not + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: aborting due to 15 previous errors diff --git a/tests/rustdoc-ui/lints/check-fail.stderr b/tests/rustdoc-ui/lints/check-fail.stderr index 99b01bac598..2eb9496e5dc 100644 --- a/tests/rustdoc-ui/lints/check-fail.stderr +++ b/tests/rustdoc-ui/lints/check-fail.stderr @@ -31,8 +31,8 @@ LL | | //! let x = 12; LL | | //! ``` | |_______^ | - = help: there is an attribute with a similar name: `test_harness` - = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function + = help: use `test_harness` to run functions marked `#[test]` instead of a potentially-implicit `main` function + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` note: the lint level is defined here --> $DIR/check-fail.rs:6:9 | @@ -51,8 +51,8 @@ LL | | /// let x = 12; LL | | /// ``` | |_______^ | - = help: there is an attribute with a similar name: `test_harness` - = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function + = help: use `test_harness` to run functions marked `#[test]` instead of a potentially-implicit `main` function + = help: this code block may be skipped during testing, because unknown attributes are treated as markers for code samples written in other programming languages, unless it is also explicitly marked as `rust` error: aborting due to 4 previous errors diff --git a/tests/ui/errors/remap-path-prefix-sysroot.rs b/tests/ui/errors/remap-path-prefix-sysroot.rs new file mode 100644 index 00000000000..4cbb38709be --- /dev/null +++ b/tests/ui/errors/remap-path-prefix-sysroot.rs @@ -0,0 +1,24 @@ +//@ revisions: with-remap without-remap +//@ compile-flags: -g -Ztranslate-remapped-path-to-local-path=yes +//@ [with-remap]compile-flags: --remap-path-prefix={{rust-src-base}}=remapped +//@ [with-remap]compile-flags: --remap-path-prefix={{src-base}}=remapped-tests-ui +//@ [without-remap]compile-flags: +//@ error-pattern: E0507 + +// The $SRC_DIR*.rs:LL:COL normalisation doesn't kick in automatically +// as the remapped revision will not begin with $SRC_DIR_REAL, +// so we have to do it ourselves. +//@ normalize-stderr-test: ".rs:\d+:\d+" -> ".rs:LL:COL" + +use std::thread; +struct Worker { + thread: thread::JoinHandle<()>, +} + +impl Drop for Worker { + fn drop(&mut self) { + self.thread.join().unwrap(); + } +} + +pub fn main(){} diff --git a/tests/ui/errors/remap-path-prefix-sysroot.with-remap.stderr b/tests/ui/errors/remap-path-prefix-sysroot.with-remap.stderr new file mode 100644 index 00000000000..88d713d2b04 --- /dev/null +++ b/tests/ui/errors/remap-path-prefix-sysroot.with-remap.stderr @@ -0,0 +1,17 @@ +error[E0507]: cannot move out of `self.thread` which is behind a mutable reference + --> remapped-tests-ui/errors/remap-path-prefix-sysroot.rs:LL:COL + | +LL | self.thread.join().unwrap(); + | ^^^^^^^^^^^ ------ `self.thread` moved due to this method call + | | + | move occurs because `self.thread` has type `JoinHandle<()>`, which does not implement the `Copy` trait + | +note: `JoinHandle::<T>::join` takes ownership of the receiver `self`, which moves `self.thread` + --> remapped/library/std/src/thread/mod.rs:LL:COL + | +LL | pub fn join(self) -> Result<T> { + | ^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/errors/remap-path-prefix-sysroot.without-remap.stderr b/tests/ui/errors/remap-path-prefix-sysroot.without-remap.stderr new file mode 100644 index 00000000000..9b337699c32 --- /dev/null +++ b/tests/ui/errors/remap-path-prefix-sysroot.without-remap.stderr @@ -0,0 +1,17 @@ +error[E0507]: cannot move out of `self.thread` which is behind a mutable reference + --> $DIR/remap-path-prefix-sysroot.rs:LL:COL + | +LL | self.thread.join().unwrap(); + | ^^^^^^^^^^^ ------ `self.thread` moved due to this method call + | | + | move occurs because `self.thread` has type `JoinHandle<()>`, which does not implement the `Copy` trait + | +note: `JoinHandle::<T>::join` takes ownership of the receiver `self`, which moves `self.thread` + --> $SRC_DIR_REAL/std/src/thread/mod.rs:LL:COL + | +LL | pub fn join(self) -> Result<T> { + | ^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0507`. |