diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index f2061f3088a25..32cd15bc0a206 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3553,6 +3553,7 @@ impl Item { pub fn opt_generics(&self) -> Option<&Generics> { match &self.kind { ItemKind::ExternCrate(..) + | ItemKind::ConstBlock(_) | ItemKind::Use(_) | ItemKind::Mod(..) | ItemKind::ForeignMod(_) @@ -3794,6 +3795,15 @@ impl ConstItemRhs { } } +#[derive(Clone, Encodable, Decodable, Debug, Walkable)] +pub struct ConstBlockItem { + pub body: Box, +} + +impl ConstBlockItem { + pub const IDENT: Ident = Ident { name: kw::Underscore, span: DUMMY_SP }; +} + // Adding a new variant? Please update `test_item` in `tests/ui/macros/stringify.rs`. #[derive(Clone, Encodable, Decodable, Debug)] pub enum ItemKind { @@ -3813,6 +3823,11 @@ pub enum ItemKind { /// /// E.g., `const FOO: i32 = 42;`. Const(Box), + /// A module-level const block. + /// Equivalent to `const _: () = const { ... }`. + /// + /// E.g., `const { assert!(true) }`. + ConstBlock(ConstBlockItem), /// A function declaration (`fn`). /// /// E.g., `fn foo(bar: usize) -> usize { .. }`. @@ -3889,6 +3904,8 @@ impl ItemKind { | ItemKind::MacroDef(ident, _) | ItemKind::Delegation(box Delegation { ident, .. }) => Some(ident), + ItemKind::ConstBlock(_) => Some(ConstBlockItem::IDENT), + ItemKind::Use(_) | ItemKind::ForeignMod(_) | ItemKind::GlobalAsm(_) @@ -3902,9 +3919,9 @@ impl ItemKind { pub fn article(&self) -> &'static str { use ItemKind::*; match self { - Use(..) | Static(..) | Const(..) | Fn(..) | Mod(..) | GlobalAsm(..) | TyAlias(..) - | Struct(..) | Union(..) | Trait(..) | TraitAlias(..) | MacroDef(..) - | Delegation(..) | DelegationMac(..) => "a", + Use(..) | Static(..) | Const(..) | ConstBlock(..) | Fn(..) | Mod(..) + | GlobalAsm(..) | TyAlias(..) | Struct(..) | Union(..) | Trait(..) | TraitAlias(..) + | MacroDef(..) | Delegation(..) | DelegationMac(..) => "a", ExternCrate(..) | ForeignMod(..) | MacCall(..) | Enum(..) | Impl { .. } => "an", } } @@ -3915,6 +3932,7 @@ impl ItemKind { ItemKind::Use(..) => "`use` import", ItemKind::Static(..) => "static item", ItemKind::Const(..) => "constant item", + ItemKind::ConstBlock(..) => "const block", ItemKind::Fn(..) => "function", ItemKind::Mod(..) => "module", ItemKind::ForeignMod(..) => "extern block", @@ -3944,7 +3962,18 @@ impl ItemKind { | Self::Trait(box Trait { generics, .. }) | Self::TraitAlias(box TraitAlias { generics, .. }) | Self::Impl(Impl { generics, .. }) => Some(generics), - _ => None, + + Self::ExternCrate(..) + | Self::Use(..) + | Self::Static(..) + | Self::ConstBlock(..) + | Self::Mod(..) + | Self::ForeignMod(..) + | Self::GlobalAsm(..) + | Self::MacCall(..) + | Self::MacroDef(..) + | Self::Delegation(..) + | Self::DelegationMac(..) => None, } } } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index dde773fd147da..40c458661320c 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -422,6 +422,7 @@ macro_rules! common_visitor_and_walkers { ByRef, Closure, Const, + ConstBlockItem, ConstItem, ConstItemRhs, Defaultness, @@ -819,6 +820,8 @@ macro_rules! common_visitor_and_walkers { visit_visitable!($($mut)? vis, use_tree), ItemKind::Static(item) => visit_visitable!($($mut)? vis, item), + ItemKind::ConstBlock(item) => + visit_visitable!($($mut)? vis, item), ItemKind::Const(item) => visit_visitable!($($mut)? vis, item), ItemKind::Mod(safety, ident, mod_kind) => diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index f5b7065247a08..00a8fde918abf 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -183,8 +183,13 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_define_opaque(hir_id, define_opaque); hir::ItemKind::Static(*m, ident, ty, body_id) } - ItemKind::Const(box ast::ConstItem { - ident, generics, ty, rhs, define_opaque, .. + ItemKind::Const(box ConstItem { + defaultness: _, + ident, + generics, + ty, + rhs, + define_opaque, }) => { let ident = self.lower_ident(*ident); let (generics, (ty, rhs)) = self.lower_generics( @@ -201,6 +206,15 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_define_opaque(hir_id, &define_opaque); hir::ItemKind::Const(ident, generics, ty, rhs) } + ItemKind::ConstBlock(ConstBlockItem { body }) => hir::ItemKind::Const( + self.lower_ident(ConstBlockItem::IDENT), + hir::Generics::empty(), + self.arena.alloc(self.ty_tup(DUMMY_SP, &[])), + hir::ConstItemRhs::Body({ + let body = self.lower_expr_mut(body); + self.record_body(&[], body) + }), + ), ItemKind::Fn(box Fn { sig: FnSig { decl, header, span: fn_sig_span }, ident, diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 2d87d8c84d7c9..af520bc94a9f0 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -525,6 +525,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { gate_all!(super_let, "`super let` is experimental"); gate_all!(frontmatter, "frontmatters are experimental"); gate_all!(coroutines, "coroutine syntax is experimental"); + gate_all!(const_block_items, "const block items are experimental"); if !visitor.features.never_patterns() { if let Some(spans) = spans.get(&sym::never_patterns) { diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index c7cbf34dedb9b..2e7f40e7ad7ca 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -205,6 +205,9 @@ impl<'a> State<'a> { define_opaque.as_deref(), ); } + ast::ItemKind::ConstBlock(ast::ConstBlockItem { body }) => { + self.print_expr(body, FixupContext::default()) + } ast::ItemKind::Const(box ast::ConstItem { defaultness, ident, diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs index dd770fe5f1a13..77758c266c2b5 100644 --- a/compiler/rustc_builtin_macros/src/cfg_eval.rs +++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs @@ -9,7 +9,7 @@ use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_expand::config::StripUnconfigured; use rustc_expand::configure; use rustc_feature::Features; -use rustc_parse::parser::{ForceCollect, Parser}; +use rustc_parse::parser::{ConstBlockItemsAllowed, ForceCollect, Parser}; use rustc_session::Session; use rustc_span::{Span, sym}; use smallvec::SmallVec; @@ -113,7 +113,8 @@ impl CfgEval<'_> { let res: PResult<'_, Annotatable> = try { match annotatable { Annotatable::Item(_) => { - let item = parser.parse_item(ForceCollect::Yes)?.unwrap(); + let item = + parser.parse_item(ForceCollect::Yes, ConstBlockItemsAllowed::No)?.unwrap(); Annotatable::Item(self.flat_map_item(item).pop().unwrap()) } Annotatable::AssocItem(_, ctxt) => { diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs index 16adaab15c525..a33d34f8d673e 100644 --- a/compiler/rustc_builtin_macros/src/source_util.rs +++ b/compiler/rustc_builtin_macros/src/source_util.rs @@ -13,7 +13,7 @@ use rustc_expand::base::{ }; use rustc_expand::module::DirOwnership; use rustc_parse::lexer::StripTokens; -use rustc_parse::parser::ForceCollect; +use rustc_parse::parser::{ConstBlockItemsAllowed, ForceCollect}; use rustc_parse::{new_parser_from_file, unwrap_or_emit_fatal, utf8_error}; use rustc_session::lint::builtin::INCOMPLETE_INCLUDE; use rustc_session::parse::ParseSess; @@ -173,7 +173,7 @@ pub(crate) fn expand_include<'cx>( )); let mut ret = SmallVec::new(); loop { - match p.parse_item(ForceCollect::No) { + match p.parse_item(ForceCollect::No, ConstBlockItemsAllowed::No) { Err(err) => { err.emit(); break; diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 946f17943fe3d..1edd1f9aab3aa 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -22,7 +22,7 @@ use rustc_hir::limit::Limit; use rustc_hir::{Stability, find_attr}; use rustc_lint_defs::RegisteredTools; use rustc_parse::MACRO_ARGUMENTS; -use rustc_parse::parser::{ForceCollect, Parser}; +use rustc_parse::parser::{ConstBlockItemsAllowed, ForceCollect, Parser}; use rustc_session::Session; use rustc_session::config::CollapseMacroDebuginfo; use rustc_session::parse::ParseSess; @@ -1497,7 +1497,7 @@ pub(crate) fn stream_pretty_printing_compatibility_hack( let mut parser = Parser::new(psess, stream.clone(), None); // No need to collect tokens for this simple check. parser - .parse_item(ForceCollect::No) + .parse_item(ForceCollect::No, ConstBlockItemsAllowed::No) .expect("failed to reparse item") .expect("an actual item") } diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 6d048c120a211..ebb342d443f25 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -21,8 +21,8 @@ use rustc_hir::Target; use rustc_hir::def::MacroKinds; use rustc_hir::limit::Limit; use rustc_parse::parser::{ - AttemptLocalParseRecovery, CommaRecoveryMode, ForceCollect, Parser, RecoverColon, RecoverComma, - token_descr, + AttemptLocalParseRecovery, CommaRecoveryMode, ConstBlockItemsAllowed, ForceCollect, Parser, + RecoverColon, RecoverComma, token_descr, }; use rustc_session::Session; use rustc_session::lint::builtin::{UNUSED_ATTRIBUTES, UNUSED_DOC_COMMENTS}; @@ -1096,7 +1096,7 @@ pub fn parse_ast_fragment<'a>( Ok(match kind { AstFragmentKind::Items => { let mut items = SmallVec::new(); - while let Some(item) = this.parse_item(ForceCollect::No)? { + while let Some(item) = this.parse_item(ForceCollect::No, ConstBlockItemsAllowed::No)? { items.push(item); } AstFragment::Items(items) diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs index 9bfda8764f552..89c318f56dfe9 100644 --- a/compiler/rustc_expand/src/proc_macro.rs +++ b/compiler/rustc_expand/src/proc_macro.rs @@ -1,6 +1,6 @@ use rustc_ast::tokenstream::TokenStream; use rustc_errors::ErrorGuaranteed; -use rustc_parse::parser::{ForceCollect, Parser}; +use rustc_parse::parser::{ConstBlockItemsAllowed, ForceCollect, Parser}; use rustc_session::config::ProcMacroExecutionStrategy; use rustc_span::Span; use rustc_span::profiling::SpannedEventArgRecorder; @@ -156,7 +156,7 @@ impl MultiItemModifier for DeriveProcMacro { let mut items = vec![]; loop { - match parser.parse_item(ForceCollect::No) { + match parser.parse_item(ForceCollect::No, ConstBlockItemsAllowed::No) { Ok(None) => break, Ok(Some(item)) => { if is_stmt { diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 26612fda5a7fb..5dfa35f062173 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -445,6 +445,8 @@ declare_features! ( (unstable, cmse_nonsecure_entry, "1.48.0", Some(75835)), /// Allows `async {}` expressions in const contexts. (unstable, const_async_blocks, "1.53.0", Some(85368)), + /// Allows `const { ... }` as a shorthand for `const _: () = const { ... };` for module items. + (unstable, const_block_items, "CURRENT_RUSTC_VERSION", None), /// Allows `const || {}` closures in const contexts. (incomplete, const_closures, "1.68.0", Some(106003)), /// Allows using `[const] Destruct` bounds and calling drop impls in const contexts. diff --git a/compiler/rustc_hir/src/target.rs b/compiler/rustc_hir/src/target.rs index 87953321af3fc..b76c48fbe8ac2 100644 --- a/compiler/rustc_hir/src/target.rs +++ b/compiler/rustc_hir/src/target.rs @@ -171,6 +171,7 @@ impl Target { ast::ItemKind::Use(..) => Target::Use, ast::ItemKind::Static { .. } => Target::Static, ast::ItemKind::Const(..) => Target::Const, + ast::ItemKind::ConstBlock(..) => Target::Const, ast::ItemKind::Fn { .. } => Target::Fn, ast::ItemKind::Mod(..) => Target::Mod, ast::ItemKind::ForeignMod { .. } => Target::ForeignMod, diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index 63109c7ba5cbf..69e7adf586b7e 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -9,7 +9,8 @@ use thin_vec::ThinVec; use tracing::debug; use super::{ - AttrWrapper, Capturing, FnParseMode, ForceCollect, Parser, PathStyle, Trailing, UsePreAttrPos, + AttrWrapper, Capturing, ConstBlockItemsAllowed, FnParseMode, ForceCollect, Parser, PathStyle, + Trailing, UsePreAttrPos, }; use crate::parser::FnContext; use crate::{errors, exp, fluent_generated as fluent}; @@ -203,6 +204,7 @@ impl<'a> Parser<'a> { false, FnParseMode { req_name: |_, _| true, context: FnContext::Free, req_body: true }, ForceCollect::No, + ConstBlockItemsAllowed::No, ) { Ok(Some(item)) => { // FIXME(#100717) diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 86991f047e46d..ffc87984c7269 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -22,8 +22,8 @@ use tracing::debug; use super::diagnostics::{ConsumeClosingDelim, dummy_arg}; use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; use super::{ - AttrWrapper, ExpKeywordPair, ExpTokenPair, FollowedByType, ForceCollect, Parser, PathStyle, - Recovered, Trailing, UsePreAttrPos, + AttrWrapper, ConstBlockItemsAllowed, ExpKeywordPair, ExpTokenPair, FollowedByType, + ForceCollect, Parser, PathStyle, Recovered, Trailing, UsePreAttrPos, }; use crate::errors::{self, FnPointerCannotBeAsync, FnPointerCannotBeConst, MacroExpandsToAdtField}; use crate::{exp, fluent_generated as fluent}; @@ -69,7 +69,7 @@ impl<'a> Parser<'a> { // `parse_item` consumes the appropriate semicolons so any leftover is an error. loop { while self.maybe_consume_incorrect_semicolon(items.last().map(|x| &**x)) {} // Eat all bad semicolons - let Some(item) = self.parse_item(ForceCollect::No)? else { + let Some(item) = self.parse_item(ForceCollect::No, ConstBlockItemsAllowed::Yes)? else { break; }; items.push(item); @@ -118,21 +118,34 @@ impl<'a> Parser<'a> { } impl<'a> Parser<'a> { - pub fn parse_item(&mut self, force_collect: ForceCollect) -> PResult<'a, Option>> { + pub fn parse_item( + &mut self, + force_collect: ForceCollect, + const_block_items_allowed: ConstBlockItemsAllowed, + ) -> PResult<'a, Option>> { let fn_parse_mode = FnParseMode { req_name: |_, _| true, context: FnContext::Free, req_body: true }; - self.parse_item_(fn_parse_mode, force_collect).map(|i| i.map(Box::new)) + self.parse_item_(fn_parse_mode, force_collect, const_block_items_allowed) + .map(|i| i.map(Box::new)) } fn parse_item_( &mut self, fn_parse_mode: FnParseMode, force_collect: ForceCollect, + const_block_items_allowed: ConstBlockItemsAllowed, ) -> PResult<'a, Option> { self.recover_vcs_conflict_marker(); let attrs = self.parse_outer_attributes()?; self.recover_vcs_conflict_marker(); - self.parse_item_common(attrs, true, false, fn_parse_mode, force_collect) + self.parse_item_common( + attrs, + true, + false, + fn_parse_mode, + force_collect, + const_block_items_allowed, + ) } pub(super) fn parse_item_common( @@ -142,10 +155,11 @@ impl<'a> Parser<'a> { attrs_allowed: bool, fn_parse_mode: FnParseMode, force_collect: ForceCollect, + const_block_items_allowed: ConstBlockItemsAllowed, ) -> PResult<'a, Option> { - if let Some(item) = - self.eat_metavar_seq(MetaVarKind::Item, |this| this.parse_item(ForceCollect::Yes)) - { + if let Some(item) = self.eat_metavar_seq(MetaVarKind::Item, |this| { + this.parse_item(ForceCollect::Yes, const_block_items_allowed) + }) { let mut item = item.expect("an actual item"); attrs.prepend_to_nt_inner(&mut item.attrs); return Ok(Some(*item)); @@ -158,6 +172,7 @@ impl<'a> Parser<'a> { let kind = this.parse_item_kind( &mut attrs, mac_allowed, + const_block_items_allowed, lo, &vis, &mut def, @@ -204,6 +219,7 @@ impl<'a> Parser<'a> { &mut self, attrs: &mut AttrVec, macros_allowed: bool, + const_block_items_allowed: ConstBlockItemsAllowed, lo: Span, vis: &Visibility, def: &mut Defaultness, @@ -253,6 +269,13 @@ impl<'a> Parser<'a> { } else if self.check_impl_frontmatter() { // IMPL ITEM self.parse_item_impl(attrs, def_())? + } else if let ConstBlockItemsAllowed::Yes = const_block_items_allowed + && self.token.is_keyword(kw::Const) + && self.look_ahead(1, |t| *t == token::OpenBrace || t.is_metavar_block()) + { + // CONST BLOCK ITEM + self.psess.gated_spans.gate(sym::const_block_items, self.token.span); + ItemKind::ConstBlock(ConstBlockItem { body: self.parse_expr()? }) } else if let Const::Yes(const_span) = self.parse_constness(Case::Sensitive) { // CONST ITEM self.recover_const_mut(const_span); @@ -312,6 +335,7 @@ impl<'a> Parser<'a> { return self.parse_item_kind( attrs, macros_allowed, + const_block_items_allowed, lo, vis, def, @@ -992,7 +1016,7 @@ impl<'a> Parser<'a> { fn_parse_mode: FnParseMode, force_collect: ForceCollect, ) -> PResult<'a, Option>>> { - Ok(self.parse_item_(fn_parse_mode, force_collect)?.map( + Ok(self.parse_item_(fn_parse_mode, force_collect, ConstBlockItemsAllowed::No)?.map( |Item { attrs, id, span, vis, kind, tokens }| { let kind = match AssocItemKind::try_from(kind) { Ok(kind) => kind, @@ -1244,7 +1268,7 @@ impl<'a> Parser<'a> { context: FnContext::Free, req_body: false, }; - Ok(self.parse_item_(fn_parse_mode, force_collect)?.map( + Ok(self.parse_item_(fn_parse_mode, force_collect, ConstBlockItemsAllowed::No)?.map( |Item { attrs, id, span, vis, kind, tokens }| { let kind = match ForeignItemKind::try_from(kind) { Ok(kind) => kind, @@ -2300,7 +2324,7 @@ impl<'a> Parser<'a> { { let kw_token = self.token; let kw_str = pprust::token_to_string(&kw_token); - let item = self.parse_item(ForceCollect::No)?; + let item = self.parse_item(ForceCollect::No, ConstBlockItemsAllowed::No)?; let mut item = item.unwrap().span; if self.token == token::Comma { item = item.to(self.token.span); diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 203a93b52012b..60f84ffacfa5f 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -145,6 +145,13 @@ pub enum ForceCollect { No, } +/// Whether to accept `const { ... }` as a shorthand for `const _: () = const { ... }`. +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum ConstBlockItemsAllowed { + Yes, + No, +} + /// If the next tokens are ill-formed `$ty::` recover them as `<$ty>::`. #[macro_export] macro_rules! maybe_recover_from_interpolated_ty_qpath { diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index ea2b896f5fb9c..e0b6be49942e0 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -6,7 +6,9 @@ use rustc_span::{Ident, kw}; use crate::errors::UnexpectedNonterminal; use crate::parser::pat::{CommaRecoveryMode, RecoverColon, RecoverComma}; -use crate::parser::{FollowedByType, ForceCollect, ParseNtResult, Parser, PathStyle}; +use crate::parser::{ + ConstBlockItemsAllowed, FollowedByType, ForceCollect, ParseNtResult, Parser, PathStyle, +}; impl<'a> Parser<'a> { /// Checks whether a non-terminal may begin with a particular token. @@ -118,7 +120,9 @@ impl<'a> Parser<'a> { match kind { // Note that TT is treated differently to all the others. NonterminalKind::TT => Ok(ParseNtResult::Tt(self.parse_token_tree())), - NonterminalKind::Item => match self.parse_item(ForceCollect::Yes)? { + NonterminalKind::Item => match self + .parse_item(ForceCollect::Yes, ConstBlockItemsAllowed::Yes)? + { Some(item) => Ok(ParseNtResult::Item(item)), None => Err(self.dcx().create_err(UnexpectedNonterminal::Item(self.token.span))), }, diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 3fe8971f3d6c6..f1baa1e25b9fe 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -20,8 +20,8 @@ use super::diagnostics::AttemptLocalParseRecovery; use super::pat::{PatternLocation, RecoverComma}; use super::path::PathStyle; use super::{ - AttrWrapper, BlockMode, FnContext, FnParseMode, ForceCollect, Parser, Restrictions, - SemiColonMode, Trailing, UsePreAttrPos, + AttrWrapper, BlockMode, ConstBlockItemsAllowed, FnContext, FnParseMode, ForceCollect, Parser, + Restrictions, SemiColonMode, Trailing, UsePreAttrPos, }; use crate::errors::{self, MalformedLoopLabel}; use crate::exp; @@ -156,6 +156,7 @@ impl<'a> Parser<'a> { true, FnParseMode { req_name: |_, _| true, context: FnContext::Free, req_body: true }, force_collect, + ConstBlockItemsAllowed::No, )? { self.mk_stmt(lo.to(item.span), StmtKind::Item(Box::new(item))) } else if self.eat(exp!(Semi)) { diff --git a/compiler/rustc_passes/src/input_stats.rs b/compiler/rustc_passes/src/input_stats.rs index fe50b730256b7..a0e31e1b4fb79 100644 --- a/compiler/rustc_passes/src/input_stats.rs +++ b/compiler/rustc_passes/src/input_stats.rs @@ -573,6 +573,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { Use, Static, Const, + ConstBlock, Fn, Mod, ForeignMod, diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index 141a60a8ec3f9..b9417af13b113 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -276,7 +276,7 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> { ast::ItemKind::ExternCrate(..) => Target::ExternCrate, ast::ItemKind::Use(_) => Target::Use, ast::ItemKind::Static(_) => Target::Static, - ast::ItemKind::Const(_) => Target::Const, + ast::ItemKind::Const(_) | ast::ItemKind::ConstBlock(_) => Target::Const, ast::ItemKind::Fn(_) | ast::ItemKind::Delegation(..) => Target::Fn, ast::ItemKind::Mod(..) => Target::Mod, ast::ItemKind::ForeignMod(_) => Target::ForeignFn, diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index cd12d5ad10cf7..9394ae170583c 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -835,6 +835,15 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { | ItemKind::Static(box StaticItem { ident, .. }) => { self.r.define_local(parent, ident, ValueNS, res, vis, sp, expansion); } + ItemKind::ConstBlock(_) => self.r.define_local( + parent, + ast::ConstBlockItem::IDENT, + ValueNS, + res, + vis, + sp, + expansion, + ), ItemKind::Fn(box Fn { ident, .. }) => { self.r.define_local(parent, ident, ValueNS, res, vis, sp, expansion); diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index ea64a1e6c64dd..a4782b2c52d9b 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -121,7 +121,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { mutability: s.mutability, nested: false, }, - ItemKind::Const(..) => DefKind::Const, + ItemKind::Const(..) | ItemKind::ConstBlock(..) => DefKind::Const, ItemKind::Fn(..) | ItemKind::Delegation(..) => DefKind::Fn, ItemKind::MacroDef(ident, def) => { let edition = i.span.edition(); diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index fe6e5b8e6eb6a..77c20948c1374 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -273,6 +273,7 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> | ast::ItemKind::Use(..) | ast::ItemKind::Static(..) | ast::ItemKind::Const(..) + | ast::ItemKind::ConstBlock(..) | ast::ItemKind::GlobalAsm(..) | ast::ItemKind::TyAlias(..) | ast::ItemKind::TraitAlias(..) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index a92bc77b5b508..a95e35388d943 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2705,8 +2705,8 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { debug!("(resolving item) resolving {:?} ({:?})", item.kind.ident(), item.kind); let def_kind = self.r.local_def_kind(item.id); - match item.kind { - ItemKind::TyAlias(box TyAlias { ref generics, .. }) => { + match &item.kind { + ItemKind::TyAlias(box TyAlias { generics, .. }) => { self.with_generic_param_rib( &generics.params, RibKind::Item(HasGenericParams::Yes(generics.span), def_kind), @@ -2717,7 +2717,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ); } - ItemKind::Fn(box Fn { ref generics, ref define_opaque, .. }) => { + ItemKind::Fn(box Fn { generics, define_opaque, .. }) => { self.with_generic_param_rib( &generics.params, RibKind::Item(HasGenericParams::Yes(generics.span), def_kind), @@ -2729,19 +2729,13 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.resolve_define_opaques(define_opaque); } - ItemKind::Enum(_, ref generics, _) - | ItemKind::Struct(_, ref generics, _) - | ItemKind::Union(_, ref generics, _) => { + ItemKind::Enum(_, generics, _) + | ItemKind::Struct(_, generics, _) + | ItemKind::Union(_, generics, _) => { self.resolve_adt(item, generics); } - ItemKind::Impl(Impl { - ref generics, - ref of_trait, - ref self_ty, - items: ref impl_items, - .. - }) => { + ItemKind::Impl(Impl { generics, of_trait, self_ty, items: impl_items, .. }) => { self.diag_metadata.current_impl_items = Some(impl_items); self.resolve_implementation( &item.attrs, @@ -2754,7 +2748,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.diag_metadata.current_impl_items = None; } - ItemKind::Trait(box Trait { ref generics, ref bounds, ref items, .. }) => { + ItemKind::Trait(box Trait { generics, bounds, items, .. }) => { // Create a new rib for the trait-wide type parameters. self.with_generic_param_rib( &generics.params, @@ -2773,7 +2767,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ); } - ItemKind::TraitAlias(box TraitAlias { ref generics, ref bounds, .. }) => { + ItemKind::TraitAlias(box TraitAlias { generics, bounds, .. }) => { // Create a new rib for the trait-wide type parameters. self.with_generic_param_rib( &generics.params, @@ -2813,13 +2807,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.parent_scope.module = orig_module; } - ItemKind::Static(box ast::StaticItem { - ident, - ref ty, - ref expr, - ref define_opaque, - .. - }) => { + ItemKind::Static(box ast::StaticItem { ident, ty, expr, define_opaque, .. }) => { self.with_static_rib(def_kind, |this| { this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| { this.visit_ty(ty); @@ -2827,7 +2815,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { if let Some(expr) = expr { // We already forbid generic params because of the above item rib, // so it doesn't matter whether this is a trivial constant. - this.resolve_static_body(expr, Some((ident, ConstantItemKind::Static))); + this.resolve_static_body(expr, Some((*ident, ConstantItemKind::Static))); } }); self.resolve_define_opaques(define_opaque); @@ -2835,11 +2823,11 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ItemKind::Const(box ast::ConstItem { ident, - ref generics, - ref ty, - ref rhs, - ref define_opaque, - .. + generics, + ty, + rhs, + define_opaque, + defaultness: _, }) => { self.with_generic_param_rib( &generics.params, @@ -2865,15 +2853,32 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { if let Some(rhs) = rhs { this.resolve_const_item_rhs( rhs, - Some((ident, ConstantItemKind::Const)), + Some((*ident, ConstantItemKind::Const)), ); } }, ); self.resolve_define_opaques(define_opaque); } + ItemKind::ConstBlock(ConstBlockItem { body }) => self.with_generic_param_rib( + &[], + RibKind::Item(HasGenericParams::No, def_kind), + item.id, + LifetimeBinderKind::ConstItem, + DUMMY_SP, + |this| { + this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| { + this.with_constant_rib( + IsRepeatExpr::No, + ConstantHasGenerics::Yes, + Some((ConstBlockItem::IDENT, ConstantItemKind::Const)), + |this| this.visit_expr(body), + ); + }) + }, + ), - ItemKind::Use(ref use_tree) => { + ItemKind::Use(use_tree) => { let maybe_exported = match use_tree.kind { UseTreeKind::Simple(_) | UseTreeKind::Glob => MaybeExported::Ok(item.id), UseTreeKind::Nested { .. } => MaybeExported::NestedUse(&item.vis), @@ -2883,7 +2888,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.future_proof_import(use_tree); } - ItemKind::MacroDef(_, ref macro_def) => { + ItemKind::MacroDef(_, macro_def) => { // Maintain macro_rules scopes in the same way as during early resolution // for diagnostics and doc links. if macro_def.macro_rules { @@ -2896,7 +2901,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { visit::walk_item(self, item); } - ItemKind::Delegation(ref delegation) => { + ItemKind::Delegation(delegation) => { let span = delegation.path.segments.last().unwrap().ident.span; self.with_generic_param_rib( &[], @@ -5341,6 +5346,7 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> { ItemKind::Mod(..) | ItemKind::Static(..) + | ItemKind::ConstBlock(..) | ItemKind::Use(..) | ItemKind::ExternCrate(..) | ItemKind::MacroDef(..) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index eca4259efa7d1..c6392c08425d4 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -715,6 +715,7 @@ symbols! { console, const_allocate, const_async_blocks, + const_block_items, const_closures, const_compare_raw_pointers, const_constructor, diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs index e9f5024e494d1..1512c80d7d240 100644 --- a/src/librustdoc/doctest/make.rs +++ b/src/librustdoc/doctest/make.rs @@ -529,7 +529,10 @@ fn parse_source( let mut prev_span_hi = 0; let not_crate_attrs = &[sym::forbid, sym::allow, sym::warn, sym::deny, sym::expect]; - let parsed = parser.parse_item(rustc_parse::parser::ForceCollect::No); + let parsed = parser.parse_item( + rustc_parse::parser::ForceCollect::No, + rustc_parse::parser::ConstBlockItemsAllowed::No, + ); let result = match parsed { Ok(Some(ref item)) diff --git a/tests/ui/feature-gates/feature-gate-const-block-items.rs b/tests/ui/feature-gates/feature-gate-const-block-items.rs new file mode 100644 index 0000000000000..5523633197bba --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-const-block-items.rs @@ -0,0 +1,7 @@ +//@ check-fail + +const { //~ ERROR: const block items are experimental + assert!(true) +} + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-const-block-items.stderr b/tests/ui/feature-gates/feature-gate-const-block-items.stderr new file mode 100644 index 0000000000000..89c9531111e8b --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-const-block-items.stderr @@ -0,0 +1,12 @@ +error[E0658]: const block items are experimental + --> $DIR/feature-gate-const-block-items.rs:3:1 + | +LL | const { + | ^^^^^ + | + = help: add `#![feature(const_block_items)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/macros/stringify.rs b/tests/ui/macros/stringify.rs index fa06da5cbfbc6..8cdae1a2b6531 100644 --- a/tests/ui/macros/stringify.rs +++ b/tests/ui/macros/stringify.rs @@ -5,6 +5,7 @@ #![allow(incomplete_features)] #![feature(auto_traits)] #![feature(box_patterns)] +#![feature(const_block_items)] #![feature(const_trait_impl)] #![feature(coroutines)] #![feature(decl_macro)] @@ -369,6 +370,9 @@ fn test_item() { c1!(item, [ pub const S: () = {}; ], "pub const S: () = {};"); c1!(item, [ const S: (); ], "const S: ();"); + // ItemKind::ConstBlock + c1!(item, [ const {}; ], "const {};"); + // ItemKind::Fn c1!(item, [ pub default const async unsafe extern "C" fn f() {} ],