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