From 97ada592c060daee132b473a27dc0f59a82060d6 Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Fri, 10 Jan 2025 22:40:32 +0000 Subject: [PATCH 01/19] jsondoclint: Support `//@ !has `. This was removed for not being used [1], but now we need it. [1]: https://github.com/rust-lang/rust/pull/133478#discussion_r1874358362 --- src/tools/jsondocck/src/main.rs | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs index b6a1d7dfa7a3..7bfa7e3355d3 100644 --- a/src/tools/jsondocck/src/main.rs +++ b/src/tools/jsondocck/src/main.rs @@ -65,6 +65,11 @@ enum CommandKind { /// Checks the path doesn't exist. HasNotPath, + /// `//@ !has ` + /// + /// Checks the path exists, but doesn't have the given value. + HasNotValue { value: String }, + /// `//@ is ` /// /// Check the path is the given value. @@ -128,10 +133,11 @@ impl CommandKind { [_path, value] => Self::HasValue { value: value.clone() }, _ => panic!("`//@ has` must have 2 or 3 arguments, but got {args:?}"), }, - ("has", true) => { - assert_eq!(args.len(), 1, "args={args:?}"); - Self::HasNotPath - } + ("has", true) => match args { + [_path] => Self::HasNotPath, + [_path, value] => Self::HasNotValue { value: value.clone() }, + _ => panic!("`//@ !has` must have 2 or 3 arguments, but got {args:?}"), + }, (_, false) if KNOWN_DIRECTIVE_NAMES.contains(&command_name) => { return None; @@ -223,6 +229,19 @@ fn check_command(command: &Command, cache: &mut Cache) -> Result<(), String> { return Err(format!("matched to {matches:?}, which didn't contain {want_value:?}")); } } + CommandKind::HasNotValue { value } => { + let wantnt_value = string_to_value(value, cache); + if matches.contains(&wantnt_value.as_ref()) { + return Err(format!( + "matched to {matches:?}, which contains unwanted {wantnt_value:?}" + )); + } else if matches.is_empty() { + return Err(format!( + "got no matches, but expected some matched (not containing {wantnt_value:?}" + )); + } + } + CommandKind::Is { value } => { let want_value = string_to_value(value, cache); let matched = get_one(&matches)?; From 1fe3331899906fed89750b85a25b9dee5e88fa0e Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Fri, 10 Jan 2025 22:42:53 +0000 Subject: [PATCH 02/19] rustdoc-json: Include items in stripped modules in `Crate::paths`. --- src/librustdoc/formats/cache.rs | 23 ++++++++++++------- tests/rustdoc-json/reexport/simple_private.rs | 6 +++++ tests/rustdoc-json/reexport/simple_public.rs | 5 ++++ 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 7a95d33723e5..cbb3ce6abe6a 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -140,6 +140,7 @@ struct CacheBuilder<'a, 'tcx> { /// This field is used to prevent duplicated impl blocks. impl_ids: DefIdMap, tcx: TyCtxt<'tcx>, + is_json_output: bool, } impl Cache { @@ -184,8 +185,13 @@ impl Cache { } let (krate, mut impl_ids) = { - let mut cache_builder = - CacheBuilder { tcx, cache: &mut cx.cache, impl_ids: Default::default() }; + let is_json_output = cx.is_json_output(); + let mut cache_builder = CacheBuilder { + tcx, + cache: &mut cx.cache, + impl_ids: Default::default(), + is_json_output, + }; krate = cache_builder.fold_crate(krate); (krate, cache_builder.impl_ids) }; @@ -307,12 +313,13 @@ impl DocFolder for CacheBuilder<'_, '_> { | clean::ProcMacroItem(..) | clean::VariantItem(..) => { use rustc_data_structures::fx::IndexEntry as Entry; - if !self.cache.stripped_mod - && !matches!( - item.stability.map(|stab| stab.level), - Some(StabilityLevel::Stable { allowed_through_unstable_modules: true, .. }) - ) - { + + let skip_because_unstable = matches!( + item.stability.map(|stab| stab.level), + Some(StabilityLevel::Stable { allowed_through_unstable_modules: true, .. }) + ); + + if (!self.cache.stripped_mod && !skip_because_unstable) || self.is_json_output { // Re-exported items mean that the same id can show up twice // in the rustdoc ast that we're looking at. We know, // however, that a re-exported item doesn't show up in the diff --git a/tests/rustdoc-json/reexport/simple_private.rs b/tests/rustdoc-json/reexport/simple_private.rs index 8a936f5da1b9..405d57d342e4 100644 --- a/tests/rustdoc-json/reexport/simple_private.rs +++ b/tests/rustdoc-json/reexport/simple_private.rs @@ -12,3 +12,9 @@ mod inner { pub use inner::Public; //@ ismany "$.index[*][?(@.name=='simple_private')].inner.module.items[*]" $use_id + +// Test for https://github.com/rust-lang/rust/issues/135309 +//@ has "$.paths[*][?(@.kind=='module')].path" '["simple_private"]' +//@ !has "$.paths[*].path" '["simple_private", "inner"]' +//@ has "$.paths[*][?(@.kind=='struct')].path" '["simple_private", "inner", "Public"]' +//@ !has "$.paths[*].path" '["simple_private", "Public"]' diff --git a/tests/rustdoc-json/reexport/simple_public.rs b/tests/rustdoc-json/reexport/simple_public.rs index e5a8dc7d2ad0..f13358283140 100644 --- a/tests/rustdoc-json/reexport/simple_public.rs +++ b/tests/rustdoc-json/reexport/simple_public.rs @@ -14,3 +14,8 @@ pub mod inner { pub use inner::Public; //@ ismany "$.index[*][?(@.name=='simple_public')].inner.module.items[*]" $import_id $inner_id + +//@ has "$.paths[*][?(@.kind=='module')].path" '["simple_public"]' +//@ has "$.paths[*][?(@.kind=='module')].path" '["simple_public", "inner"]' +//@ has "$.paths[*][?(@.kind=='struct')].path" '["simple_public", "inner", "Public"]' +//@ !has "$.paths[*].path" '["simple_public", "Public"]' From 2a2b090d12afd9fbc4b04138a228122a8896cead Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Fri, 10 Jan 2025 23:07:01 +0000 Subject: [PATCH 03/19] jsondoclint: Check that `Path` types exitst in `Crate::paths`. --- src/tools/jsondoclint/src/validator.rs | 6 ++ src/tools/jsondoclint/src/validator/tests.rs | 97 +++++++++++++++++++- 2 files changed, 102 insertions(+), 1 deletion(-) diff --git a/src/tools/jsondoclint/src/validator.rs b/src/tools/jsondoclint/src/validator.rs index f7c752033c59..791b231c27a0 100644 --- a/src/tools/jsondoclint/src/validator.rs +++ b/src/tools/jsondoclint/src/validator.rs @@ -303,6 +303,12 @@ impl<'a> Validator<'a> { PathKind::Trait => self.add_trait_or_alias_id(&x.id), PathKind::Type => self.add_type_id(&x.id), } + + // FIXME: More robust support for checking things in $.index also exist in $.paths + if !self.krate.paths.contains_key(&x.id) { + self.fail(&x.id, ErrorKind::Custom(format!("No entry in '$.paths' for {x:?}"))); + } + if let Some(args) = &x.args { self.check_generic_args(&**args); } diff --git a/src/tools/jsondoclint/src/validator/tests.rs b/src/tools/jsondoclint/src/validator/tests.rs index e842e1318db9..7fcb8ffd1f99 100644 --- a/src/tools/jsondoclint/src/validator/tests.rs +++ b/src/tools/jsondoclint/src/validator/tests.rs @@ -1,5 +1,5 @@ use rustc_hash::FxHashMap; -use rustdoc_json_types::{FORMAT_VERSION, Item, ItemKind, Visibility}; +use rustdoc_json_types::{Abi, FORMAT_VERSION, FunctionHeader, Item, ItemKind, Visibility}; use super::*; use crate::json_find::SelectorPart; @@ -102,6 +102,101 @@ fn errors_on_local_in_paths_and_not_index() { }]); } +#[test] +fn errors_on_missing_path() { + // crate-name=foo + // ``` + // pub struct Bar; + // pub fn mk_bar() -> Bar { ... } + // ``` + + let generics = Generics { params: vec![], where_predicates: vec![] }; + + let krate = Crate { + root: Id(0), + crate_version: None, + includes_private: false, + index: FxHashMap::from_iter([ + (Id(0), Item { + id: Id(0), + crate_id: 0, + name: Some("foo".to_owned()), + span: None, + visibility: Visibility::Public, + docs: None, + links: FxHashMap::default(), + attrs: Vec::new(), + deprecation: None, + inner: ItemEnum::Module(Module { + is_crate: true, + items: vec![Id(1), Id(2)], + is_stripped: false, + }), + }), + (Id(1), Item { + id: Id(0), + crate_id: 0, + name: Some("Bar".to_owned()), + span: None, + visibility: Visibility::Public, + docs: None, + links: FxHashMap::default(), + attrs: Vec::new(), + deprecation: None, + inner: ItemEnum::Struct(Struct { + kind: StructKind::Unit, + generics: generics.clone(), + impls: vec![], + }), + }), + (Id(2), Item { + id: Id(0), + crate_id: 0, + name: Some("mk_bar".to_owned()), + span: None, + visibility: Visibility::Public, + docs: None, + links: FxHashMap::default(), + attrs: Vec::new(), + deprecation: None, + inner: ItemEnum::Function(Function { + sig: FunctionSignature { + inputs: vec![], + output: Some(Type::ResolvedPath(Path { + name: "Bar".to_owned(), + id: Id(1), + args: None, + })), + is_c_variadic: false, + }, + generics, + header: FunctionHeader { + is_const: false, + is_unsafe: false, + is_async: false, + abi: Abi::Rust, + }, + has_body: true, + }), + }), + ]), + paths: FxHashMap::from_iter([(Id(0), ItemSummary { + crate_id: 0, + path: vec!["foo".to_owned()], + kind: ItemKind::Module, + })]), + external_crates: FxHashMap::default(), + format_version: rustdoc_json_types::FORMAT_VERSION, + }; + + check(&krate, &[Error { + kind: ErrorKind::Custom( + r#"No entry in '$.paths' for Path { name: "Bar", id: Id(1), args: None }"#.to_owned(), + ), + id: Id(1), + }]); +} + #[test] #[should_panic = "LOCAL_CRATE_ID is wrong"] fn checks_local_crate_id_is_correct() { From ad550f86e56dcbb19b3ec3a5cf826f7037f18214 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sun, 12 Jan 2025 12:49:24 +0200 Subject: [PATCH 04/19] Remove some empty expected files to fix blessing https://github.com/rust-lang/rust/pull/134808 made --bless remove empty expected files. Remove some empty files that were causing noise in unrelated `--bless` invocations. --- tests/rustdoc-ui/crate-reference-in-block-module.stderr | 0 tests/rustdoc-ui/macro-docs.stdout | 0 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 tests/rustdoc-ui/crate-reference-in-block-module.stderr delete mode 100644 tests/rustdoc-ui/macro-docs.stdout diff --git a/tests/rustdoc-ui/crate-reference-in-block-module.stderr b/tests/rustdoc-ui/crate-reference-in-block-module.stderr deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/rustdoc-ui/macro-docs.stdout b/tests/rustdoc-ui/macro-docs.stdout deleted file mode 100644 index e69de29bb2d1..000000000000 From e54264c509ae6a93f0b1f1b2d36f7c9aabc5e681 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sun, 12 Jan 2025 15:05:46 +0200 Subject: [PATCH 05/19] Deny `clippy::format_in_format_args` and fix the only occurrence --- compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs | 15 ++++++--------- src/bootstrap/src/core/build_steps/clippy.rs | 6 +++++- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 2f4b42587fb2..46eed2db2364 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -2460,16 +2460,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { spans.push_span_label( param.span, format!( - "{} {} to match the {} type of this parameter", + "{} need{} to match the {} type of this parameter", display_list_with_comma_and(&other_param_matched_names), - format!( - "need{}", - pluralize!(if other_param_matched_names.len() == 1 { - 0 - } else { - 1 - }) - ), + pluralize!(if other_param_matched_names.len() == 1 { + 0 + } else { + 1 + }), matched_ty, ), ); diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index 518db156fea9..4d124cefa1d9 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -391,7 +391,11 @@ impl Step for CI { let compiler_clippy_cfg = LintConfig { allow: vec!["clippy::all".into()], warn: vec![], - deny: vec!["clippy::correctness".into(), "clippy::clone_on_ref_ptr".into()], + deny: vec![ + "clippy::correctness".into(), + "clippy::clone_on_ref_ptr".into(), + "clippy::format_in_format_args".into(), + ], forbid: vec![], }; From 9c5b99dc92005d52d7b877f8501bc90da767c5df Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sun, 12 Jan 2025 15:06:44 +0200 Subject: [PATCH 06/19] Deny `clippy:;four_forward_slashes` and fix the only occurrence --- compiler/rustc_resolve/src/rustdoc.rs | 2 +- src/bootstrap/src/core/build_steps/clippy.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index 84e43d0e0166..7998596c59ef 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -347,7 +347,7 @@ pub fn strip_generics_from_path(path_str: &str) -> Result, MalformedGen /// Returns whether the first doc-comment is an inner attribute. /// -//// If there are no doc-comments, return true. +/// If there are no doc-comments, return true. /// FIXME(#78591): Support both inner and outer attributes on the same item. pub fn inner_docs(attrs: &[impl AttributeExt]) -> bool { attrs diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index 4d124cefa1d9..57efdaf3113f 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -395,6 +395,7 @@ impl Step for CI { "clippy::correctness".into(), "clippy::clone_on_ref_ptr".into(), "clippy::format_in_format_args".into(), + "clippy::four_forward_slashes".into(), ], forbid: vec![], }; From 3b262bdf24b17df602a94815ad3135882c99183d Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sun, 12 Jan 2025 15:11:58 +0200 Subject: [PATCH 07/19] Deny `clippy::char_lit_as_u8` (no occurrences) --- src/bootstrap/src/core/build_steps/clippy.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index 57efdaf3113f..3588e5a76005 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -385,7 +385,10 @@ impl Step for CI { let library_clippy_cfg = LintConfig { allow: vec!["clippy::all".into()], warn: vec![], - deny: vec!["clippy::correctness".into()], + deny: vec![ + "clippy::correctness".into(), + "clippy::char_lit_as_u8".into(), + ], forbid: vec![], }; let compiler_clippy_cfg = LintConfig { @@ -393,6 +396,7 @@ impl Step for CI { warn: vec![], deny: vec![ "clippy::correctness".into(), + "clippy::char_lit_as_u8".into(), "clippy::clone_on_ref_ptr".into(), "clippy::format_in_format_args".into(), "clippy::four_forward_slashes".into(), From fc683cbc0ee05e4d00195b87bee7ea9c963afa06 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sun, 12 Jan 2025 15:15:49 +0200 Subject: [PATCH 08/19] Deny `clippy::non_minimal_cfg` (no occurrences) --- src/bootstrap/src/core/build_steps/clippy.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index 3588e5a76005..a94ab22a0d1c 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -388,6 +388,7 @@ impl Step for CI { deny: vec![ "clippy::correctness".into(), "clippy::char_lit_as_u8".into(), + "clippy::non_minimal_cfg".into(), ], forbid: vec![], }; @@ -400,6 +401,7 @@ impl Step for CI { "clippy::clone_on_ref_ptr".into(), "clippy::format_in_format_args".into(), "clippy::four_forward_slashes".into(), + "clippy::non_minimal_cfg".into(), ], forbid: vec![], }; From e6056b54cfc3fe2cf5eddfdee7daf954577fe107 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sun, 12 Jan 2025 15:17:29 +0200 Subject: [PATCH 09/19] Deny `clippy::needless_bool` and `clippy::needless_bool_assign` (no occurrences) --- src/bootstrap/src/core/build_steps/clippy.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index a94ab22a0d1c..07b9affc16eb 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -388,6 +388,8 @@ impl Step for CI { deny: vec![ "clippy::correctness".into(), "clippy::char_lit_as_u8".into(), + "clippy::needless_bool".into(), + "clippy::needless_bool_assign".into(), "clippy::non_minimal_cfg".into(), ], forbid: vec![], @@ -401,6 +403,8 @@ impl Step for CI { "clippy::clone_on_ref_ptr".into(), "clippy::format_in_format_args".into(), "clippy::four_forward_slashes".into(), + "clippy::needless_bool".into(), + "clippy::needless_bool_assign".into(), "clippy::non_minimal_cfg".into(), ], forbid: vec![], From 132e640fbfb55e4fb3b6af8ff9ccd95d449361fe Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sun, 12 Jan 2025 15:22:06 +0200 Subject: [PATCH 10/19] Deny `clippy::print_literal` (no occurrences) --- src/bootstrap/src/core/build_steps/clippy.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index 07b9affc16eb..18ce81251b54 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -391,6 +391,7 @@ impl Step for CI { "clippy::needless_bool".into(), "clippy::needless_bool_assign".into(), "clippy::non_minimal_cfg".into(), + "clippy::print_literal".into(), ], forbid: vec![], }; @@ -406,6 +407,7 @@ impl Step for CI { "clippy::needless_bool".into(), "clippy::needless_bool_assign".into(), "clippy::non_minimal_cfg".into(), + "clippy::print_literal".into(), ], forbid: vec![], }; From 57fcee8655485c30be5288914331f856c8d1a2ba Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sun, 12 Jan 2025 15:24:29 +0200 Subject: [PATCH 11/19] Deny `clippy::same_item_push` (no occurrences) --- src/bootstrap/src/core/build_steps/clippy.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index 18ce81251b54..299eddd52a8c 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -392,6 +392,7 @@ impl Step for CI { "clippy::needless_bool_assign".into(), "clippy::non_minimal_cfg".into(), "clippy::print_literal".into(), + "clippy::same_item_push".into(), ], forbid: vec![], }; @@ -408,6 +409,7 @@ impl Step for CI { "clippy::needless_bool_assign".into(), "clippy::non_minimal_cfg".into(), "clippy::print_literal".into(), + "clippy::same_item_push".into(), ], forbid: vec![], }; From fb2e70690b82408c1d4dc20e32f2e005fba65cfd Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sun, 12 Jan 2025 15:26:24 +0200 Subject: [PATCH 12/19] Deny `clippy::single_char_add_str` (no occurrences) --- src/bootstrap/src/core/build_steps/clippy.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index 299eddd52a8c..22d4049480b5 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -393,6 +393,7 @@ impl Step for CI { "clippy::non_minimal_cfg".into(), "clippy::print_literal".into(), "clippy::same_item_push".into(), + "clippy::single_char_add_str".into(), ], forbid: vec![], }; @@ -410,6 +411,7 @@ impl Step for CI { "clippy::non_minimal_cfg".into(), "clippy::print_literal".into(), "clippy::same_item_push".into(), + "clippy::single_char_add_str".into(), ], forbid: vec![], }; From fcc7803822dcb3ff09ec56c858293889ab165d2b Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sun, 12 Jan 2025 15:29:56 +0200 Subject: [PATCH 13/19] Deny `clippy::to_string_in_format_args` (no occurrences) --- src/bootstrap/src/core/build_steps/clippy.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index 22d4049480b5..a6c95e596951 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -394,6 +394,7 @@ impl Step for CI { "clippy::print_literal".into(), "clippy::same_item_push".into(), "clippy::single_char_add_str".into(), + "clippy::to_string_in_format_args".into(), ], forbid: vec![], }; @@ -412,6 +413,7 @@ impl Step for CI { "clippy::print_literal".into(), "clippy::same_item_push".into(), "clippy::single_char_add_str".into(), + "clippy::to_string_in_format_args".into(), ], forbid: vec![], }; From af7bc3158a3d298490c6792b88a9f13152b899f8 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sun, 12 Jan 2025 15:58:01 +0200 Subject: [PATCH 14/19] Deny `clippy::four_forward_slashes` in library (no occurrences) --- src/bootstrap/src/core/build_steps/clippy.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index a6c95e596951..bf915a795f94 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -388,6 +388,7 @@ impl Step for CI { deny: vec![ "clippy::correctness".into(), "clippy::char_lit_as_u8".into(), + "clippy::four_forward_slashes".into(), "clippy::needless_bool".into(), "clippy::needless_bool_assign".into(), "clippy::non_minimal_cfg".into(), From 562107760d6fdbe77bbcb8e1b251ef54e2bb9c7d Mon Sep 17 00:00:00 2001 From: Aditya-PS-05 Date: Sun, 12 Jan 2025 19:31:05 +0530 Subject: [PATCH 15/19] Update unstable lint docs to include required feature attributes --- compiler/rustc_lint/src/unqualified_local_imports.rs | 1 + compiler/rustc_lint_defs/src/builtin.rs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/compiler/rustc_lint/src/unqualified_local_imports.rs b/compiler/rustc_lint/src/unqualified_local_imports.rs index c9dd6b32d882..b27398a950c8 100644 --- a/compiler/rustc_lint/src/unqualified_local_imports.rs +++ b/compiler/rustc_lint/src/unqualified_local_imports.rs @@ -12,6 +12,7 @@ declare_lint! { /// ### Example /// /// ```rust,edition2018 + /// #![feature(unqualified_local_imports)] /// #![warn(unqualified_local_imports)] /// /// mod localmod { diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 8399f4c12f4f..8fbafe9c8839 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -2671,6 +2671,7 @@ declare_lint! { /// ### Example /// /// ```rust + /// #![feature(strict_provenance_lints)] /// #![warn(fuzzy_provenance_casts)] /// /// fn main() { @@ -2714,6 +2715,7 @@ declare_lint! { /// ### Example /// /// ```rust + /// #![feature(strict_provenance_lints)] /// #![warn(lossy_provenance_casts)] /// /// fn main() { @@ -4033,6 +4035,7 @@ declare_lint! { /// ### Example /// /// ```rust + /// #![feature(test_unstable_lint)] /// #![allow(test_unstable_lint)] /// ``` /// From 4de8cefbdf032077154576a646f340883927c5b3 Mon Sep 17 00:00:00 2001 From: Boxy Date: Fri, 10 Jan 2025 23:19:17 +0000 Subject: [PATCH 16/19] De-abstract tagged pointer abstraction --- compiler/rustc_data_structures/src/marker.rs | 4 +- .../rustc_data_structures/src/tagged_ptr.rs | 357 +++++++++--------- .../src/tagged_ptr/copy.rs | 330 ---------------- .../src/tagged_ptr/copy/tests.rs | 50 --- .../src/tagged_ptr/drop.rs | 178 --------- .../src/tagged_ptr/drop/tests.rs | 72 ---- .../src/tagged_ptr/impl_tag.rs | 144 ------- .../src/tagged_ptr/impl_tag/tests.rs | 34 -- .../src/tagged_ptr/tests.rs | 105 ++++++ compiler/rustc_middle/src/ty/list.rs | 2 +- 10 files changed, 291 insertions(+), 985 deletions(-) delete mode 100644 compiler/rustc_data_structures/src/tagged_ptr/copy.rs delete mode 100644 compiler/rustc_data_structures/src/tagged_ptr/copy/tests.rs delete mode 100644 compiler/rustc_data_structures/src/tagged_ptr/drop.rs delete mode 100644 compiler/rustc_data_structures/src/tagged_ptr/drop/tests.rs delete mode 100644 compiler/rustc_data_structures/src/tagged_ptr/impl_tag.rs delete mode 100644 compiler/rustc_data_structures/src/tagged_ptr/impl_tag/tests.rs create mode 100644 compiler/rustc_data_structures/src/tagged_ptr/tests.rs diff --git a/compiler/rustc_data_structures/src/marker.rs b/compiler/rustc_data_structures/src/marker.rs index 2b629024bfe4..6ae97222f77f 100644 --- a/compiler/rustc_data_structures/src/marker.rs +++ b/compiler/rustc_data_structures/src/marker.rs @@ -72,7 +72,7 @@ impl_dyn_send!( [Vec where T: DynSend, A: std::alloc::Allocator + DynSend] [Box where T: ?Sized + DynSend, A: std::alloc::Allocator + DynSend] [crate::sync::RwLock where T: DynSend] - [crate::tagged_ptr::CopyTaggedPtr where P: Send + crate::tagged_ptr::Pointer, T: Send + crate::tagged_ptr::Tag, const CP: bool] + [crate::tagged_ptr::TaggedRef<'a, P, T> where 'a, P: Sync, T: Send + crate::tagged_ptr::Tag] [rustc_arena::TypedArena where T: DynSend] [indexmap::IndexSet where V: DynSend, S: DynSend] [indexmap::IndexMap where K: DynSend, V: DynSend, S: DynSend] @@ -148,7 +148,7 @@ impl_dyn_sync!( [crate::sync::RwLock where T: DynSend + DynSync] [crate::sync::WorkerLocal where T: DynSend] [crate::intern::Interned<'a, T> where 'a, T: DynSync] - [crate::tagged_ptr::CopyTaggedPtr where P: Sync + crate::tagged_ptr::Pointer, T: Sync + crate::tagged_ptr::Tag, const CP: bool] + [crate::tagged_ptr::TaggedRef<'a, P, T> where 'a, P: Sync, T: Sync + crate::tagged_ptr::Tag] [parking_lot::lock_api::Mutex where R: DynSync, T: ?Sized + DynSend] [parking_lot::lock_api::RwLock where R: DynSync, T: ?Sized + DynSend + DynSync] [indexmap::IndexSet where V: DynSync, S: DynSync] diff --git a/compiler/rustc_data_structures/src/tagged_ptr.rs b/compiler/rustc_data_structures/src/tagged_ptr.rs index 2914eece6796..94db421f77e8 100644 --- a/compiler/rustc_data_structures/src/tagged_ptr.rs +++ b/compiler/rustc_data_structures/src/tagged_ptr.rs @@ -1,116 +1,26 @@ -//! This module implements tagged pointers. +//! This module implements tagged pointers. In order to utilize the pointer +//! packing, you must have a tag type implementing the [`Tag`] trait. //! -//! In order to utilize the pointer packing, you must have two types: a pointer, -//! and a tag. -//! -//! The pointer must implement the [`Pointer`] trait, with the primary -//! requirement being convertible to and from a raw pointer. Note that the -//! pointer must be dereferenceable, so raw pointers generally cannot implement -//! the [`Pointer`] trait. This implies that the pointer must also be non-null. -//! -//! Many common pointer types already implement the [`Pointer`] trait. -//! -//! The tag must implement the [`Tag`] trait. -//! -//! We assert that the tag and the [`Pointer`] types are compatible at compile +//! We assert that the tag and the reference type is compatible at compile //! time. +use std::fmt; +use std::hash::{Hash, Hasher}; +use std::marker::PhantomData; +use std::num::NonZero; use std::ops::Deref; use std::ptr::NonNull; -use std::rc::Rc; -use std::sync::Arc; use crate::aligned::Aligned; +use crate::stable_hasher::{HashStable, StableHasher}; -mod copy; -mod drop; -mod impl_tag; - -pub use copy::CopyTaggedPtr; -pub use drop::TaggedPtr; - -/// This describes the pointer type encapsulated by [`TaggedPtr`] and -/// [`CopyTaggedPtr`]. -/// -/// # Safety -/// -/// The pointer returned from [`into_ptr`] must be a [valid], pointer to -/// [`::Target`]. -/// -/// Note that if `Self` implements [`DerefMut`] the pointer returned from -/// [`into_ptr`] must be valid for writes (and thus calling [`NonNull::as_mut`] -/// on it must be safe). -/// -/// The [`BITS`] constant must be correct. [`BITS`] least-significant bits, -/// must be zero on all pointers returned from [`into_ptr`]. -/// -/// For example, if the alignment of [`Self::Target`] is 2, then `BITS` should be 1. -/// -/// [`BITS`]: Pointer::BITS -/// [`into_ptr`]: Pointer::into_ptr -/// [valid]: std::ptr#safety -/// [`::Target`]: Deref::Target -/// [`Self::Target`]: Deref::Target -/// [`DerefMut`]: std::ops::DerefMut -pub unsafe trait Pointer: Deref { - /// Number of unused (always zero) **least-significant bits** in this - /// pointer, usually related to the pointees alignment. - /// - /// For example if [`BITS`] = `2`, then given `ptr = Self::into_ptr(..)`, - /// `ptr.addr() & 0b11 == 0` must be true. - /// - /// Most likely the value you want to use here is the following, unless - /// your [`Self::Target`] type is unsized (e.g., `ty::List` in rustc) - /// or your pointer is over/under aligned, in which case you'll need to - /// manually figure out what the right type to pass to [`bits_for`] is, or - /// what the value to set here. - /// - /// ```rust - /// # use std::ops::Deref; - /// # use rustc_data_structures::tagged_ptr::bits_for; - /// # struct T; - /// # impl Deref for T { type Target = u8; fn deref(&self) -> &u8 { &0 } } - /// # impl T { - /// const BITS: u32 = bits_for::<::Target>(); - /// # } - /// ``` - /// - /// [`BITS`]: Pointer::BITS - /// [`Self::Target`]: Deref::Target - const BITS: u32; - - /// Turns this pointer into a raw, non-null pointer. - /// - /// The inverse of this function is [`from_ptr`]. - /// - /// This function guarantees that the least-significant [`Self::BITS`] bits - /// are zero. - /// - /// [`from_ptr`]: Pointer::from_ptr - /// [`Self::BITS`]: Pointer::BITS - fn into_ptr(self) -> NonNull; - - /// Re-creates the original pointer, from a raw pointer returned by [`into_ptr`]. - /// - /// # Safety - /// - /// The passed `ptr` must be returned from [`into_ptr`]. - /// - /// This acts as [`ptr::read::()`] semantically, it should not be called more than - /// once on non-[`Copy`] `Pointer`s. - /// - /// [`into_ptr`]: Pointer::into_ptr - /// [`ptr::read::()`]: std::ptr::read - unsafe fn from_ptr(ptr: NonNull) -> Self; -} - -/// This describes tags that the [`TaggedPtr`] struct can hold. +/// This describes tags that the [`TaggedRef`] struct can hold. /// /// # Safety /// -/// The [`BITS`] constant must be correct. -/// -/// No more than [`BITS`] least-significant bits may be set in the returned usize. +/// - The [`BITS`] constant must be correct. +/// - No more than [`BITS`] least-significant bits may be set in the returned usize. +/// - [`Eq`] and [`Hash`] must be implementable with the returned `usize` from `into_usize`. /// /// [`BITS`]: Tag::BITS pub unsafe trait Tag: Copy { @@ -166,118 +76,217 @@ pub const fn bits_for_tags(mut tags: &[usize]) -> u32 { bits } -unsafe impl Pointer for Box { - const BITS: u32 = bits_for::(); +/// A covariant [`Copy`] tagged borrow. This is essentially `{ pointer: &'a P, tag: T }` packed +/// in a single reference. +pub struct TaggedRef<'a, Pointee: Aligned + ?Sized, T: Tag> { + /// This is semantically a pair of `pointer: &'a P` and `tag: T` fields, + /// however we pack them in a single pointer, to save space. + /// + /// We pack the tag into the **most**-significant bits of the pointer to + /// ease retrieval of the value. A left shift is a multiplication and + /// those are embeddable in instruction encoding, for example: + /// + /// ```asm + /// // () + /// example::shift_read3: + /// mov eax, dword ptr [8*rdi] + /// ret + /// + /// example::mask_read3: + /// and rdi, -8 + /// mov eax, dword ptr [rdi] + /// ret + /// ``` + /// + /// This is ASM outputted by rustc for reads of values behind tagged + /// pointers for different approaches of tagging: + /// - `shift_read3` uses `<< 3` (the tag is in the most-significant bits) + /// - `mask_read3` uses `& !0b111` (the tag is in the least-significant bits) + /// + /// The shift approach thus produces less instructions and is likely faster + /// (see ). + /// + /// Encoding diagram: + /// ```text + /// [ packed.addr ] + /// [ tag ] [ pointer.addr >> T::BITS ] <-- usize::BITS - T::BITS bits + /// ^ + /// | + /// T::BITS bits + /// ``` + /// + /// The tag can be retrieved by `packed.addr() >> T::BITS` and the pointer + /// can be retrieved by `packed.map_addr(|addr| addr << T::BITS)`. + packed: NonNull, + tag_pointer_ghost: PhantomData<(&'a Pointee, T)>, +} +impl<'a, P, T> TaggedRef<'a, P, T> +where + P: Aligned + ?Sized, + T: Tag, +{ + /// Tags `pointer` with `tag`. + /// + /// [`TaggedRef`]: crate::tagged_ptr::TaggedRef #[inline] - fn into_ptr(self) -> NonNull { - // Safety: pointers from `Box::into_raw` are valid & non-null - unsafe { NonNull::new_unchecked(Box::into_raw(self)) } + pub fn new(pointer: &'a P, tag: T) -> Self { + Self { packed: Self::pack(NonNull::from(pointer), tag), tag_pointer_ghost: PhantomData } } + /// Retrieves the pointer. #[inline] - unsafe fn from_ptr(ptr: NonNull) -> Self { - // Safety: `ptr` comes from `into_ptr` which calls `Box::into_raw` - unsafe { Box::from_raw(ptr.as_ptr()) } + pub fn pointer(self) -> &'a P { + // SAFETY: pointer_raw returns the original pointer + unsafe { self.pointer_raw().as_ref() } } -} - -unsafe impl Pointer for Rc { - const BITS: u32 = bits_for::(); + /// Retrieves the tag. #[inline] - fn into_ptr(self) -> NonNull { - // Safety: pointers from `Rc::into_raw` are valid & non-null - unsafe { NonNull::new_unchecked(Rc::into_raw(self).cast_mut()) } + pub fn tag(&self) -> T { + // Unpack the tag, according to the `self.packed` encoding scheme + let tag = self.packed.addr().get() >> Self::TAG_BIT_SHIFT; + + // Safety: + // The shift retrieves the original value from `T::into_usize`, + // satisfying `T::from_usize`'s preconditions. + unsafe { T::from_usize(tag) } } + /// Sets the tag to a new value. #[inline] - unsafe fn from_ptr(ptr: NonNull) -> Self { - // Safety: `ptr` comes from `into_ptr` which calls `Rc::into_raw` - unsafe { Rc::from_raw(ptr.as_ptr()) } + pub fn set_tag(&mut self, tag: T) { + self.packed = Self::pack(self.pointer_raw(), tag); } -} -unsafe impl Pointer for Arc { - const BITS: u32 = bits_for::(); + const TAG_BIT_SHIFT: u32 = usize::BITS - T::BITS; + const ASSERTION: () = { assert!(T::BITS <= bits_for::

()) }; + /// Pack pointer `ptr` with a `tag`, according to `self.packed` encoding scheme. #[inline] - fn into_ptr(self) -> NonNull { - // Safety: pointers from `Arc::into_raw` are valid & non-null - unsafe { NonNull::new_unchecked(Arc::into_raw(self).cast_mut()) } + fn pack(ptr: NonNull

, tag: T) -> NonNull

{ + // Trigger assert! + let () = Self::ASSERTION; + + let packed_tag = tag.into_usize() << Self::TAG_BIT_SHIFT; + + ptr.map_addr(|addr| { + // Safety: + // - The pointer is `NonNull` => it's address is `NonZero` + // - `P::BITS` least significant bits are always zero (`Pointer` contract) + // - `T::BITS <= P::BITS` (from `Self::ASSERTION`) + // + // Thus `addr >> T::BITS` is guaranteed to be non-zero. + // + // `{non_zero} | packed_tag` can't make the value zero. + + let packed = (addr.get() >> T::BITS) | packed_tag; + unsafe { NonZero::new_unchecked(packed) } + }) } + /// Retrieves the original raw pointer from `self.packed`. #[inline] - unsafe fn from_ptr(ptr: NonNull) -> Self { - // Safety: `ptr` comes from `into_ptr` which calls `Arc::into_raw` - unsafe { Arc::from_raw(ptr.as_ptr()) } + pub(super) fn pointer_raw(&self) -> NonNull

{ + self.packed.map_addr(|addr| unsafe { NonZero::new_unchecked(addr.get() << T::BITS) }) } } -unsafe impl<'a, T: 'a + ?Sized + Aligned> Pointer for &'a T { - const BITS: u32 = bits_for::(); +impl Copy for TaggedRef<'_, P, T> +where + P: Aligned + ?Sized, + T: Tag, +{ +} +impl Clone for TaggedRef<'_, P, T> +where + P: Aligned + ?Sized, + T: Tag, +{ #[inline] - fn into_ptr(self) -> NonNull { - NonNull::from(self) + fn clone(&self) -> Self { + *self } +} + +impl Deref for TaggedRef<'_, P, T> +where + P: Aligned + ?Sized, + T: Tag, +{ + type Target = P; #[inline] - unsafe fn from_ptr(ptr: NonNull) -> Self { - // Safety: - // `ptr` comes from `into_ptr` which gets the pointer from a reference - unsafe { ptr.as_ref() } + fn deref(&self) -> &Self::Target { + self.pointer() } } -unsafe impl<'a, T: 'a + ?Sized + Aligned> Pointer for &'a mut T { - const BITS: u32 = bits_for::(); +impl fmt::Debug for TaggedRef<'_, P, T> +where + P: Aligned + fmt::Debug + ?Sized, + T: Tag + fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("TaggedRef") + .field("pointer", &self.pointer()) + .field("tag", &self.tag()) + .finish() + } +} +impl PartialEq for TaggedRef<'_, P, T> +where + P: Aligned + ?Sized, + T: Tag, +{ #[inline] - fn into_ptr(self) -> NonNull { - NonNull::from(self) + #[allow(ambiguous_wide_pointer_comparisons)] + fn eq(&self, other: &Self) -> bool { + self.packed == other.packed } +} +impl Eq for TaggedRef<'_, P, T> {} + +impl Hash for TaggedRef<'_, P, T> { #[inline] - unsafe fn from_ptr(mut ptr: NonNull) -> Self { - // Safety: - // `ptr` comes from `into_ptr` which gets the pointer from a reference - unsafe { ptr.as_mut() } + fn hash(&self, state: &mut H) { + self.packed.hash(state); } } -/// A tag type used in [`CopyTaggedPtr`] and [`TaggedPtr`] tests. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -#[cfg(test)] -enum Tag2 { - B00 = 0b00, - B01 = 0b01, - B10 = 0b10, - B11 = 0b11, +impl<'a, P, T, HCX> HashStable for TaggedRef<'a, P, T> +where + P: HashStable + Aligned + ?Sized, + T: Tag + HashStable, +{ + fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) { + self.pointer().hash_stable(hcx, hasher); + self.tag().hash_stable(hcx, hasher); + } } -#[cfg(test)] -unsafe impl Tag for Tag2 { - const BITS: u32 = 2; - - fn into_usize(self) -> usize { - self as _ - } +// Safety: +// `TaggedRef` is semantically just `{ ptr: P, tag: T }`, as such +// it's ok to implement `Sync` as long as `P: Sync, T: Sync` +unsafe impl Sync for TaggedRef<'_, P, T> +where + P: Sync + Aligned + ?Sized, + T: Sync + Tag, +{ +} - unsafe fn from_usize(tag: usize) -> Self { - match tag { - 0b00 => Tag2::B00, - 0b01 => Tag2::B01, - 0b10 => Tag2::B10, - 0b11 => Tag2::B11, - _ => unreachable!(), - } - } +// Safety: +// `TaggedRef` is semantically just `{ ptr: P, tag: T }`, as such +// it's ok to implement `Send` as long as `P: Send, T: Send` +unsafe impl Send for TaggedRef<'_, P, T> +where + P: Sync + Aligned + ?Sized, + T: Send + Tag, +{ } #[cfg(test)] -impl crate::stable_hasher::HashStable for Tag2 { - fn hash_stable(&self, hcx: &mut HCX, hasher: &mut crate::stable_hasher::StableHasher) { - (*self as u8).hash_stable(hcx, hasher); - } -} +mod tests; diff --git a/compiler/rustc_data_structures/src/tagged_ptr/copy.rs b/compiler/rustc_data_structures/src/tagged_ptr/copy.rs deleted file mode 100644 index 25e107b0f413..000000000000 --- a/compiler/rustc_data_structures/src/tagged_ptr/copy.rs +++ /dev/null @@ -1,330 +0,0 @@ -use std::fmt; -use std::hash::{Hash, Hasher}; -use std::marker::PhantomData; -use std::mem::ManuallyDrop; -use std::num::NonZero; -use std::ops::{Deref, DerefMut}; -use std::ptr::NonNull; - -use super::{Pointer, Tag}; -use crate::stable_hasher::{HashStable, StableHasher}; - -/// A [`Copy`] tagged pointer. -/// -/// This is essentially `{ pointer: P, tag: T }` packed in a single pointer. -/// -/// You should use this instead of the [`TaggedPtr`] type in all cases where -/// `P` implements [`Copy`]. -/// -/// If `COMPARE_PACKED` is true, then the pointers will be compared and hashed without -/// unpacking. Otherwise we don't implement [`PartialEq`], [`Eq`] and [`Hash`]; -/// if you want that, wrap the [`CopyTaggedPtr`]. -/// -/// [`TaggedPtr`]: crate::tagged_ptr::TaggedPtr -pub struct CopyTaggedPtr -where - P: Pointer, - T: Tag, -{ - /// This is semantically a pair of `pointer: P` and `tag: T` fields, - /// however we pack them in a single pointer, to save space. - /// - /// We pack the tag into the **most**-significant bits of the pointer to - /// ease retrieval of the value. A left shift is a multiplication and - /// those are embeddable in instruction encoding, for example: - /// - /// ```asm - /// // () - /// example::shift_read3: - /// mov eax, dword ptr [8*rdi] - /// ret - /// - /// example::mask_read3: - /// and rdi, -8 - /// mov eax, dword ptr [rdi] - /// ret - /// ``` - /// - /// This is ASM outputted by rustc for reads of values behind tagged - /// pointers for different approaches of tagging: - /// - `shift_read3` uses `<< 3` (the tag is in the most-significant bits) - /// - `mask_read3` uses `& !0b111` (the tag is in the least-significant bits) - /// - /// The shift approach thus produces less instructions and is likely faster - /// (see ). - /// - /// Encoding diagram: - /// ```text - /// [ packed.addr ] - /// [ tag ] [ pointer.addr >> T::BITS ] <-- usize::BITS - T::BITS bits - /// ^ - /// | - /// T::BITS bits - /// ``` - /// - /// The tag can be retrieved by `packed.addr() >> T::BITS` and the pointer - /// can be retrieved by `packed.map_addr(|addr| addr << T::BITS)`. - packed: NonNull, - tag_ghost: PhantomData, -} - -// Note that even though `CopyTaggedPtr` is only really expected to work with -// `P: Copy`, can't add `P: Copy` bound, because `CopyTaggedPtr` is used in the -// `TaggedPtr`'s implementation. -impl CopyTaggedPtr -where - P: Pointer, - T: Tag, -{ - /// Tags `pointer` with `tag`. - /// - /// Note that this leaks `pointer`: it won't be dropped when - /// `CopyTaggedPtr` is dropped. If you have a pointer with a significant - /// drop, use [`TaggedPtr`] instead. - /// - /// [`TaggedPtr`]: crate::tagged_ptr::TaggedPtr - #[inline] - pub fn new(pointer: P, tag: T) -> Self { - Self { packed: Self::pack(P::into_ptr(pointer), tag), tag_ghost: PhantomData } - } - - /// Retrieves the pointer. - #[inline] - pub fn pointer(self) -> P - where - P: Copy, - { - // SAFETY: pointer_raw returns the original pointer - // - // Note that this isn't going to double-drop or anything because we have - // P: Copy - unsafe { P::from_ptr(self.pointer_raw()) } - } - - /// Retrieves the tag. - #[inline] - pub fn tag(&self) -> T { - // Unpack the tag, according to the `self.packed` encoding scheme - let tag = self.packed.addr().get() >> Self::TAG_BIT_SHIFT; - - // Safety: - // The shift retrieves the original value from `T::into_usize`, - // satisfying `T::from_usize`'s preconditions. - unsafe { T::from_usize(tag) } - } - - /// Sets the tag to a new value. - #[inline] - pub fn set_tag(&mut self, tag: T) { - self.packed = Self::pack(self.pointer_raw(), tag); - } - - const TAG_BIT_SHIFT: u32 = usize::BITS - T::BITS; - const ASSERTION: () = { assert!(T::BITS <= P::BITS) }; - - /// Pack pointer `ptr` that comes from [`P::into_ptr`] with a `tag`, - /// according to `self.packed` encoding scheme. - /// - /// [`P::into_ptr`]: Pointer::into_ptr - #[inline] - fn pack(ptr: NonNull, tag: T) -> NonNull { - // Trigger assert! - let () = Self::ASSERTION; - - let packed_tag = tag.into_usize() << Self::TAG_BIT_SHIFT; - - ptr.map_addr(|addr| { - // Safety: - // - The pointer is `NonNull` => it's address is `NonZero` - // - `P::BITS` least significant bits are always zero (`Pointer` contract) - // - `T::BITS <= P::BITS` (from `Self::ASSERTION`) - // - // Thus `addr >> T::BITS` is guaranteed to be non-zero. - // - // `{non_zero} | packed_tag` can't make the value zero. - - let packed = (addr.get() >> T::BITS) | packed_tag; - unsafe { NonZero::new_unchecked(packed) } - }) - } - - /// Retrieves the original raw pointer from `self.packed`. - #[inline] - pub(super) fn pointer_raw(&self) -> NonNull { - self.packed.map_addr(|addr| unsafe { NonZero::new_unchecked(addr.get() << T::BITS) }) - } - - /// This provides a reference to the `P` pointer itself, rather than the - /// `Deref::Target`. It is used for cases where we want to call methods - /// that may be implement differently for the Pointer than the Pointee - /// (e.g., `Rc::clone` vs cloning the inner value). - pub(super) fn with_pointer_ref(&self, f: impl FnOnce(&P) -> R) -> R { - // Safety: - // - `self.raw.pointer_raw()` is originally returned from `P::into_ptr` - // and as such is valid for `P::from_ptr`. - // - This also allows us to not care whatever `f` panics or not. - // - Even though we create a copy of the pointer, we store it inside - // `ManuallyDrop` and only access it by-ref, so we don't double-drop. - // - // Semantically this is just `f(&self.pointer)` (where `self.pointer` - // is non-packed original pointer). - // - // Note that even though `CopyTaggedPtr` is only really expected to - // work with `P: Copy`, we have to assume `P: ?Copy`, because - // `CopyTaggedPtr` is used in the `TaggedPtr`'s implementation. - let ptr = unsafe { ManuallyDrop::new(P::from_ptr(self.pointer_raw())) }; - f(&ptr) - } -} - -impl Copy for CopyTaggedPtr -where - P: Pointer + Copy, - T: Tag, -{ -} - -impl Clone for CopyTaggedPtr -where - P: Pointer + Copy, - T: Tag, -{ - #[inline] - fn clone(&self) -> Self { - *self - } -} - -impl Deref for CopyTaggedPtr -where - P: Pointer, - T: Tag, -{ - type Target = P::Target; - - #[inline] - fn deref(&self) -> &Self::Target { - // Safety: - // `pointer_raw` returns the original pointer from `P::into_ptr` which, - // by the `Pointer`'s contract, must be valid. - unsafe { self.pointer_raw().as_ref() } - } -} - -impl DerefMut for CopyTaggedPtr -where - P: Pointer + DerefMut, - T: Tag, -{ - #[inline] - fn deref_mut(&mut self) -> &mut Self::Target { - // Safety: - // `pointer_raw` returns the original pointer from `P::into_ptr` which, - // by the `Pointer`'s contract, must be valid for writes if - // `P: DerefMut`. - unsafe { self.pointer_raw().as_mut() } - } -} - -impl fmt::Debug for CopyTaggedPtr -where - P: Pointer + fmt::Debug, - T: Tag + fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.with_pointer_ref(|ptr| { - f.debug_struct("CopyTaggedPtr").field("pointer", ptr).field("tag", &self.tag()).finish() - }) - } -} - -impl PartialEq for CopyTaggedPtr -where - P: Pointer, - T: Tag, -{ - #[inline] - #[allow(ambiguous_wide_pointer_comparisons)] - fn eq(&self, other: &Self) -> bool { - self.packed == other.packed - } -} - -impl Eq for CopyTaggedPtr -where - P: Pointer, - T: Tag, -{ -} - -impl Hash for CopyTaggedPtr -where - P: Pointer, - T: Tag, -{ - #[inline] - fn hash(&self, state: &mut H) { - self.packed.hash(state); - } -} - -impl HashStable for CopyTaggedPtr -where - P: Pointer + HashStable, - T: Tag + HashStable, -{ - fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) { - self.with_pointer_ref(|ptr| ptr.hash_stable(hcx, hasher)); - self.tag().hash_stable(hcx, hasher); - } -} - -// Safety: -// `CopyTaggedPtr` is semantically just `{ ptr: P, tag: T }`, as such -// it's ok to implement `Sync` as long as `P: Sync, T: Sync` -unsafe impl Sync for CopyTaggedPtr -where - P: Sync + Pointer, - T: Sync + Tag, -{ -} - -// Safety: -// `CopyTaggedPtr` is semantically just `{ ptr: P, tag: T }`, as such -// it's ok to implement `Send` as long as `P: Send, T: Send` -unsafe impl Send for CopyTaggedPtr -where - P: Send + Pointer, - T: Send + Tag, -{ -} - -/// Test that `new` does not compile if there is not enough alignment for the -/// tag in the pointer. -/// -/// ```compile_fail,E0080 -/// use rustc_data_structures::tagged_ptr::{CopyTaggedPtr, Tag}; -/// -/// #[derive(Copy, Clone, Debug, PartialEq, Eq)] -/// enum Tag2 { B00 = 0b00, B01 = 0b01, B10 = 0b10, B11 = 0b11 }; -/// -/// unsafe impl Tag for Tag2 { -/// const BITS: u32 = 2; -/// -/// fn into_usize(self) -> usize { todo!() } -/// unsafe fn from_usize(tag: usize) -> Self { todo!() } -/// } -/// -/// let value = 12u16; -/// let reference = &value; -/// let tag = Tag2::B01; -/// -/// let _ptr = CopyTaggedPtr::<_, _, true>::new(reference, tag); -/// ``` -// For some reason miri does not get the compile error -// probably it `check`s instead of `build`ing? -#[cfg(not(miri))] -const _: () = (); - -#[cfg(test)] -mod tests; diff --git a/compiler/rustc_data_structures/src/tagged_ptr/copy/tests.rs b/compiler/rustc_data_structures/src/tagged_ptr/copy/tests.rs deleted file mode 100644 index 160af8a65d9c..000000000000 --- a/compiler/rustc_data_structures/src/tagged_ptr/copy/tests.rs +++ /dev/null @@ -1,50 +0,0 @@ -use std::ptr; - -use crate::hashes::Hash128; -use crate::stable_hasher::{HashStable, StableHasher}; -use crate::tagged_ptr::{CopyTaggedPtr, Pointer, Tag, Tag2}; - -#[test] -fn smoke() { - let value = 12u32; - let reference = &value; - let tag = Tag2::B01; - - let ptr = tag_ptr(reference, tag); - - assert_eq!(ptr.tag(), tag); - assert_eq!(*ptr, 12); - assert!(ptr::eq(ptr.pointer(), reference)); - - let copy = ptr; - - let mut ptr = ptr; - ptr.set_tag(Tag2::B00); - assert_eq!(ptr.tag(), Tag2::B00); - - assert_eq!(copy.tag(), tag); - assert_eq!(*copy, 12); - assert!(ptr::eq(copy.pointer(), reference)); -} - -#[test] -fn stable_hash_hashes_as_tuple() { - let hash_packed = { - let mut hasher = StableHasher::new(); - tag_ptr(&12, Tag2::B11).hash_stable(&mut (), &mut hasher); - hasher.finish::() - }; - - let hash_tupled = { - let mut hasher = StableHasher::new(); - (&12, Tag2::B11).hash_stable(&mut (), &mut hasher); - hasher.finish::() - }; - - assert_eq!(hash_packed, hash_tupled); -} - -/// Helper to create tagged pointers without specifying `COMPARE_PACKED` if it does not matter. -fn tag_ptr(ptr: P, tag: T) -> CopyTaggedPtr { - CopyTaggedPtr::new(ptr, tag) -} diff --git a/compiler/rustc_data_structures/src/tagged_ptr/drop.rs b/compiler/rustc_data_structures/src/tagged_ptr/drop.rs deleted file mode 100644 index 319a8cdd3990..000000000000 --- a/compiler/rustc_data_structures/src/tagged_ptr/drop.rs +++ /dev/null @@ -1,178 +0,0 @@ -use std::fmt; -use std::hash::{Hash, Hasher}; -use std::ops::{Deref, DerefMut}; - -use super::{CopyTaggedPtr, Pointer, Tag}; -use crate::stable_hasher::{HashStable, StableHasher}; - -/// A tagged pointer that supports pointers that implement [`Drop`]. -/// -/// This is essentially `{ pointer: P, tag: T }` packed in a single pointer. -/// -/// You should use [`CopyTaggedPtr`] instead of the this type in all cases -/// where `P` implements [`Copy`]. -/// -/// If `COMPARE_PACKED` is true, then the pointers will be compared and hashed without -/// unpacking. Otherwise we don't implement [`PartialEq`], [`Eq`] and [`Hash`]; -/// if you want that, wrap the [`TaggedPtr`]. -pub struct TaggedPtr -where - P: Pointer, - T: Tag, -{ - raw: CopyTaggedPtr, -} - -impl TaggedPtr -where - P: Pointer, - T: Tag, -{ - /// Tags `pointer` with `tag`. - #[inline] - pub fn new(pointer: P, tag: T) -> Self { - TaggedPtr { raw: CopyTaggedPtr::new(pointer, tag) } - } - - /// Retrieves the tag. - #[inline] - pub fn tag(&self) -> T { - self.raw.tag() - } - - /// Sets the tag to a new value. - #[inline] - pub fn set_tag(&mut self, tag: T) { - self.raw.set_tag(tag) - } -} - -impl Clone for TaggedPtr -where - P: Pointer + Clone, - T: Tag, -{ - fn clone(&self) -> Self { - let ptr = self.raw.with_pointer_ref(P::clone); - - Self::new(ptr, self.tag()) - } -} - -impl Deref for TaggedPtr -where - P: Pointer, - T: Tag, -{ - type Target = P::Target; - - #[inline] - fn deref(&self) -> &Self::Target { - self.raw.deref() - } -} - -impl DerefMut for TaggedPtr -where - P: Pointer + DerefMut, - T: Tag, -{ - #[inline] - fn deref_mut(&mut self) -> &mut Self::Target { - self.raw.deref_mut() - } -} - -impl Drop for TaggedPtr -where - P: Pointer, - T: Tag, -{ - fn drop(&mut self) { - // No need to drop the tag, as it's Copy - unsafe { - drop(P::from_ptr(self.raw.pointer_raw())); - } - } -} - -impl fmt::Debug for TaggedPtr -where - P: Pointer + fmt::Debug, - T: Tag + fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.raw.with_pointer_ref(|ptr| { - f.debug_struct("TaggedPtr").field("pointer", ptr).field("tag", &self.tag()).finish() - }) - } -} - -impl PartialEq for TaggedPtr -where - P: Pointer, - T: Tag, -{ - #[inline] - fn eq(&self, other: &Self) -> bool { - self.raw.eq(&other.raw) - } -} - -impl Eq for TaggedPtr -where - P: Pointer, - T: Tag, -{ -} - -impl Hash for TaggedPtr -where - P: Pointer, - T: Tag, -{ - #[inline] - fn hash(&self, state: &mut H) { - self.raw.hash(state); - } -} - -impl HashStable for TaggedPtr -where - P: Pointer + HashStable, - T: Tag + HashStable, -{ - fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) { - self.raw.hash_stable(hcx, hasher); - } -} - -/// Test that `new` does not compile if there is not enough alignment for the -/// tag in the pointer. -/// -/// ```compile_fail,E0080 -/// use rustc_data_structures::tagged_ptr::{TaggedPtr, Tag}; -/// -/// #[derive(Copy, Clone, Debug, PartialEq, Eq)] -/// enum Tag2 { B00 = 0b00, B01 = 0b01, B10 = 0b10, B11 = 0b11 }; -/// -/// unsafe impl Tag for Tag2 { -/// const BITS: u32 = 2; -/// -/// fn into_usize(self) -> usize { todo!() } -/// unsafe fn from_usize(tag: usize) -> Self { todo!() } -/// } -/// -/// let value = 12u16; -/// let reference = &value; -/// let tag = Tag2::B01; -/// -/// let _ptr = TaggedPtr::<_, _, true>::new(reference, tag); -/// ``` -// For some reason miri does not get the compile error -// probably it `check`s instead of `build`ing? -#[cfg(not(miri))] -const _: () = (); - -#[cfg(test)] -mod tests; diff --git a/compiler/rustc_data_structures/src/tagged_ptr/drop/tests.rs b/compiler/rustc_data_structures/src/tagged_ptr/drop/tests.rs deleted file mode 100644 index 4d342c72cc52..000000000000 --- a/compiler/rustc_data_structures/src/tagged_ptr/drop/tests.rs +++ /dev/null @@ -1,72 +0,0 @@ -use std::ptr; -use std::sync::Arc; - -use crate::tagged_ptr::{Pointer, Tag, Tag2, TaggedPtr}; - -#[test] -fn smoke() { - let value = 12u32; - let reference = &value; - let tag = Tag2::B01; - - let ptr = tag_ptr(reference, tag); - - assert_eq!(ptr.tag(), tag); - assert_eq!(*ptr, 12); - - let clone = ptr.clone(); - assert_eq!(clone.tag(), tag); - assert_eq!(*clone, 12); - - let mut ptr = ptr; - ptr.set_tag(Tag2::B00); - assert_eq!(ptr.tag(), Tag2::B00); - - assert_eq!(clone.tag(), tag); - assert_eq!(*clone, 12); - assert!(ptr::eq(&*ptr, &*clone)) -} - -#[test] -fn boxed() { - let value = 12u32; - let boxed = Box::new(value); - let tag = Tag2::B01; - - let ptr = tag_ptr(boxed, tag); - - assert_eq!(ptr.tag(), tag); - assert_eq!(*ptr, 12); - - let clone = ptr.clone(); - assert_eq!(clone.tag(), tag); - assert_eq!(*clone, 12); - - let mut ptr = ptr; - ptr.set_tag(Tag2::B00); - assert_eq!(ptr.tag(), Tag2::B00); - - assert_eq!(clone.tag(), tag); - assert_eq!(*clone, 12); - assert!(!ptr::eq(&*ptr, &*clone)) -} - -#[test] -fn arclones() { - let value = 12u32; - let arc = Arc::new(value); - let tag = Tag2::B01; - - let ptr = tag_ptr(arc, tag); - - assert_eq!(ptr.tag(), tag); - assert_eq!(*ptr, 12); - - let clone = ptr.clone(); - assert!(ptr::eq(&*ptr, &*clone)) -} - -/// Helper to create tagged pointers without specifying `COMPARE_PACKED` if it does not matter. -fn tag_ptr(ptr: P, tag: T) -> TaggedPtr { - TaggedPtr::new(ptr, tag) -} diff --git a/compiler/rustc_data_structures/src/tagged_ptr/impl_tag.rs b/compiler/rustc_data_structures/src/tagged_ptr/impl_tag.rs deleted file mode 100644 index f17a0bf26d74..000000000000 --- a/compiler/rustc_data_structures/src/tagged_ptr/impl_tag.rs +++ /dev/null @@ -1,144 +0,0 @@ -/// Implements [`Tag`] for a given type. -/// -/// You can use `impl_tag` on structs and enums. -/// You need to specify the type and all its possible values, -/// which can only be paths with optional fields. -/// -/// [`Tag`]: crate::tagged_ptr::Tag -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// #![feature(macro_metavar_expr)] -/// use rustc_data_structures::{impl_tag, tagged_ptr::Tag}; -/// -/// #[derive(Copy, Clone, PartialEq, Debug)] -/// enum SomeTag { -/// A, -/// B, -/// X { v: bool }, -/// Y(bool, bool), -/// } -/// -/// impl_tag! { -/// // The type for which the `Tag` will be implemented -/// impl Tag for SomeTag; -/// // You need to specify all possible tag values: -/// SomeTag::A, // 0 -/// SomeTag::B, // 1 -/// // For variants with fields, you need to specify the fields: -/// SomeTag::X { v: true }, // 2 -/// SomeTag::X { v: false }, // 3 -/// // For tuple variants use named syntax: -/// SomeTag::Y { 0: true, 1: true }, // 4 -/// SomeTag::Y { 0: false, 1: true }, // 5 -/// SomeTag::Y { 0: true, 1: false }, // 6 -/// SomeTag::Y { 0: false, 1: false }, // 7 -/// } -/// -/// // Tag values are assigned in order: -/// assert_eq!(SomeTag::A.into_usize(), 0); -/// assert_eq!(SomeTag::X { v: false }.into_usize(), 3); -/// assert_eq!(SomeTag::Y(false, true).into_usize(), 5); -/// -/// assert_eq!(unsafe { SomeTag::from_usize(1) }, SomeTag::B); -/// assert_eq!(unsafe { SomeTag::from_usize(2) }, SomeTag::X { v: true }); -/// assert_eq!(unsafe { SomeTag::from_usize(7) }, SomeTag::Y(false, false)); -/// ``` -/// -/// Structs are supported: -/// -/// ``` -/// #![feature(macro_metavar_expr)] -/// # use rustc_data_structures::impl_tag; -/// #[derive(Copy, Clone)] -/// struct Flags { a: bool, b: bool } -/// -/// impl_tag! { -/// impl Tag for Flags; -/// Flags { a: true, b: true }, -/// Flags { a: false, b: true }, -/// Flags { a: true, b: false }, -/// Flags { a: false, b: false }, -/// } -/// ``` -/// -/// Not specifying all values results in a compile error: -/// -/// ```compile_fail,E0004 -/// #![feature(macro_metavar_expr)] -/// # use rustc_data_structures::impl_tag; -/// #[derive(Copy, Clone)] -/// enum E { -/// A, -/// B, -/// } -/// -/// impl_tag! { -/// impl Tag for E; -/// E::A, -/// } -/// ``` -#[macro_export] -macro_rules! impl_tag { - ( - impl Tag for $Self:ty; - $( - $($path:ident)::* $( { $( $fields:tt )* })?, - )* - ) => { - // Safety: - // `bits_for_tags` is called on the same `${index()}`-es as - // `into_usize` returns, thus `BITS` constant is correct. - unsafe impl $crate::tagged_ptr::Tag for $Self { - const BITS: u32 = $crate::tagged_ptr::bits_for_tags(&[ - $( - ${index()}, - $( ${ignore($path)} )* - )* - ]); - - #[inline] - fn into_usize(self) -> usize { - // This forbids use of repeating patterns (`Enum::V`&`Enum::V`, etc) - // (or at least it should, see ) - #[forbid(unreachable_patterns)] - match self { - // `match` is doing heavy lifting here, by requiring exhaustiveness - $( - $($path)::* $( { $( $fields )* } )? => ${index()}, - )* - } - } - - #[inline] - unsafe fn from_usize(tag: usize) -> Self { - match tag { - $( - ${index()} => $($path)::* $( { $( $fields )* } )?, - )* - - // Safety: - // `into_usize` only returns `${index()}` of the same - // repetition as we are filtering above, thus if this is - // reached, the safety contract of this function was - // already breached. - _ => unsafe { - debug_assert!( - false, - "invalid tag: {tag}\ - (this is a bug in the caller of `from_usize`)" - ); - std::hint::unreachable_unchecked() - }, - } - } - - } - }; -} - -#[cfg(test)] -mod tests; diff --git a/compiler/rustc_data_structures/src/tagged_ptr/impl_tag/tests.rs b/compiler/rustc_data_structures/src/tagged_ptr/impl_tag/tests.rs deleted file mode 100644 index 62c926153e1e..000000000000 --- a/compiler/rustc_data_structures/src/tagged_ptr/impl_tag/tests.rs +++ /dev/null @@ -1,34 +0,0 @@ -#[test] -fn bits_constant() { - use crate::tagged_ptr::Tag; - - #[derive(Copy, Clone)] - struct Unit; - impl_tag! { impl Tag for Unit; Unit, } - assert_eq!(Unit::BITS, 0); - - #[derive(Copy, Clone)] - enum Enum3 { - A, - B, - C, - } - impl_tag! { impl Tag for Enum3; Enum3::A, Enum3::B, Enum3::C, } - assert_eq!(Enum3::BITS, 2); - - #[derive(Copy, Clone)] - struct Eight(bool, bool, bool); - impl_tag! { - impl Tag for Eight; - Eight { 0: true, 1: true, 2: true }, - Eight { 0: true, 1: true, 2: false }, - Eight { 0: true, 1: false, 2: true }, - Eight { 0: true, 1: false, 2: false }, - Eight { 0: false, 1: true, 2: true }, - Eight { 0: false, 1: true, 2: false }, - Eight { 0: false, 1: false, 2: true }, - Eight { 0: false, 1: false, 2: false }, - } - - assert_eq!(Eight::BITS, 3); -} diff --git a/compiler/rustc_data_structures/src/tagged_ptr/tests.rs b/compiler/rustc_data_structures/src/tagged_ptr/tests.rs new file mode 100644 index 000000000000..b1bdee18d6d4 --- /dev/null +++ b/compiler/rustc_data_structures/src/tagged_ptr/tests.rs @@ -0,0 +1,105 @@ +use std::ptr; + +use super::*; +use crate::hashes::Hash128; +use crate::stable_hasher::{HashStable, StableHasher}; + +/// A tag type used in [`TaggedRef`] tests. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum Tag2 { + B00 = 0b00, + B01 = 0b01, + B10 = 0b10, + B11 = 0b11, +} + +unsafe impl Tag for Tag2 { + const BITS: u32 = 2; + + fn into_usize(self) -> usize { + self as _ + } + + unsafe fn from_usize(tag: usize) -> Self { + match tag { + 0b00 => Tag2::B00, + 0b01 => Tag2::B01, + 0b10 => Tag2::B10, + 0b11 => Tag2::B11, + _ => unreachable!(), + } + } +} + +impl crate::stable_hasher::HashStable for Tag2 { + fn hash_stable(&self, hcx: &mut HCX, hasher: &mut crate::stable_hasher::StableHasher) { + (*self as u8).hash_stable(hcx, hasher); + } +} + +#[test] +fn smoke() { + let value = 12u32; + let reference = &value; + let tag = Tag2::B01; + + let ptr = TaggedRef::new(reference, tag); + + assert_eq!(ptr.tag(), tag); + assert_eq!(*ptr, 12); + assert!(ptr::eq(ptr.pointer(), reference)); + + let copy = ptr; + + let mut ptr = ptr; + ptr.set_tag(Tag2::B00); + assert_eq!(ptr.tag(), Tag2::B00); + + assert_eq!(copy.tag(), tag); + assert_eq!(*copy, 12); + assert!(ptr::eq(copy.pointer(), reference)); +} + +#[test] +fn stable_hash_hashes_as_tuple() { + let hash_packed = { + let mut hasher = StableHasher::new(); + TaggedRef::new(&12, Tag2::B11).hash_stable(&mut (), &mut hasher); + hasher.finish::() + }; + + let hash_tupled = { + let mut hasher = StableHasher::new(); + (&12, Tag2::B11).hash_stable(&mut (), &mut hasher); + hasher.finish::() + }; + + assert_eq!(hash_packed, hash_tupled); +} + +/// Test that `new` does not compile if there is not enough alignment for the +/// tag in the pointer. +/// +/// ```compile_fail,E0080 +/// use rustc_data_structures::tagged_ptr::{TaggedRef, Tag}; +/// +/// #[derive(Copy, Clone, Debug, PartialEq, Eq)] +/// enum Tag2 { B00 = 0b00, B01 = 0b01, B10 = 0b10, B11 = 0b11 }; +/// +/// unsafe impl Tag for Tag2 { +/// const BITS: u32 = 2; +/// +/// fn into_usize(self) -> usize { todo!() } +/// unsafe fn from_usize(tag: usize) -> Self { todo!() } +/// } +/// +/// let value = 12u16; +/// let reference = &value; +/// let tag = Tag2::B01; +/// +/// let _ptr = TaggedRef::<_, _, true>::new(reference, tag); +/// ``` +// For some reason miri does not get the compile error +// probably it `check`s instead of `build`ing? +#[cfg(not(miri))] +const _: () = (); diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs index 30a5586f59ca..6718493f6b32 100644 --- a/compiler/rustc_middle/src/ty/list.rs +++ b/compiler/rustc_middle/src/ty/list.rs @@ -21,7 +21,7 @@ use crate::arena::Arena; /// pointer. /// - Because of this, you cannot get a `List` that is a sub-list of another /// `List`. You can get a sub-slice `&[T]`, however. -/// - `List` can be used with `CopyTaggedPtr`, which is useful within +/// - `List` can be used with `TaggedRef`, which is useful within /// structs whose size must be minimized. /// - Because of the uniqueness assumption, we can use the address of a /// `List` for faster equality comparisons and hashing. From f25b0815a749508f58e2d16cb11e72d416fa4708 Mon Sep 17 00:00:00 2001 From: Urgau Date: Sun, 12 Jan 2025 16:12:34 +0100 Subject: [PATCH 17/19] run_make_support: add `#![warn(unreachable_pub)]` --- src/tools/run-make-support/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 819bbc161e69..ffd4ca22a008 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -6,6 +6,7 @@ // We want to control use declaration ordering and spacing (and preserve use group comments), so // skip rustfmt on this file. #![cfg_attr(rustfmt, rustfmt::skip)] +#![warn(unreachable_pub)] mod command; mod macros; From 6024a06dbad00a71e687d1709dc0d4e1b42d3c2e Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sat, 11 Jan 2025 08:26:57 -0500 Subject: [PATCH 18/19] Update the explanation for why we use box_new in vec! --- library/alloc/src/macros.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/macros.rs b/library/alloc/src/macros.rs index 6ee3907cc8ea..c000fd6f4efa 100644 --- a/library/alloc/src/macros.rs +++ b/library/alloc/src/macros.rs @@ -48,8 +48,8 @@ macro_rules! vec { ); ($($x:expr),+ $(,)?) => ( <[_]>::into_vec( - // Using the intrinsic produces a dramatic improvement in compile - // time when constructing arrays with many elements. + // Using the intrinsic produces a dramatic improvement in stack usage for + // unoptimized programs using this code path to construct large Vecs. $crate::boxed::box_new([$($x),+]) ) ); From 7ece88a2d7795cb0beb719848a563c6870531632 Mon Sep 17 00:00:00 2001 From: Aditya-PS-05 Date: Mon, 13 Jan 2025 00:14:24 +0530 Subject: [PATCH 19/19] remove test_unstable_lint feature --- compiler/rustc_lint_defs/src/builtin.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 8fbafe9c8839..0c6147f4a46c 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -4035,7 +4035,8 @@ declare_lint! { /// ### Example /// /// ```rust - /// #![feature(test_unstable_lint)] + /// // This lint is intentionally used to test the compiler's behavior + /// // when an unstable lint is enabled without the corresponding feature gate. /// #![allow(test_unstable_lint)] /// ``` ///