From 2a1ce930fb80a240f66308bdd36ee6cf1c5ae6f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 30 May 2025 11:09:46 +0200 Subject: [PATCH 01/10] rename feature gate --- compiler/rustc_ast_passes/src/feature_gate.rs | 2 +- compiler/rustc_feature/src/unstable.rs | 4 ++-- compiler/rustc_span/src/symbol.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 915613a391374..1ead444995fa3 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -505,7 +505,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { gate_all!(fn_delegation, "functions delegation is not yet fully implemented"); gate_all!(postfix_match, "postfix match is experimental"); gate_all!(mut_ref, "mutable by-reference bindings are experimental"); - gate_all!(global_registration, "global registration is experimental"); + gate_all!(crate_local_distributed_slice, "crate local distributed slice is experimental"); gate_all!(return_type_notation, "return type notation is experimental"); gate_all!(pin_ergonomics, "pinned reference syntax is experimental"); gate_all!(unsafe_fields, "`unsafe` fields are experimental"); diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index b46eac6d8a602..01f588ad78e55 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -526,8 +526,8 @@ declare_features! ( (incomplete, generic_const_parameter_types, "1.87.0", Some(137626)), /// Allows any generic constants being used as pattern type range ends (incomplete, generic_pattern_types, "1.86.0", Some(136574)), - /// Allows registering static items globally, possibly across crates, to iterate over at runtime. - (unstable, global_registration, "1.80.0", Some(125119)), + /// Allows the creation of crate local distributed slices, slices where the elements can be added all throughout the crate + (unstable, crate_local_distributed_slice, "CURRENT_RUSTC_VERSION", Some(125119)), /// Allows using guards in patterns. (incomplete, guard_patterns, "1.85.0", Some(129967)), /// Allows using `..=X` as a patterns in slices. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index ae94169b01dc2..694ef0b098390 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -751,6 +751,7 @@ symbols! { cr, crate_in_paths, crate_local, + crate_local_distributed_slice, crate_name, crate_type, crate_visibility_modifier, @@ -1086,7 +1087,6 @@ symbols! { global_alloc_ty, global_allocator, global_asm, - global_registration, globs, gt, guard_patterns, From 9f66c467d194f3443d0a55e489016936132a1ac3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Wed, 28 May 2025 11:09:56 +0200 Subject: [PATCH 02/10] add registry macro --- compiler/rustc_ast/src/ast.rs | 14 +++++++++ compiler/rustc_ast/src/visit.rs | 4 ++- compiler/rustc_ast_lowering/src/item.rs | 2 ++ .../rustc_ast_pretty/src/pprust/state/item.rs | 8 +++++ .../src/distributed_slice.rs | 31 +++++++++++++++++++ compiler/rustc_builtin_macros/src/lib.rs | 2 ++ compiler/rustc_builtin_macros/src/test.rs | 2 ++ compiler/rustc_expand/src/build.rs | 2 ++ compiler/rustc_feature/src/unstable.rs | 4 +-- compiler/rustc_parse/src/parser/item.rs | 14 ++++++++- compiler/rustc_resolve/src/def_collector.rs | 1 + compiler/rustc_span/src/symbol.rs | 1 + library/core/src/macros/mod.rs | 10 ++++++ library/core/src/prelude/v1.rs | 4 +++ library/std/src/prelude/v1.rs | 4 +++ .../create_slice.rs | 7 +++++ .../create_slice.stderr | 17 ++++++++++ ...ure-gate-crate-local-distributed-slice.rs} | 0 ...gate-crate-local-distributed-slice.stderr} | 0 19 files changed, 123 insertions(+), 4 deletions(-) create mode 100644 compiler/rustc_builtin_macros/src/distributed_slice.rs create mode 100644 tests/ui/crate_local_distributed_slice/create_slice.rs create mode 100644 tests/ui/crate_local_distributed_slice/create_slice.stderr rename tests/ui/feature-gates/{feature-gate-global-registration.rs => feature-gate-crate-local-distributed-slice.rs} (100%) rename tests/ui/feature-gates/{feature-gate-global-registration.stderr => feature-gate-crate-local-distributed-slice.stderr} (100%) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 7b103126e4599..5fb2817e39290 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3614,6 +3614,18 @@ pub struct DelegationMac { pub body: Option>, } +#[derive(Clone, Encodable, Decodable, Debug, Default)] +pub enum DistributedSlice { + /// This const or static has nothing to do with global registration whatsoever + #[default] + None, + /// This const or static declares a global registry that can be added to + Declaration(Span), + /// This const (we never do this to statics) represents an addition to a global registry + /// declared somewhere else. + Addition { declaration: Path }, +} + #[derive(Clone, Encodable, Decodable, Debug)] pub struct StaticItem { pub ident: Ident, @@ -3622,6 +3634,7 @@ pub struct StaticItem { pub mutability: Mutability, pub expr: Option>, pub define_opaque: Option>, + pub distributed_slice: DistributedSlice, } #[derive(Clone, Encodable, Decodable, Debug)] @@ -3632,6 +3645,7 @@ pub struct ConstItem { pub ty: P, pub expr: Option>, pub define_opaque: Option>, + pub distributed_slice: DistributedSlice, } // Adding a new variant? Please update `test_item` in `tests/ui/macros/stringify.rs`. diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index e1c2dd053242c..d7590889674b6 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -451,6 +451,7 @@ macro_rules! common_visitor_and_walkers { mutability: _, expr, define_opaque, + distributed_slice: _, }) => { try_visit!(vis.visit_ident(ident)); try_visit!(vis.visit_ty(ty)); @@ -614,7 +615,7 @@ macro_rules! common_visitor_and_walkers { } fn walk_const_item<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, item: &$($lt)? $($mut)? ConstItem) $(-> >::Result)? { - let ConstItem { defaultness, ident, generics, ty, expr, define_opaque } = item; + let ConstItem { defaultness, ident, generics, ty, expr, define_opaque, distributed_slice: _ } = item; try_visit!(visit_defaultness(vis, defaultness)); try_visit!(vis.visit_ident(ident)); try_visit!(vis.visit_generics(generics)); @@ -739,6 +740,7 @@ macro_rules! common_visitor_and_walkers { expr, safety: _, define_opaque, + distributed_slice: _, }) => { try_visit!(vis.visit_ident(ident)); try_visit!(vis.visit_ty(ty)); diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index d3aacaa15a8c5..6a3176d00bae6 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -175,6 +175,7 @@ impl<'hir> LoweringContext<'_, 'hir> { mutability: m, expr: e, define_opaque, + distributed_slice, }) => { let ident = self.lower_ident(*ident); let (ty, body_id) = @@ -660,6 +661,7 @@ impl<'hir> LoweringContext<'_, 'hir> { expr: _, safety, define_opaque, + distributed_slice, }) => { let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy)); diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 3638eb31c6186..b77b792c8099e 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -45,6 +45,8 @@ impl<'a> State<'a> { expr, safety, define_opaque, + // FIXME(gr) pretty print global registry + distributed_slice: _, }) => self.print_item_const( *ident, Some(*mutability), @@ -195,7 +197,9 @@ impl<'a> State<'a> { mutability: mutbl, expr: body, define_opaque, + distributed_slice: _, }) => { + // FIXME(gr): pretty print global registry self.print_safety(*safety); self.print_item_const( *ident, @@ -216,7 +220,9 @@ impl<'a> State<'a> { ty, expr, define_opaque, + distributed_slice: _, }) => { + // FIXME(gr): pretty print global registry self.print_item_const( *ident, None, @@ -565,6 +571,8 @@ impl<'a> State<'a> { ty, expr, define_opaque, + // FIXME(gr) pretty print global registry + distributed_slice: _, }) => { self.print_item_const( *ident, diff --git a/compiler/rustc_builtin_macros/src/distributed_slice.rs b/compiler/rustc_builtin_macros/src/distributed_slice.rs new file mode 100644 index 0000000000000..8e2bfac4778e2 --- /dev/null +++ b/compiler/rustc_builtin_macros/src/distributed_slice.rs @@ -0,0 +1,31 @@ +use rustc_ast::{DistributedSlice, ItemKind, ast}; +use rustc_expand::base::{Annotatable, ExtCtxt}; +use rustc_span::Span; + +pub(crate) fn distributed_slice( + _ecx: &mut ExtCtxt<'_>, + span: Span, + _meta_item: &ast::MetaItem, + mut orig_item: Annotatable, +) -> Vec { + // TODO: FIXME(gr) + // FIXME(gr): check item + + let Annotatable::Item(item) = &mut orig_item else { + panic!("expected `#[distributed_slice]` on an item") + }; + + match &mut item.kind { + ItemKind::Static(static_item) => { + static_item.distributed_slice = DistributedSlice::Declaration(span); + } + ItemKind::Const(const_item) => { + const_item.distributed_slice = DistributedSlice::Declaration(span); + } + other => { + panic!("expected `#[distributed_slice]` on a const or static item, not {other:?}"); + } + } + + vec![orig_item] +} diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 667d90429f287..1edbe48923ae4 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -41,6 +41,7 @@ mod concat_idents; mod define_opaque; mod derive; mod deriving; +mod distributed_slice; mod edition_panic; mod env; mod errors; @@ -121,6 +122,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { global_allocator: global_allocator::expand, test: test::expand_test, test_case: test::expand_test_case, + distributed_slice: distributed_slice::distributed_slice, } register_derive! { diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index 1cef4f9514cd7..f914943d341e3 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -377,6 +377,8 @@ pub(crate) fn expand_test_or_bench( ], ), // } ), + // FIXME(gr) tests should be GR + distributed_slice: Default::default(), } .into(), ), diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 14b8cc90d97d6..39ea02ce81b73 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -700,6 +700,7 @@ impl<'a> ExtCtxt<'a> { mutability, expr: Some(expr), define_opaque: None, + distributed_slice: Default::default(), } .into(), ), @@ -726,6 +727,7 @@ impl<'a> ExtCtxt<'a> { ty, expr: Some(expr), define_opaque: None, + distributed_slice: Default::default(), } .into(), ), diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 01f588ad78e55..af620162540ad 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -454,6 +454,8 @@ declare_features! ( /// Allows function attribute `#[coverage(on/off)]`, to control coverage /// instrumentation of that function. (unstable, coverage_attribute, "1.74.0", Some(84605)), + /// Allows the creation of crate local distributed slices, slices where the elements can be added all throughout the crate + (unstable, crate_local_distributed_slice, "CURRENT_RUSTC_VERSION", Some(125119)), /// Allows non-builtin attributes in inner attribute position. (unstable, custom_inner_attributes, "1.30.0", Some(54726)), /// Allows custom test frameworks with `#![test_runner]` and `#[test_case]`. @@ -526,8 +528,6 @@ declare_features! ( (incomplete, generic_const_parameter_types, "1.87.0", Some(137626)), /// Allows any generic constants being used as pattern type range ends (incomplete, generic_pattern_types, "1.86.0", Some(136574)), - /// Allows the creation of crate local distributed slices, slices where the elements can be added all throughout the crate - (unstable, crate_local_distributed_slice, "CURRENT_RUSTC_VERSION", Some(125119)), /// Allows using guards in patterns. (incomplete, guard_patterns, "1.85.0", Some(129967)), /// Allows using `..=X` as a patterns in slices. diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index c7b0eb11e5a03..32b57a38cb00e 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -260,6 +260,7 @@ impl<'a> Parser<'a> { ty, expr, define_opaque: None, + distributed_slice: Default::default(), })) } } else if self.check_keyword(exp!(Trait)) || self.check_auto_or_unsafe_trait_item() { @@ -966,6 +967,7 @@ impl<'a> Parser<'a> { mutability: _, expr, define_opaque, + distributed_slice, }) => { self.dcx().emit_err(errors::AssociatedStaticItemNotAllowed { span }); AssocItemKind::Const(Box::new(ConstItem { @@ -975,6 +977,7 @@ impl<'a> Parser<'a> { ty, expr, define_opaque, + distributed_slice, })) } _ => return self.error_bad_item_kind(span, &kind, "`trait`s or `impl`s"), @@ -1241,6 +1244,7 @@ impl<'a> Parser<'a> { expr, safety: Safety::Default, define_opaque: None, + distributed_slice: Default::default(), })) } _ => return self.error_bad_item_kind(span, &kind, "`extern` blocks"), @@ -1398,7 +1402,15 @@ impl<'a> Parser<'a> { self.expect_semi()?; - let item = StaticItem { ident, ty, safety, mutability, expr, define_opaque: None }; + let item = StaticItem { + ident, + ty, + safety, + mutability, + expr, + define_opaque: None, + distributed_slice: Default::default(), + }; Ok(ItemKind::Static(Box::new(item))) } diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 25485be562269..041208d65e305 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -246,6 +246,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { expr: _, safety, define_opaque: _, + distributed_slice: _, }) => { let safety = match safety { ast::Safety::Unsafe(_) | ast::Safety::Default => hir::Safety::Unsafe, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 694ef0b098390..1525499a7835e 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -833,6 +833,7 @@ symbols! { discriminant_value, disjoint_bitor, dispatch_from_dyn, + distributed_slice, div, div_assign, diverging_block_default, diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index e70a1dab6e9a9..0b639a996e98e 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1804,4 +1804,14 @@ pub(crate) mod builtin { pub macro deref($pat:pat) { builtin # deref($pat) } + + /// Create a global registry. + /// + // FIXME(gr): docs + #[unstable(feature = "crate_local_distributed_slice", issue = "125119")] + #[rustc_builtin_macro] + #[cfg(not(bootstrap))] + pub macro distributed_slice($item:item) { + /* compiler built-in */ + } } diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/v1.rs index 8f1b5275871e6..fcdf4d56d445c 100644 --- a/library/core/src/prelude/v1.rs +++ b/library/core/src/prelude/v1.rs @@ -81,6 +81,10 @@ pub use crate::macros::builtin::{ alloc_error_handler, bench, derive, global_allocator, test, test_case, }; +#[unstable(feature = "crate_local_distributed_slice", issue = "125119")] +#[cfg(not(bootstrap))] +pub use crate::macros::builtin::distributed_slice; + #[unstable(feature = "derive_const", issue = "none")] pub use crate::macros::builtin::derive_const; diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs index c15d8c40085a5..4d1d728eb9d74 100644 --- a/library/std/src/prelude/v1.rs +++ b/library/std/src/prelude/v1.rs @@ -68,6 +68,10 @@ pub use core::prelude::v1::{ alloc_error_handler, bench, derive, global_allocator, test, test_case, }; +#[unstable(feature = "crate_local_distributed_slice", issue = "125119")] +#[cfg(not(bootstrap))] +pub use core::prelude::v1::distributed_slice; + #[unstable(feature = "derive_const", issue = "none")] pub use core::prelude::v1::derive_const; diff --git a/tests/ui/crate_local_distributed_slice/create_slice.rs b/tests/ui/crate_local_distributed_slice/create_slice.rs new file mode 100644 index 0000000000000..e19f672e6687d --- /dev/null +++ b/tests/ui/crate_local_distributed_slice/create_slice.rs @@ -0,0 +1,7 @@ +#![feature(crate_local_distributed_slice)] +// @build-pass + +#[distributed_slice(crate)] +const MEOWS: [&str; _]; + +fn main() {} diff --git a/tests/ui/crate_local_distributed_slice/create_slice.stderr b/tests/ui/crate_local_distributed_slice/create_slice.stderr new file mode 100644 index 0000000000000..15baba2d8fd66 --- /dev/null +++ b/tests/ui/crate_local_distributed_slice/create_slice.stderr @@ -0,0 +1,17 @@ +error: free constant item without body + --> $DIR/create_slice.rs:5:1 + | +LL | const MEOWS: [&str; _]; + | ^^^^^^^^^^^^^^^^^^^^^^- + | | + | help: provide a definition for the constant: `= ;` + +error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants + --> $DIR/create_slice.rs:5:21 + | +LL | const MEOWS: [&str; _]; + | ^ not allowed in type signatures + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0121`. diff --git a/tests/ui/feature-gates/feature-gate-global-registration.rs b/tests/ui/feature-gates/feature-gate-crate-local-distributed-slice.rs similarity index 100% rename from tests/ui/feature-gates/feature-gate-global-registration.rs rename to tests/ui/feature-gates/feature-gate-crate-local-distributed-slice.rs diff --git a/tests/ui/feature-gates/feature-gate-global-registration.stderr b/tests/ui/feature-gates/feature-gate-crate-local-distributed-slice.stderr similarity index 100% rename from tests/ui/feature-gates/feature-gate-global-registration.stderr rename to tests/ui/feature-gates/feature-gate-crate-local-distributed-slice.stderr From d252f6d671e12d3e457316a5c27d08db121f12b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Wed, 28 May 2025 17:05:00 +0200 Subject: [PATCH 03/10] allow registry items to have no body --- compiler/rustc_ast_passes/src/ast_validation.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index d6fe04d2994b5..19bf37e9210ab 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1084,9 +1084,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> { _ => visit::walk_item(self, item), } } - ItemKind::Const(box ConstItem { defaultness, expr, .. }) => { + ItemKind::Const(box ConstItem { defaultness, expr, distributed_slice, .. }) => { self.check_defaultness(item.span, *defaultness); - if expr.is_none() { + + // declarations of global registries have no body deliberately - items are added + // later using global registry additions + if expr.is_none() && !matches!(distributed_slice, DistributedSlice::Declaration(_)) + { self.dcx().emit_err(errors::ConstWithoutBody { span: item.span, replace_span: self.ending_semi_or_hi(item.span), @@ -1094,13 +1098,16 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } visit::walk_item(self, item); } - ItemKind::Static(box StaticItem { expr, safety, .. }) => { + ItemKind::Static(box StaticItem { expr, safety, distributed_slice, .. }) => { self.check_item_safety(item.span, *safety); if matches!(safety, Safety::Unsafe(_)) { self.dcx().emit_err(errors::UnsafeStatic { span: item.span }); } - if expr.is_none() { + // declarations of global registries have no body deliberately - items are added + // later using global registry additions + if expr.is_none() && !matches!(distributed_slice, DistributedSlice::Declaration(_)) + { self.dcx().emit_err(errors::StaticWithoutBody { span: item.span, replace_span: self.ending_semi_or_hi(item.span), From 2446c323a72fe0c941c16c4f6f206e40b833e912 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Thu, 29 May 2025 10:55:24 +0200 Subject: [PATCH 04/10] propagate spans of registries down to hir and remove placeholder type errors --- compiler/rustc_ast_lowering/src/item.rs | 35 +++++++++++++++++-- compiler/rustc_hir/src/hir.rs | 34 +++++++++++------- compiler/rustc_hir/src/intravisit.rs | 4 +-- .../rustc_hir_analysis/src/check/wfcheck.rs | 4 +-- compiler/rustc_hir_analysis/src/collect.rs | 2 +- .../src/collect/resolve_bound_vars.rs | 2 +- .../rustc_hir_analysis/src/collect/type_of.rs | 4 +-- .../rustc_hir_analysis/src/hir_wf_check.rs | 4 +-- compiler/rustc_hir_pretty/src/lib.rs | 4 +-- compiler/rustc_hir_typeck/src/demand.rs | 4 +-- compiler/rustc_hir_typeck/src/pat.rs | 2 +- compiler/rustc_lint/src/context.rs | 3 +- compiler/rustc_lint/src/non_local_def.rs | 2 +- compiler/rustc_lint/src/types.rs | 4 +-- compiler/rustc_middle/src/hir/map.rs | 2 +- compiler/rustc_mir_build/src/builder/mod.rs | 2 +- compiler/rustc_passes/src/reachable.rs | 2 +- .../src/error_reporting/infer/mod.rs | 2 +- .../src/error_reporting/traits/suggestions.rs | 4 +-- 19 files changed, 79 insertions(+), 41 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 6a3176d00bae6..64149782deeda 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -5,7 +5,7 @@ use rustc_ast::*; use rustc_errors::ErrorGuaranteed; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; -use rustc_hir::{self as hir, HirId, LifetimeSource, PredicateOrigin}; +use rustc_hir::{self as hir, DistributedSlice, HirId, LifetimeSource, PredicateOrigin}; use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; use rustc_span::edit_distance::find_best_match_for_name; @@ -148,6 +148,22 @@ impl<'hir> LoweringContext<'_, 'hir> { self.arena.alloc(item) } + fn lower_distributed_slice( + &mut self, + distributed_slice: &ast::DistributedSlice, + ) -> DistributedSlice<'hir> { + match distributed_slice { + ast::DistributedSlice::None => DistributedSlice::None, + ast::DistributedSlice::Declaration(span) => { + DistributedSlice::Declaration(self.lower_span(*span)) + } + ast::DistributedSlice::Addition { declaration } => { + // DistributedSlice::Addition(self.lower_qpath(id, qself, p, param_mode, allow_return_type_notation, itctx, modifiers)) + todo!() + } + } + } + fn lower_item_kind( &mut self, span: Span, @@ -181,7 +197,13 @@ impl<'hir> LoweringContext<'_, 'hir> { let (ty, body_id) = self.lower_const_item(t, span, e.as_deref(), ImplTraitPosition::StaticTy); self.lower_define_opaque(hir_id, define_opaque); - hir::ItemKind::Static(*m, ident, ty, body_id) + hir::ItemKind::Static( + *m, + ident, + ty, + body_id, + self.lower_distributed_slice(distributed_slice), + ) } ItemKind::Const(box ast::ConstItem { ident, @@ -189,6 +211,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ty, expr, define_opaque, + distributed_slice, .. }) => { let ident = self.lower_ident(*ident); @@ -201,7 +224,13 @@ impl<'hir> LoweringContext<'_, 'hir> { }, ); self.lower_define_opaque(hir_id, &define_opaque); - hir::ItemKind::Const(ident, generics, ty, body_id) + hir::ItemKind::Const( + ident, + generics, + ty, + body_id, + self.lower_distributed_slice(distributed_slice), + ) } ItemKind::Fn(box Fn { sig: FnSig { decl, header, span: fn_sig_span }, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index b4fcc16c09c85..70d37985dccb3 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -4106,11 +4106,11 @@ impl<'hir> Item<'hir> { expect_use, (&'hir UsePath<'hir>, UseKind), ItemKind::Use(p, uk), (p, *uk); - expect_static, (Mutability, Ident, &'hir Ty<'hir>, BodyId), - ItemKind::Static(mutbl, ident, ty, body), (*mutbl, *ident, ty, *body); + expect_static, (Mutability, Ident, &'hir Ty<'hir>, BodyId, DistributedSlice<'hir>), + ItemKind::Static(mutbl, ident, ty, body, distributed_slice), (*mutbl, *ident, *ty, *body, *distributed_slice); - expect_const, (Ident, &'hir Generics<'hir>, &'hir Ty<'hir>, BodyId), - ItemKind::Const(ident, generics, ty, body), (*ident, generics, ty, *body); + expect_const, (Ident, &'hir Generics<'hir>, &'hir Ty<'hir>, BodyId, DistributedSlice<'hir>), + ItemKind::Const(ident, generics, ty, body, distributed_slice), (*ident, generics, *ty, *body, *distributed_slice); expect_fn, (Ident, &FnSig<'hir>, &'hir Generics<'hir>, BodyId), ItemKind::Fn { ident, sig, generics, body, .. }, (*ident, sig, generics, *body); @@ -4263,6 +4263,14 @@ impl FnHeader { } } +#[derive(Debug, Clone, Copy, HashStable_Generic, Default)] +pub enum DistributedSlice<'hir> { + #[default] + None, + Declaration(Span), + Addition(QPath<'hir>), +} + #[derive(Debug, Clone, Copy, HashStable_Generic)] pub enum ItemKind<'hir> { /// An `extern crate` item, with optional *original* crate name if the crate was renamed. @@ -4278,9 +4286,9 @@ pub enum ItemKind<'hir> { Use(&'hir UsePath<'hir>, UseKind), /// A `static` item. - Static(Mutability, Ident, &'hir Ty<'hir>, BodyId), + Static(Mutability, Ident, &'hir Ty<'hir>, BodyId, DistributedSlice<'hir>), /// A `const` item. - Const(Ident, &'hir Generics<'hir>, &'hir Ty<'hir>, BodyId), + Const(Ident, &'hir Generics<'hir>, &'hir Ty<'hir>, BodyId, DistributedSlice<'hir>), /// A function declaration. Fn { sig: FnSig<'hir>, @@ -4375,7 +4383,7 @@ impl ItemKind<'_> { Some(match self { ItemKind::Fn { generics, .. } | ItemKind::TyAlias(_, generics, _) - | ItemKind::Const(_, generics, _, _) + | ItemKind::Const(_, generics, _, _, _) | ItemKind::Enum(_, generics, _) | ItemKind::Struct(_, generics, _) | ItemKind::Union(_, generics, _) @@ -4577,8 +4585,8 @@ impl<'hir> OwnerNode<'hir> { match self { OwnerNode::Item(Item { kind: - ItemKind::Static(_, _, _, body) - | ItemKind::Const(_, _, _, body) + ItemKind::Static(_, _, _, body, _) + | ItemKind::Const(_, _, _, body, _) | ItemKind::Fn { body, .. }, .. }) @@ -4803,8 +4811,8 @@ impl<'hir> Node<'hir> { match self { Node::Item(it) => match it.kind { ItemKind::TyAlias(_, _, ty) - | ItemKind::Static(_, _, ty, _) - | ItemKind::Const(_, _, ty, _) => Some(ty), + | ItemKind::Static(_, _, ty, _, _) + | ItemKind::Const(_, _, ty, _, _) => Some(ty), ItemKind::Impl(impl_item) => Some(&impl_item.self_ty), _ => None, }, @@ -4835,8 +4843,8 @@ impl<'hir> Node<'hir> { Node::Item(Item { owner_id, kind: - ItemKind::Const(_, _, _, body) - | ItemKind::Static(.., body) + ItemKind::Const(_, _, _, body, _) + | ItemKind::Static(.., body, _) | ItemKind::Fn { body, .. }, .. }) diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 1fd44e44b9ce0..b1ec45e2d371b 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -545,12 +545,12 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V:: UseKind::Glob | UseKind::ListStem => {} } } - ItemKind::Static(_, ident, ref typ, body) => { + ItemKind::Static(_, ident, ref typ, body, _ds) => { try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_ty_unambig(typ)); try_visit!(visitor.visit_nested_body(body)); } - ItemKind::Const(ident, ref generics, ref typ, body) => { + ItemKind::Const(ident, ref generics, ref typ, body, _ds) => { try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_generics(generics)); try_visit!(visitor.visit_ty_unambig(typ)); diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index b764b714fe17e..9060a667a800e 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -297,10 +297,10 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) -> Result<() hir::ItemKind::Fn { ident, sig, .. } => { check_item_fn(tcx, def_id, ident, item.span, sig.decl) } - hir::ItemKind::Static(_, _, ty, _) => { + hir::ItemKind::Static(_, _, ty, _, _) => { check_static_item(tcx, def_id, ty.span, UnsizedHandling::Forbid) } - hir::ItemKind::Const(_, _, ty, _) => check_const_item(tcx, def_id, ty.span, item.span), + hir::ItemKind::Const(_, _, ty, _, _) => check_const_item(tcx, def_id, ty.span, item.span), hir::ItemKind::Struct(_, generics, _) => { let res = check_type_defn(tcx, item, false); check_variances_for_type_defn(tcx, item, generics); diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index a649e7d67af37..a866346d96efa 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -762,7 +762,7 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { tcx.ensure_ok().predicates_of(def_id); } - hir::ItemKind::Static(_, _, ty, _) | hir::ItemKind::Const(_, _, ty, _) => { + hir::ItemKind::Static(_, _, ty, _, _) | hir::ItemKind::Const(_, _, ty, _, _) => { tcx.ensure_ok().generics_of(def_id); tcx.ensure_ok().type_of(def_id); tcx.ensure_ok().predicates_of(def_id); diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index d45f0475e9910..1820c6225fd8c 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -635,7 +635,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { intravisit::walk_item(self, item); } hir::ItemKind::TyAlias(_, generics, _) - | hir::ItemKind::Const(_, generics, _, _) + | hir::ItemKind::Const(_, generics, _, _, _) | hir::ItemKind::Enum(_, generics, _) | hir::ItemKind::Struct(_, generics, _) | hir::ItemKind::Union(_, generics, _) diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 141d96b57e579..07a6f19babb97 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -206,7 +206,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ }, Node::Item(item) => match item.kind { - ItemKind::Static(_, ident, ty, body_id) => { + ItemKind::Static(_, ident, ty, body_id, distributed_slice) => { if ty.is_suggestable_infer_ty() { infer_placeholder_type( icx.lowerer(), @@ -220,7 +220,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ icx.lower_ty(ty) } } - ItemKind::Const(ident, _, ty, body_id) => { + ItemKind::Const(ident, _, ty, body_id, distributed_slice) => { if ty.is_suggestable_infer_ty() { infer_placeholder_type( icx.lowerer(), diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs index 4633f3951a784..ded09826b8d9f 100644 --- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs @@ -146,8 +146,8 @@ fn diagnostic_hir_wf_check<'tcx>( }, hir::Node::Item(item) => match item.kind { hir::ItemKind::TyAlias(_, _, ty) - | hir::ItemKind::Static(_, _, ty, _) - | hir::ItemKind::Const(_, _, ty, _) => vec![ty], + | hir::ItemKind::Static(_, _, ty, _, _) + | hir::ItemKind::Const(_, _, ty, _, _) => vec![ty], hir::ItemKind::Impl(impl_) => match &impl_.of_trait { Some(t) => t .path diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index b23b3125c59a3..64e6e6812ebac 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -593,7 +593,7 @@ impl<'a> State<'a> { self.end(ib); self.end(cb); } - hir::ItemKind::Static(m, ident, ty, expr) => { + hir::ItemKind::Static(m, ident, ty, expr, distributed_slice) => { let (cb, ib) = self.head("static"); if m.is_mut() { self.word_space("mut"); @@ -609,7 +609,7 @@ impl<'a> State<'a> { self.word(";"); self.end(cb); } - hir::ItemKind::Const(ident, generics, ty, expr) => { + hir::ItemKind::Const(ident, generics, ty, expr, distributed_slice) => { let (cb, ib) = self.head("const"); self.print_ident(ident); self.print_generic_params(generics.params); diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 152c88ad92a5f..253361ed552db 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -722,8 +722,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { )) => { if let Some(hir::Node::Item(hir::Item { kind: - hir::ItemKind::Static(_, ident, ty, _) - | hir::ItemKind::Const(ident, _, ty, _), + hir::ItemKind::Static(_, ident, ty, _, _) + | hir::ItemKind::Const(ident, _, ty, _, _), .. })) = self.tcx.hir_get_if_local(*def_id) { diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 17d48184dd971..84f629e30ebd4 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -1492,7 +1492,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match opt_def_id { Some(def_id) => match self.tcx.hir_get_if_local(def_id) { Some(hir::Node::Item(hir::Item { - kind: hir::ItemKind::Const(_, _, _, body_id), + kind: hir::ItemKind::Const(_, _, _, body_id, _), .. })) => match self.tcx.hir_node(body_id.hir_id) { hir::Node::Expr(expr) => { diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 5679d4566dcd4..4da3cda333488 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -932,7 +932,8 @@ impl<'tcx> LateContext<'tcx> { .. }) => *init, hir::Node::Item(item) => match item.kind { - hir::ItemKind::Const(.., body_id) | hir::ItemKind::Static(.., body_id) => { + hir::ItemKind::Const(.., body_id, _) + | hir::ItemKind::Static(.., body_id, _) => { Some(self.tcx.hir_body(body_id).value) } _ => None, diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs index b877f909fc029..63022e382e550 100644 --- a/compiler/rustc_lint/src/non_local_def.rs +++ b/compiler/rustc_lint/src/non_local_def.rs @@ -183,7 +183,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { && parent_opt_item_name != Some(kw::Underscore) && let Some(parent) = parent.as_local() && let Node::Item(item) = cx.tcx.hir_node_by_def_id(parent) - && let ItemKind::Const(ident, _, ty, _) = item.kind + && let ItemKind::Const(ident, _, ty, _, _) = item.kind && let TyKind::Tup(&[]) = ty.kind { Some(ident.span) diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 77dc63351136c..79b8f815d4802 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1735,8 +1735,8 @@ impl ImproperCTypesDefinitions { impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDefinitions { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { match item.kind { - hir::ItemKind::Static(_, _, ty, _) - | hir::ItemKind::Const(_, _, ty, _) + hir::ItemKind::Static(_, _, ty, _, _) + | hir::ItemKind::Const(_, _, ty, _, _) | hir::ItemKind::TyAlias(_, _, ty) => { self.check_ty_maybe_containing_foreign_fnptr( cx, diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index 3de97c8c0d99e..693d5e977dbc6 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -920,7 +920,7 @@ impl<'tcx> TyCtxt<'tcx> { }) => until_within(*outer_span, generics.where_clause_span), // Constants and Statics. Node::Item(Item { - kind: ItemKind::Const(_, _, ty, _) | ItemKind::Static(_, _, ty, _), + kind: ItemKind::Const(_, _, ty, _, _) | ItemKind::Static(_, _, ty, _, _), span: outer_span, .. }) diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs index 3d5f6f4cf451e..8f52e79d54842 100644 --- a/compiler/rustc_mir_build/src/builder/mod.rs +++ b/compiler/rustc_mir_build/src/builder/mod.rs @@ -558,7 +558,7 @@ fn construct_const<'a, 'tcx>( // Figure out what primary body this item has. let (span, const_ty_span) = match tcx.hir_node(hir_id) { Node::Item(hir::Item { - kind: hir::ItemKind::Static(_, _, ty, _) | hir::ItemKind::Const(_, _, ty, _), + kind: hir::ItemKind::Static(_, _, ty, _, _) | hir::ItemKind::Const(_, _, ty, _, _), span, .. }) diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index 7e15267a953ba..ea35190567189 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -204,7 +204,7 @@ impl<'tcx> ReachableContext<'tcx> { } } - hir::ItemKind::Const(_, _, _, init) => { + hir::ItemKind::Const(_, _, _, init, distributed_slice) => { // Only things actually ending up in the final constant value are reachable // for codegen. Everything else is only needed during const-eval, so even if // const-eval happens in a downstream crate, all they need is diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index 8e2137da6552d..f4a7d88137d81 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -2026,7 +2026,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } LetVisitor { span }.visit_body(body).break_value() } - hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(_, _, ty, _), .. }) => { + hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(_, _, ty, _, _), .. }) => { Some(&ty.peel_refs().kind) } _ => None, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index c4f1f7d712a7c..ad84c463753b0 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -358,7 +358,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { | hir::ItemKind::Impl(hir::Impl { generics, .. }) | hir::ItemKind::Fn { generics, .. } | hir::ItemKind::TyAlias(_, generics, _) - | hir::ItemKind::Const(_, generics, _, _) + | hir::ItemKind::Const(_, generics, _, _, _) | hir::ItemKind::TraitAlias(_, generics, _), .. }) @@ -418,7 +418,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { | hir::ItemKind::Impl(hir::Impl { generics, .. }) | hir::ItemKind::Fn { generics, .. } | hir::ItemKind::TyAlias(_, generics, _) - | hir::ItemKind::Const(_, generics, _, _) + | hir::ItemKind::Const(_, generics, _, _, _) | hir::ItemKind::TraitAlias(_, generics, _), .. }) if !param_ty => { From 29f698f18a1ec484c543b69fc687a415aa3d38f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Thu, 29 May 2025 11:15:29 +0200 Subject: [PATCH 05/10] add register macro --- compiler/rustc_ast/src/ast.rs | 2 +- compiler/rustc_ast/src/visit.rs | 17 ++++- compiler/rustc_ast_lowering/src/item.rs | 14 +++- .../src/distributed_slice.rs | 75 +++++++++++++++++-- compiler/rustc_builtin_macros/src/lib.rs | 1 + compiler/rustc_parse/src/parser/mod.rs | 2 +- compiler/rustc_parse/src/parser/path.rs | 4 +- compiler/rustc_span/src/symbol.rs | 1 + library/core/src/macros/mod.rs | 10 +++ library/core/src/prelude/v1.rs | 2 +- library/std/src/prelude/v1.rs | 2 +- .../create_slice.rs | 6 +- .../create_slice.stderr | 20 +++-- 13 files changed, 131 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 5fb2817e39290..f071cd2a0d3a9 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3623,7 +3623,7 @@ pub enum DistributedSlice { Declaration(Span), /// This const (we never do this to statics) represents an addition to a global registry /// declared somewhere else. - Addition { declaration: Path }, + Addition { declaration: Path, id: NodeId }, } #[derive(Clone, Encodable, Decodable, Debug)] diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index d7590889674b6..9f34f4b88f64f 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -451,11 +451,16 @@ macro_rules! common_visitor_and_walkers { mutability: _, expr, define_opaque, - distributed_slice: _, + distributed_slice, }) => { try_visit!(vis.visit_ident(ident)); try_visit!(vis.visit_ty(ty)); visit_opt!(vis, visit_expr, expr); + match distributed_slice { + DistributedSlice::None => {} + DistributedSlice::Declaration(span) => try_visit!(visit_span(vis, span)), + DistributedSlice::Addition { declaration, id } => try_visit!(vis.visit_path(declaration$(${ignore($lt)}, *id)?)), + } walk_define_opaques(vis, define_opaque) } ItemKind::Const(item) => { @@ -615,12 +620,20 @@ macro_rules! common_visitor_and_walkers { } fn walk_const_item<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, item: &$($lt)? $($mut)? ConstItem) $(-> >::Result)? { - let ConstItem { defaultness, ident, generics, ty, expr, define_opaque, distributed_slice: _ } = item; + let ConstItem { defaultness, ident, generics, ty, expr, define_opaque, distributed_slice } = item; try_visit!(visit_defaultness(vis, defaultness)); try_visit!(vis.visit_ident(ident)); try_visit!(vis.visit_generics(generics)); try_visit!(vis.visit_ty(ty)); visit_opt!(vis, visit_expr, expr); + + match distributed_slice { + DistributedSlice::None => {} + DistributedSlice::Declaration(span) => try_visit!(visit_span(vis, span)), + DistributedSlice::Addition { declaration, id } => try_visit!(vis.visit_path(declaration$(${ignore($lt)}, *id)?)), + } + + walk_define_opaques(vis, define_opaque) } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 64149782deeda..97f71308475d9 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -22,6 +22,7 @@ use super::{ AstOwner, FnDeclKind, ImplTraitContext, ImplTraitPosition, LoweringContext, ParamMode, ResolverAstLoweringExt, }; +use crate::AllowReturnTypeNotation; pub(super) struct ItemLowerer<'a, 'hir> { pub(super) tcx: TyCtxt<'hir>, @@ -157,9 +158,16 @@ impl<'hir> LoweringContext<'_, 'hir> { ast::DistributedSlice::Declaration(span) => { DistributedSlice::Declaration(self.lower_span(*span)) } - ast::DistributedSlice::Addition { declaration } => { - // DistributedSlice::Addition(self.lower_qpath(id, qself, p, param_mode, allow_return_type_notation, itctx, modifiers)) - todo!() + ast::DistributedSlice::Addition { declaration, id } => { + DistributedSlice::Addition(self.lower_qpath( + *id, + &None, + declaration, + ParamMode::Optional, + AllowReturnTypeNotation::No, + ImplTraitContext::Disallowed(ImplTraitPosition::Path), + None, + )) } } } diff --git a/compiler/rustc_builtin_macros/src/distributed_slice.rs b/compiler/rustc_builtin_macros/src/distributed_slice.rs index 8e2bfac4778e2..cd95c1987a29a 100644 --- a/compiler/rustc_builtin_macros/src/distributed_slice.rs +++ b/compiler/rustc_builtin_macros/src/distributed_slice.rs @@ -1,7 +1,23 @@ -use rustc_ast::{DistributedSlice, ItemKind, ast}; -use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_span::Span; +use rustc_ast::ptr::P; +use rustc_ast::tokenstream::TokenStream; +use rustc_ast::{ + ConstItem, DUMMY_NODE_ID, Defaultness, DistributedSlice, Expr, Generics, Item, ItemKind, Path, + Ty, TyKind, ast, +}; +use rustc_errors::PResult; +use rustc_expand::base::{ + Annotatable, DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult, +}; +use rustc_parse::exp; +use rustc_parse::parser::{Parser, PathStyle}; +use rustc_span::{Ident, Span, kw}; +use smallvec::smallvec; +use thin_vec::ThinVec; +/// ```rust +/// #[distributed_slice(crate)] +/// const MEOWS: [&str; _]; +/// ``` pub(crate) fn distributed_slice( _ecx: &mut ExtCtxt<'_>, span: Span, @@ -12,7 +28,7 @@ pub(crate) fn distributed_slice( // FIXME(gr): check item let Annotatable::Item(item) = &mut orig_item else { - panic!("expected `#[distributed_slice]` on an item") + panic!("expected `#[distributed_slice(crate)]` on an item") }; match &mut item.kind { @@ -23,9 +39,58 @@ pub(crate) fn distributed_slice( const_item.distributed_slice = DistributedSlice::Declaration(span); } other => { - panic!("expected `#[distributed_slice]` on a const or static item, not {other:?}"); + panic!( + "expected `#[distributed_slice(crate)]` on a const or static item, not {other:?}" + ); } } vec![orig_item] } + +fn parse_element(mut p: Parser<'_>) -> PResult<'_, (Path, P)> { + let ident = p.parse_path(PathStyle::Expr)?; + p.expect(exp![Comma])?; + let expr = p.parse_expr()?; + + // optional trailing comma + let _ = p.eat(exp![Comma]); + + Ok((ident, expr)) +} + +/// ```rust +/// distributed_slice_element!(MEOWS, "mrow"); +/// ``` +pub(crate) fn distributed_slice_element( + cx: &mut ExtCtxt<'_>, + span: Span, + tts: TokenStream, +) -> MacroExpanderResult<'static> { + let (path, expr) = match parse_element(cx.new_parser_from_tts(tts)) { + Ok((ident, expr)) => (ident, expr), + Err(err) => { + let guar = err.emit(); + return ExpandResult::Ready(DummyResult::any(span, guar)); + } + }; + + ExpandResult::Ready(MacEager::items(smallvec![P(Item { + attrs: ThinVec::new(), + id: DUMMY_NODE_ID, + span, + vis: ast::Visibility { kind: ast::VisibilityKind::Inherited, span, tokens: None }, + kind: ItemKind::Const(Box::new(ConstItem { + defaultness: Defaultness::Final, + ident: Ident { name: kw::Underscore, span }, + generics: Generics::default(), + // leave out the ty, we discover it when + // when name-resolving to the registry definition + ty: P(Ty { id: DUMMY_NODE_ID, kind: TyKind::Infer, span, tokens: None }), + expr: Some(expr), + define_opaque: None, + distributed_slice: DistributedSlice::Addition { declaration: path, id: DUMMY_NODE_ID } + })), + tokens: None + })])) +} diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 1edbe48923ae4..3b3d476ebd9f9 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -88,6 +88,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { concat_idents: concat_idents::expand_concat_idents, const_format_args: format::expand_format_args, core_panic: edition_panic::expand_panic, + distributed_slice_element: distributed_slice::distributed_slice_element, env: env::expand_env, file: source_util::expand_file, format_args: format::expand_format_args, diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index b2e902513672d..c154ea34f3b84 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -20,7 +20,7 @@ pub use diagnostics::AttemptLocalParseRecovery; pub(crate) use expr::ForbiddenLetReason; pub(crate) use item::FnParseMode; pub use pat::{CommaRecoveryMode, RecoverColon, RecoverComma}; -use path::PathStyle; +pub use path::PathStyle; use rustc_ast::ptr::P; use rustc_ast::token::{ self, IdentIsRaw, InvisibleOrigin, MetaVarKind, NtExprKind, NtPatKind, Token, TokenKind, diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 9bce2fa74caa2..95b995eb76461 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -25,7 +25,7 @@ use crate::parser::{CommaRecoveryMode, RecoverColon, RecoverComma}; /// Specifies how to parse a path. #[derive(Copy, Clone, PartialEq)] -pub(super) enum PathStyle { +pub enum PathStyle { /// In some contexts, notably in expressions, paths with generic arguments are ambiguous /// with something else. For example, in expressions `segment < ....` can be interpreted /// as a comparison and `segment ( ....` can be interpreted as a function call. @@ -149,7 +149,7 @@ impl<'a> Parser<'a> { true } - pub(super) fn parse_path(&mut self, style: PathStyle) -> PResult<'a, Path> { + pub fn parse_path(&mut self, style: PathStyle) -> PResult<'a, Path> { self.parse_path_inner(style, None) } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 1525499a7835e..0bd58ddecfcaf 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -834,6 +834,7 @@ symbols! { disjoint_bitor, dispatch_from_dyn, distributed_slice, + distributed_slice_element, div, div_assign, diverging_block_default, diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 0b639a996e98e..1a3370ba18206 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1814,4 +1814,14 @@ pub(crate) mod builtin { pub macro distributed_slice($item:item) { /* compiler built-in */ } + + /// Create a global registry. + /// + // FIXME(gr): docs + #[unstable(feature = "crate_local_distributed_slice", issue = "125119")] + #[rustc_builtin_macro] + #[cfg(not(bootstrap))] + pub macro distributed_slice_element($path:path, $expr:expr) { + /* compiler built-in */ + } } diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/v1.rs index fcdf4d56d445c..3e0f12b64eb57 100644 --- a/library/core/src/prelude/v1.rs +++ b/library/core/src/prelude/v1.rs @@ -83,7 +83,7 @@ pub use crate::macros::builtin::{ #[unstable(feature = "crate_local_distributed_slice", issue = "125119")] #[cfg(not(bootstrap))] -pub use crate::macros::builtin::distributed_slice; +pub use crate::macros::builtin::{distributed_slice, distributed_slice_element}; #[unstable(feature = "derive_const", issue = "none")] pub use crate::macros::builtin::derive_const; diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs index 4d1d728eb9d74..0a548ae7431bd 100644 --- a/library/std/src/prelude/v1.rs +++ b/library/std/src/prelude/v1.rs @@ -70,7 +70,7 @@ pub use core::prelude::v1::{ #[unstable(feature = "crate_local_distributed_slice", issue = "125119")] #[cfg(not(bootstrap))] -pub use core::prelude::v1::distributed_slice; +pub use core::prelude::v1::{distributed_slice, distributed_slice_element}; #[unstable(feature = "derive_const", issue = "none")] pub use core::prelude::v1::derive_const; diff --git a/tests/ui/crate_local_distributed_slice/create_slice.rs b/tests/ui/crate_local_distributed_slice/create_slice.rs index e19f672e6687d..3b6bee6f8fcd9 100644 --- a/tests/ui/crate_local_distributed_slice/create_slice.rs +++ b/tests/ui/crate_local_distributed_slice/create_slice.rs @@ -4,4 +4,8 @@ #[distributed_slice(crate)] const MEOWS: [&str; _]; -fn main() {} +distributed_slice_element!(MEOWS, "mrow"); + +fn main() { + println!("{MEOWS:?}"); +} diff --git a/tests/ui/crate_local_distributed_slice/create_slice.stderr b/tests/ui/crate_local_distributed_slice/create_slice.stderr index 15baba2d8fd66..3f7f39f594c01 100644 --- a/tests/ui/crate_local_distributed_slice/create_slice.stderr +++ b/tests/ui/crate_local_distributed_slice/create_slice.stderr @@ -1,17 +1,21 @@ -error: free constant item without body - --> $DIR/create_slice.rs:5:1 - | -LL | const MEOWS: [&str; _]; - | ^^^^^^^^^^^^^^^^^^^^^^- - | | - | help: provide a definition for the constant: `= ;` - error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants --> $DIR/create_slice.rs:5:21 | LL | const MEOWS: [&str; _]; | ^ not allowed in type signatures +error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants + --> $DIR/create_slice.rs:7:1 + | +LL | distributed_slice_element!(MEOWS, "mrow"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not allowed in type signatures + | +help: replace this with a fully-specified type + | +LL - distributed_slice_element!(MEOWS, "mrow"); +LL + &str; + | + error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0121`. From 2a4495a2d6d4e87b0f305df43903d1ca6015f079 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Thu, 29 May 2025 12:56:29 +0200 Subject: [PATCH 06/10] collecting registered items and typeck --- compiler/rustc_ast_lowering/src/block.rs | 2 +- compiler/rustc_ast_lowering/src/expr.rs | 23 ++-- compiler/rustc_ast_lowering/src/item.rs | 100 +++++++++++++----- compiler/rustc_ast_lowering/src/lib.rs | 59 +++++++---- compiler/rustc_ast_lowering/src/path.rs | 21 ++-- compiler/rustc_hir/src/hir.rs | 12 +-- compiler/rustc_hir_analysis/src/collect.rs | 2 + .../src/collect/distributed_slice.rs | 21 ++++ .../rustc_hir_analysis/src/collect/type_of.rs | 39 ++++++- compiler/rustc_hir_typeck/src/lib.rs | 18 ++++ compiler/rustc_middle/src/query/mod.rs | 5 + compiler/rustc_resolve/src/late.rs | 26 ++++- .../create_slice.rs | 2 +- 13 files changed, 258 insertions(+), 72 deletions(-) create mode 100644 compiler/rustc_hir_analysis/src/collect/distributed_slice.rs diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs index c3222b79e55c9..df34d6cb87a08 100644 --- a/compiler/rustc_ast_lowering/src/block.rs +++ b/compiler/rustc_ast_lowering/src/block.rs @@ -97,7 +97,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Let statements are allowed to have impl trait in bindings. let super_ = l.super_; let ty = l.ty.as_ref().map(|t| { - self.lower_ty(t, self.impl_trait_in_bindings_ctxt(ImplTraitPosition::Variable)) + self.lower_ty(t, self.impl_trait_in_bindings_ctxt(ImplTraitPosition::Variable), false) }); let init = l.kind.init().map(|init| self.lower_expr(init)); let hir_id = self.lower_node_id(l.id); diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 9f3aed9216c2d..5e0d00cf05c9d 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -106,7 +106,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ExprKind::ConstBlock(c) => hir::ExprKind::ConstBlock(self.lower_const_block(c)), ExprKind::Repeat(expr, count) => { let expr = self.lower_expr(expr); - let count = self.lower_array_length_to_const_arg(count); + let count = self.lower_array_length_to_const_arg(count, false); hir::ExprKind::Repeat(expr, count) } ExprKind::Tup(elts) => hir::ExprKind::Tup(self.lower_exprs(elts)), @@ -154,14 +154,20 @@ impl<'hir> LoweringContext<'_, 'hir> { } ExprKind::Cast(expr, ty) => { let expr = self.lower_expr(expr); - let ty = - self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast)); + let ty = self.lower_ty( + ty, + ImplTraitContext::Disallowed(ImplTraitPosition::Cast), + false, + ); hir::ExprKind::Cast(expr, ty) } ExprKind::Type(expr, ty) => { let expr = self.lower_expr(expr); - let ty = - self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast)); + let ty = self.lower_ty( + ty, + ImplTraitContext::Disallowed(ImplTraitPosition::Cast), + false, + ); hir::ExprKind::Type(expr, ty) } ExprKind::AddrOf(k, m, ohs) => { @@ -329,6 +335,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_ty( container, ImplTraitContext::Disallowed(ImplTraitPosition::OffsetOf), + false, ), self.arena.alloc_from_iter(fields.iter().map(|&ident| self.lower_ident(ident))), ), @@ -360,7 +367,11 @@ impl<'hir> LoweringContext<'_, 'hir> { *kind, self.lower_expr(expr), ty.as_ref().map(|ty| { - self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast)) + self.lower_ty( + ty, + ImplTraitContext::Disallowed(ImplTraitPosition::Cast), + false, + ) }), ), diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 97f71308475d9..94477f5f22e8d 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -22,7 +22,6 @@ use super::{ AstOwner, FnDeclKind, ImplTraitContext, ImplTraitPosition, LoweringContext, ParamMode, ResolverAstLoweringExt, }; -use crate::AllowReturnTypeNotation; pub(super) struct ItemLowerer<'a, 'hir> { pub(super) tcx: TyCtxt<'hir>, @@ -152,22 +151,28 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_distributed_slice( &mut self, distributed_slice: &ast::DistributedSlice, - ) -> DistributedSlice<'hir> { + ) -> DistributedSlice { match distributed_slice { ast::DistributedSlice::None => DistributedSlice::None, ast::DistributedSlice::Declaration(span) => { DistributedSlice::Declaration(self.lower_span(*span)) } ast::DistributedSlice::Addition { declaration, id } => { - DistributedSlice::Addition(self.lower_qpath( - *id, - &None, - declaration, - ParamMode::Optional, - AllowReturnTypeNotation::No, - ImplTraitContext::Disallowed(ImplTraitPosition::Path), - None, - )) + let Some(res) = self.resolver.get_partial_res(*id) else { + self.dcx().span_delayed_bug(declaration.span, "should have errored in resolve"); + return DistributedSlice::None; + }; + + let Some(did) = res.expect_full_res().opt_def_id() else { + self.dcx().span_delayed_bug(declaration.span, "should have errored in resolve"); + return DistributedSlice::None; + }; + + let Some(local) = did.as_local() else { + panic!("adding to slice outside local crate"); + }; + + DistributedSlice::Addition(local) } } } @@ -202,8 +207,13 @@ impl<'hir> LoweringContext<'_, 'hir> { distributed_slice, }) => { let ident = self.lower_ident(*ident); - let (ty, body_id) = - self.lower_const_item(t, span, e.as_deref(), ImplTraitPosition::StaticTy); + let (ty, body_id) = self.lower_const_item( + t, + span, + e.as_deref(), + ImplTraitPosition::StaticTy, + distributed_slice, + ); self.lower_define_opaque(hir_id, define_opaque); hir::ItemKind::Static( *m, @@ -228,7 +238,13 @@ impl<'hir> LoweringContext<'_, 'hir> { id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { - this.lower_const_item(ty, span, expr.as_deref(), ImplTraitPosition::ConstTy) + this.lower_const_item( + ty, + span, + expr.as_deref(), + ImplTraitPosition::ConstTy, + distributed_slice, + ) }, ); self.lower_define_opaque(hir_id, &define_opaque); @@ -339,6 +355,7 @@ impl<'hir> LoweringContext<'_, 'hir> { in_assoc_ty: false, }, }, + false, ), }, ); @@ -422,6 +439,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let lowered_ty = this.lower_ty( ty, ImplTraitContext::Disallowed(ImplTraitPosition::ImplSelf), + false, ); (trait_ref, lowered_ty) @@ -524,8 +542,13 @@ impl<'hir> LoweringContext<'_, 'hir> { span: Span, body: Option<&Expr>, impl_trait_position: ImplTraitPosition, + distributed_slice: &ast::DistributedSlice, ) -> (&'hir hir::Ty<'hir>, hir::BodyId) { - let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(impl_trait_position)); + let ty = self.lower_ty( + ty, + ImplTraitContext::Disallowed(impl_trait_position), + matches!(distributed_slice, ast::DistributedSlice::Declaration(..)), + ); (ty, self.lower_const_body(span, body)) } @@ -700,8 +723,11 @@ impl<'hir> LoweringContext<'_, 'hir> { define_opaque, distributed_slice, }) => { - let ty = - self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy)); + let ty = self.lower_ty( + ty, + ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy), + false, + ); let safety = self.lower_safety(*safety, hir::Safety::Unsafe); if define_opaque.is_some() { self.dcx().span_err(i.span, "foreign statics cannot define opaque types"); @@ -796,7 +822,8 @@ impl<'hir> LoweringContext<'_, 'hir> { &mut self, (index, f): (usize, &FieldDef), ) -> hir::FieldDef<'hir> { - let ty = self.lower_ty(&f.ty, ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy)); + let ty = + self.lower_ty(&f.ty, ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy), false); let hir_id = self.lower_node_id(f.id); self.lower_attrs(hir_id, &f.attrs, f.span); hir::FieldDef { @@ -834,8 +861,11 @@ impl<'hir> LoweringContext<'_, 'hir> { i.id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { - let ty = this - .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); + let ty = this.lower_ty( + ty, + ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy), + false, + ); let body = expr.as_ref().map(|x| this.lower_const_body(i.span, Some(x))); hir::TraitItemKind::Const(ty, body) @@ -931,6 +961,7 @@ impl<'hir> LoweringContext<'_, 'hir> { this.lower_ty( x, ImplTraitContext::Disallowed(ImplTraitPosition::AssocTy), + false, ) }); hir::TraitItemKind::Type( @@ -1027,8 +1058,11 @@ impl<'hir> LoweringContext<'_, 'hir> { i.id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { - let ty = this - .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); + let ty = this.lower_ty( + ty, + ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy), + false, + ); let body = this.lower_const_body(i.span, expr.as_deref()); this.lower_define_opaque(hir_id, &define_opaque); hir::ImplItemKind::Const(ty, body) @@ -1093,6 +1127,7 @@ impl<'hir> LoweringContext<'_, 'hir> { in_assoc_ty: true, }, }, + false, ); hir::ImplItemKind::Type(ty) } @@ -1921,8 +1956,11 @@ impl<'hir> LoweringContext<'_, 'hir> { }) => hir::WherePredicateKind::BoundPredicate(hir::WhereBoundPredicate { bound_generic_params: self .lower_generic_params(bound_generic_params, hir::GenericParamSource::Binder), - bounded_ty: self - .lower_ty(bounded_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Bound)), + bounded_ty: self.lower_ty( + bounded_ty, + ImplTraitContext::Disallowed(ImplTraitPosition::Bound), + false, + ), bounds: self.lower_param_bounds( bounds, ImplTraitContext::Disallowed(ImplTraitPosition::Bound), @@ -1945,10 +1983,16 @@ impl<'hir> LoweringContext<'_, 'hir> { } WherePredicateKind::EqPredicate(WhereEqPredicate { lhs_ty, rhs_ty }) => { hir::WherePredicateKind::EqPredicate(hir::WhereEqPredicate { - lhs_ty: self - .lower_ty(lhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Bound)), - rhs_ty: self - .lower_ty(rhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Bound)), + lhs_ty: self.lower_ty( + lhs_ty, + ImplTraitContext::Disallowed(ImplTraitPosition::Bound), + false, + ), + rhs_ty: self.lower_ty( + rhs_ty, + ImplTraitContext::Disallowed(ImplTraitPosition::Bound), + false, + ), }) } }); diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 422e79ca82ffd..f818c15f5b100 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1007,7 +1007,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let kind = match &constraint.kind { AssocItemConstraintKind::Equality { term } => { let term = match term { - Term::Ty(ty) => self.lower_ty(ty, itctx).into(), + Term::Ty(ty) => self.lower_ty(ty, itctx, false).into(), Term::Const(c) => self.lower_anon_const_to_const_arg(c).into(), }; hir::AssocItemConstraintKind::Equality { term } @@ -1131,7 +1131,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } _ => {} } - GenericArg::Type(self.lower_ty(ty, itctx).try_as_ambig_ty().unwrap()) + GenericArg::Type(self.lower_ty(ty, itctx, false).try_as_ambig_ty().unwrap()) } ast::GenericArg::Const(ct) => { GenericArg::Const(self.lower_anon_const_to_const_arg(ct).try_as_ambig_ct().unwrap()) @@ -1140,8 +1140,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } #[instrument(level = "debug", skip(self))] - fn lower_ty(&mut self, t: &Ty, itctx: ImplTraitContext) -> &'hir hir::Ty<'hir> { - self.arena.alloc(self.lower_ty_direct(t, itctx)) + fn lower_ty( + &mut self, + t: &Ty, + itctx: ImplTraitContext, + is_registry_declaration: bool, + ) -> &'hir hir::Ty<'hir> { + self.arena.alloc(self.lower_ty_direct(t, itctx, is_registry_declaration)) } fn lower_path_ty( @@ -1203,11 +1208,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.ty(span, hir::TyKind::Tup(tys)) } - fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir> { + fn lower_ty_direct( + &mut self, + t: &Ty, + itctx: ImplTraitContext, + is_registry_declaration: bool, + ) -> hir::Ty<'hir> { let kind = match &t.kind { TyKind::Infer => hir::TyKind::Infer(()), TyKind::Err(guar) => hir::TyKind::Err(*guar), - TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)), + TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx, false)), TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)), TyKind::Ref(region, mt) => { let lifetime = self.lower_ty_direct_lifetime(t, *region); @@ -1241,15 +1251,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let generic_params = self.lower_lifetime_binder(t.id, &f.generic_params); hir::TyKind::UnsafeBinder(self.arena.alloc(hir::UnsafeBinderTy { generic_params, - inner_ty: self.lower_ty(&f.inner_ty, itctx), + inner_ty: self.lower_ty(&f.inner_ty, itctx, false), })) } TyKind::Never => hir::TyKind::Never, TyKind::Tup(tys) => hir::TyKind::Tup( - self.arena.alloc_from_iter(tys.iter().map(|ty| self.lower_ty_direct(ty, itctx))), + self.arena + .alloc_from_iter(tys.iter().map(|ty| self.lower_ty_direct(ty, itctx, false))), ), TyKind::Paren(ty) => { - return self.lower_ty_direct(ty, itctx); + return self.lower_ty_direct(ty, itctx, is_registry_declaration); } TyKind::Path(qself, path) => { return self.lower_path_ty(t, qself, path, ParamMode::Explicit, itctx); @@ -1272,8 +1283,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { )) } TyKind::Array(ty, length) => hir::TyKind::Array( - self.lower_ty(ty, itctx), - self.lower_array_length_to_const_arg(length), + self.lower_ty(ty, itctx, false), + self.lower_array_length_to_const_arg(length, is_registry_declaration), ), TyKind::Typeof(expr) => hir::TyKind::Typeof(self.lower_anon_const_to_anon_const(expr)), TyKind::TraitObject(bounds, kind) => { @@ -1367,7 +1378,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } TyKind::Pat(ty, pat) => { - hir::TyKind::Pat(self.lower_ty(ty, itctx), self.lower_ty_pat(pat, ty.span)) + hir::TyKind::Pat(self.lower_ty(ty, itctx, false), self.lower_ty_pat(pat, ty.span)) } TyKind::MacCall(_) => { span_bug!(t.span, "`TyKind::MacCall` should have been expanded by now") @@ -1567,7 +1578,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ImplTraitContext::Disallowed(ImplTraitPosition::PointerParam) } }; - self.lower_ty_direct(¶m.ty, itctx) + self.lower_ty_direct(¶m.ty, itctx, false) })); let output = match coro { @@ -1606,7 +1617,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ImplTraitContext::Disallowed(ImplTraitPosition::PointerReturn) } }; - hir::FnRetTy::Return(self.lower_ty(ty, itctx)) + hir::FnRetTy::Return(self.lower_ty(ty, itctx, false)) } FnRetTy::Default(span) => hir::FnRetTy::DefaultReturn(self.lower_span(*span)), }, @@ -1718,7 +1729,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Not `OpaqueTyOrigin::AsyncFn`: that's only used for the // `impl Future` opaque type that `async fn` implicitly // generates. - self.lower_ty(ty, itctx) + self.lower_ty(ty, itctx, false) } FnRetTy::Default(ret_ty_span) => self.arena.alloc(self.ty_tup(*ret_ty_span, &[])), }; @@ -1911,6 +1922,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.lower_ty( def, ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault), + false, ) }); @@ -1919,8 +1931,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { (hir::ParamName::Plain(self.lower_ident(param.ident)), kind) } GenericParamKind::Const { ty, kw_span: _, default } => { - let ty = self - .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault)); + let ty = self.lower_ty( + ty, + ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault), + false, + ); // Not only do we deny const param defaults in binders but we also map them to `None` // since later compiler stages cannot handle them (and shouldn't need to be able to). @@ -1986,7 +2001,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext) -> hir::MutTy<'hir> { - hir::MutTy { ty: self.lower_ty(&mt.ty, itctx), mutbl: mt.mutbl } + hir::MutTy { ty: self.lower_ty(&mt.ty, itctx, false), mutbl: mt.mutbl } } #[instrument(level = "debug", skip(self), ret)] @@ -2063,12 +2078,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.expr_block(block) } - fn lower_array_length_to_const_arg(&mut self, c: &AnonConst) -> &'hir hir::ConstArg<'hir> { + fn lower_array_length_to_const_arg( + &mut self, + c: &AnonConst, + is_registry_declaration: bool, + ) -> &'hir hir::ConstArg<'hir> { // We cannot just match on `ExprKind::Underscore` as `(_)` is represented as // `ExprKind::Paren(ExprKind::Underscore)` and should also be lowered to `GenericArg::Infer` match c.value.peel_parens().kind { ExprKind::Underscore => { - if !self.tcx.features().generic_arg_infer() { + if !self.tcx.features().generic_arg_infer() && !is_registry_declaration { feature_err( &self.tcx.sess, sym::generic_arg_infer, diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 5cda64ce7b4ba..7ce403eb5fe89 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -36,7 +36,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let qself = qself .as_ref() // Reject cases like `::Assoc` and `::Assoc`. - .map(|q| self.lower_ty(&q.ty, ImplTraitContext::Disallowed(ImplTraitPosition::Path))); + .map(|q| { + self.lower_ty(&q.ty, ImplTraitContext::Disallowed(ImplTraitPosition::Path), false) + }); let partial_res = self.resolver.get_partial_res(id).unwrap_or_else(|| PartialRes::new(Res::Err)); @@ -510,7 +512,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // we generally don't permit such things (see #51008). let ParenthesizedArgs { span, inputs, inputs_span, output } = data; let inputs = self.arena.alloc_from_iter(inputs.iter().map(|ty| { - self.lower_ty_direct(ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam)) + self.lower_ty_direct( + ty, + ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam), + false, + ) })); let output_ty = match output { // Only allow `impl Trait` in return position. i.e.: @@ -520,7 +526,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // ``` FnRetTy::Ty(ty) if matches!(itctx, ImplTraitContext::OpaqueTy { .. }) => { if self.tcx.features().impl_trait_in_fn_trait_return() { - self.lower_ty(ty, itctx) + self.lower_ty(ty, itctx, false) } else { self.lower_ty( ty, @@ -528,12 +534,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ImplTraitPosition::FnTraitReturn, sym::impl_trait_in_fn_trait_return, ), + false, ) } } - FnRetTy::Ty(ty) => { - self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn)) - } + FnRetTy::Ty(ty) => self.lower_ty( + ty, + ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn), + false, + ), FnRetTy::Default(_) => self.arena.alloc(self.ty_tup(*span, &[])), }; let args = smallvec![GenericArg::Type( diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 70d37985dccb3..e506f71ff470f 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -4106,10 +4106,10 @@ impl<'hir> Item<'hir> { expect_use, (&'hir UsePath<'hir>, UseKind), ItemKind::Use(p, uk), (p, *uk); - expect_static, (Mutability, Ident, &'hir Ty<'hir>, BodyId, DistributedSlice<'hir>), + expect_static, (Mutability, Ident, &'hir Ty<'hir>, BodyId, DistributedSlice), ItemKind::Static(mutbl, ident, ty, body, distributed_slice), (*mutbl, *ident, *ty, *body, *distributed_slice); - expect_const, (Ident, &'hir Generics<'hir>, &'hir Ty<'hir>, BodyId, DistributedSlice<'hir>), + expect_const, (Ident, &'hir Generics<'hir>, &'hir Ty<'hir>, BodyId, DistributedSlice), ItemKind::Const(ident, generics, ty, body, distributed_slice), (*ident, generics, *ty, *body, *distributed_slice); expect_fn, (Ident, &FnSig<'hir>, &'hir Generics<'hir>, BodyId), @@ -4264,11 +4264,11 @@ impl FnHeader { } #[derive(Debug, Clone, Copy, HashStable_Generic, Default)] -pub enum DistributedSlice<'hir> { +pub enum DistributedSlice { #[default] None, Declaration(Span), - Addition(QPath<'hir>), + Addition(LocalDefId), } #[derive(Debug, Clone, Copy, HashStable_Generic)] @@ -4286,9 +4286,9 @@ pub enum ItemKind<'hir> { Use(&'hir UsePath<'hir>, UseKind), /// A `static` item. - Static(Mutability, Ident, &'hir Ty<'hir>, BodyId, DistributedSlice<'hir>), + Static(Mutability, Ident, &'hir Ty<'hir>, BodyId, DistributedSlice), /// A `const` item. - Const(Ident, &'hir Generics<'hir>, &'hir Ty<'hir>, BodyId, DistributedSlice<'hir>), + Const(Ident, &'hir Generics<'hir>, &'hir Ty<'hir>, BodyId, DistributedSlice), /// A function declaration. Fn { sig: FnSig<'hir>, diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index a866346d96efa..e61737ae2621f 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -46,6 +46,7 @@ use tracing::{debug, instrument}; use crate::errors; use crate::hir_ty_lowering::{FeedConstTy, HirTyLowerer, RegionInferReason}; +mod distributed_slice; pub(crate) mod dump; mod generics_of; mod item_bounds; @@ -79,6 +80,7 @@ pub(crate) fn provide(providers: &mut Providers) { const_conditions: predicates_of::const_conditions, explicit_implied_const_bounds: predicates_of::explicit_implied_const_bounds, type_param_predicates: predicates_of::type_param_predicates, + distributed_slice_elements: distributed_slice::distributed_slice_elements, trait_def, adt_def, fn_sig, diff --git a/compiler/rustc_hir_analysis/src/collect/distributed_slice.rs b/compiler/rustc_hir_analysis/src/collect/distributed_slice.rs new file mode 100644 index 0000000000000..2a3bed998205e --- /dev/null +++ b/compiler/rustc_hir_analysis/src/collect/distributed_slice.rs @@ -0,0 +1,21 @@ +use rustc_hir::def_id::{DefIdMap, LocalDefId}; +use rustc_hir::{DistributedSlice, ItemKind}; +use rustc_middle::ty::TyCtxt; + +pub(super) fn distributed_slice_elements<'tcx>( + tcx: TyCtxt<'tcx>, + _: (), +) -> DefIdMap> { + let mut res = DefIdMap::>::default(); + + for i in tcx.hir_free_items() { + let addition_def_id = i.owner_id.def_id; + if let ItemKind::Const(.., DistributedSlice::Addition(declaration_def_id)) = + tcx.hir_expect_item(addition_def_id).kind + { + res.entry(declaration_def_id.to_def_id()).or_default().push(addition_def_id); + } + } + + res +} diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 07a6f19babb97..7ef5d002965b6 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -113,6 +113,33 @@ fn const_arg_anon_type_of<'tcx>(icx: &ItemCtxt<'tcx>, arg_hir_id: HirId, span: S } } +fn type_of_distributed_slice<'tcx>( + tcx: TyCtxt<'tcx>, + icx: &ItemCtxt<'tcx>, + ty: &rustc_hir::Ty<'tcx>, + def_id: LocalDefId, +) -> Ty<'tcx> { + use rustc_hir::*; + use rustc_middle::ty::Ty; + + let TyKind::Array(ty, len) = ty.kind else { + panic!("gr should be an array"); + }; + + let ConstArgKind::Infer { .. } = len.kind else { + // FIXME(gr) exact + todo!("expected infer"); + }; + + let res: Option<&Vec> = tcx.distributed_slice_elements(()).get(&def_id.to_def_id()); + + Ty::new_array_with_const_len( + tcx, + icx.lower_ty(ty), + ty::Const::from_target_usize(tcx, res.map(|i| i.len()).unwrap_or(0) as u64), + ) +} + pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, Ty<'_>> { use rustc_hir::*; use rustc_middle::ty::Ty; @@ -207,7 +234,9 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ Node::Item(item) => match item.kind { ItemKind::Static(_, ident, ty, body_id, distributed_slice) => { - if ty.is_suggestable_infer_ty() { + if let DistributedSlice::Declaration(_) = distributed_slice { + type_of_distributed_slice(tcx, &icx, ty, def_id) + } else if ty.is_suggestable_infer_ty() { infer_placeholder_type( icx.lowerer(), def_id, @@ -221,7 +250,13 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ } } ItemKind::Const(ident, _, ty, body_id, distributed_slice) => { - if ty.is_suggestable_infer_ty() { + if let DistributedSlice::Declaration(_) = distributed_slice { + type_of_distributed_slice(tcx, &icx, ty, def_id) + } else if let DistributedSlice::Addition(_) = distributed_slice { + // if it's a global registration addition, then the type can be infered from the declaration + // during typeck + icx.lower_ty(ty) + } else if ty.is_suggestable_infer_ty() { infer_placeholder_type( icx.lowerer(), def_id, diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 5a8148221631d..295b67077299a 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -263,6 +263,24 @@ fn infer_type_if_missing<'tcx>(fcx: &FnCtxt<'_, 'tcx>, node: Node<'tcx>) -> Opti let def_id = fcx.body_id; let expected_type = if let Some(&hir::Ty { kind: hir::TyKind::Infer(()), span, .. }) = node.ty() { + // if it's a global registration addition, then the type can be infered from the declaration + if let Node::Item(hir::Item { + span, + kind: hir::ItemKind::Const(.., hir::DistributedSlice::Addition(def_id)), + .. + }) = node + { + // we reject generic const items (`#![feature(generic_const_items)]`) in + // `#[distributed_slice(crate)]` + let array_ty: Ty<'tcx> = tcx.type_of(*def_id).instantiate_identity(); + let normalized_array_ty = fcx.structurally_resolve_type(*span, array_ty); + + match normalized_array_ty.kind() { + ty::Array(element_ty, _) => return Some(*element_ty), + _ => panic!("not an array"), + } + } + if let Some(item) = tcx.opt_associated_item(def_id.into()) && let ty::AssocKind::Const { .. } = item.kind && let ty::AssocItemContainer::Impl = item.container diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 279033ee0724c..e1a7ad74bb999 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -697,6 +697,11 @@ rustc_queries! { desc { "getting wasm import module map" } } + query distributed_slice_elements(_: ()) -> &'tcx DefIdMap> { + arena_cache + desc { "collects all registered items for global registry declarations in the current crate" } + } + /// Returns the explicitly user-written *predicates and bounds* of the trait given by `DefId`. /// /// Traits are unusual, because predicates on associated types are diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index fb1534d0b2798..3caca95be9432 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -438,6 +438,8 @@ pub(crate) enum PathSource<'a> { ReturnTypeNotation, /// Paths from `#[define_opaque]` attributes DefineOpaques, + /// Paths in `register!(, ...);`, for registering new expressions + DistributedSlice, } impl<'a> PathSource<'a> { @@ -451,7 +453,8 @@ impl<'a> PathSource<'a> { | PathSource::Pat | PathSource::TupleStruct(..) | PathSource::Delegation - | PathSource::ReturnTypeNotation => ValueNS, + | PathSource::ReturnTypeNotation + | PathSource::DistributedSlice => ValueNS, PathSource::TraitItem(ns) => ns, PathSource::PreciseCapturingArg(ns) => ns, } @@ -469,6 +472,7 @@ impl<'a> PathSource<'a> { | PathSource::TraitItem(..) | PathSource::DefineOpaques | PathSource::Delegation + | PathSource::DistributedSlice | PathSource::PreciseCapturingArg(..) => false, } } @@ -510,6 +514,7 @@ impl<'a> PathSource<'a> { }, PathSource::ReturnTypeNotation | PathSource::Delegation => "function", PathSource::PreciseCapturingArg(..) => "type or const parameter", + PathSource::DistributedSlice => "const or static value", } } @@ -519,6 +524,9 @@ impl<'a> PathSource<'a> { pub(crate) fn is_expected(self, res: Res) -> bool { match self { + PathSource::DistributedSlice => { + matches!(res, Res::Def(DefKind::Const | DefKind::Static { .. }, _)) + } PathSource::DefineOpaques => { matches!( res, @@ -623,6 +631,9 @@ impl<'a> PathSource<'a> { (PathSource::TraitItem(..) | PathSource::ReturnTypeNotation, false) => E0576, (PathSource::PreciseCapturingArg(..), true) => E0799, (PathSource::PreciseCapturingArg(..), false) => E0800, + // FIXME(gr): new error codes + (PathSource::DistributedSlice, true) => E0800, + (PathSource::DistributedSlice, false) => E0800, } } } @@ -2063,7 +2074,8 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { | PathSource::Struct | PathSource::TupleStruct(..) | PathSource::DefineOpaques - | PathSource::Delegation => true, + | PathSource::Delegation + | PathSource::DistributedSlice => true, }; if inferred { // Do not create a parameter for patterns and expressions: type checking can infer @@ -2807,6 +2819,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ref ty, ref expr, ref define_opaque, + ref distributed_slice, .. }) => { self.with_generic_param_rib( @@ -2834,6 +2847,15 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { |this| this.visit_ty(ty), ); + if let DistributedSlice::Addition { declaration, id } = distributed_slice { + this.smart_resolve_path( + *id, + &None, + declaration, + PathSource::DistributedSlice, + ); + } + if let Some(expr) = expr { this.resolve_const_body(expr, Some((ident, ConstantItemKind::Const))); } diff --git a/tests/ui/crate_local_distributed_slice/create_slice.rs b/tests/ui/crate_local_distributed_slice/create_slice.rs index 3b6bee6f8fcd9..08a6c2d6b9860 100644 --- a/tests/ui/crate_local_distributed_slice/create_slice.rs +++ b/tests/ui/crate_local_distributed_slice/create_slice.rs @@ -1,5 +1,5 @@ #![feature(crate_local_distributed_slice)] -// @build-pass +// @run-pass #[distributed_slice(crate)] const MEOWS: [&str; _]; From 37e5111720fa2549144f5a7d7bdc64e0fbda5b45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Thu, 29 May 2025 17:40:19 +0200 Subject: [PATCH 07/10] finish typechecking --- compiler/rustc_ast/src/ast.rs | 2 +- compiler/rustc_ast/src/visit.rs | 20 +++++++-- compiler/rustc_ast_lowering/src/expr.rs | 2 +- compiler/rustc_ast_lowering/src/item.rs | 42 ++++++++++++++---- compiler/rustc_ast_lowering/src/lib.rs | 4 +- .../rustc_ast_passes/src/ast_validation.rs | 8 ++-- .../src/distributed_slice.rs | 8 ++-- compiler/rustc_hir/src/hir.rs | 14 ++++-- compiler/rustc_hir/src/intravisit.rs | 1 + compiler/rustc_hir_analysis/src/collect.rs | 1 + .../rustc_hir_analysis/src/collect/type_of.rs | 30 ++++++++----- compiler/rustc_hir_analysis/src/lib.rs | 2 +- compiler/rustc_hir_pretty/src/lib.rs | 3 ++ compiler/rustc_hir_typeck/src/expr.rs | 2 + .../rustc_hir_typeck/src/expr_use_visitor.rs | 2 + compiler/rustc_hir_typeck/src/lib.rs | 27 +++--------- compiler/rustc_lint/src/dangling.rs | 5 ++- compiler/rustc_mir_build/src/thir/cx/expr.rs | 43 ++++++++++++++++++- compiler/rustc_passes/src/input_stats.rs | 1 + compiler/rustc_passes/src/liveness.rs | 3 ++ compiler/rustc_passes/src/naked_functions.rs | 1 + library/std/src/prelude/v1.rs | 2 +- .../create_slice.rs | 4 +- .../create_slice.run.stdout | 1 + .../create_slice.stderr | 21 --------- 25 files changed, 164 insertions(+), 85 deletions(-) create mode 100644 tests/ui/crate_local_distributed_slice/create_slice.run.stdout delete mode 100644 tests/ui/crate_local_distributed_slice/create_slice.stderr diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index f071cd2a0d3a9..0b8d697cc191a 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3620,7 +3620,7 @@ pub enum DistributedSlice { #[default] None, /// This const or static declares a global registry that can be added to - Declaration(Span), + Declaration(Span, NodeId), /// This const (we never do this to statics) represents an addition to a global registry /// declared somewhere else. Addition { declaration: Path, id: NodeId }, diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 9f34f4b88f64f..80a5a53985be7 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -458,8 +458,14 @@ macro_rules! common_visitor_and_walkers { visit_opt!(vis, visit_expr, expr); match distributed_slice { DistributedSlice::None => {} - DistributedSlice::Declaration(span) => try_visit!(visit_span(vis, span)), - DistributedSlice::Addition { declaration, id } => try_visit!(vis.visit_path(declaration$(${ignore($lt)}, *id)?)), + DistributedSlice::Declaration(span, id) => { + try_visit!(visit_span(vis, span)); + try_visit!(visit_id(vis, id)); + } + DistributedSlice::Addition { declaration, id } => { + try_visit!(vis.visit_path(declaration$(${ignore($lt)}, *id)?)); + try_visit!(visit_id(vis, id)); + } } walk_define_opaques(vis, define_opaque) } @@ -629,8 +635,14 @@ macro_rules! common_visitor_and_walkers { match distributed_slice { DistributedSlice::None => {} - DistributedSlice::Declaration(span) => try_visit!(visit_span(vis, span)), - DistributedSlice::Addition { declaration, id } => try_visit!(vis.visit_path(declaration$(${ignore($lt)}, *id)?)), + DistributedSlice::Declaration(span, id) => { + try_visit!(visit_span(vis, span)); + try_visit!(visit_id(vis, id)); + } + DistributedSlice::Addition { declaration, id } => { + try_visit!(vis.visit_path(declaration$(${ignore($lt)}, *id)?)); + try_visit!(visit_id(vis, id)); + } } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 5e0d00cf05c9d..3c774a25a1fda 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -428,7 +428,7 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::ConstBlock { def_id, hir_id: this.lower_node_id(c.id), - body: this.lower_const_body(c.value.span, Some(&c.value)), + body: this.lower_const_body(c.value.span, Some(&c.value), None), } }) } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 94477f5f22e8d..28dc9467acf43 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -154,7 +154,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ) -> DistributedSlice { match distributed_slice { ast::DistributedSlice::None => DistributedSlice::None, - ast::DistributedSlice::Declaration(span) => { + ast::DistributedSlice::Declaration(span, _) => { DistributedSlice::Declaration(self.lower_span(*span)) } ast::DistributedSlice::Addition { declaration, id } => { @@ -544,12 +544,19 @@ impl<'hir> LoweringContext<'_, 'hir> { impl_trait_position: ImplTraitPosition, distributed_slice: &ast::DistributedSlice, ) -> (&'hir hir::Ty<'hir>, hir::BodyId) { + let distributed_slice_declaration = + if let ast::DistributedSlice::Declaration(_, node_id) = distributed_slice { + Some(*node_id) + } else { + None + }; + let ty = self.lower_ty( ty, ImplTraitContext::Disallowed(impl_trait_position), - matches!(distributed_slice, ast::DistributedSlice::Declaration(..)), + distributed_slice_declaration.is_some(), ); - (ty, self.lower_const_body(span, body)) + (ty, self.lower_const_body(span, body, distributed_slice_declaration)) } #[instrument(level = "debug", skip(self))] @@ -866,7 +873,8 @@ impl<'hir> LoweringContext<'_, 'hir> { ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy), false, ); - let body = expr.as_ref().map(|x| this.lower_const_body(i.span, Some(x))); + let body = + expr.as_ref().map(|x| this.lower_const_body(i.span, Some(x), None)); hir::TraitItemKind::Const(ty, body) }, @@ -1063,7 +1071,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy), false, ); - let body = this.lower_const_body(i.span, expr.as_deref()); + let body = this.lower_const_body(i.span, expr.as_deref(), None); this.lower_define_opaque(hir_id, &define_opaque); hir::ImplItemKind::Const(ty, body) }, @@ -1342,13 +1350,29 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_fn_body(decl, contract, |this| this.lower_block_expr(body)) } - pub(super) fn lower_const_body(&mut self, span: Span, expr: Option<&Expr>) -> hir::BodyId { + pub(super) fn lower_const_body( + &mut self, + span: Span, + expr: Option<&Expr>, + global_registry_declaration: Option, + ) -> hir::BodyId { self.lower_body(|this| { ( &[], - match expr { - Some(expr) => this.lower_expr_mut(expr), - None => this.expr_err(span, this.dcx().span_delayed_bug(span, "no block")), + match (expr, global_registry_declaration) { + (Some(expr), None) => this.lower_expr_mut(expr), + (None, Some(node_id)) => { + let expr_hir_id = this.lower_node_id(node_id); + hir::Expr { + hir_id: expr_hir_id, + kind: rustc_hir::ExprKind::DistributedSliceDeferredArray, + span: this.lower_span(span), + } + } + (Some(expr), Some(_)) => panic!("distributed slice with initializer"), + (None, None) => { + this.expr_err(span, this.dcx().span_delayed_bug(span, "no block")) + } }, ) }) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index f818c15f5b100..bbc80f5e62ad8 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2156,7 +2156,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.arena.alloc(hir::AnonConst { def_id, hir_id, - body: this.lower_const_body(path_expr.span, Some(&path_expr)), + body: this.lower_const_body(path_expr.span, Some(&path_expr), None), span, }) }); @@ -2223,7 +2223,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::AnonConst { def_id, hir_id, - body: this.lower_const_body(c.value.span, Some(&c.value)), + body: this.lower_const_body(c.value.span, Some(&c.value), None), span: this.lower_span(c.value.span), } })) diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 19bf37e9210ab..23148e0974c61 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1089,7 +1089,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { // declarations of global registries have no body deliberately - items are added // later using global registry additions - if expr.is_none() && !matches!(distributed_slice, DistributedSlice::Declaration(_)) + if expr.is_none() && !matches!(distributed_slice, DistributedSlice::Declaration(..)) { self.dcx().emit_err(errors::ConstWithoutBody { span: item.span, @@ -1104,9 +1104,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.dcx().emit_err(errors::UnsafeStatic { span: item.span }); } - // declarations of global registries have no body deliberately - items are added - // later using global registry additions - if expr.is_none() && !matches!(distributed_slice, DistributedSlice::Declaration(_)) + // declarations of distributed slices have no body deliberately - items are added + // later using `distributed_slice_element` + if expr.is_none() && !matches!(distributed_slice, DistributedSlice::Declaration(..)) { self.dcx().emit_err(errors::StaticWithoutBody { span: item.span, diff --git a/compiler/rustc_builtin_macros/src/distributed_slice.rs b/compiler/rustc_builtin_macros/src/distributed_slice.rs index cd95c1987a29a..dc43ed3a02df0 100644 --- a/compiler/rustc_builtin_macros/src/distributed_slice.rs +++ b/compiler/rustc_builtin_macros/src/distributed_slice.rs @@ -33,10 +33,10 @@ pub(crate) fn distributed_slice( match &mut item.kind { ItemKind::Static(static_item) => { - static_item.distributed_slice = DistributedSlice::Declaration(span); + static_item.distributed_slice = DistributedSlice::Declaration(span, DUMMY_NODE_ID); } ItemKind::Const(const_item) => { - const_item.distributed_slice = DistributedSlice::Declaration(span); + const_item.distributed_slice = DistributedSlice::Declaration(span, DUMMY_NODE_ID); } other => { panic!( @@ -49,14 +49,14 @@ pub(crate) fn distributed_slice( } fn parse_element(mut p: Parser<'_>) -> PResult<'_, (Path, P)> { - let ident = p.parse_path(PathStyle::Expr)?; + let path = p.parse_path(PathStyle::Expr)?; p.expect(exp![Comma])?; let expr = p.parse_expr()?; // optional trailing comma let _ = p.eat(exp![Comma]); - Ok((ident, expr)) + Ok((path, expr)) } /// ```rust diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index e506f71ff470f..77cb0d5dad2a9 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2329,6 +2329,7 @@ impl Expr<'_> { | ExprKind::Type(..) | ExprKind::UnsafeBinderCast(..) | ExprKind::Use(..) + | ExprKind::DistributedSliceDeferredArray | ExprKind::Err(_) => ExprPrecedence::Unambiguous, ExprKind::DropTemps(expr, ..) => expr.precedence(), @@ -2402,6 +2403,7 @@ impl Expr<'_> { | ExprKind::Yield(..) | ExprKind::Cast(..) | ExprKind::DropTemps(..) + | ExprKind::DistributedSliceDeferredArray | ExprKind::Err(_) => false, } } @@ -2449,9 +2451,11 @@ impl Expr<'_> { pub fn can_have_side_effects(&self) -> bool { match self.peel_drop_temps().kind { - ExprKind::Path(_) | ExprKind::Lit(_) | ExprKind::OffsetOf(..) | ExprKind::Use(..) => { - false - } + ExprKind::Path(_) + | ExprKind::Lit(_) + | ExprKind::OffsetOf(..) + | ExprKind::Use(..) + | ExprKind::DistributedSliceDeferredArray => false, ExprKind::Type(base, _) | ExprKind::Unary(_, base) | ExprKind::Field(base, _) @@ -2818,6 +2822,10 @@ pub enum ExprKind<'hir> { /// e.g. `unsafe<'a> &'a i32` <=> `&i32`. UnsafeBinderCast(UnsafeBinderCastKind, &'hir Expr<'hir>, Option<&'hir Ty<'hir>>), + /// Built from elements throughout the crate, when first accessed in const-eval + /// Mostly acts as a literal whose value we defer to create + DistributedSliceDeferredArray, + /// A placeholder for an expression that wasn't syntactically well formed in some way. Err(rustc_span::ErrorGuaranteed), } diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index b1ec45e2d371b..5686e4089d76d 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -920,6 +920,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) visit_opt!(visitor, visit_ty_unambig, ty); } ExprKind::Lit(lit) => try_visit!(visitor.visit_lit(expression.hir_id, lit, false)), + ExprKind::DistributedSliceDeferredArray => {} ExprKind::Err(_) => {} } V::Result::output() diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index e61737ae2621f..e368aa5852b29 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -42,6 +42,7 @@ use rustc_trait_selection::error_reporting::traits::suggestions::NextTypeParamNa use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::{ObligationCtxt, hir_ty_lowering_dyn_compatibility_violations}; use tracing::{debug, instrument}; +pub use type_of::type_of_distributed_slice; use crate::errors; use crate::hir_ty_lowering::{FeedConstTy, HirTyLowerer, RegionInferReason}; diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 7ef5d002965b6..e0341f79fff08 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -113,16 +113,16 @@ fn const_arg_anon_type_of<'tcx>(icx: &ItemCtxt<'tcx>, arg_hir_id: HirId, span: S } } -fn type_of_distributed_slice<'tcx>( +pub fn type_of_distributed_slice<'tcx>( tcx: TyCtxt<'tcx>, - icx: &ItemCtxt<'tcx>, + lowerer: &dyn HirTyLowerer<'tcx>, ty: &rustc_hir::Ty<'tcx>, def_id: LocalDefId, ) -> Ty<'tcx> { use rustc_hir::*; use rustc_middle::ty::Ty; - let TyKind::Array(ty, len) = ty.kind else { + let TyKind::Array(element_ty, len) = ty.kind else { panic!("gr should be an array"); }; @@ -133,11 +133,13 @@ fn type_of_distributed_slice<'tcx>( let res: Option<&Vec> = tcx.distributed_slice_elements(()).get(&def_id.to_def_id()); - Ty::new_array_with_const_len( + let res = Ty::new_array_with_const_len( tcx, - icx.lower_ty(ty), + lowerer.lower_ty(element_ty), ty::Const::from_target_usize(tcx, res.map(|i| i.len()).unwrap_or(0) as u64), - ) + ); + + res } pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, Ty<'_>> { @@ -235,7 +237,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ Node::Item(item) => match item.kind { ItemKind::Static(_, ident, ty, body_id, distributed_slice) => { if let DistributedSlice::Declaration(_) = distributed_slice { - type_of_distributed_slice(tcx, &icx, ty, def_id) + type_of_distributed_slice(tcx, icx.lowerer(), ty, def_id) } else if ty.is_suggestable_infer_ty() { infer_placeholder_type( icx.lowerer(), @@ -252,10 +254,16 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ ItemKind::Const(ident, _, ty, body_id, distributed_slice) => { if let DistributedSlice::Declaration(_) = distributed_slice { type_of_distributed_slice(tcx, &icx, ty, def_id) - } else if let DistributedSlice::Addition(_) = distributed_slice { - // if it's a global registration addition, then the type can be infered from the declaration - // during typeck - icx.lower_ty(ty) + } else if let DistributedSlice::Addition(declaration_def_id) = distributed_slice { + // we reject generic const items (`#![feature(generic_const_items)]`) in `#[distributed_slice(crate)]` + let array_ty = tcx.type_of(declaration_def_id).instantiate_identity(); + + let ty = match array_ty.kind() { + ty::Array(element_ty, _) => *element_ty, + _ => panic!("not an array"), + }; + + ty } else if ty.is_suggestable_infer_ty() { infer_placeholder_type( icx.lowerer(), diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index a64c24f5455bf..aeb552264963c 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -103,7 +103,7 @@ use rustc_span::symbol::sym; use rustc_span::{ErrorGuaranteed, Span}; use rustc_trait_selection::traits; -pub use crate::collect::suggest_impl_trait; +pub use crate::collect::{suggest_impl_trait, type_of_distributed_slice}; use crate::hir_ty_lowering::{FeedConstTy, HirTyLowerer}; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 64e6e6812ebac..63eaa2e008375 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1671,6 +1671,9 @@ impl<'a> State<'a> { self.word_space("yield"); self.print_expr_cond_paren(expr, expr.precedence() < ExprPrecedence::Jump); } + hir::ExprKind::DistributedSliceDeferredArray => { + // literally nothing to print. + } hir::ExprKind::Err(_) => { self.popen(); self.word("/*ERROR*/"); diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 082ddac7e5ae2..09ed3a0a0a254 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -384,6 +384,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ExprKind::ConstBlock(_) | ExprKind::Loop(_, _, _, _) | ExprKind::Lit(_) + | ExprKind::DistributedSliceDeferredArray | ExprKind::Path(_) | ExprKind::Continue(_) | ExprKind::OffsetOf(_, _) @@ -505,6 +506,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let tcx = self.tcx; match expr.kind { + ExprKind::DistributedSliceDeferredArray => self.next_ty_var(expr.span), ExprKind::Lit(ref lit) => self.check_expr_lit(lit, expected), ExprKind::Binary(op, lhs, rhs) => self.check_expr_binop(expr, op, lhs, rhs, expected), ExprKind::Assign(lhs, rhs, span) => { diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index 2034131882820..bb148ea540bea 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -508,6 +508,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx hir::ExprKind::Continue(..) | hir::ExprKind::Lit(..) + | hir::ExprKind::DistributedSliceDeferredArray | hir::ExprKind::ConstBlock(..) | hir::ExprKind::OffsetOf(..) | hir::ExprKind::Err(_) => {} @@ -1437,6 +1438,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx | hir::ExprKind::InlineAsm(..) | hir::ExprKind::OffsetOf(..) | hir::ExprKind::UnsafeBinderCast(UnsafeBinderCastKind::Wrap, ..) + | hir::ExprKind::DistributedSliceDeferredArray | hir::ExprKind::Err(_) => Ok(self.cat_rvalue(expr.hir_id, expr_ty)), } } diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 295b67077299a..5d74429668ce5 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -45,11 +45,11 @@ use fn_ctxt::FnCtxt; use rustc_data_structures::unord::UnordSet; use rustc_errors::codes::*; use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err}; -use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{HirId, HirIdMap, Node}; +use rustc_hir::{self as hir, DistributedSlice, HirId, HirIdMap, ItemKind, Node}; use rustc_hir_analysis::check::check_abi; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; +use rustc_hir_analysis::type_of_distributed_slice; use rustc_infer::traits::{ObligationCauseCode, ObligationInspector, WellFormedLoc}; use rustc_middle::query::Providers; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -174,6 +174,11 @@ fn typeck_with_inspect<'tcx>( } else { let expected_type = if let Some(infer_ty) = infer_type_if_missing(&fcx, node) { infer_ty + } else if let Node::Item(item) = node + && let ItemKind::Const(.., DistributedSlice::Declaration(..)) = item.kind + && let Some(ty) = node.ty() + { + type_of_distributed_slice(tcx, fcx.lowerer(), ty, def_id) } else if let Some(ty) = node.ty() && ty.is_suggestable_infer_ty() { @@ -263,24 +268,6 @@ fn infer_type_if_missing<'tcx>(fcx: &FnCtxt<'_, 'tcx>, node: Node<'tcx>) -> Opti let def_id = fcx.body_id; let expected_type = if let Some(&hir::Ty { kind: hir::TyKind::Infer(()), span, .. }) = node.ty() { - // if it's a global registration addition, then the type can be infered from the declaration - if let Node::Item(hir::Item { - span, - kind: hir::ItemKind::Const(.., hir::DistributedSlice::Addition(def_id)), - .. - }) = node - { - // we reject generic const items (`#![feature(generic_const_items)]`) in - // `#[distributed_slice(crate)]` - let array_ty: Ty<'tcx> = tcx.type_of(*def_id).instantiate_identity(); - let normalized_array_ty = fcx.structurally_resolve_type(*span, array_ty); - - match normalized_array_ty.kind() { - ty::Array(element_ty, _) => return Some(*element_ty), - _ => panic!("not an array"), - } - } - if let Some(item) = tcx.opt_associated_item(def_id.into()) && let ty::AssocKind::Const { .. } = item.kind && let ty::AssocItemContainer::Impl = item.container diff --git a/compiler/rustc_lint/src/dangling.rs b/compiler/rustc_lint/src/dangling.rs index 91c7922638de5..ae0064cee52d2 100644 --- a/compiler/rustc_lint/src/dangling.rs +++ b/compiler/rustc_lint/src/dangling.rs @@ -153,7 +153,10 @@ fn lint_expr(cx: &LateContext<'_>, expr: &Expr<'_>) { fn is_temporary_rvalue(expr: &Expr<'_>) -> bool { match expr.kind { // Const is not temporary. - ExprKind::ConstBlock(..) | ExprKind::Repeat(..) | ExprKind::Lit(..) => false, + ExprKind::ConstBlock(..) + | ExprKind::Repeat(..) + | ExprKind::Lit(..) + | ExprKind::DistributedSliceDeferredArray => false, // This is literally lvalue. ExprKind::Path(..) => false, diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 226dc920a496c..cee40f3cfb96a 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -4,6 +4,7 @@ use rustc_ast::UnsafeBinderCastKind; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; +use rustc_hir::def_id::LocalDefId; use rustc_index::Idx; use rustc_middle::hir::place::{ Place as HirPlace, PlaceBase as HirPlaceBase, ProjectionKind as HirProjectionKind, @@ -18,7 +19,7 @@ use rustc_middle::ty::{ self, AdtKind, GenericArgs, InlineConstArgs, InlineConstArgsParts, ScalarInt, Ty, UpvarArgs, }; use rustc_middle::{bug, span_bug}; -use rustc_span::{Span, sym}; +use rustc_span::{DUMMY_SP, Span, sym}; use tracing::{debug, info, instrument, trace}; use crate::thir::cx::ThirBuildCx; @@ -928,6 +929,46 @@ impl<'tcx> ThirBuildCx<'tcx> { hir::ExprKind::DropTemps(source) => ExprKind::Use { source: self.mirror_expr(source) }, hir::ExprKind::Array(fields) => ExprKind::Array { fields: self.mirror_exprs(fields) }, + hir::ExprKind::DistributedSliceDeferredArray => { + // get the declaration's defid + let declaration_def_id = self.body_owner; + let elements: &[LocalDefId] = self + .tcx + .distributed_slice_elements(()) + .get(&declaration_def_id) + .map(|i| i.as_slice()) + .unwrap_or_default(); + + // FIXME(gr) proper span in grda + let span = DUMMY_SP; + + let ty = match expr_ty.kind() { + ty::Array(element_ty, _) => *element_ty, + _ => panic!("not an array"), + }; + + let fields = elements + .iter() + .map(|&def_id| { + let (temp_lifetime, backwards_incompatible) = self + .rvalue_scopes + .temporary_scope(self.region_scope_tree, expr.hir_id.local_id); + + self.thir.exprs.push(Expr { + kind: ExprKind::NamedConst { + def_id: def_id.to_def_id(), + args: GenericArgs::empty(), + user_ty: None, + }, + ty, + temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible }, + span, + }) + }) + .collect(); + + ExprKind::Array { fields } + } hir::ExprKind::Tup(fields) => ExprKind::Tuple { fields: self.mirror_exprs(fields) }, hir::ExprKind::Yield(v, _) => ExprKind::Yield { value: self.mirror_expr(v) }, diff --git a/compiler/rustc_passes/src/input_stats.rs b/compiler/rustc_passes/src/input_stats.rs index 7181544817225..15422d760bd2e 100644 --- a/compiler/rustc_passes/src/input_stats.rs +++ b/compiler/rustc_passes/src/input_stats.rs @@ -359,6 +359,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { Repeat, Yield, UnsafeBinderCast, + DistributedSliceDeferredArray, Err ] ); diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 763d9fda80494..08a0f20c15c6e 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -434,6 +434,7 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { | hir::ExprKind::Break(..) | hir::ExprKind::Continue(_) | hir::ExprKind::Lit(_) + | hir::ExprKind::DistributedSliceDeferredArray | hir::ExprKind::ConstBlock(..) | hir::ExprKind::Ret(..) | hir::ExprKind::Become(..) @@ -1160,6 +1161,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } hir::ExprKind::Lit(..) + | hir::ExprKind::DistributedSliceDeferredArray | hir::ExprKind::ConstBlock(..) | hir::ExprKind::Err(_) | hir::ExprKind::Path(hir::QPath::TypeRelative(..)) @@ -1445,6 +1447,7 @@ fn check_expr<'tcx>(this: &mut Liveness<'_, 'tcx>, expr: &'tcx Expr<'tcx>) { | hir::ExprKind::Break(..) | hir::ExprKind::Continue(..) | hir::ExprKind::Lit(_) + | hir::ExprKind::DistributedSliceDeferredArray | hir::ExprKind::ConstBlock(..) | hir::ExprKind::Block(..) | hir::ExprKind::AddrOf(..) diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs index 3c9f8b72c3635..a6fb31594464c 100644 --- a/compiler/rustc_passes/src/naked_functions.rs +++ b/compiler/rustc_passes/src/naked_functions.rs @@ -187,6 +187,7 @@ impl CheckInlineAssembly { | ExprKind::Become(..) | ExprKind::Struct(..) | ExprKind::Repeat(..) + | ExprKind::DistributedSliceDeferredArray | ExprKind::Yield(..) => { self.items.push((ItemKind::NonAsm, span)); } diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs index 0a548ae7431bd..4d1d728eb9d74 100644 --- a/library/std/src/prelude/v1.rs +++ b/library/std/src/prelude/v1.rs @@ -70,7 +70,7 @@ pub use core::prelude::v1::{ #[unstable(feature = "crate_local_distributed_slice", issue = "125119")] #[cfg(not(bootstrap))] -pub use core::prelude::v1::{distributed_slice, distributed_slice_element}; +pub use core::prelude::v1::distributed_slice; #[unstable(feature = "derive_const", issue = "none")] pub use core::prelude::v1::derive_const; diff --git a/tests/ui/crate_local_distributed_slice/create_slice.rs b/tests/ui/crate_local_distributed_slice/create_slice.rs index 08a6c2d6b9860..490b9ecdbf023 100644 --- a/tests/ui/crate_local_distributed_slice/create_slice.rs +++ b/tests/ui/crate_local_distributed_slice/create_slice.rs @@ -1,10 +1,12 @@ #![feature(crate_local_distributed_slice)] -// @run-pass +//@ run-pass +//@ check-run-results #[distributed_slice(crate)] const MEOWS: [&str; _]; distributed_slice_element!(MEOWS, "mrow"); +distributed_slice_element!(MEOWS, "mew"); fn main() { println!("{MEOWS:?}"); diff --git a/tests/ui/crate_local_distributed_slice/create_slice.run.stdout b/tests/ui/crate_local_distributed_slice/create_slice.run.stdout new file mode 100644 index 0000000000000..50e2bc49a4611 --- /dev/null +++ b/tests/ui/crate_local_distributed_slice/create_slice.run.stdout @@ -0,0 +1 @@ +["mrow", "mew"] diff --git a/tests/ui/crate_local_distributed_slice/create_slice.stderr b/tests/ui/crate_local_distributed_slice/create_slice.stderr deleted file mode 100644 index 3f7f39f594c01..0000000000000 --- a/tests/ui/crate_local_distributed_slice/create_slice.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants - --> $DIR/create_slice.rs:5:21 - | -LL | const MEOWS: [&str; _]; - | ^ not allowed in type signatures - -error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants - --> $DIR/create_slice.rs:7:1 - | -LL | distributed_slice_element!(MEOWS, "mrow"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not allowed in type signatures - | -help: replace this with a fully-specified type - | -LL - distributed_slice_element!(MEOWS, "mrow"); -LL + &str; - | - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0121`. From 9f5725c49ae24fe51d7105e8c8af6089d439d8a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 30 May 2025 10:49:06 +0200 Subject: [PATCH 08/10] shuffle based on defpathhash --- Cargo.lock | 2 ++ compiler/rustc_hir_analysis/Cargo.toml | 2 ++ .../src/collect/distributed_slice.rs | 19 +++++++++++++++++-- .../create_slice.run.stdout | 2 +- 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e486f6148cc11..1cf3aefdd9a29 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3812,6 +3812,8 @@ name = "rustc_hir_analysis" version = "0.0.0" dependencies = [ "itertools", + "rand 0.9.1", + "rand_xoshiro", "rustc_abi", "rustc_arena", "rustc_ast", diff --git a/compiler/rustc_hir_analysis/Cargo.toml b/compiler/rustc_hir_analysis/Cargo.toml index f2b82c679b933..c044ac3087a0f 100644 --- a/compiler/rustc_hir_analysis/Cargo.toml +++ b/compiler/rustc_hir_analysis/Cargo.toml @@ -10,6 +10,8 @@ doctest = false [dependencies] # tidy-alphabetical-start itertools = "0.12" +rand = { version = "0.9.0", default-features = false } +rand_xoshiro = { version = "0.7.0" } rustc_abi = { path = "../rustc_abi" } rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } diff --git a/compiler/rustc_hir_analysis/src/collect/distributed_slice.rs b/compiler/rustc_hir_analysis/src/collect/distributed_slice.rs index 2a3bed998205e..3c841193a6e5e 100644 --- a/compiler/rustc_hir_analysis/src/collect/distributed_slice.rs +++ b/compiler/rustc_hir_analysis/src/collect/distributed_slice.rs @@ -1,3 +1,5 @@ +use rand::SeedableRng; +use rand::seq::SliceRandom; use rustc_hir::def_id::{DefIdMap, LocalDefId}; use rustc_hir::{DistributedSlice, ItemKind}; use rustc_middle::ty::TyCtxt; @@ -6,16 +8,29 @@ pub(super) fn distributed_slice_elements<'tcx>( tcx: TyCtxt<'tcx>, _: (), ) -> DefIdMap> { - let mut res = DefIdMap::>::default(); + let mut slice_elements = DefIdMap::>::default(); for i in tcx.hir_free_items() { let addition_def_id = i.owner_id.def_id; if let ItemKind::Const(.., DistributedSlice::Addition(declaration_def_id)) = tcx.hir_expect_item(addition_def_id).kind { - res.entry(declaration_def_id.to_def_id()).or_default().push(addition_def_id); + slice_elements.entry(declaration_def_id.to_def_id()).or_default().push(addition_def_id); } } + let mut res = DefIdMap::>::default(); + + for (key, mut registered_values) in + tcx.with_stable_hashing_context(|hcx| slice_elements.into_sorted(&hcx, true)) + { + // shuffle seeded by the defpathhash of the registry + let item_seed = tcx.def_path_hash(key).0.to_smaller_hash(); + let mut rng = rand_xoshiro::Xoshiro128StarStar::seed_from_u64(item_seed.as_u64()); + registered_values.as_mut_slice().shuffle(&mut rng); + + res.insert(key, registered_values); + } + res } diff --git a/tests/ui/crate_local_distributed_slice/create_slice.run.stdout b/tests/ui/crate_local_distributed_slice/create_slice.run.stdout index 50e2bc49a4611..484b65a358e13 100644 --- a/tests/ui/crate_local_distributed_slice/create_slice.run.stdout +++ b/tests/ui/crate_local_distributed_slice/create_slice.run.stdout @@ -1 +1 @@ -["mrow", "mew"] +["mew", "mrow"] From 0314c6fca4cd16dff9d0f5c9f1ff2f9691ddd9f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 30 May 2025 18:04:50 +0200 Subject: [PATCH 09/10] tests --- compiler/rustc_ast/src/ast.rs | 2 + compiler/rustc_ast/src/visit.rs | 2 + compiler/rustc_ast_lowering/messages.ftl | 2 + compiler/rustc_ast_lowering/src/errors.rs | 7 ++ compiler/rustc_ast_lowering/src/item.rs | 60 +++++++++++++--- .../rustc_ast_passes/src/ast_validation.rs | 12 ++-- .../rustc_ast_pretty/src/pprust/state/item.rs | 1 - compiler/rustc_builtin_macros/messages.ftl | 20 ++++++ .../src/distributed_slice.rs | 71 ++++++++++++++++--- compiler/rustc_builtin_macros/src/errors.rs | 48 +++++++++++++ compiler/rustc_hir/src/hir.rs | 33 +++++---- compiler/rustc_hir/src/intravisit.rs | 6 +- compiler/rustc_hir_analysis/messages.ftl | 15 ++++ .../src/check/compare_impl_item.rs | 4 +- .../rustc_hir_analysis/src/check/wfcheck.rs | 2 +- compiler/rustc_hir_analysis/src/collect.rs | 23 ++++-- .../src/collect/resolve_bound_vars.rs | 4 +- .../rustc_hir_analysis/src/collect/type_of.rs | 71 +++++++++++++++---- compiler/rustc_hir_analysis/src/errors.rs | 37 ++++++++++ .../rustc_hir_analysis/src/hir_wf_check.rs | 7 +- compiler/rustc_hir_pretty/src/lib.rs | 41 ++++++++--- compiler/rustc_hir_typeck/src/lib.rs | 20 +++++- compiler/rustc_lint/src/types.rs | 2 +- compiler/rustc_mir_build/src/builder/mod.rs | 6 +- compiler/rustc_passes/src/dead.rs | 20 +++++- compiler/rustc_passes/src/reachable.rs | 10 +-- compiler/rustc_resolve/src/late.rs | 2 +- .../create_static_slice.rs | 13 ++++ .../create_static_slice.run.stdout | 1 + .../exact_length.rs | 7 ++ .../exact_length.stderr | 15 ++++ .../generic_const.rs | 9 +++ .../generic_const.stderr | 8 +++ .../initializer.rs | 7 ++ .../initializer.stderr | 8 +++ .../crate_local_distributed_slice/no_crate.rs | 12 ++++ .../no_crate.stderr | 13 ++++ .../no_element.rs | 16 +++++ .../no_element.stderr | 20 ++++++ .../crate_local_distributed_slice/no_type.rs | 9 +++ .../no_type.stderr | 9 +++ .../non_slice.rs | 9 +++ .../non_slice.stderr | 15 ++++ .../random_const.rs | 11 +++ .../random_const.stderr | 32 +++++++++ .../reference_const.rs | 15 ++++ .../reference_const.run.stdout | 1 + .../self_referential.rs | 10 +++ .../self_referential.stderr | 28 ++++++++ .../wrong_item.rs | 7 ++ .../wrong_item.stderr | 10 +++ .../wrong_location.rs | 24 +++++++ .../wrong_location.stderr | 32 +++++++++ .../wrong_type.rs | 9 +++ .../wrong_type.stderr | 9 +++ 55 files changed, 798 insertions(+), 89 deletions(-) create mode 100644 tests/ui/crate_local_distributed_slice/create_static_slice.rs create mode 100644 tests/ui/crate_local_distributed_slice/create_static_slice.run.stdout create mode 100644 tests/ui/crate_local_distributed_slice/exact_length.rs create mode 100644 tests/ui/crate_local_distributed_slice/exact_length.stderr create mode 100644 tests/ui/crate_local_distributed_slice/generic_const.rs create mode 100644 tests/ui/crate_local_distributed_slice/generic_const.stderr create mode 100644 tests/ui/crate_local_distributed_slice/initializer.rs create mode 100644 tests/ui/crate_local_distributed_slice/initializer.stderr create mode 100644 tests/ui/crate_local_distributed_slice/no_crate.rs create mode 100644 tests/ui/crate_local_distributed_slice/no_crate.stderr create mode 100644 tests/ui/crate_local_distributed_slice/no_element.rs create mode 100644 tests/ui/crate_local_distributed_slice/no_element.stderr create mode 100644 tests/ui/crate_local_distributed_slice/no_type.rs create mode 100644 tests/ui/crate_local_distributed_slice/no_type.stderr create mode 100644 tests/ui/crate_local_distributed_slice/non_slice.rs create mode 100644 tests/ui/crate_local_distributed_slice/non_slice.stderr create mode 100644 tests/ui/crate_local_distributed_slice/random_const.rs create mode 100644 tests/ui/crate_local_distributed_slice/random_const.stderr create mode 100644 tests/ui/crate_local_distributed_slice/reference_const.rs create mode 100644 tests/ui/crate_local_distributed_slice/reference_const.run.stdout create mode 100644 tests/ui/crate_local_distributed_slice/self_referential.rs create mode 100644 tests/ui/crate_local_distributed_slice/self_referential.stderr create mode 100644 tests/ui/crate_local_distributed_slice/wrong_item.rs create mode 100644 tests/ui/crate_local_distributed_slice/wrong_item.stderr create mode 100644 tests/ui/crate_local_distributed_slice/wrong_location.rs create mode 100644 tests/ui/crate_local_distributed_slice/wrong_location.stderr create mode 100644 tests/ui/crate_local_distributed_slice/wrong_type.rs create mode 100644 tests/ui/crate_local_distributed_slice/wrong_type.stderr diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 0b8d697cc191a..81f81a9a17d38 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3624,6 +3624,8 @@ pub enum DistributedSlice { /// This const (we never do this to statics) represents an addition to a global registry /// declared somewhere else. Addition { declaration: Path, id: NodeId }, + /// Applied to an invalid item, error guaranteed to have be emitted + Err(ErrorGuaranteed), } #[derive(Clone, Encodable, Decodable, Debug)] diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 80a5a53985be7..3bf823ae9ffef 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -458,6 +458,7 @@ macro_rules! common_visitor_and_walkers { visit_opt!(vis, visit_expr, expr); match distributed_slice { DistributedSlice::None => {} + DistributedSlice::Err(..) => {} DistributedSlice::Declaration(span, id) => { try_visit!(visit_span(vis, span)); try_visit!(visit_id(vis, id)); @@ -635,6 +636,7 @@ macro_rules! common_visitor_and_walkers { match distributed_slice { DistributedSlice::None => {} + DistributedSlice::Err(..) => {} DistributedSlice::Declaration(span, id) => { try_visit!(visit_span(vis, span)); try_visit!(visit_id(vis, id)); diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index 5ef76fb64aaf2..6e05fa7d596db 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -56,6 +56,8 @@ ast_lowering_coroutine_too_many_parameters = ast_lowering_default_field_in_tuple = default fields are not supported in tuple structs .label = default fields are only supported on structs +ast_lowering_distributed_slice_with_initializer = + distributed slice elements are added with `distributed_slice_element!(...)` ast_lowering_does_not_support_modifiers = the `{$class_name}` register class does not support template modifiers diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index 576fa9731e906..272c85f65289c 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -475,3 +475,10 @@ pub(crate) struct UseConstGenericArg { #[suggestion_part(code = "{other_args}")] pub call_args: Span, } + +#[derive(Diagnostic)] +#[diag(ast_lowering_distributed_slice_with_initializer)] +pub(crate) struct DistributedSliceWithInitializer { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 28dc9467acf43..0739ebe41ee65 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -5,7 +5,10 @@ use rustc_ast::*; use rustc_errors::ErrorGuaranteed; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; -use rustc_hir::{self as hir, DistributedSlice, HirId, LifetimeSource, PredicateOrigin}; +use rustc_hir::{ + self as hir, DistributedSlice, HirId, InvalidDistributedSliceDeclaration, LifetimeSource, + PredicateOrigin, +}; use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; use rustc_span::edit_distance::find_best_match_for_name; @@ -22,6 +25,7 @@ use super::{ AstOwner, FnDeclKind, ImplTraitContext, ImplTraitPosition, LoweringContext, ParamMode, ResolverAstLoweringExt, }; +use crate::errors::DistributedSliceWithInitializer; pub(super) struct ItemLowerer<'a, 'hir> { pub(super) tcx: TyCtxt<'hir>, @@ -154,6 +158,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ) -> DistributedSlice { match distributed_slice { ast::DistributedSlice::None => DistributedSlice::None, + ast::DistributedSlice::Err(_) => DistributedSlice::None, ast::DistributedSlice::Declaration(span, _) => { DistributedSlice::Declaration(self.lower_span(*span)) } @@ -733,13 +738,25 @@ impl<'hir> LoweringContext<'_, 'hir> { let ty = self.lower_ty( ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy), - false, + matches!(distributed_slice, ast::DistributedSlice::Err(_)), ); let safety = self.lower_safety(*safety, hir::Safety::Unsafe); if define_opaque.is_some() { self.dcx().span_err(i.span, "foreign statics cannot define opaque types"); } - (ident, hir::ForeignItemKind::Static(ty, *mutability, safety)) + ( + ident, + hir::ForeignItemKind::Static( + ty, + *mutability, + safety, + if let ast::DistributedSlice::Err(eg) = distributed_slice { + InvalidDistributedSliceDeclaration::Yes(*eg) + } else { + InvalidDistributedSliceDeclaration::No + }, + ), + ) } ForeignItemKind::TyAlias(box TyAlias { ident, .. }) => { (ident, hir::ForeignItemKind::Type) @@ -861,6 +878,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ty, expr, define_opaque, + distributed_slice, .. }) => { let (generics, kind) = self.lower_generics( @@ -871,12 +889,20 @@ impl<'hir> LoweringContext<'_, 'hir> { let ty = this.lower_ty( ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy), - false, + matches!(distributed_slice, ast::DistributedSlice::Err(_)), ); let body = expr.as_ref().map(|x| this.lower_const_body(i.span, Some(x), None)); - hir::TraitItemKind::Const(ty, body) + hir::TraitItemKind::Const( + ty, + body, + if let ast::DistributedSlice::Err(eg) = distributed_slice { + InvalidDistributedSliceDeclaration::Yes(*eg) + } else { + InvalidDistributedSliceDeclaration::No + }, + ) }, ); @@ -1058,6 +1084,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ty, expr, define_opaque, + distributed_slice, .. }) => ( *ident, @@ -1069,11 +1096,19 @@ impl<'hir> LoweringContext<'_, 'hir> { let ty = this.lower_ty( ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy), - false, + matches!(distributed_slice, ast::DistributedSlice::Err(_)), ); let body = this.lower_const_body(i.span, expr.as_deref(), None); this.lower_define_opaque(hir_id, &define_opaque); - hir::ImplItemKind::Const(ty, body) + hir::ImplItemKind::Const( + ty, + body, + if let ast::DistributedSlice::Err(eg) = distributed_slice { + InvalidDistributedSliceDeclaration::Yes(*eg) + } else { + InvalidDistributedSliceDeclaration::No + }, + ) }, ), ), @@ -1369,7 +1404,16 @@ impl<'hir> LoweringContext<'_, 'hir> { span: this.lower_span(span), } } - (Some(expr), Some(_)) => panic!("distributed slice with initializer"), + (Some(_), Some(node_id)) => { + let eg = this.tcx.dcx().emit_err(DistributedSliceWithInitializer { span }); + + let expr_hir_id = this.lower_node_id(node_id); + hir::Expr { + hir_id: expr_hir_id, + kind: rustc_hir::ExprKind::Err(eg), + span: this.lower_span(span), + } + } (None, None) => { this.expr_err(span, this.dcx().span_delayed_bug(span, "no block")) } diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 23148e0974c61..6c7c56bce9518 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1443,11 +1443,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> { if let AssocCtxt::Impl { .. } = ctxt { match &item.kind { - AssocItemKind::Const(box ConstItem { expr: None, .. }) => { - self.dcx().emit_err(errors::AssocConstWithoutBody { - span: item.span, - replace_span: self.ending_semi_or_hi(item.span), - }); + AssocItemKind::Const(box ConstItem { expr: None, distributed_slice, .. }) => { + if !matches!(distributed_slice, DistributedSlice::Err(..)) { + self.dcx().emit_err(errors::AssocConstWithoutBody { + span: item.span, + replace_span: self.ending_semi_or_hi(item.span), + }); + } } AssocItemKind::Fn(box Fn { body, .. }) => { if body.is_none() && !self.is_sdylib_interface { diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index b77b792c8099e..b9f9d7d35d470 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -222,7 +222,6 @@ impl<'a> State<'a> { define_opaque, distributed_slice: _, }) => { - // FIXME(gr): pretty print global registry self.print_item_const( *ident, None, diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index d32e6f1558e47..e794813664695 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -134,6 +134,26 @@ builtin_macros_derive_path_args_list = traits in `#[derive(...)]` don't accept a builtin_macros_derive_path_args_value = traits in `#[derive(...)]` don't accept values .suggestion = remove the value +builtin_macros_distributed_slice_assoc_item = + expected this to be a module-level const or a static + .note = this is an associated item + .label = because of this attribute + +builtin_macros_distributed_slice_expected_const_static = + expected this to be a const or a static + .label = because of this attribute + +builtin_macros_distributed_slice_expected_crate = + `#[distributed_slice]` must take one parameter `crate` + .suggestion = add `crate` + +builtin_macros_distributed_slice_foreign_item = + expected this to be a non-extern const or a static + .note = this is inside an `extern` block + .label = because of this attribute + +builtin_macros_distributed_slice_generic = + distributed slices can't be generic builtin_macros_env_not_defined = environment variable `{$var}` not defined at compile time .cargo = Cargo sets build script variables at run time. Use `std::env::var({$var_expr})` instead .custom = use `std::env::var({$var_expr})` to read the variable at run time diff --git a/compiler/rustc_builtin_macros/src/distributed_slice.rs b/compiler/rustc_builtin_macros/src/distributed_slice.rs index dc43ed3a02df0..dc6ea7b49567f 100644 --- a/compiler/rustc_builtin_macros/src/distributed_slice.rs +++ b/compiler/rustc_builtin_macros/src/distributed_slice.rs @@ -1,8 +1,8 @@ use rustc_ast::ptr::P; use rustc_ast::tokenstream::TokenStream; use rustc_ast::{ - ConstItem, DUMMY_NODE_ID, Defaultness, DistributedSlice, Expr, Generics, Item, ItemKind, Path, - Ty, TyKind, ast, + AssocItemKind, ConstItem, DUMMY_NODE_ID, Defaultness, DistributedSlice, Expr, ForeignItemKind, + Generics, Item, ItemKind, Path, Ty, TyKind, ast, }; use rustc_errors::PResult; use rustc_expand::base::{ @@ -14,21 +14,59 @@ use rustc_span::{Ident, Span, kw}; use smallvec::smallvec; use thin_vec::ThinVec; +use crate::errors::{ + DistributedSliceAssocItem, DistributedSliceExpectedConstStatic, DistributedSliceExpectedCrate, + DistributedSliceForeignItem, DistributedSliceGeneric, +}; + /// ```rust /// #[distributed_slice(crate)] /// const MEOWS: [&str; _]; /// ``` pub(crate) fn distributed_slice( - _ecx: &mut ExtCtxt<'_>, + ecx: &mut ExtCtxt<'_>, span: Span, - _meta_item: &ast::MetaItem, + meta_item: &ast::MetaItem, mut orig_item: Annotatable, ) -> Vec { // TODO: FIXME(gr) - // FIXME(gr): check item + + if let Some([ast::MetaItemInner::MetaItem(mi)]) = meta_item.meta_item_list() { + if !mi.is_word() || !mi.path.is_ident(kw::Crate) { + ecx.dcx().emit_err(DistributedSliceExpectedCrate { span: meta_item.span }); + } + } else { + ecx.dcx().emit_err(DistributedSliceExpectedCrate { span: meta_item.span }); + }; + + let item_span = orig_item.span(); let Annotatable::Item(item) = &mut orig_item else { - panic!("expected `#[distributed_slice(crate)]` on an item") + if let Annotatable::ForeignItem(fi) = &mut orig_item { + let eg = ecx.dcx().emit_err(DistributedSliceForeignItem { + span: item_span, + attr_span: meta_item.span, + }); + + if let ForeignItemKind::Static(static_item) = &mut fi.kind { + static_item.distributed_slice = DistributedSlice::Err(eg); + } + } else if let Annotatable::AssocItem(ai, ..) = &mut orig_item { + let eg = ecx + .dcx() + .emit_err(DistributedSliceAssocItem { span: item_span, attr_span: meta_item.span }); + + if let AssocItemKind::Const(const_item) = &mut ai.kind { + const_item.distributed_slice = DistributedSlice::Err(eg); + } + } else { + ecx.dcx().emit_err(DistributedSliceExpectedConstStatic { + span: orig_item.span(), + attr_span: meta_item.span, + }); + } + + return vec![orig_item]; }; match &mut item.kind { @@ -36,12 +74,20 @@ pub(crate) fn distributed_slice( static_item.distributed_slice = DistributedSlice::Declaration(span, DUMMY_NODE_ID); } ItemKind::Const(const_item) => { + if !const_item.generics.params.is_empty() + || !const_item.generics.where_clause.is_empty() + { + ecx.dcx().emit_err(DistributedSliceGeneric { span: item_span }); + } + const_item.distributed_slice = DistributedSlice::Declaration(span, DUMMY_NODE_ID); } - other => { - panic!( - "expected `#[distributed_slice(crate)]` on a const or static item, not {other:?}" - ); + _ => { + ecx.dcx().emit_err(DistributedSliceExpectedConstStatic { + span: item.span, + attr_span: meta_item.span, + }); + return vec![orig_item]; } } @@ -69,7 +115,10 @@ pub(crate) fn distributed_slice_element( ) -> MacroExpanderResult<'static> { let (path, expr) = match parse_element(cx.new_parser_from_tts(tts)) { Ok((ident, expr)) => (ident, expr), - Err(err) => { + Err(mut err) => { + if err.span.is_dummy() { + err.span(span); + } let guar = err.emit(); return ExpandResult::Ready(DummyResult::any(span, guar)); } diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index 3a2e96a5e5af4..5fec24319b470 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -965,3 +965,51 @@ pub(crate) struct AsmExpectedOther { pub(crate) span: Span, pub(crate) is_inline_asm: bool, } + +#[derive(Diagnostic)] +#[diag(builtin_macros_distributed_slice_expected_const_static)] +pub(crate) struct DistributedSliceExpectedConstStatic { + #[primary_span] + pub(crate) span: Span, + #[label] + pub(crate) attr_span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_distributed_slice_foreign_item)] +#[note] +pub(crate) struct DistributedSliceForeignItem { + #[primary_span] + pub(crate) span: Span, + #[label] + pub(crate) attr_span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_distributed_slice_assoc_item)] +#[note] +pub(crate) struct DistributedSliceAssocItem { + #[primary_span] + pub(crate) span: Span, + #[label] + pub(crate) attr_span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_distributed_slice_expected_crate)] +pub(crate) struct DistributedSliceExpectedCrate { + #[primary_span] + #[suggestion( + code = "#[distributed_slice(crate)]", + style = "verbose", + applicability = "maybe-incorrect" + )] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_distributed_slice_generic)] +pub(crate) struct DistributedSliceGeneric { + #[primary_span] + pub(crate) span: Span, +} diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 77cb0d5dad2a9..6c710c838c9df 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -3104,8 +3104,8 @@ impl<'hir> TraitItem<'hir> { } expect_methods_self_kind! { - expect_const, (&'hir Ty<'hir>, Option), - TraitItemKind::Const(ty, body), (ty, *body); + expect_const, (&'hir Ty<'hir>, Option, InvalidDistributedSliceDeclaration), + TraitItemKind::Const(ty, body, idsd), (ty, *body, *idsd); expect_fn, (&FnSig<'hir>, &TraitFn<'hir>), TraitItemKind::Fn(ty, trfn), (ty, trfn); @@ -3129,7 +3129,7 @@ pub enum TraitFn<'hir> { #[derive(Debug, Clone, Copy, HashStable_Generic)] pub enum TraitItemKind<'hir> { /// An associated constant with an optional value (otherwise `impl`s must contain a value). - Const(&'hir Ty<'hir>, Option), + Const(&'hir Ty<'hir>, Option, InvalidDistributedSliceDeclaration), /// An associated function with an optional body. Fn(FnSig<'hir>, TraitFn<'hir>), /// An associated type with (possibly empty) bounds and optional concrete @@ -3179,7 +3179,7 @@ impl<'hir> ImplItem<'hir> { } expect_methods_self_kind! { - expect_const, (&'hir Ty<'hir>, BodyId), ImplItemKind::Const(ty, body), (ty, *body); + expect_const, (&'hir Ty<'hir>, BodyId, InvalidDistributedSliceDeclaration), ImplItemKind::Const(ty, body, idsd), (ty, *body, *idsd); expect_fn, (&FnSig<'hir>, BodyId), ImplItemKind::Fn(ty, body), (ty, *body); expect_type, &'hir Ty<'hir>, ImplItemKind::Type(ty), ty; } @@ -3190,7 +3190,7 @@ impl<'hir> ImplItem<'hir> { pub enum ImplItemKind<'hir> { /// An associated constant of the given type, set to the constant result /// of the expression. - Const(&'hir Ty<'hir>, BodyId), + Const(&'hir Ty<'hir>, BodyId, InvalidDistributedSliceDeclaration), /// An associated function implementation with the given signature and body. Fn(FnSig<'hir>, BodyId), /// An associated type. @@ -4511,6 +4511,13 @@ impl ForeignItem<'_> { } } +/// Some info propagated to limit diagnostics after a distributed slice has already been recognized. +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub enum InvalidDistributedSliceDeclaration { + Yes(ErrorGuaranteed), + No, +} + /// An item within an `extern` block. #[derive(Debug, Clone, Copy, HashStable_Generic)] pub enum ForeignItemKind<'hir> { @@ -4522,7 +4529,7 @@ pub enum ForeignItemKind<'hir> { /// arbitrary patterns for parameters. Fn(FnSig<'hir>, &'hir [Option], &'hir Generics<'hir>), /// A foreign static item (`static ext: u8`). - Static(&'hir Ty<'hir>, Mutability, Safety), + Static(&'hir Ty<'hir>, Mutability, Safety, InvalidDistributedSliceDeclaration), /// A foreign type. Type, } @@ -4600,11 +4607,12 @@ impl<'hir> OwnerNode<'hir> { }) | OwnerNode::TraitItem(TraitItem { kind: - TraitItemKind::Fn(_, TraitFn::Provided(body)) | TraitItemKind::Const(_, Some(body)), + TraitItemKind::Fn(_, TraitFn::Provided(body)) + | TraitItemKind::Const(_, Some(body), _), .. }) | OwnerNode::ImplItem(ImplItem { - kind: ImplItemKind::Fn(_, body) | ImplItemKind::Const(_, body), + kind: ImplItemKind::Fn(_, body) | ImplItemKind::Const(_, body, _), .. }) => Some(*body), _ => None, @@ -4825,12 +4833,12 @@ impl<'hir> Node<'hir> { _ => None, }, Node::TraitItem(it) => match it.kind { - TraitItemKind::Const(ty, _) => Some(ty), + TraitItemKind::Const(ty, _, _) => Some(ty), TraitItemKind::Type(_, ty) => ty, _ => None, }, Node::ImplItem(it) => match it.kind { - ImplItemKind::Const(ty, _) => Some(ty), + ImplItemKind::Const(ty, _, _) => Some(ty), ImplItemKind::Type(ty) => Some(ty), _ => None, }, @@ -4859,12 +4867,13 @@ impl<'hir> Node<'hir> { | Node::TraitItem(TraitItem { owner_id, kind: - TraitItemKind::Const(_, Some(body)) | TraitItemKind::Fn(_, TraitFn::Provided(body)), + TraitItemKind::Const(_, Some(body), _) + | TraitItemKind::Fn(_, TraitFn::Provided(body)), .. }) | Node::ImplItem(ImplItem { owner_id, - kind: ImplItemKind::Const(_, body) | ImplItemKind::Fn(_, body), + kind: ImplItemKind::Const(_, body, _) | ImplItemKind::Fn(_, body), .. }) => Some((owner_id.def_id, *body)), diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 5686e4089d76d..9565367eb8548 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -659,7 +659,7 @@ pub fn walk_foreign_item<'v, V: Visitor<'v>>( visit_opt!(visitor, visit_ident, ident); } } - ForeignItemKind::Static(ref typ, _, _) => { + ForeignItemKind::Static(ref typ, _, _, _) => { try_visit!(visitor.visit_ty_unambig(typ)); } ForeignItemKind::Type => (), @@ -1167,7 +1167,7 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>( try_visit!(visitor.visit_defaultness(&defaultness)); try_visit!(visitor.visit_id(hir_id)); match *kind { - TraitItemKind::Const(ref ty, default) => { + TraitItemKind::Const(ref ty, default, _) => { try_visit!(visitor.visit_ty_unambig(ty)); visit_opt!(visitor, visit_nested_body, default); } @@ -1225,7 +1225,7 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>( try_visit!(visitor.visit_defaultness(defaultness)); try_visit!(visitor.visit_id(impl_item.hir_id())); match *kind { - ImplItemKind::Const(ref ty, body) => { + ImplItemKind::Const(ref ty, body, _) => { try_visit!(visitor.visit_ty_unambig(ty)); visitor.visit_nested_body(body) } diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index a3a0e276f74cd..51034824cb051 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -148,6 +148,21 @@ hir_analysis_dispatch_from_dyn_repr = structs implementing `DispatchFromDyn` may hir_analysis_dispatch_from_dyn_zst = the trait `DispatchFromDyn` may only be implemented for structs containing the field being coerced, ZST fields with 1 byte alignment that don't mention type/const generics, and nothing else .note = extra field `{$name}` of type `{$ty}` is not allowed +hir_analysis_distributed_slice_non_array = + expected this type to be an array + .note = a distributed slice must have an array type with an inferred length + .suggestion = change the type to an array +hir_analysis_distributed_slice_non_infer_length = + expected this length to be `_` + .note = the length of a distributed slice is determined by the added elements throughout the crate + .suggestion = "replace the length with `_`" + +hir_analysis_distributed_slice_wrong_target = + `distributed_slice_element!()` can only add to a distributed slice + .label = element added here + .wrong_declaration = not a distributed slice + .suggestion = add `#[distributed_slice(crate)]` + hir_analysis_drop_impl_negative = negative `Drop` impls are not supported hir_analysis_drop_impl_on_wrong_item = diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 47681a78ecca8..240a5ec4fa9ff 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -2075,7 +2075,7 @@ fn compare_const_predicate_entailment<'tcx>( debug!(?impl_ty, ?trait_ty); // Locate the Span containing just the type of the offending impl - let (ty, _) = tcx.hir_expect_impl_item(impl_ct_def_id).expect_const(); + let (ty, _, _) = tcx.hir_expect_impl_item(impl_ct_def_id).expect_const(); cause.span = ty.span; let mut diag = struct_span_code_err!( @@ -2088,7 +2088,7 @@ fn compare_const_predicate_entailment<'tcx>( let trait_c_span = trait_ct.def_id.as_local().map(|trait_ct_def_id| { // Add a label to the Span containing just the type of the const - let (ty, _) = tcx.hir_expect_trait_item(trait_ct_def_id).expect_const(); + let (ty, _, _) = tcx.hir_expect_trait_item(trait_ct_def_id).expect_const(); ty.span }); diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 9060a667a800e..b60f313c3f844 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -856,7 +856,7 @@ fn check_dyn_incompatible_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitI }; let mut trait_should_be_self = vec![]; match &item.kind { - hir::TraitItemKind::Const(ty, _) | hir::TraitItemKind::Type(_, Some(ty)) + hir::TraitItemKind::Const(ty, _, _) | hir::TraitItemKind::Type(_, Some(ty)) if could_be_self(trait_def_id.def_id, ty) => { trait_should_be_self.push(ty.span) diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index e368aa5852b29..01769678a26ce 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -29,7 +29,10 @@ use rustc_errors::{ use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, InferKind, Visitor, VisitorExt, walk_generics}; -use rustc_hir::{self as hir, GenericParamKind, HirId, Node, PreciseCapturingArgKind}; +use rustc_hir::{ + self as hir, GenericParamKind, HirId, InvalidDistributedSliceDeclaration, Node, + PreciseCapturingArgKind, +}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::{DynCompatibilityViolation, ObligationCause}; use rustc_middle::hir::nested_filter; @@ -165,7 +168,11 @@ pub(crate) fn placeholder_type_error<'tcx>( suggest: bool, hir_ty: Option<&hir::Ty<'_>>, kind: &'static str, + distributed_slice_declaration: InvalidDistributedSliceDeclaration, ) { + if let InvalidDistributedSliceDeclaration::Yes(..) = distributed_slice_declaration { + return; + } if placeholder_types.is_empty() { return; } @@ -274,6 +281,7 @@ fn reject_placeholder_type_signatures_in_item<'tcx>( suggest && !visitor.may_contain_const_infer, None, item.kind.descr(), + InvalidDistributedSliceDeclaration::No, ); } @@ -700,7 +708,7 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { tcx.ensure_ok().codegen_fn_attrs(item.owner_id); tcx.ensure_ok().fn_sig(item.owner_id) } - hir::ForeignItemKind::Static(..) => { + hir::ForeignItemKind::Static(.., distributed_slice) => { tcx.ensure_ok().codegen_fn_attrs(item.owner_id); let mut visitor = HirPlaceholderCollector::default(); visitor.visit_foreign_item(item); @@ -711,6 +719,7 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { false, None, "static variable", + distributed_slice, ); } _ => (), @@ -779,6 +788,7 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { false, None, it.kind.descr(), + InvalidDistributedSliceDeclaration::No, ); } } @@ -806,7 +816,7 @@ fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) { tcx.ensure_ok().fn_sig(def_id); } - hir::TraitItemKind::Const(ty, body_id) => { + hir::TraitItemKind::Const(ty, body_id, distributed_slice) => { tcx.ensure_ok().type_of(def_id); if !tcx.dcx().has_stashed_diagnostic(ty.span, StashKey::ItemNoType) && !(ty.is_suggestable_infer_ty() && body_id.is_some()) @@ -821,6 +831,7 @@ fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) { false, None, "associated constant", + distributed_slice, ); } } @@ -839,6 +850,7 @@ fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) { false, None, "associated type", + InvalidDistributedSliceDeclaration::No, ); } @@ -857,6 +869,7 @@ fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) { false, None, "associated type", + InvalidDistributedSliceDeclaration::No, ); } }; @@ -888,9 +901,10 @@ fn lower_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) { false, None, "associated type", + InvalidDistributedSliceDeclaration::No, ); } - hir::ImplItemKind::Const(ty, _) => { + hir::ImplItemKind::Const(ty, _, distributed_slice) => { // Account for `const T: _ = ..;` if !ty.is_suggestable_infer_ty() { let mut visitor = HirPlaceholderCollector::default(); @@ -902,6 +916,7 @@ fn lower_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) { false, None, "associated constant", + distributed_slice, ); } } diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 1820c6225fd8c..29d7d589c7857 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -855,7 +855,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { } }) } - Const(_, _) => self.visit_early(trait_item.hir_id(), trait_item.generics, |this| { + Const(_, _, _) => self.visit_early(trait_item.hir_id(), trait_item.generics, |this| { intravisit::walk_trait_item(this, trait_item) }), } @@ -872,7 +872,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { this.visit_generics(impl_item.generics); this.visit_ty_unambig(ty); }), - Const(_, _) => self.visit_early(impl_item.hir_id(), impl_item.generics, |this| { + Const(_, _, _) => self.visit_early(impl_item.hir_id(), impl_item.generics, |this| { intravisit::walk_impl_item(this, impl_item) }), } diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index e0341f79fff08..07af0fd0f19ee 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -3,7 +3,7 @@ use core::ops::ControlFlow; use rustc_errors::{Applicability, StashKey, Suggestions}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::VisitorExt; -use rustc_hir::{self as hir, AmbigArg, HirId}; +use rustc_hir::{self as hir, AmbigArg, HirId, InvalidDistributedSliceDeclaration}; use rustc_middle::query::plumbing::CyclePlaceholder; use rustc_middle::ty::print::with_forced_trimmed_paths; use rustc_middle::ty::util::IntTypeExt; @@ -14,7 +14,10 @@ use rustc_middle::{bug, span_bug}; use rustc_span::{DUMMY_SP, Ident, Span}; use super::{HirPlaceholderCollector, ItemCtxt, bad_placeholder}; -use crate::errors::TypeofReservedKeywordUsed; +use crate::errors::{ + DistributedSliceNonArray, DistributedSliceNonInferLength, DistributedSliceWrongTarget, + TypeofReservedKeywordUsed, +}; use crate::hir_ty_lowering::HirTyLowerer; mod opaque; @@ -118,24 +121,33 @@ pub fn type_of_distributed_slice<'tcx>( lowerer: &dyn HirTyLowerer<'tcx>, ty: &rustc_hir::Ty<'tcx>, def_id: LocalDefId, + emit_diagnostics: bool, ) -> Ty<'tcx> { use rustc_hir::*; use rustc_middle::ty::Ty; - let TyKind::Array(element_ty, len) = ty.kind else { - panic!("gr should be an array"); - }; + let element_ty = if let TyKind::Array(element_ty, len) = ty.kind { + if let ConstArgKind::Infer { .. } = len.kind { + } else if emit_diagnostics { + tcx.dcx().emit_err(DistributedSliceNonInferLength { span: len.span() }); + }; - let ConstArgKind::Infer { .. } = len.kind else { - // FIXME(gr) exact - todo!("expected infer"); + lowerer.lower_ty(element_ty) + } else { + let lowered = lowerer.lower_ty(ty); + + if emit_diagnostics { + tcx.dcx().emit_err(DistributedSliceNonArray { span: ty.span, orig_ty: lowered }); + } + + lowered }; let res: Option<&Vec> = tcx.distributed_slice_elements(()).get(&def_id.to_def_id()); let res = Ty::new_array_with_const_len( tcx, - lowerer.lower_ty(element_ty), + element_ty, ty::Const::from_target_usize(tcx, res.map(|i| i.len()).unwrap_or(0) as u64), ); @@ -186,7 +198,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ let args = ty::GenericArgs::identity_for_item(tcx, def_id); Ty::new_fn_def(tcx, def_id.to_def_id(), args) } - TraitItemKind::Const(ty, body_id) => body_id + TraitItemKind::Const(ty, body_id, distributed_slice) => body_id .and_then(|body_id| { ty.is_suggestable_infer_ty().then(|| { infer_placeholder_type( @@ -196,6 +208,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ ty.span, item.ident, "associated constant", + distributed_slice, ) }) }) @@ -211,7 +224,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ let args = ty::GenericArgs::identity_for_item(tcx, def_id); Ty::new_fn_def(tcx, def_id.to_def_id(), args) } - ImplItemKind::Const(ty, body_id) => { + ImplItemKind::Const(ty, body_id, distributed_slice) => { if ty.is_suggestable_infer_ty() { infer_placeholder_type( icx.lowerer(), @@ -220,6 +233,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ ty.span, item.ident, "associated constant", + distributed_slice, ) } else { icx.lower_ty(ty) @@ -237,7 +251,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ Node::Item(item) => match item.kind { ItemKind::Static(_, ident, ty, body_id, distributed_slice) => { if let DistributedSlice::Declaration(_) = distributed_slice { - type_of_distributed_slice(tcx, icx.lowerer(), ty, def_id) + type_of_distributed_slice(tcx, icx.lowerer(), ty, def_id, true) } else if ty.is_suggestable_infer_ty() { infer_placeholder_type( icx.lowerer(), @@ -246,6 +260,8 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ ty.span, ident, "static variable", + // if it was, we would've handled it above + InvalidDistributedSliceDeclaration::No, ) } else { icx.lower_ty(ty) @@ -253,14 +269,32 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ } ItemKind::Const(ident, _, ty, body_id, distributed_slice) => { if let DistributedSlice::Declaration(_) = distributed_slice { - type_of_distributed_slice(tcx, &icx, ty, def_id) + type_of_distributed_slice(tcx, &icx, ty, def_id, true) } else if let DistributedSlice::Addition(declaration_def_id) = distributed_slice { + let declaration_item = tcx.hir_expect_item(declaration_def_id); + if let hir::ItemKind::Const(_, _, _, _, ds) + | hir::ItemKind::Static(_, _, _, _, ds) = declaration_item.kind + { + if !matches!(ds, DistributedSlice::Declaration(..)) { + tcx.dcx().emit_err(DistributedSliceWrongTarget { + span: item.span, + wrong_declaration: declaration_item.span, + suggestion_before: declaration_item.span.shrink_to_lo(), + }); + } + } else { + tcx.dcx().span_delayed_bug( + item.span, + "should have errored during name resolution", + ); + } + // we reject generic const items (`#![feature(generic_const_items)]`) in `#[distributed_slice(crate)]` let array_ty = tcx.type_of(declaration_def_id).instantiate_identity(); let ty = match array_ty.kind() { ty::Array(element_ty, _) => *element_ty, - _ => panic!("not an array"), + _ => bug!("not an array"), }; ty @@ -272,6 +306,8 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ ty.span, ident, "constant", + // if it was, we would've handled it above + InvalidDistributedSliceDeclaration::No, ) } else { icx.lower_ty(ty) @@ -318,7 +354,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ let args = ty::GenericArgs::identity_for_item(tcx, def_id); Ty::new_fn_def(tcx, def_id.to_def_id(), args) } - ForeignItemKind::Static(t, _, _) => icx.lower_ty(t), + ForeignItemKind::Static(t, _, _, _) => icx.lower_ty(t), ForeignItemKind::Type => Ty::new_foreign(tcx, def_id.to_def_id()), }, @@ -453,10 +489,15 @@ fn infer_placeholder_type<'tcx>( span: Span, item_ident: Ident, kind: &'static str, + invalid_distributed_slice: InvalidDistributedSliceDeclaration, ) -> Ty<'tcx> { let tcx = cx.tcx(); let ty = tcx.typeck(def_id).node_type(body_id.hir_id); + if let InvalidDistributedSliceDeclaration::Yes(eg) = invalid_distributed_slice { + return Ty::new_error(tcx, eg); + } + // If this came from a free `const` or `static mut?` item, // then the user may have written e.g. `const A = 42;`. // In this case, the parser has stashed a diagnostic for diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 152714b340731..368a8059ef2f0 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1707,3 +1707,40 @@ pub(crate) struct SelfInTypeAlias { #[label] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(hir_analysis_distributed_slice_wrong_target)] +pub(crate) struct DistributedSliceWrongTarget { + #[primary_span] + #[label] + pub span: Span, + + #[label(hir_analysis_wrong_declaration)] + pub wrong_declaration: Span, + + #[suggestion( + code = "#[distributed_slice(crate)]\n", + style = "verbose", + applicability = "maybe-incorrect" + )] + pub suggestion_before: Span, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_distributed_slice_non_infer_length)] +#[note] +pub(crate) struct DistributedSliceNonInferLength { + #[primary_span] + #[suggestion(code = "_", style = "verbose", applicability = "maybe-incorrect")] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_distributed_slice_non_array)] +#[note] +pub(crate) struct DistributedSliceNonArray<'a> { + #[primary_span] + #[suggestion(code = "[{orig_ty}; _]", style = "verbose", applicability = "maybe-incorrect")] + pub span: Span, + pub orig_ty: Ty<'a>, +} diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs index ded09826b8d9f..69dc1fef292cb 100644 --- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs @@ -136,12 +136,12 @@ fn diagnostic_hir_wf_check<'tcx>( WellFormedLoc::Ty(_) => match tcx.hir_node(hir_id) { hir::Node::ImplItem(item) => match item.kind { hir::ImplItemKind::Type(ty) => vec![ty], - hir::ImplItemKind::Const(ty, _) => vec![ty], + hir::ImplItemKind::Const(ty, _, _) => vec![ty], ref item => bug!("Unexpected ImplItem {:?}", item), }, hir::Node::TraitItem(item) => match item.kind { hir::TraitItemKind::Type(_, ty) => ty.into_iter().collect(), - hir::TraitItemKind::Const(ty, _) => vec![ty], + hir::TraitItemKind::Const(ty, _, _) => vec![ty], ref item => bug!("Unexpected TraitItem {:?}", item), }, hir::Node::Item(item) => match item.kind { @@ -172,7 +172,8 @@ fn diagnostic_hir_wf_check<'tcx>( }, hir::Node::Field(field) => vec![field.ty], hir::Node::ForeignItem(ForeignItem { - kind: ForeignItemKind::Static(ty, _, _), .. + kind: ForeignItemKind::Static(ty, _, _, _), + .. }) => vec![*ty], hir::Node::GenericParam(hir::GenericParam { kind: hir::GenericParamKind::Type { default: Some(ty), .. }, diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 63eaa2e008375..07a437ae809b5 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -17,9 +17,9 @@ use rustc_ast_pretty::pprust::state::MacHeader; use rustc_ast_pretty::pprust::{Comments, PrintState}; use rustc_attr_data_structures::{AttributeKind, PrintAttribute}; use rustc_hir::{ - BindingMode, ByRef, ConstArgKind, GenericArg, GenericBound, GenericParam, GenericParamKind, - HirId, ImplicitSelfKind, LifetimeParamKind, Node, PatKind, PreciseCapturingArg, RangeEnd, Term, - TyPatKind, + BindingMode, ByRef, ConstArgKind, DistributedSlice, GenericArg, GenericBound, GenericParam, + GenericParamKind, HirId, ImplicitSelfKind, LifetimeParamKind, Node, PatKind, + PreciseCapturingArg, RangeEnd, Term, TyPatKind, }; use rustc_span::source_map::SourceMap; use rustc_span::{FileName, Ident, Span, Symbol, kw}; @@ -488,7 +488,7 @@ impl<'a> State<'a> { self.word(";"); self.end(cb) } - hir::ForeignItemKind::Static(t, m, safety) => { + hir::ForeignItemKind::Static(t, m, safety, _) => { self.print_safety(safety); let (cb, ib) = self.head("static"); if m.is_mut() { @@ -559,6 +559,14 @@ impl<'a> State<'a> { self.maybe_print_comment(item.span.lo()); let attrs = self.attrs(item.hir_id()); self.print_attrs_as_outer(attrs); + + if let hir::ItemKind::Const(.., DistributedSlice::Declaration(..)) + | hir::ItemKind::Static(.., DistributedSlice::Declaration(..)) = item.kind + { + self.word("#[distributed_slice(crate)]"); + self.hardbreak_if_not_bol(); + } + self.ann.pre(self, AnnNode::Item(item)); match item.kind { hir::ItemKind::ExternCrate(orig_name, ident) => { @@ -593,7 +601,7 @@ impl<'a> State<'a> { self.end(ib); self.end(cb); } - hir::ItemKind::Static(m, ident, ty, expr, distributed_slice) => { + hir::ItemKind::Static(m, ident, ty, expr, _ds) => { let (cb, ib) = self.head("static"); if m.is_mut() { self.word_space("mut"); @@ -609,7 +617,13 @@ impl<'a> State<'a> { self.word(";"); self.end(cb); } - hir::ItemKind::Const(ident, generics, ty, expr, distributed_slice) => { + hir::ItemKind::Const( + ident, + generics, + ty, + expr, + DistributedSlice::None | DistributedSlice::Declaration(..), + ) => { let (cb, ib) = self.head("const"); self.print_ident(ident); self.print_generic_params(generics.params); @@ -624,6 +638,17 @@ impl<'a> State<'a> { self.word(";"); self.end(cb); } + hir::ItemKind::Const(.., expr, DistributedSlice::Addition(d)) => { + let (cb, ib) = self.head("distributed_slice_element!"); + self.popen(); + self.word(format!("{d:?}")); + self.word(","); + self.ann.nested(self, Nested::Body(expr)); + self.pclose(); + self.word(";"); + self.end(ib); + self.end(cb); + } hir::ItemKind::Fn { ident, sig, generics, body, .. } => { let (cb, ib) = self.head(""); self.print_fn(sig.header, Some(ident.name), generics, sig.decl, &[], Some(body)); @@ -911,7 +936,7 @@ impl<'a> State<'a> { self.maybe_print_comment(ti.span.lo()); self.print_attrs_as_outer(self.attrs(ti.hir_id())); match ti.kind { - hir::TraitItemKind::Const(ty, default) => { + hir::TraitItemKind::Const(ty, default, _) => { self.print_associated_const(ti.ident, ti.generics, ty, default); } hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(arg_idents)) => { @@ -940,7 +965,7 @@ impl<'a> State<'a> { self.print_attrs_as_outer(self.attrs(ii.hir_id())); match ii.kind { - hir::ImplItemKind::Const(ty, expr) => { + hir::ImplItemKind::Const(ty, expr, _) => { self.print_associated_const(ii.ident, ii.generics, ty, Some(expr)); } hir::ImplItemKind::Fn(ref sig, body) => { diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 5d74429668ce5..0e1c743237f0f 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -172,13 +172,27 @@ fn typeck_with_inspect<'tcx>( check_fn(&mut fcx, fn_sig, None, decl, def_id, body, tcx.features().unsized_fn_params()); } else { - let expected_type = if let Some(infer_ty) = infer_type_if_missing(&fcx, node) { + let expected_type = if let Node::Item(item) = node + && let ItemKind::Const(.., DistributedSlice::Addition(declaration_def_id, ..)) = + item.kind + { + // we reject generic const items (`#![feature(generic_const_items)]`) in `#[distributed_slice(crate)]` + let array_ty = tcx.type_of(declaration_def_id).instantiate_identity(); + + let ty = match array_ty.kind() { + ty::Array(element_ty, _) => *element_ty, + _ => bug!("not an array"), + }; + + ty + } else if let Some(infer_ty) = infer_type_if_missing(&fcx, node) { infer_ty } else if let Node::Item(item) = node - && let ItemKind::Const(.., DistributedSlice::Declaration(..)) = item.kind + && let ItemKind::Const(.., DistributedSlice::Declaration(..)) + | ItemKind::Static(.., DistributedSlice::Declaration(..)) = item.kind && let Some(ty) = node.ty() { - type_of_distributed_slice(tcx, fcx.lowerer(), ty, def_id) + type_of_distributed_slice(tcx, fcx.lowerer(), ty, def_id, false) } else if let Some(ty) = node.ty() && ty.is_suggestable_infer_ty() { diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 79b8f815d4802..18cae36068a1c 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1641,7 +1641,7 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDeclarations { vis.check_foreign_fn(it.owner_id.def_id, sig.decl); } } - hir::ForeignItemKind::Static(ty, _, _) if !abi.is_rustic_abi() => { + hir::ForeignItemKind::Static(ty, _, _, _) if !abi.is_rustic_abi() => { vis.check_foreign_static(it.owner_id, ty.span); } hir::ForeignItemKind::Static(..) | hir::ForeignItemKind::Type => (), diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs index 8f52e79d54842..6bb81c3faa90b 100644 --- a/compiler/rustc_mir_build/src/builder/mod.rs +++ b/compiler/rustc_mir_build/src/builder/mod.rs @@ -562,9 +562,11 @@ fn construct_const<'a, 'tcx>( span, .. }) - | Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(ty, _), span, .. }) + | Node::ImplItem(hir::ImplItem { + kind: hir::ImplItemKind::Const(ty, _, _), span, .. + }) | Node::TraitItem(hir::TraitItem { - kind: hir::TraitItemKind::Const(ty, Some(_)), + kind: hir::TraitItemKind::Const(ty, Some(_), _), span, .. }) => (*span, ty.span), diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 6b82252f32c26..1726a1357a338 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -14,7 +14,7 @@ use rustc_errors::MultiSpan; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId}; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{self as hir, Node, PatKind, QPath, TyKind}; +use rustc_hir::{self as hir, DistributedSlice, Node, PatKind, QPath, TyKind}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::privacy::Level; use rustc_middle::query::Providers; @@ -435,6 +435,22 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { } intravisit::walk_item(self, item) } + hir::ItemKind::Const(.., DistributedSlice::Declaration(..)) + | hir::ItemKind::Static(.., DistributedSlice::Declaration(..)) => { + let defid = item.owner_id.to_def_id(); + let elements: &[LocalDefId] = self + .tcx + .distributed_slice_elements(()) + .get(&defid) + .map(|i| i.as_slice()) + .unwrap_or_default(); + + intravisit::walk_item(self, item); + + for element in elements { + self.check_def_id(element.to_def_id()); + } + } _ => intravisit::walk_item(self, item), }, Node::TraitItem(trait_item) => { @@ -805,7 +821,7 @@ fn check_trait_item( use hir::TraitItemKind::{Const, Fn}; if matches!(tcx.def_kind(id.owner_id), DefKind::AssocConst | DefKind::AssocFn) { let trait_item = tcx.hir_trait_item(id); - if matches!(trait_item.kind, Const(_, Some(_)) | Fn(..)) + if matches!(trait_item.kind, Const(_, Some(_), _) | Fn(..)) && let Some(comes_from_allow) = has_allow_dead_code_or_lang_attr(tcx, trait_item.owner_id.def_id) { diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index ea35190567189..681a0d8a926d3 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -145,7 +145,7 @@ impl<'tcx> ReachableContext<'tcx> { _ => false, }, Node::TraitItem(trait_method) => match trait_method.kind { - hir::TraitItemKind::Const(_, ref default) => default.is_some(), + hir::TraitItemKind::Const(_, ref default, _) => default.is_some(), hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)) => true, hir::TraitItemKind::Fn(_, hir::TraitFn::Required(_)) | hir::TraitItemKind::Type(..) => false, @@ -204,7 +204,7 @@ impl<'tcx> ReachableContext<'tcx> { } } - hir::ItemKind::Const(_, _, _, init, distributed_slice) => { + hir::ItemKind::Const(_, _, _, init, ..) => { // Only things actually ending up in the final constant value are reachable // for codegen. Everything else is only needed during const-eval, so even if // const-eval happens in a downstream crate, all they need is @@ -249,11 +249,11 @@ impl<'tcx> ReachableContext<'tcx> { } Node::TraitItem(trait_method) => { match trait_method.kind { - hir::TraitItemKind::Const(_, None) + hir::TraitItemKind::Const(_, None, _) | hir::TraitItemKind::Fn(_, hir::TraitFn::Required(_)) => { // Keep going, nothing to get exported } - hir::TraitItemKind::Const(_, Some(body_id)) + hir::TraitItemKind::Const(_, Some(body_id), _) | hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body_id)) => { self.visit_nested_body(body_id); } @@ -261,7 +261,7 @@ impl<'tcx> ReachableContext<'tcx> { } } Node::ImplItem(impl_item) => match impl_item.kind { - hir::ImplItemKind::Const(_, body) => { + hir::ImplItemKind::Const(_, body, _) => { self.visit_nested_body(body); } hir::ImplItemKind::Fn(_, body) => { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 3caca95be9432..02eb6029dd232 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -514,7 +514,7 @@ impl<'a> PathSource<'a> { }, PathSource::ReturnTypeNotation | PathSource::Delegation => "function", PathSource::PreciseCapturingArg(..) => "type or const parameter", - PathSource::DistributedSlice => "const or static value", + PathSource::DistributedSlice => "const or static distributed slice", } } diff --git a/tests/ui/crate_local_distributed_slice/create_static_slice.rs b/tests/ui/crate_local_distributed_slice/create_static_slice.rs new file mode 100644 index 0000000000000..4cd067464fcb1 --- /dev/null +++ b/tests/ui/crate_local_distributed_slice/create_static_slice.rs @@ -0,0 +1,13 @@ +#![feature(crate_local_distributed_slice)] +//@ run-pass +//@ check-run-results + +#[distributed_slice(crate)] +static MEOWS: [&str; _]; + +distributed_slice_element!(MEOWS, "mrow"); +distributed_slice_element!(MEOWS, "mew"); + +fn main() { + println!("{MEOWS:?}"); +} diff --git a/tests/ui/crate_local_distributed_slice/create_static_slice.run.stdout b/tests/ui/crate_local_distributed_slice/create_static_slice.run.stdout new file mode 100644 index 0000000000000..484b65a358e13 --- /dev/null +++ b/tests/ui/crate_local_distributed_slice/create_static_slice.run.stdout @@ -0,0 +1 @@ +["mew", "mrow"] diff --git a/tests/ui/crate_local_distributed_slice/exact_length.rs b/tests/ui/crate_local_distributed_slice/exact_length.rs new file mode 100644 index 0000000000000..9f7cc9b41276c --- /dev/null +++ b/tests/ui/crate_local_distributed_slice/exact_length.rs @@ -0,0 +1,7 @@ +#![feature(crate_local_distributed_slice)] + +#[distributed_slice(crate)] +const MEOWS: [&str; 10]; +//~^ ERROR expected this length to be `_` + +fn main() {} diff --git a/tests/ui/crate_local_distributed_slice/exact_length.stderr b/tests/ui/crate_local_distributed_slice/exact_length.stderr new file mode 100644 index 0000000000000..1fd4bc4f5a499 --- /dev/null +++ b/tests/ui/crate_local_distributed_slice/exact_length.stderr @@ -0,0 +1,15 @@ +error: expected this length to be `_` + --> $DIR/exact_length.rs:4:21 + | +LL | const MEOWS: [&str; 10]; + | ^^ + | + = note: the length of a distributed slice is determined by the added elements throughout the crate +help: "replace the length with `_`" + | +LL - const MEOWS: [&str; 10]; +LL + const MEOWS: [&str; _]; + | + +error: aborting due to 1 previous error + diff --git a/tests/ui/crate_local_distributed_slice/generic_const.rs b/tests/ui/crate_local_distributed_slice/generic_const.rs new file mode 100644 index 0000000000000..f45b90ddeb687 --- /dev/null +++ b/tests/ui/crate_local_distributed_slice/generic_const.rs @@ -0,0 +1,9 @@ +#![allow(incomplete_features)] +#![feature(crate_local_distributed_slice)] +#![feature(generic_const_items)] + +#[distributed_slice(crate)] +const MEOWS: [T; _]; +//~^ ERROR distributed slices can't be generic + +fn main() {} diff --git a/tests/ui/crate_local_distributed_slice/generic_const.stderr b/tests/ui/crate_local_distributed_slice/generic_const.stderr new file mode 100644 index 0000000000000..8b3ad898a4306 --- /dev/null +++ b/tests/ui/crate_local_distributed_slice/generic_const.stderr @@ -0,0 +1,8 @@ +error: distributed slices can't be generic + --> $DIR/generic_const.rs:6:1 + | +LL | const MEOWS: [T; _]; + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/crate_local_distributed_slice/initializer.rs b/tests/ui/crate_local_distributed_slice/initializer.rs new file mode 100644 index 0000000000000..149fb530673d1 --- /dev/null +++ b/tests/ui/crate_local_distributed_slice/initializer.rs @@ -0,0 +1,7 @@ +#![feature(crate_local_distributed_slice)] + +#[distributed_slice(crate)] +const MEOWS: [&str; _] = ["meow"]; +//~^ ERROR distributed slice elements are added with `distributed_slice_element!(...)` + +fn main() {} diff --git a/tests/ui/crate_local_distributed_slice/initializer.stderr b/tests/ui/crate_local_distributed_slice/initializer.stderr new file mode 100644 index 0000000000000..131d25ca4a984 --- /dev/null +++ b/tests/ui/crate_local_distributed_slice/initializer.stderr @@ -0,0 +1,8 @@ +error: distributed slice elements are added with `distributed_slice_element!(...)` + --> $DIR/initializer.rs:4:1 + | +LL | const MEOWS: [&str; _] = ["meow"]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/crate_local_distributed_slice/no_crate.rs b/tests/ui/crate_local_distributed_slice/no_crate.rs new file mode 100644 index 0000000000000..5253ebbf804a9 --- /dev/null +++ b/tests/ui/crate_local_distributed_slice/no_crate.rs @@ -0,0 +1,12 @@ +#![feature(crate_local_distributed_slice)] + +#[distributed_slice] +//~^ ERROR `#[distributed_slice]` must take one parameter `crate +const MEOWS: [&str; _]; + +distributed_slice_element!(MEOWS, "mrow"); +distributed_slice_element!(MEOWS, "mew"); + +fn main() { + println!("{MEOWS:?}"); +} diff --git a/tests/ui/crate_local_distributed_slice/no_crate.stderr b/tests/ui/crate_local_distributed_slice/no_crate.stderr new file mode 100644 index 0000000000000..8f93302ed6209 --- /dev/null +++ b/tests/ui/crate_local_distributed_slice/no_crate.stderr @@ -0,0 +1,13 @@ +error: `#[distributed_slice]` must take one parameter `crate` + --> $DIR/no_crate.rs:3:1 + | +LL | #[distributed_slice] + | ^^^^^^^^^^^^^^^^^^^^ + | +help: add `crate` + | +LL | #[distributed_slice(crate)] + | +++++++ + +error: aborting due to 1 previous error + diff --git a/tests/ui/crate_local_distributed_slice/no_element.rs b/tests/ui/crate_local_distributed_slice/no_element.rs new file mode 100644 index 0000000000000..11740ff72ba6e --- /dev/null +++ b/tests/ui/crate_local_distributed_slice/no_element.rs @@ -0,0 +1,16 @@ +#![feature(crate_local_distributed_slice)] + +#[distributed_slice(crate)] +const MEOWS: [&str; _]; + +distributed_slice_element!(MEOWS,); +//~^ ERROR expected expression, found end of macro argument +distributed_slice_element!(MEOWS); +//~^ ERROR expected one of `,` or `::`, found `` +distributed_slice_element!(); +//~^ ERROR expected identifier, found `` +distributed_slice_element!(MEOWS, "mew", ); // trailing comma ok + +fn main() { + println!("{MEOWS:?}"); +} diff --git a/tests/ui/crate_local_distributed_slice/no_element.stderr b/tests/ui/crate_local_distributed_slice/no_element.stderr new file mode 100644 index 0000000000000..c382bf917fe0f --- /dev/null +++ b/tests/ui/crate_local_distributed_slice/no_element.stderr @@ -0,0 +1,20 @@ +error: expected expression, found end of macro arguments + --> $DIR/no_element.rs:6:34 + | +LL | distributed_slice_element!(MEOWS,); + | ^ expected expression + +error: expected one of `,` or `::`, found `` + --> $DIR/no_element.rs:8:28 + | +LL | distributed_slice_element!(MEOWS); + | ^^^^^ expected one of `,` or `::` + +error: expected identifier, found `` + --> $DIR/no_element.rs:10:1 + | +LL | distributed_slice_element!(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/crate_local_distributed_slice/no_type.rs b/tests/ui/crate_local_distributed_slice/no_type.rs new file mode 100644 index 0000000000000..b251023eaeebc --- /dev/null +++ b/tests/ui/crate_local_distributed_slice/no_type.rs @@ -0,0 +1,9 @@ +#![feature(crate_local_distributed_slice)] + +#[distributed_slice(crate)] +const MEOWS: [_; _]; +//~^ ERROR type annotations needed [E0282] + +distributed_slice_element!(MEOWS, "MROW"); + +fn main() {} diff --git a/tests/ui/crate_local_distributed_slice/no_type.stderr b/tests/ui/crate_local_distributed_slice/no_type.stderr new file mode 100644 index 0000000000000..61f1604918346 --- /dev/null +++ b/tests/ui/crate_local_distributed_slice/no_type.stderr @@ -0,0 +1,9 @@ +error[E0282]: type annotations needed + --> $DIR/no_type.rs:4:1 + | +LL | const MEOWS: [_; _]; + | ^^^^^^^^^^^^^^^^^^^^ cannot infer type + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/crate_local_distributed_slice/non_slice.rs b/tests/ui/crate_local_distributed_slice/non_slice.rs new file mode 100644 index 0000000000000..3481dad9da602 --- /dev/null +++ b/tests/ui/crate_local_distributed_slice/non_slice.rs @@ -0,0 +1,9 @@ +#![feature(crate_local_distributed_slice)] + +#[distributed_slice(crate)] +const MEOWS: &str; +//~^ ERROR expected this type to be an array + +distributed_slice_element!(MEOWS, "hellow"); + +fn main() {} diff --git a/tests/ui/crate_local_distributed_slice/non_slice.stderr b/tests/ui/crate_local_distributed_slice/non_slice.stderr new file mode 100644 index 0000000000000..d24157b53d940 --- /dev/null +++ b/tests/ui/crate_local_distributed_slice/non_slice.stderr @@ -0,0 +1,15 @@ +error: expected this type to be an array + --> $DIR/non_slice.rs:4:14 + | +LL | const MEOWS: &str; + | ^^^^ + | + = note: a distributed slice must have an array type with an inferred length +help: change the type to an array + | +LL - const MEOWS: &str; +LL + const MEOWS: [&'static str; _]; + | + +error: aborting due to 1 previous error + diff --git a/tests/ui/crate_local_distributed_slice/random_const.rs b/tests/ui/crate_local_distributed_slice/random_const.rs new file mode 100644 index 0000000000000..6208c59481b67 --- /dev/null +++ b/tests/ui/crate_local_distributed_slice/random_const.rs @@ -0,0 +1,11 @@ +#![feature(crate_local_distributed_slice)] + +const CONST_MEOWS: [&str; 2] = ["meow", "prrr"]; +static STATIC_MEOWS: [&str; 2] = ["meow", "prrr"]; + +distributed_slice_element!(CONST_MEOWS, "mrow"); +//~^ ERROR `distributed_slice_element!()` can only add to a distributed slice +distributed_slice_element!(STATIC_MEOWS, "mrow"); +//~^ ERROR `distributed_slice_element!()` can only add to a distributed slice + +fn main() {} diff --git a/tests/ui/crate_local_distributed_slice/random_const.stderr b/tests/ui/crate_local_distributed_slice/random_const.stderr new file mode 100644 index 0000000000000..66596ca779785 --- /dev/null +++ b/tests/ui/crate_local_distributed_slice/random_const.stderr @@ -0,0 +1,32 @@ +error: `distributed_slice_element!()` can only add to a distributed slice + --> $DIR/random_const.rs:6:1 + | +LL | const CONST_MEOWS: [&str; 2] = ["meow", "prrr"]; + | ------------------------------------------------ not a distributed slice +... +LL | distributed_slice_element!(CONST_MEOWS, "mrow"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ element added here + | +help: add `#[distributed_slice(crate)]` + | +LL + #[distributed_slice(crate)] +LL | const CONST_MEOWS: [&str; 2] = ["meow", "prrr"]; + | + +error: `distributed_slice_element!()` can only add to a distributed slice + --> $DIR/random_const.rs:8:1 + | +LL | static STATIC_MEOWS: [&str; 2] = ["meow", "prrr"]; + | -------------------------------------------------- not a distributed slice +... +LL | distributed_slice_element!(STATIC_MEOWS, "mrow"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ element added here + | +help: add `#[distributed_slice(crate)]` + | +LL + #[distributed_slice(crate)] +LL | static STATIC_MEOWS: [&str; 2] = ["meow", "prrr"]; + | + +error: aborting due to 2 previous errors + diff --git a/tests/ui/crate_local_distributed_slice/reference_const.rs b/tests/ui/crate_local_distributed_slice/reference_const.rs new file mode 100644 index 0000000000000..02cb4a860077e --- /dev/null +++ b/tests/ui/crate_local_distributed_slice/reference_const.rs @@ -0,0 +1,15 @@ +#![feature(crate_local_distributed_slice)] +//@ run-pass +//@ check-run-results + +#[distributed_slice(crate)] +const MEOWS: [&str; _]; + +const NYA: &str = "nya"; + +distributed_slice_element!(MEOWS, "mrow"); +distributed_slice_element!(MEOWS, NYA); + +fn main() { + println!("{MEOWS:?}"); +} diff --git a/tests/ui/crate_local_distributed_slice/reference_const.run.stdout b/tests/ui/crate_local_distributed_slice/reference_const.run.stdout new file mode 100644 index 0000000000000..9d5128a7afe89 --- /dev/null +++ b/tests/ui/crate_local_distributed_slice/reference_const.run.stdout @@ -0,0 +1 @@ +["mrow", "nya"] diff --git a/tests/ui/crate_local_distributed_slice/self_referential.rs b/tests/ui/crate_local_distributed_slice/self_referential.rs new file mode 100644 index 0000000000000..cd52cc5f7cf1b --- /dev/null +++ b/tests/ui/crate_local_distributed_slice/self_referential.rs @@ -0,0 +1,10 @@ +#![feature(crate_local_distributed_slice)] + +#[distributed_slice(crate)] +const MEOWS: [&str; _]; +//~^ ERROR cycle detected when simplifying constant for the type system `MEOWS` + +distributed_slice_element!(MEOWS, "mrow"); +distributed_slice_element!(MEOWS, MEOWS[0]); + +fn main() {} diff --git a/tests/ui/crate_local_distributed_slice/self_referential.stderr b/tests/ui/crate_local_distributed_slice/self_referential.stderr new file mode 100644 index 0000000000000..847978b85970a --- /dev/null +++ b/tests/ui/crate_local_distributed_slice/self_referential.stderr @@ -0,0 +1,28 @@ +error[E0391]: cycle detected when simplifying constant for the type system `MEOWS` + --> $DIR/self_referential.rs:4:1 + | +LL | const MEOWS: [&str; _]; + | ^^^^^^^^^^^^^^^^^^^^^^ + | +note: ...which requires const-evaluating + checking `MEOWS`... + --> $DIR/self_referential.rs:4:1 + | +LL | const MEOWS: [&str; _]; + | ^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires simplifying constant for the type system `_`... + --> $DIR/self_referential.rs:8:1 + | +LL | distributed_slice_element!(MEOWS, MEOWS[0]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires const-evaluating + checking `_`... + --> $DIR/self_referential.rs:8:35 + | +LL | distributed_slice_element!(MEOWS, MEOWS[0]); + | ^^^^^ + = note: ...which again requires simplifying constant for the type system `MEOWS`, completing the cycle + = note: cycle used when running analysis passes on this crate + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/crate_local_distributed_slice/wrong_item.rs b/tests/ui/crate_local_distributed_slice/wrong_item.rs new file mode 100644 index 0000000000000..af9d1be373644 --- /dev/null +++ b/tests/ui/crate_local_distributed_slice/wrong_item.rs @@ -0,0 +1,7 @@ +#![feature(crate_local_distributed_slice)] + +#[distributed_slice(crate)] +fn prr() {} +//~^ ERROR expected this to be a const or a static + +fn main() {} diff --git a/tests/ui/crate_local_distributed_slice/wrong_item.stderr b/tests/ui/crate_local_distributed_slice/wrong_item.stderr new file mode 100644 index 0000000000000..c796dda129a5f --- /dev/null +++ b/tests/ui/crate_local_distributed_slice/wrong_item.stderr @@ -0,0 +1,10 @@ +error: expected this to be a const or a static + --> $DIR/wrong_item.rs:4:1 + | +LL | #[distributed_slice(crate)] + | --------------------------- because of this attribute +LL | fn prr() {} + | ^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/crate_local_distributed_slice/wrong_location.rs b/tests/ui/crate_local_distributed_slice/wrong_location.rs new file mode 100644 index 0000000000000..a8446c0e1f2b8 --- /dev/null +++ b/tests/ui/crate_local_distributed_slice/wrong_location.rs @@ -0,0 +1,24 @@ +#![feature(crate_local_distributed_slice)] + +struct X; + +impl X { + #[distributed_slice(crate)] + const A: [i32; _]; + //~^ ERROR expected this to be a module-level const or a static +} + + +trait Y { + #[distributed_slice(crate)] + const A: [i32; _]; + //~^ ERROR expected this to be a module-level const or a static +} + +extern "C" { + #[distributed_slice(crate)] + static A: [i32; _]; + //~^ ERROR expected this to be a non-extern const or a static +} + +fn main() {} diff --git a/tests/ui/crate_local_distributed_slice/wrong_location.stderr b/tests/ui/crate_local_distributed_slice/wrong_location.stderr new file mode 100644 index 0000000000000..4b071da426149 --- /dev/null +++ b/tests/ui/crate_local_distributed_slice/wrong_location.stderr @@ -0,0 +1,32 @@ +error: expected this to be a module-level const or a static + --> $DIR/wrong_location.rs:7:5 + | +LL | #[distributed_slice(crate)] + | --------------------------- because of this attribute +LL | const A: [i32; _]; + | ^^^^^^^^^^^^^^^^^^ + | + = note: this is an associated item + +error: expected this to be a module-level const or a static + --> $DIR/wrong_location.rs:14:5 + | +LL | #[distributed_slice(crate)] + | --------------------------- because of this attribute +LL | const A: [i32; _]; + | ^^^^^^^^^^^^^^^^^^ + | + = note: this is an associated item + +error: expected this to be a non-extern const or a static + --> $DIR/wrong_location.rs:20:5 + | +LL | #[distributed_slice(crate)] + | --------------------------- because of this attribute +LL | static A: [i32; _]; + | ^^^^^^^^^^^^^^^^^^^ + | + = note: this is inside an `extern` block + +error: aborting due to 3 previous errors + diff --git a/tests/ui/crate_local_distributed_slice/wrong_type.rs b/tests/ui/crate_local_distributed_slice/wrong_type.rs new file mode 100644 index 0000000000000..77e93274faa65 --- /dev/null +++ b/tests/ui/crate_local_distributed_slice/wrong_type.rs @@ -0,0 +1,9 @@ +#![feature(crate_local_distributed_slice)] + +#[distributed_slice(crate)] +const MEOWS: [&str; _]; + +distributed_slice_element!(MEOWS, 10); +//~^ ERROR mismatched types + +fn main() {} diff --git a/tests/ui/crate_local_distributed_slice/wrong_type.stderr b/tests/ui/crate_local_distributed_slice/wrong_type.stderr new file mode 100644 index 0000000000000..9427abd0eedf5 --- /dev/null +++ b/tests/ui/crate_local_distributed_slice/wrong_type.stderr @@ -0,0 +1,9 @@ +error[E0308]: mismatched types + --> $DIR/wrong_type.rs:6:35 + | +LL | distributed_slice_element!(MEOWS, 10); + | ^^ expected `&str`, found integer + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. From e7a54455dea081f1542a8db4905bef9eafdc3cef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 30 May 2025 18:06:50 +0200 Subject: [PATCH 10/10] distributed_slice_elements (multiple) plus tests --- compiler/rustc_ast/src/ast.rs | 4 + compiler/rustc_ast/src/visit.rs | 8 + compiler/rustc_ast_lowering/messages.ftl | 3 + compiler/rustc_ast_lowering/src/errors.rs | 8 + compiler/rustc_ast_lowering/src/item.rs | 63 ++++++- .../src/distributed_slice.rs | 42 +++++ compiler/rustc_builtin_macros/src/lib.rs | 1 + compiler/rustc_hir/src/hir.rs | 8 + .../src/collect/distributed_slice.rs | 23 ++- .../rustc_hir_analysis/src/collect/type_of.rs | 164 +++++++++++++----- compiler/rustc_hir_pretty/src/lib.rs | 11 ++ compiler/rustc_hir_typeck/src/lib.rs | 17 +- .../src/middle/distributed_slice.rs | 8 + compiler/rustc_middle/src/middle/mod.rs | 1 + compiler/rustc_middle/src/query/mod.rs | 3 +- compiler/rustc_mir_build/src/thir/cx/expr.rs | 103 +++++++++-- compiler/rustc_passes/src/dead.rs | 12 +- compiler/rustc_resolve/src/late.rs | 4 +- compiler/rustc_span/src/symbol.rs | 1 + library/core/src/macros/mod.rs | 10 ++ library/core/src/prelude/v1.rs | 2 +- library/std/src/prelude/v1.rs | 2 +- .../crate_local_distributed_slice/add_many.rs | 13 ++ .../add_many.run.stdout | 1 + .../add_many_ident.rs | 15 ++ .../add_many_ident.run.stdout | 1 + .../add_many_wrong.rs | 16 ++ .../add_many_wrong.stderr | 14 ++ .../add_many_wrong_type.rs | 15 ++ .../add_many_wrong_type.stderr | 9 + 30 files changed, 509 insertions(+), 73 deletions(-) create mode 100644 compiler/rustc_middle/src/middle/distributed_slice.rs create mode 100644 tests/ui/crate_local_distributed_slice/add_many.rs create mode 100644 tests/ui/crate_local_distributed_slice/add_many.run.stdout create mode 100644 tests/ui/crate_local_distributed_slice/add_many_ident.rs create mode 100644 tests/ui/crate_local_distributed_slice/add_many_ident.run.stdout create mode 100644 tests/ui/crate_local_distributed_slice/add_many_wrong.rs create mode 100644 tests/ui/crate_local_distributed_slice/add_many_wrong.stderr create mode 100644 tests/ui/crate_local_distributed_slice/add_many_wrong_type.rs create mode 100644 tests/ui/crate_local_distributed_slice/add_many_wrong_type.stderr diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 81f81a9a17d38..e1a6b6c3d9c45 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3624,6 +3624,10 @@ pub enum DistributedSlice { /// This const (we never do this to statics) represents an addition to a global registry /// declared somewhere else. Addition { declaration: Path, id: NodeId }, + /// This const (we never do this to statics) represents an addition of an array + /// to a global registry declared somewhere else. All elements are added, though not necessarily + /// in the same order as in the original slice. + AdditionMany { declaration: Path, id: NodeId }, /// Applied to an invalid item, error guaranteed to have be emitted Err(ErrorGuaranteed), } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 3bf823ae9ffef..e6b0d71a0b891 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -467,6 +467,10 @@ macro_rules! common_visitor_and_walkers { try_visit!(vis.visit_path(declaration$(${ignore($lt)}, *id)?)); try_visit!(visit_id(vis, id)); } + DistributedSlice::AdditionMany { declaration, id } => { + try_visit!(vis.visit_path(declaration$(${ignore($lt)}, *id)?)); + try_visit!(visit_id(vis, id)); + } } walk_define_opaques(vis, define_opaque) } @@ -645,6 +649,10 @@ macro_rules! common_visitor_and_walkers { try_visit!(vis.visit_path(declaration$(${ignore($lt)}, *id)?)); try_visit!(visit_id(vis, id)); } + DistributedSlice::AdditionMany { declaration, id } => { + try_visit!(vis.visit_path(declaration$(${ignore($lt)}, *id)?)); + try_visit!(visit_id(vis, id)); + } } diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index 6e05fa7d596db..2b4ae009777e4 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -56,6 +56,9 @@ ast_lowering_coroutine_too_many_parameters = ast_lowering_default_field_in_tuple = default fields are not supported in tuple structs .label = default fields are only supported on structs +ast_lowering_distributed_slice_elements_wrong_expr = + `distributed_slice_elements!()` only accepts a path or array literal + .note = arbitrary expressions are not supported ast_lowering_distributed_slice_with_initializer = distributed slice elements are added with `distributed_slice_element!(...)` ast_lowering_does_not_support_modifiers = diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index 272c85f65289c..67d6e4fb0ff26 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -482,3 +482,11 @@ pub(crate) struct DistributedSliceWithInitializer { #[primary_span] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(ast_lowering_distributed_slice_elements_wrong_expr)] +#[note] +pub(crate) struct DistributedSliceElementsWrongExpr { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 0739ebe41ee65..6dd18b2124c53 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -6,8 +6,8 @@ use rustc_errors::ErrorGuaranteed; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; use rustc_hir::{ - self as hir, DistributedSlice, HirId, InvalidDistributedSliceDeclaration, LifetimeSource, - PredicateOrigin, + self as hir, DistributedSlice, DistributedSliceAdditionManyKind, HirId, + InvalidDistributedSliceDeclaration, LifetimeSource, PredicateOrigin, }; use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; @@ -25,7 +25,7 @@ use super::{ AstOwner, FnDeclKind, ImplTraitContext, ImplTraitPosition, LoweringContext, ParamMode, ResolverAstLoweringExt, }; -use crate::errors::DistributedSliceWithInitializer; +use crate::errors::{DistributedSliceElementsWrongExpr, DistributedSliceWithInitializer}; pub(super) struct ItemLowerer<'a, 'hir> { pub(super) tcx: TyCtxt<'hir>, @@ -155,6 +155,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_distributed_slice( &mut self, distributed_slice: &ast::DistributedSlice, + expr: Option<&Expr>, ) -> DistributedSlice { match distributed_slice { ast::DistributedSlice::None => DistributedSlice::None, @@ -179,6 +180,58 @@ impl<'hir> LoweringContext<'_, 'hir> { DistributedSlice::Addition(local) } + ast::DistributedSlice::AdditionMany { declaration, id } => { + let Some(res) = self.resolver.get_partial_res(*id) else { + self.dcx().span_delayed_bug(declaration.span, "should have errored in resolve"); + return DistributedSlice::None; + }; + + let Some(did) = res.expect_full_res().opt_def_id() else { + self.dcx().span_delayed_bug(declaration.span, "should have errored in resolve"); + return DistributedSlice::None; + }; + + let Some(local) = did.as_local() else { + panic!("adding to slice outside local crate"); + }; + + let initializer = expr + .expect("generated by `distributed_slice_elements!` and always has an expr"); + + DistributedSlice::AdditionMany( + local, + match &initializer.kind { + ExprKind::Array(elems) => { + DistributedSliceAdditionManyKind::ArrayLit { length: elems.len() } + } + ExprKind::Path(_, _) => { + let Some(res) = self.resolver.get_partial_res(initializer.id) else { + self.dcx().span_delayed_bug( + declaration.span, + "should have errored in resolve", + ); + return DistributedSlice::None; + }; + + let Some(did) = res.expect_full_res().opt_def_id() else { + self.dcx().span_delayed_bug( + declaration.span, + "should have errored in resolve", + ); + return DistributedSlice::None; + }; + + DistributedSliceAdditionManyKind::Path { res: did } + } + _ => { + let eg = self.dcx().emit_err(DistributedSliceElementsWrongExpr { + span: initializer.span, + }); + DistributedSliceAdditionManyKind::Err(eg) + } + }, + ) + } } } @@ -225,7 +278,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ident, ty, body_id, - self.lower_distributed_slice(distributed_slice), + self.lower_distributed_slice(distributed_slice, e.as_deref()), ) } ItemKind::Const(box ast::ConstItem { @@ -258,7 +311,7 @@ impl<'hir> LoweringContext<'_, 'hir> { generics, ty, body_id, - self.lower_distributed_slice(distributed_slice), + self.lower_distributed_slice(distributed_slice, expr.as_deref()), ) } ItemKind::Fn(box Fn { diff --git a/compiler/rustc_builtin_macros/src/distributed_slice.rs b/compiler/rustc_builtin_macros/src/distributed_slice.rs index dc6ea7b49567f..90f45eba3dcd8 100644 --- a/compiler/rustc_builtin_macros/src/distributed_slice.rs +++ b/compiler/rustc_builtin_macros/src/distributed_slice.rs @@ -143,3 +143,45 @@ pub(crate) fn distributed_slice_element( tokens: None })])) } + +/// ```rust +/// distributed_slice_elements!(MEOWS, ["mrow"]); +/// ``` +pub(crate) fn distributed_slice_elements( + cx: &mut ExtCtxt<'_>, + span: Span, + tts: TokenStream, +) -> MacroExpanderResult<'static> { + let (path, expr) = match parse_element(cx.new_parser_from_tts(tts)) { + Ok((ident, expr)) => (ident, expr), + Err(mut err) => { + if err.span.is_dummy() { + err.span(span); + } + let guar = err.emit(); + return ExpandResult::Ready(DummyResult::any(span, guar)); + } + }; + + ExpandResult::Ready(MacEager::items(smallvec![P(Item { + attrs: ThinVec::new(), + id: DUMMY_NODE_ID, + span, + vis: ast::Visibility { kind: ast::VisibilityKind::Inherited, span, tokens: None }, + kind: ItemKind::Const(Box::new(ConstItem { + defaultness: Defaultness::Final, + ident: Ident { name: kw::Underscore, span }, + generics: Generics::default(), + // leave out the ty, we discover it when + // when name-resolving to the registry definition + ty: P(Ty { id: DUMMY_NODE_ID, kind: TyKind::Infer, span, tokens: None }), + expr: Some(expr), + define_opaque: None, + distributed_slice: DistributedSlice::AdditionMany { + declaration: path, + id: DUMMY_NODE_ID + } + })), + tokens: None + })])) +} diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 3b3d476ebd9f9..bbc0ab2c6681f 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -89,6 +89,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { const_format_args: format::expand_format_args, core_panic: edition_panic::expand_panic, distributed_slice_element: distributed_slice::distributed_slice_element, + distributed_slice_elements: distributed_slice::distributed_slice_elements, env: env::expand_env, file: source_util::expand_file, format_args: format::expand_format_args, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 6c710c838c9df..64b19ced90927 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -4271,12 +4271,20 @@ impl FnHeader { } } +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub enum DistributedSliceAdditionManyKind { + ArrayLit { length: usize }, + Path { res: DefId }, + Err(ErrorGuaranteed), +} + #[derive(Debug, Clone, Copy, HashStable_Generic, Default)] pub enum DistributedSlice { #[default] None, Declaration(Span), Addition(LocalDefId), + AdditionMany(LocalDefId, DistributedSliceAdditionManyKind), } #[derive(Debug, Clone, Copy, HashStable_Generic)] diff --git a/compiler/rustc_hir_analysis/src/collect/distributed_slice.rs b/compiler/rustc_hir_analysis/src/collect/distributed_slice.rs index 3c841193a6e5e..339d4aa437f81 100644 --- a/compiler/rustc_hir_analysis/src/collect/distributed_slice.rs +++ b/compiler/rustc_hir_analysis/src/collect/distributed_slice.rs @@ -1,25 +1,38 @@ use rand::SeedableRng; use rand::seq::SliceRandom; -use rustc_hir::def_id::{DefIdMap, LocalDefId}; +use rustc_hir::def_id::DefIdMap; use rustc_hir::{DistributedSlice, ItemKind}; +use rustc_middle::middle::distributed_slice::DistributedSliceAddition; use rustc_middle::ty::TyCtxt; pub(super) fn distributed_slice_elements<'tcx>( tcx: TyCtxt<'tcx>, _: (), -) -> DefIdMap> { - let mut slice_elements = DefIdMap::>::default(); +) -> DefIdMap> { + let mut slice_elements = DefIdMap::>::default(); for i in tcx.hir_free_items() { let addition_def_id = i.owner_id.def_id; if let ItemKind::Const(.., DistributedSlice::Addition(declaration_def_id)) = tcx.hir_expect_item(addition_def_id).kind { - slice_elements.entry(declaration_def_id.to_def_id()).or_default().push(addition_def_id); + slice_elements + .entry(declaration_def_id.to_def_id()) + .or_default() + .push(DistributedSliceAddition::Single(addition_def_id)); + } + + if let ItemKind::Const(.., DistributedSlice::AdditionMany(declaration_def_id, _)) = + tcx.hir_expect_item(addition_def_id).kind + { + slice_elements + .entry(declaration_def_id.to_def_id()) + .or_default() + .push(DistributedSliceAddition::Many(addition_def_id)); } } - let mut res = DefIdMap::>::default(); + let mut res = DefIdMap::>::default(); for (key, mut registered_values) in tcx.with_stable_hashing_context(|hcx| slice_elements.into_sorted(&hcx, true)) diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 07af0fd0f19ee..ea9207d03aebb 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -3,7 +3,10 @@ use core::ops::ControlFlow; use rustc_errors::{Applicability, StashKey, Suggestions}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::VisitorExt; -use rustc_hir::{self as hir, AmbigArg, HirId, InvalidDistributedSliceDeclaration}; +use rustc_hir::{ + self as hir, AmbigArg, DistributedSlice, HirId, InvalidDistributedSliceDeclaration, +}; +use rustc_middle::middle::distributed_slice::DistributedSliceAddition; use rustc_middle::query::plumbing::CyclePlaceholder; use rustc_middle::ty::print::with_forced_trimmed_paths; use rustc_middle::ty::util::IntTypeExt; @@ -116,17 +119,15 @@ fn const_arg_anon_type_of<'tcx>(icx: &ItemCtxt<'tcx>, arg_hir_id: HirId, span: S } } -pub fn type_of_distributed_slice<'tcx>( +fn distributed_slice_element_type<'tcx>( tcx: TyCtxt<'tcx>, lowerer: &dyn HirTyLowerer<'tcx>, ty: &rustc_hir::Ty<'tcx>, - def_id: LocalDefId, emit_diagnostics: bool, ) -> Ty<'tcx> { use rustc_hir::*; - use rustc_middle::ty::Ty; - let element_ty = if let TyKind::Array(element_ty, len) = ty.kind { + if let TyKind::Array(element_ty, len) = ty.kind { if let ConstArgKind::Infer { .. } = len.kind { } else if emit_diagnostics { tcx.dcx().emit_err(DistributedSliceNonInferLength { span: len.span() }); @@ -141,17 +142,87 @@ pub fn type_of_distributed_slice<'tcx>( } lowered - }; + } +} + +pub fn type_of_distributed_slice<'tcx>( + tcx: TyCtxt<'tcx>, + lowerer: &dyn HirTyLowerer<'tcx>, + ty: &rustc_hir::Ty<'tcx>, + def_id: LocalDefId, + emit_diagnostics: bool, +) -> Ty<'tcx> { + let element_ty = distributed_slice_element_type(tcx, lowerer, ty, emit_diagnostics); + + let elements: Option<&Vec> = + tcx.distributed_slice_elements(()).get(&def_id.to_def_id()); + + let mut num_elements = 0; + + for i in elements.map(|i| i.as_slice()).unwrap_or_default() { + match i { + DistributedSliceAddition::Single(_) => { + num_elements += 1; + } + DistributedSliceAddition::Many(local_def_id) => { + let ty = tcx.type_of(*local_def_id).instantiate_identity(); + + // FIXME(gr): instead generate additions? + match ty.kind() { + ty::Array(_, len) => { + num_elements += len + .try_to_target_usize(tcx) + .expect("it's a usize because it's a length"); + } + _ => { + tcx.dcx().span_delayed_bug( + tcx.def_span(*local_def_id), + "adding not-an-array with distributed_slice_elements!(", + ); + } + } + } + } + } + + Ty::new_array(tcx, element_ty, num_elements) +} - let res: Option<&Vec> = tcx.distributed_slice_elements(()).get(&def_id.to_def_id()); +fn distributed_slice_addition_element_type<'tcx>( + tcx: TyCtxt<'tcx>, + lowerer: &dyn HirTyLowerer<'tcx>, + declaration_def_id: LocalDefId, + addition_span: Span, + emit_diagnostics: bool, +) -> Ty<'tcx> { + let declaration_item = tcx.hir_expect_item(declaration_def_id); + + let hir_ty = if let hir::ItemKind::Const(_, _, ty, _, ds) + | hir::ItemKind::Static(_, _, ty, _, ds) = declaration_item.kind + { + if !matches!(ds, DistributedSlice::Declaration(..)) && emit_diagnostics { + tcx.dcx().emit_err(DistributedSliceWrongTarget { + span: addition_span, + wrong_declaration: declaration_item.span, + suggestion_before: declaration_item.span.shrink_to_lo(), + }); + } - let res = Ty::new_array_with_const_len( - tcx, - element_ty, - ty::Const::from_target_usize(tcx, res.map(|i| i.len()).unwrap_or(0) as u64), - ); + ty + } else { + bug!("should have errored during name resolution"); + }; - res + match hir_ty.kind { + hir::TyKind::Array(element_ty, _) => lowerer.lower_ty(element_ty), + _ => Ty::new_error( + tcx, + tcx.dcx().span_delayed_bug( + declaration_item.span, + "adding not-an-array with distributed_slice_elements!(", + ), + ), + } } pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, Ty<'_>> { @@ -269,35 +340,50 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ } ItemKind::Const(ident, _, ty, body_id, distributed_slice) => { if let DistributedSlice::Declaration(_) = distributed_slice { - type_of_distributed_slice(tcx, &icx, ty, def_id, true) + type_of_distributed_slice(tcx, icx.lowerer(), ty, def_id, true) } else if let DistributedSlice::Addition(declaration_def_id) = distributed_slice { - let declaration_item = tcx.hir_expect_item(declaration_def_id); - if let hir::ItemKind::Const(_, _, _, _, ds) - | hir::ItemKind::Static(_, _, _, _, ds) = declaration_item.kind - { - if !matches!(ds, DistributedSlice::Declaration(..)) { - tcx.dcx().emit_err(DistributedSliceWrongTarget { - span: item.span, - wrong_declaration: declaration_item.span, - suggestion_before: declaration_item.span.shrink_to_lo(), - }); + distributed_slice_addition_element_type( + tcx, + icx.lowerer(), + declaration_def_id, + item.span, + true, + ) + } else if let DistributedSlice::AdditionMany(declaration_def_id, am) = + distributed_slice + { + let element_ty = distributed_slice_addition_element_type( + tcx, + icx.lowerer(), + declaration_def_id, + item.span, + true, + ); + + 'res: { + let length = match am { + DistributedSliceAdditionManyKind::ArrayLit { length } => { + Ok(ty::Const::from_target_usize(tcx, length as u64)) + } + DistributedSliceAdditionManyKind::Path { res } => { + let ty = tcx.type_of(res).instantiate_identity(); + + Ok(match ty.kind() { + ty::Array(_, len) => *len, + // usually means ty::Error which we can just return + _ => break 'res ty, + }) + } + DistributedSliceAdditionManyKind::Err(eg) => { + Err(Ty::new_error(tcx, eg)) + } + }; + + match length { + Ok(length) => Ty::new_array_with_const_len(tcx, element_ty, length), + Err(e) => e, } - } else { - tcx.dcx().span_delayed_bug( - item.span, - "should have errored during name resolution", - ); } - - // we reject generic const items (`#![feature(generic_const_items)]`) in `#[distributed_slice(crate)]` - let array_ty = tcx.type_of(declaration_def_id).instantiate_identity(); - - let ty = match array_ty.kind() { - ty::Array(element_ty, _) => *element_ty, - _ => bug!("not an array"), - }; - - ty } else if ty.is_suggestable_infer_ty() { infer_placeholder_type( icx.lowerer(), diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 07a437ae809b5..57583e9130bce 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -649,6 +649,17 @@ impl<'a> State<'a> { self.end(ib); self.end(cb); } + hir::ItemKind::Const(.., expr, DistributedSlice::AdditionMany(d, _)) => { + let (cb, ib) = self.head("distributed_slice_elements!"); + self.popen(); + self.word(format!("{d:?}")); + self.word(","); + self.ann.nested(self, Nested::Body(expr)); + self.pclose(); + self.word(";"); + self.end(ib); + self.end(cb); + } hir::ItemKind::Fn { ident, sig, generics, body, .. } => { let (cb, ib) = self.head(""); self.print_fn(sig.header, Some(ident.name), generics, sig.decl, &[], Some(body)); diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 0e1c743237f0f..acf510d51ab0d 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -181,10 +181,25 @@ fn typeck_with_inspect<'tcx>( let ty = match array_ty.kind() { ty::Array(element_ty, _) => *element_ty, - _ => bug!("not an array"), + // totally wrong but we'll have already emitted a diagnostic of this + _ => array_ty, }; ty + } else if let Node::Item(item) = node + && let ItemKind::Const(.., DistributedSlice::AdditionMany(declaration_def_id, ..)) = + item.kind + { + // we reject generic const items (`#![feature(generic_const_items)]`) in `#[distributed_slice(crate)]` + let array_ty = tcx.type_of(declaration_def_id).instantiate_identity(); + + let element_ty = match array_ty.kind() { + ty::Array(element_ty, _) => *element_ty, + // totally wrong but we'll have already emitted a diagnostic of this + _ => array_ty, + }; + + Ty::new_array_with_const_len(tcx, element_ty, fcx.next_const_var(item.span)) } else if let Some(infer_ty) = infer_type_if_missing(&fcx, node) { infer_ty } else if let Node::Item(item) = node diff --git a/compiler/rustc_middle/src/middle/distributed_slice.rs b/compiler/rustc_middle/src/middle/distributed_slice.rs new file mode 100644 index 0000000000000..283f5a0a49f82 --- /dev/null +++ b/compiler/rustc_middle/src/middle/distributed_slice.rs @@ -0,0 +1,8 @@ +use rustc_hir::def_id::LocalDefId; +use rustc_macros::HashStable; + +#[derive(Debug, HashStable)] +pub enum DistributedSliceAddition { + Single(LocalDefId), + Many(LocalDefId), +} diff --git a/compiler/rustc_middle/src/middle/mod.rs b/compiler/rustc_middle/src/middle/mod.rs index 4587dcaddc487..e49ccd948836a 100644 --- a/compiler/rustc_middle/src/middle/mod.rs +++ b/compiler/rustc_middle/src/middle/mod.rs @@ -30,6 +30,7 @@ pub mod lib_features { } } } +pub mod distributed_slice; pub mod privacy; pub mod region; pub mod resolve_bound_vars; diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index e1a7ad74bb999..9b19e246ef785 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -51,6 +51,7 @@ use crate::lint::LintExpectation; use crate::metadata::ModChild; use crate::middle::codegen_fn_attrs::CodegenFnAttrs; use crate::middle::debugger_visualizer::DebuggerVisualizerFile; +use crate::middle::distributed_slice::DistributedSliceAddition; use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo}; use crate::middle::lib_features::LibFeatures; use crate::middle::privacy::EffectiveVisibilities; @@ -697,7 +698,7 @@ rustc_queries! { desc { "getting wasm import module map" } } - query distributed_slice_elements(_: ()) -> &'tcx DefIdMap> { + query distributed_slice_elements(_: ()) -> &'tcx DefIdMap> { arena_cache desc { "collects all registered items for global registry declarations in the current crate" } } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index cee40f3cfb96a..c37dd26b0a17f 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -4,11 +4,11 @@ use rustc_ast::UnsafeBinderCastKind; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; -use rustc_hir::def_id::LocalDefId; use rustc_index::Idx; use rustc_middle::hir::place::{ Place as HirPlace, PlaceBase as HirPlaceBase, ProjectionKind as HirProjectionKind, }; +use rustc_middle::middle::distributed_slice::DistributedSliceAddition; use rustc_middle::middle::region; use rustc_middle::mir::{self, AssignOp, BinOp, BorrowKind, UnOp}; use rustc_middle::thir::*; @@ -932,7 +932,7 @@ impl<'tcx> ThirBuildCx<'tcx> { hir::ExprKind::DistributedSliceDeferredArray => { // get the declaration's defid let declaration_def_id = self.body_owner; - let elements: &[LocalDefId] = self + let elements: &[DistributedSliceAddition] = self .tcx .distributed_slice_elements(()) .get(&declaration_def_id) @@ -942,28 +942,97 @@ impl<'tcx> ThirBuildCx<'tcx> { // FIXME(gr) proper span in grda let span = DUMMY_SP; - let ty = match expr_ty.kind() { + let element_type = match expr_ty.kind() { ty::Array(element_ty, _) => *element_ty, _ => panic!("not an array"), }; + // all none because we're definitely in const + let temp_lifetime = + TempLifetime { temp_lifetime: None, backwards_incompatible: None }; + let fields = elements .iter() - .map(|&def_id| { - let (temp_lifetime, backwards_incompatible) = self - .rvalue_scopes - .temporary_scope(self.region_scope_tree, expr.hir_id.local_id); - - self.thir.exprs.push(Expr { - kind: ExprKind::NamedConst { - def_id: def_id.to_def_id(), - args: GenericArgs::empty(), - user_ty: None, + .flat_map(|addition| { + match addition { + &DistributedSliceAddition::Single(local_def_id) => { + vec![self.thir.exprs.push(Expr { + kind: ExprKind::NamedConst { + def_id: local_def_id.to_def_id(), + args: GenericArgs::empty(), + user_ty: None, + }, + ty: element_type, + temp_lifetime, + span, + })] + } + &DistributedSliceAddition::Many(local_def_id) => { + // local_def_id are the elements we want to add to the final + // ditributed slice. We call it `source`. + + // we're adding all source elements to a literal that will + // initialize the distributed slice. For single elements that's + // simple, but for multiple elements like here, it's more + // complicated. `res` is the final set of elements we'd like to be + // part of the constructor of the slice + let mut res_elems = Vec::new(); + + let source_ty = + self.tcx.normalize_erasing_regions(self.typing_env, self.tcx.type_of(local_def_id).instantiate_identity()); + + + // extract its length, we know for sure it's going to be an array. + let source_len = match source_ty.kind() { + ty::Array(_, source_len) => source_len.try_to_target_usize(tcx).expect("valid usize"), + // _ => panic!("not an array"), + _ => 0, + }; + + // construct a thir expression which is the source elements as an + // array. It's type is `source_ty` + // e.g. [1, 2, 3] added using distributed_slice_elements!([1, 2, 3]) + let source_elems = self.thir.exprs.push(Expr { + kind: ExprKind::NamedConst { + def_id: local_def_id.to_def_id(), + args: GenericArgs::empty(), + user_ty: None, + }, + ty: source_ty, + temp_lifetime, + span, + }); + + // now generate index expressions that index source_elems. + // i.e. source_elems[0], source_elems[1], ... source_elems[n]. + // these expressions become part of the initializer of the + // distributed slice, i.e. we add them to res + for i in 0..source_len { + // index into source_elems + let index = self.thir.exprs.push(Expr { + kind: ExprKind::NonHirLiteral { + lit: ty::ScalarInt::try_from_target_usize(i, tcx) + .expect("won't overflow because i comes from a `try_to_target_usize`"), + user_ty: None, + }, + ty: tcx.types.usize, + temp_lifetime, + span, + }); + + // index expression, i.e. `source_elems[0], source_elems[1], ...` + // where 0 and 1 are the indices constructed above + res_elems.push(self.thir.exprs.push(Expr { + kind: ExprKind::Index { lhs: source_elems, index }, + ty: element_type, + temp_lifetime, + span, + })); + } + + res_elems }, - ty, - temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible }, - span, - }) + } }) .collect(); diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 1726a1357a338..a113599404c1f 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -16,6 +16,7 @@ use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{self as hir, DistributedSlice, Node, PatKind, QPath, TyKind}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; +use rustc_middle::middle::distributed_slice::DistributedSliceAddition; use rustc_middle::middle::privacy::Level; use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt}; @@ -438,7 +439,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { hir::ItemKind::Const(.., DistributedSlice::Declaration(..)) | hir::ItemKind::Static(.., DistributedSlice::Declaration(..)) => { let defid = item.owner_id.to_def_id(); - let elements: &[LocalDefId] = self + let elements: &[DistributedSliceAddition] = self .tcx .distributed_slice_elements(()) .get(&defid) @@ -448,7 +449,14 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { intravisit::walk_item(self, item); for element in elements { - self.check_def_id(element.to_def_id()); + match element { + &DistributedSliceAddition::Single(local_def_id) => { + self.check_def_id(local_def_id.to_def_id()); + } + &DistributedSliceAddition::Many(local_def_id) => { + self.check_def_id(local_def_id.to_def_id()); + } + } } } _ => intravisit::walk_item(self, item), diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 02eb6029dd232..9d20ceb94e2c0 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2847,7 +2847,9 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { |this| this.visit_ty(ty), ); - if let DistributedSlice::Addition { declaration, id } = distributed_slice { + if let DistributedSlice::Addition { declaration, id } + | DistributedSlice::AdditionMany { declaration, id } = distributed_slice + { this.smart_resolve_path( *id, &None, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 0bd58ddecfcaf..5c4ce38367b55 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -835,6 +835,7 @@ symbols! { dispatch_from_dyn, distributed_slice, distributed_slice_element, + distributed_slice_elements, div, div_assign, diverging_block_default, diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 1a3370ba18206..1c3b709420f01 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1824,4 +1824,14 @@ pub(crate) mod builtin { pub macro distributed_slice_element($path:path, $expr:expr) { /* compiler built-in */ } + + /// Create a global registry. + /// + // FIXME(gr): docs + #[unstable(feature = "crate_local_distributed_slice", issue = "125119")] + #[rustc_builtin_macro] + #[cfg(not(bootstrap))] + pub macro distributed_slice_elements($path:path, $expr:expr) { + /* compiler built-in */ + } } diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/v1.rs index 3e0f12b64eb57..36f4d499ebfca 100644 --- a/library/core/src/prelude/v1.rs +++ b/library/core/src/prelude/v1.rs @@ -83,7 +83,7 @@ pub use crate::macros::builtin::{ #[unstable(feature = "crate_local_distributed_slice", issue = "125119")] #[cfg(not(bootstrap))] -pub use crate::macros::builtin::{distributed_slice, distributed_slice_element}; +pub use crate::macros::builtin::{distributed_slice, distributed_slice_element, distributed_slice_elements}; #[unstable(feature = "derive_const", issue = "none")] pub use crate::macros::builtin::derive_const; diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs index 4d1d728eb9d74..4ee5e42dcdbf0 100644 --- a/library/std/src/prelude/v1.rs +++ b/library/std/src/prelude/v1.rs @@ -70,7 +70,7 @@ pub use core::prelude::v1::{ #[unstable(feature = "crate_local_distributed_slice", issue = "125119")] #[cfg(not(bootstrap))] -pub use core::prelude::v1::distributed_slice; +pub use core::prelude::v1::{distributed_slice, distributed_slice_element, distributed_slice_elements}; #[unstable(feature = "derive_const", issue = "none")] pub use core::prelude::v1::derive_const; diff --git a/tests/ui/crate_local_distributed_slice/add_many.rs b/tests/ui/crate_local_distributed_slice/add_many.rs new file mode 100644 index 0000000000000..dd5c30fc02fdf --- /dev/null +++ b/tests/ui/crate_local_distributed_slice/add_many.rs @@ -0,0 +1,13 @@ +#![feature(crate_local_distributed_slice)] +//@ run-pass +//@ check-run-results + +#[distributed_slice(crate)] +const MEOWS: [&str; _]; + +distributed_slice_element!(MEOWS, "mrow"); +distributed_slice_elements!(MEOWS, ["mew", "prrr", "meow"]); + +fn main() { + println!("{MEOWS:?}"); +} diff --git a/tests/ui/crate_local_distributed_slice/add_many.run.stdout b/tests/ui/crate_local_distributed_slice/add_many.run.stdout new file mode 100644 index 0000000000000..9a4c6cfe55cb3 --- /dev/null +++ b/tests/ui/crate_local_distributed_slice/add_many.run.stdout @@ -0,0 +1 @@ +["mrow", "mew", "prrr", "meow"] diff --git a/tests/ui/crate_local_distributed_slice/add_many_ident.rs b/tests/ui/crate_local_distributed_slice/add_many_ident.rs new file mode 100644 index 0000000000000..99b15a80465de --- /dev/null +++ b/tests/ui/crate_local_distributed_slice/add_many_ident.rs @@ -0,0 +1,15 @@ +#![feature(crate_local_distributed_slice)] +//@ run-pass +//@ check-run-results + +#[distributed_slice(crate)] +const MEOWS: [&str; _]; + +distributed_slice_element!(MEOWS, "mrow"); + +const THREE_MEOWS: [&str; 3] = ["mew", "prrr", "meow"]; +distributed_slice_elements!(MEOWS, THREE_MEOWS); + +fn main() { + println!("{MEOWS:?}"); +} diff --git a/tests/ui/crate_local_distributed_slice/add_many_ident.run.stdout b/tests/ui/crate_local_distributed_slice/add_many_ident.run.stdout new file mode 100644 index 0000000000000..c7d3694d0fbf8 --- /dev/null +++ b/tests/ui/crate_local_distributed_slice/add_many_ident.run.stdout @@ -0,0 +1 @@ +["mew", "prrr", "meow", "mrow"] diff --git a/tests/ui/crate_local_distributed_slice/add_many_wrong.rs b/tests/ui/crate_local_distributed_slice/add_many_wrong.rs new file mode 100644 index 0000000000000..f7562c3091916 --- /dev/null +++ b/tests/ui/crate_local_distributed_slice/add_many_wrong.rs @@ -0,0 +1,16 @@ +#![feature(crate_local_distributed_slice)] + +#[distributed_slice(crate)] +const MEOWS: [&str; _]; + +distributed_slice_element!(MEOWS, "mrow"); + +const THREE_MEOWS: [&str; 3] = ["mew", "prrr", "meow"]; +distributed_slice_elements!(MEOWS, { +//~^ ERROR `distributed_slice_elements!()` only accepts a path or array literal + THREE_MEOWS +}); + +fn main() { + println!("{MEOWS:?}"); +} diff --git a/tests/ui/crate_local_distributed_slice/add_many_wrong.stderr b/tests/ui/crate_local_distributed_slice/add_many_wrong.stderr new file mode 100644 index 0000000000000..aa9dce750d79e --- /dev/null +++ b/tests/ui/crate_local_distributed_slice/add_many_wrong.stderr @@ -0,0 +1,14 @@ +error: `distributed_slice_elements!()` only accepts a path or array literal + --> $DIR/add_many_wrong.rs:9:36 + | +LL | distributed_slice_elements!(MEOWS, { + | ____________________________________^ +LL | | +LL | | THREE_MEOWS +LL | | }); + | |_^ + | + = note: arbitrary expressions are not supported + +error: aborting due to 1 previous error + diff --git a/tests/ui/crate_local_distributed_slice/add_many_wrong_type.rs b/tests/ui/crate_local_distributed_slice/add_many_wrong_type.rs new file mode 100644 index 0000000000000..188a3ee646773 --- /dev/null +++ b/tests/ui/crate_local_distributed_slice/add_many_wrong_type.rs @@ -0,0 +1,15 @@ +#![feature(crate_local_distributed_slice)] + +#[distributed_slice(crate)] +const MEOWS: [&str; _]; + +distributed_slice_element!(MEOWS, "mrow"); + +const NON_ARRAY: &str = "meow"; +distributed_slice_elements!(MEOWS, NON_ARRAY); +//~^ ERROR mismatched types [E0308] + + +fn main() { + println!("{MEOWS:?}"); +} diff --git a/tests/ui/crate_local_distributed_slice/add_many_wrong_type.stderr b/tests/ui/crate_local_distributed_slice/add_many_wrong_type.stderr new file mode 100644 index 0000000000000..4d582af94a4d1 --- /dev/null +++ b/tests/ui/crate_local_distributed_slice/add_many_wrong_type.stderr @@ -0,0 +1,9 @@ +error[E0308]: mismatched types + --> $DIR/add_many_wrong_type.rs:9:36 + | +LL | distributed_slice_elements!(MEOWS, NON_ARRAY); + | ^^^^^^^^^ expected `[&str; _]`, found `&str` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`.