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_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 7b103126e4599..e1a6b6c3d9c45 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -3614,6 +3614,24 @@ 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, NodeId),
+ /// 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),
+}
+
#[derive(Clone, Encodable, Decodable, Debug)]
pub struct StaticItem {
pub ident: Ident,
@@ -3622,6 +3640,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 +3651,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..e6b0d71a0b891 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -451,10 +451,27 @@ macro_rules! common_visitor_and_walkers {
mutability: _,
expr,
define_opaque,
+ 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::Err(..) => {}
+ 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));
+ }
+ 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)
}
ItemKind::Const(item) => {
@@ -614,12 +631,31 @@ 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));
try_visit!(vis.visit_ty(ty));
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));
+ }
+ DistributedSlice::Addition { declaration, id } => {
+ 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)
}
@@ -739,6 +775,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/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl
index 5ef76fb64aaf2..2b4ae009777e4 100644
--- a/compiler/rustc_ast_lowering/messages.ftl
+++ b/compiler/rustc_ast_lowering/messages.ftl
@@ -56,6 +56,11 @@ 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 =
the `{$class_name}` register class does not support template modifiers
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/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs
index 576fa9731e906..67d6e4fb0ff26 100644
--- a/compiler/rustc_ast_lowering/src/errors.rs
+++ b/compiler/rustc_ast_lowering/src/errors.rs
@@ -475,3 +475,18 @@ 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,
+}
+
+#[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/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 9f3aed9216c2d..3c774a25a1fda 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,
+ )
}),
),
@@ -417,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 d3aacaa15a8c5..6dd18b2124c53 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, HirId, LifetimeSource, PredicateOrigin};
+use rustc_hir::{
+ self as hir, DistributedSlice, DistributedSliceAdditionManyKind, 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::{DistributedSliceElementsWrongExpr, DistributedSliceWithInitializer};
pub(super) struct ItemLowerer<'a, 'hir> {
pub(super) tcx: TyCtxt<'hir>,
@@ -148,6 +152,89 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.arena.alloc(item)
}
+ fn lower_distributed_slice(
+ &mut self,
+ distributed_slice: &ast::DistributedSlice,
+ expr: Option<&Expr>,
+ ) -> DistributedSlice {
+ match distributed_slice {
+ ast::DistributedSlice::None => DistributedSlice::None,
+ ast::DistributedSlice::Err(_) => DistributedSlice::None,
+ ast::DistributedSlice::Declaration(span, _) => {
+ DistributedSlice::Declaration(self.lower_span(*span))
+ }
+ ast::DistributedSlice::Addition { 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");
+ };
+
+ 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)
+ }
+ },
+ )
+ }
+ }
+ }
+
fn lower_item_kind(
&mut self,
span: Span,
@@ -175,12 +262,24 @@ impl<'hir> LoweringContext<'_, 'hir> {
mutability: m,
expr: e,
define_opaque,
+ 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, ident, ty, body_id)
+ hir::ItemKind::Static(
+ *m,
+ ident,
+ ty,
+ body_id,
+ self.lower_distributed_slice(distributed_slice, e.as_deref()),
+ )
}
ItemKind::Const(box ast::ConstItem {
ident,
@@ -188,6 +287,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
ty,
expr,
define_opaque,
+ distributed_slice,
..
}) => {
let ident = self.lower_ident(*ident);
@@ -196,11 +296,23 @@ 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);
- hir::ItemKind::Const(ident, generics, ty, body_id)
+ hir::ItemKind::Const(
+ ident,
+ generics,
+ ty,
+ body_id,
+ self.lower_distributed_slice(distributed_slice, expr.as_deref()),
+ )
}
ItemKind::Fn(box Fn {
sig: FnSig { decl, header, span: fn_sig_span },
@@ -301,6 +413,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
in_assoc_ty: false,
},
},
+ false,
),
},
);
@@ -384,6 +497,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let lowered_ty = this.lower_ty(
ty,
ImplTraitContext::Disallowed(ImplTraitPosition::ImplSelf),
+ false,
);
(trait_ref, lowered_ty)
@@ -486,9 +600,21 @@ 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));
- (ty, self.lower_const_body(span, body))
+ 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),
+ distributed_slice_declaration.is_some(),
+ );
+ (ty, self.lower_const_body(span, body, distributed_slice_declaration))
}
#[instrument(level = "debug", skip(self))]
@@ -660,14 +786,30 @@ impl<'hir> LoweringContext<'_, 'hir> {
expr: _,
safety,
define_opaque,
+ distributed_slice,
}) => {
- let ty =
- self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy));
+ let ty = self.lower_ty(
+ ty,
+ ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy),
+ 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)
@@ -757,7 +899,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 {
@@ -788,6 +931,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
ty,
expr,
define_opaque,
+ distributed_slice,
..
}) => {
let (generics, kind) = self.lower_generics(
@@ -795,11 +939,23 @@ impl<'hir> LoweringContext<'_, 'hir> {
i.id,
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| {
- let ty = this
- .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy));
- let body = expr.as_ref().map(|x| this.lower_const_body(i.span, Some(x)));
+ let ty = this.lower_ty(
+ ty,
+ ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy),
+ 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
+ },
+ )
},
);
@@ -892,6 +1048,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
this.lower_ty(
x,
ImplTraitContext::Disallowed(ImplTraitPosition::AssocTy),
+ false,
)
});
hir::TraitItemKind::Type(
@@ -980,6 +1137,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
ty,
expr,
define_opaque,
+ distributed_slice,
..
}) => (
*ident,
@@ -988,11 +1146,22 @@ impl<'hir> LoweringContext<'_, 'hir> {
i.id,
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| {
- let ty = this
- .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy));
- let body = this.lower_const_body(i.span, expr.as_deref());
+ let ty = this.lower_ty(
+ ty,
+ ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy),
+ 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
+ },
+ )
},
),
),
@@ -1054,6 +1223,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
in_assoc_ty: true,
},
},
+ false,
);
hir::ImplItemKind::Type(ty)
}
@@ -1268,13 +1438,38 @@ 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(_), 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"))
+ }
},
)
})
@@ -1882,8 +2077,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),
@@ -1906,10 +2104,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..bbc80f5e62ad8 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,
@@ -2137,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,
})
});
@@ -2204,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_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_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index d6fe04d2994b5..6c7c56bce9518 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 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,
replace_span: self.ending_semi_or_hi(item.span),
@@ -1436,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_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_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
index 3638eb31c6186..b9f9d7d35d470 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,6 +220,7 @@ impl<'a> State<'a> {
ty,
expr,
define_opaque,
+ distributed_slice: _,
}) => {
self.print_item_const(
*ident,
@@ -565,6 +570,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/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
new file mode 100644
index 0000000000000..90f45eba3dcd8
--- /dev/null
+++ b/compiler/rustc_builtin_macros/src/distributed_slice.rs
@@ -0,0 +1,187 @@
+use rustc_ast::ptr::P;
+use rustc_ast::tokenstream::TokenStream;
+use rustc_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::{
+ 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;
+
+use crate::errors::{
+ DistributedSliceAssocItem, DistributedSliceExpectedConstStatic, DistributedSliceExpectedCrate,
+ DistributedSliceForeignItem, DistributedSliceGeneric,
+};
+
+/// ```rust
+/// #[distributed_slice(crate)]
+/// const MEOWS: [&str; _];
+/// ```
+pub(crate) fn distributed_slice(
+ ecx: &mut ExtCtxt<'_>,
+ span: Span,
+ meta_item: &ast::MetaItem,
+ mut orig_item: Annotatable,
+) -> Vec {
+ // TODO: FIXME(gr)
+
+ 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 {
+ 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 {
+ ItemKind::Static(static_item) => {
+ 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);
+ }
+ _ => {
+ ecx.dcx().emit_err(DistributedSliceExpectedConstStatic {
+ span: item.span,
+ attr_span: meta_item.span,
+ });
+ return vec![orig_item];
+ }
+ }
+
+ vec![orig_item]
+}
+
+fn parse_element(mut p: Parser<'_>) -> PResult<'_, (Path, P)> {
+ 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((path, 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(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::Addition { declaration: path, id: DUMMY_NODE_ID }
+ })),
+ 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/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_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index 667d90429f287..bbc0ab2c6681f 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;
@@ -87,6 +88,8 @@ 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,
+ distributed_slice_elements: distributed_slice::distributed_slice_elements,
env: env::expand_env,
file: source_util::expand_file,
format_args: format::expand_format_args,
@@ -121,6 +124,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 b46eac6d8a602..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 registering static items globally, possibly across crates, to iterate over at runtime.
- (unstable, global_registration, "1.80.0", 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_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index b4fcc16c09c85..64b19ced90927 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),
}
@@ -3096,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);
@@ -3121,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
@@ -3171,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;
}
@@ -3182,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.
@@ -4106,11 +4114,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),
+ 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),
+ 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 +4271,22 @@ 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)]
pub enum ItemKind<'hir> {
/// An `extern crate` item, with optional *original* crate name if the crate was renamed.
@@ -4278,9 +4302,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),
/// A `const` item.
- Const(Ident, &'hir Generics<'hir>, &'hir Ty<'hir>, BodyId),
+ Const(Ident, &'hir Generics<'hir>, &'hir Ty<'hir>, BodyId, DistributedSlice),
/// A function declaration.
Fn {
sig: FnSig<'hir>,
@@ -4375,7 +4399,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, _)
@@ -4495,6 +4519,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> {
@@ -4506,7 +4537,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,
}
@@ -4577,18 +4608,19 @@ 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, .. },
..
})
| 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,
@@ -4803,18 +4835,18 @@ 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,
},
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,
},
@@ -4835,20 +4867,21 @@ 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, .. },
..
})
| 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 1fd44e44b9ce0..9565367eb8548 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));
@@ -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 => (),
@@ -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()
@@ -1166,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);
}
@@ -1224,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/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/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 b764b714fe17e..b60f313c3f844 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);
@@ -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 a649e7d67af37..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;
@@ -42,10 +45,12 @@ 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};
+mod distributed_slice;
pub(crate) mod dump;
mod generics_of;
mod item_bounds;
@@ -79,6 +84,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,
@@ -162,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;
}
@@ -271,6 +281,7 @@ fn reject_placeholder_type_signatures_in_item<'tcx>(
suggest && !visitor.may_contain_const_infer,
None,
item.kind.descr(),
+ InvalidDistributedSliceDeclaration::No,
);
}
@@ -697,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);
@@ -708,6 +719,7 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
false,
None,
"static variable",
+ distributed_slice,
);
}
_ => (),
@@ -762,7 +774,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);
@@ -776,6 +788,7 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
false,
None,
it.kind.descr(),
+ InvalidDistributedSliceDeclaration::No,
);
}
}
@@ -803,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())
@@ -818,6 +831,7 @@ fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
false,
None,
"associated constant",
+ distributed_slice,
);
}
}
@@ -836,6 +850,7 @@ fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
false,
None,
"associated type",
+ InvalidDistributedSliceDeclaration::No,
);
}
@@ -854,6 +869,7 @@ fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
false,
None,
"associated type",
+ InvalidDistributedSliceDeclaration::No,
);
}
};
@@ -885,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();
@@ -899,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/distributed_slice.rs b/compiler/rustc_hir_analysis/src/collect/distributed_slice.rs
new file mode 100644
index 0000000000000..339d4aa437f81
--- /dev/null
+++ b/compiler/rustc_hir_analysis/src/collect/distributed_slice.rs
@@ -0,0 +1,49 @@
+use rand::SeedableRng;
+use rand::seq::SliceRandom;
+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();
+
+ 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(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();
+
+ 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/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
index d45f0475e9910..29d7d589c7857 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, _)
@@ -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 141d96b57e579..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};
+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;
@@ -14,7 +17,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;
@@ -113,6 +119,112 @@ fn const_arg_anon_type_of<'tcx>(icx: &ItemCtxt<'tcx>, arg_hir_id: HirId, span: S
}
}
+fn distributed_slice_element_type<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ lowerer: &dyn HirTyLowerer<'tcx>,
+ ty: &rustc_hir::Ty<'tcx>,
+ emit_diagnostics: bool,
+) -> Ty<'tcx> {
+ use rustc_hir::*;
+
+ 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() });
+ };
+
+ 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
+ }
+}
+
+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)
+}
+
+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(),
+ });
+ }
+
+ ty
+ } else {
+ bug!("should have errored during name resolution");
+ };
+
+ 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<'_>> {
use rustc_hir::*;
use rustc_middle::ty::Ty;
@@ -157,7 +269,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(
@@ -167,6 +279,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_
ty.span,
item.ident,
"associated constant",
+ distributed_slice,
)
})
})
@@ -182,7 +295,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(),
@@ -191,6 +304,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)
@@ -206,8 +320,10 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_
},
Node::Item(item) => match item.kind {
- ItemKind::Static(_, ident, ty, body_id) => {
- if ty.is_suggestable_infer_ty() {
+ ItemKind::Static(_, ident, ty, body_id, distributed_slice) => {
+ if let DistributedSlice::Declaration(_) = distributed_slice {
+ type_of_distributed_slice(tcx, icx.lowerer(), ty, def_id, true)
+ } else if ty.is_suggestable_infer_ty() {
infer_placeholder_type(
icx.lowerer(),
def_id,
@@ -215,13 +331,60 @@ 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)
}
}
- ItemKind::Const(ident, _, ty, body_id) => {
- if ty.is_suggestable_infer_ty() {
+ ItemKind::Const(ident, _, ty, body_id, distributed_slice) => {
+ if let DistributedSlice::Declaration(_) = distributed_slice {
+ type_of_distributed_slice(tcx, icx.lowerer(), ty, def_id, true)
+ } else if let DistributedSlice::Addition(declaration_def_id) = distributed_slice {
+ 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 if ty.is_suggestable_infer_ty() {
infer_placeholder_type(
icx.lowerer(),
def_id,
@@ -229,6 +392,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)
@@ -275,7 +440,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()),
},
@@ -410,10 +575,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 4633f3951a784..69dc1fef292cb 100644
--- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
@@ -136,18 +136,18 @@ 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 {
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
@@ -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_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 b23b3125c59a3..57583e9130bce 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) => {
+ 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) => {
+ 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,28 @@ 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::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));
@@ -911,7 +947,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 +976,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) => {
@@ -1671,6 +1707,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/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/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 5a8148221631d..acf510d51ab0d 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};
@@ -172,8 +172,42 @@ 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,
+ // 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
+ && 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, false)
} else if let Some(ty) = node.ty()
&& ty.is_suggestable_infer_ty()
{
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/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_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..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 => (),
@@ -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_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 279033ee0724c..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,6 +698,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_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs
index 3d5f6f4cf451e..6bb81c3faa90b 100644
--- a/compiler/rustc_mir_build/src/builder/mod.rs
+++ b/compiler/rustc_mir_build/src/builder/mod.rs
@@ -558,13 +558,15 @@ 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,
..
})
- | 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_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 226dc920a496c..c37dd26b0a17f 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -8,6 +8,7 @@ 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::*;
@@ -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,115 @@ 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: &[DistributedSliceAddition] = 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 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()
+ .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
+ },
+ }
+ })
+ .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_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_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_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index 6b82252f32c26..a113599404c1f 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -14,8 +14,9 @@ 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::distributed_slice::DistributedSliceAddition;
use rustc_middle::middle::privacy::Level;
use rustc_middle::query::Providers;
use rustc_middle::ty::{self, TyCtxt};
@@ -435,6 +436,29 @@ 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: &[DistributedSliceAddition] = self
+ .tcx
+ .distributed_slice_elements(())
+ .get(&defid)
+ .map(|i| i.as_slice())
+ .unwrap_or_default();
+
+ intravisit::walk_item(self, item);
+
+ for element in elements {
+ 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),
},
Node::TraitItem(trait_item) => {
@@ -805,7 +829,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/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/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs
index 7e15267a953ba..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) => {
+ 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/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_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index fb1534d0b2798..9d20ceb94e2c0 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 distributed slice",
}
}
@@ -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,17 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|this| this.visit_ty(ty),
);
+ if let DistributedSlice::Addition { declaration, id }
+ | DistributedSlice::AdditionMany { 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/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index ae94169b01dc2..5c4ce38367b55 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,
@@ -832,6 +833,9 @@ symbols! {
discriminant_value,
disjoint_bitor,
dispatch_from_dyn,
+ distributed_slice,
+ distributed_slice_element,
+ distributed_slice_elements,
div,
div_assign,
diverging_block_default,
@@ -1086,7 +1090,6 @@ symbols! {
global_alloc_ty,
global_allocator,
global_asm,
- global_registration,
globs,
gt,
guard_patterns,
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 => {
diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs
index e70a1dab6e9a9..1c3b709420f01 100644
--- a/library/core/src/macros/mod.rs
+++ b/library/core/src/macros/mod.rs
@@ -1804,4 +1804,34 @@ 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 */
+ }
+
+ /// 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 */
+ }
+
+ /// 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 8f1b5275871e6..36f4d499ebfca 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, 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 c15d8c40085a5..4ee5e42dcdbf0 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, 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`.
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..490b9ecdbf023
--- /dev/null
+++ b/tests/ui/crate_local_distributed_slice/create_slice.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_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..484b65a358e13
--- /dev/null
+++ b/tests/ui/crate_local_distributed_slice/create_slice.run.stdout
@@ -0,0 +1 @@
+["mew", "mrow"]
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`.
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