diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index db7cace49ae8f..6a384fbbdeaa9 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3551,6 +3551,7 @@ impl Item { pub fn opt_generics(&self) -> Option<&Generics> { match &self.kind { ItemKind::ExternCrate(..) + | ItemKind::ConstBlock(_) | ItemKind::Use(_) | ItemKind::Mod(..) | ItemKind::ForeignMod(_) @@ -3768,7 +3769,7 @@ pub struct ConstItem { pub defaultness: Defaultness, pub ident: Ident, pub generics: Generics, - pub ty: Box, + pub ty: FnRetTy, pub rhs: Option, pub define_opaque: Option>, } @@ -3792,6 +3793,16 @@ impl ConstItemRhs { } } +#[derive(Clone, Encodable, Decodable, Debug, Walkable)] +pub struct ConstBlockItem { + // FIXME(const_block_items): current invariant is body.kind == InlineConst + 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 { @@ -3811,6 +3822,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 { .. }`. @@ -3887,6 +3903,8 @@ impl ItemKind { | ItemKind::MacroDef(ident, _) | ItemKind::Delegation(box Delegation { ident, .. }) => Some(ident), + ItemKind::ConstBlock(_) => Some(ConstBlockItem::IDENT), + ItemKind::Use(_) | ItemKind::ForeignMod(_) | ItemKind::GlobalAsm(_) @@ -3900,9 +3918,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", } } @@ -3913,6 +3931,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", @@ -3942,7 +3961,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..54c39d6290a8d 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( @@ -192,8 +197,10 @@ impl<'hir> LoweringContext<'_, 'hir> { id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { - let ty = this - .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); + let ty = this.lower_fn_ret_ty_or_unit( + ty, + ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy), + ); let rhs = this.lower_const_item_rhs(attrs, rhs.as_ref(), span); (ty, rhs) }, @@ -201,6 +208,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, @@ -803,8 +819,10 @@ impl<'hir> LoweringContext<'_, 'hir> { i.id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { - let ty = this - .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); + let ty = this.lower_fn_ret_ty_or_unit( + ty, + ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy), + ); let rhs = rhs .as_ref() .map(|rhs| this.lower_const_item_rhs(attrs, Some(rhs), i.span)); @@ -1015,8 +1033,10 @@ impl<'hir> LoweringContext<'_, 'hir> { i.id, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { - let ty = this - .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy)); + let ty = this.lower_fn_ret_ty_or_unit( + ty, + ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy), + ); this.lower_define_opaque(hir_id, &define_opaque); let rhs = this.lower_const_item_rhs(attrs, rhs.as_ref(), i.span); hir::ImplItemKind::Const(ty, rhs) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index dff46ece65430..0a04dfa4da9eb 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1801,6 +1801,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::FnRetTy::Return(self.arena.alloc(opaque_ty)) } + fn lower_fn_ret_ty_or_unit( + &mut self, + fn_ret_ty: &FnRetTy, + ictxt: ImplTraitContext, + ) -> &'hir hir::Ty<'hir> { + match fn_ret_ty { + FnRetTy::Ty(ty) => self.lower_ty(ty, ictxt), + FnRetTy::Default(span) => self.arena.alloc(self.ty_tup(*span, &[])), + } + } + /// Transforms `-> T` into `Future`. fn lower_coroutine_fn_output_type_to_bound( &mut self, @@ -1810,15 +1821,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { itctx: ImplTraitContext, ) -> hir::GenericBound<'hir> { // Compute the `T` in `Future` from the return type. - let output_ty = match output { - FnRetTy::Ty(ty) => { - // Not `OpaqueTyOrigin::AsyncFn`: that's only used for the - // `impl Future` opaque type that `async fn` implicitly - // generates. - self.lower_ty(ty, itctx) - } - FnRetTy::Default(ret_ty_span) => self.arena.alloc(self.ty_tup(*ret_ty_span, &[])), - }; + // Not `OpaqueTyOrigin::AsyncFn`: that's only used for the + // `impl Future` opaque type that `async fn` implicitly + // generates. + let output_ty = self.lower_fn_ret_ty_or_unit(output, itctx); // "<$assoc_ty_name = T>" let (assoc_ty_name, trait_lang_item) = match coro { diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 2d87d8c84d7c9..aa6b3ce7195ce 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -511,6 +511,11 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { gate_all!(generic_const_items, "generic const items are experimental"); gate_all!(guard_patterns, "guard patterns are experimental", "consider using match arm guards"); gate_all!(default_field_values, "default values on fields are experimental"); + gate_all!( + const_items_unit_type_default, + "omitting type on const item declaration is experimental", + "consider specifying the type explicitly" + ); 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"); @@ -525,6 +530,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..049d8b73ab100 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -47,7 +47,7 @@ impl<'a> State<'a> { *ident, Some(*mutability), &ast::Generics::default(), - ty, + Some(ty), expr.as_deref(), vis, *safety, @@ -87,7 +87,7 @@ impl<'a> State<'a> { ident: Ident, mutbl: Option, generics: &ast::Generics, - ty: &ast::Ty, + ty: Option<&ast::Ty>, body: Option<&ast::Expr>, vis: &ast::Visibility, safety: ast::Safety, @@ -107,8 +107,10 @@ impl<'a> State<'a> { self.word_space(leading); self.print_ident(ident); self.print_generic_params(&generics.params); - self.word_space(":"); - self.print_type(ty); + if let Some(ty) = ty { + self.word_space(":"); + self.print_type(ty); + } if body.is_some() { self.space(); } @@ -197,7 +199,7 @@ impl<'a> State<'a> { *ident, Some(*mutbl), &ast::Generics::default(), - ty, + Some(ty), body.as_deref(), &item.vis, ast::Safety::Default, @@ -205,6 +207,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, @@ -217,7 +222,10 @@ impl<'a> State<'a> { *ident, None, generics, - ty, + match ty { + ast::FnRetTy::Default(_) => None, + ast::FnRetTy::Ty(ty) => Some(ty), + }, rhs.as_ref().map(|ct| ct.expr()), &item.vis, ast::Safety::Default, @@ -569,7 +577,10 @@ impl<'a> State<'a> { *ident, None, generics, - ty, + match ty { + ast::FnRetTy::Default(_) => None, + ast::FnRetTy::Ty(ty) => Some(ty), + }, rhs.as_ref().map(|ct| ct.expr()), vis, ast::Safety::Default, diff --git a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs index e5d9d2080c08e..9c9490a0628e4 100644 --- a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs +++ b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs @@ -4,7 +4,7 @@ use rustc_ast::{ }; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::{Ident, Span, kw, sym}; -use thin_vec::{ThinVec, thin_vec}; +use thin_vec::thin_vec; use crate::errors; use crate::util::check_builtin_macro_attribute; @@ -42,9 +42,14 @@ pub(crate) fn expand( let stmts = thin_vec![generate_handler(ecx, ident, span, sig_span)]; // Generate anonymous constant serving as container for the allocator methods. - let const_ty = ecx.ty(sig_span, TyKind::Tup(ThinVec::new())); + let const_body = ast::ConstItemRhs::Body(ecx.expr_block(ecx.block(span, stmts))); - let const_item = ecx.item_const(span, Ident::new(kw::Underscore, span), const_ty, const_body); + let const_item = ecx.item_const( + span, + Ident::new(kw::Underscore, span), + ast::FnRetTy::Default(sig_span), + const_body, + ); let const_item = if is_stmt { Annotatable::Stmt(Box::new(ecx.stmt_item(span, const_item))) } else { diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs index dd770fe5f1a13..5a38c91fb3f2f 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::{AllowConstBlockItems, 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, AllowConstBlockItems::Yes)?.unwrap(); Annotatable::Item(self.flat_map_item(item).pop().unwrap()) } Annotatable::AssocItem(_, ctxt) => { diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs index e69f0838f22e9..aa699f17e7902 100644 --- a/compiler/rustc_builtin_macros/src/global_allocator.rs +++ b/compiler/rustc_builtin_macros/src/global_allocator.rs @@ -46,9 +46,13 @@ pub(crate) fn expand( let stmts = ALLOCATOR_METHODS.iter().map(|method| f.allocator_fn(method)).collect(); // Generate anonymous constant serving as container for the allocator methods. - let const_ty = ecx.ty(ty_span, TyKind::Tup(ThinVec::new())); let const_body = ast::ConstItemRhs::Body(ecx.expr_block(ecx.block(span, stmts))); - let const_item = ecx.item_const(span, Ident::new(kw::Underscore, span), const_ty, const_body); + let const_item = ecx.item_const( + span, + Ident::new(kw::Underscore, span), + ast::FnRetTy::Default(ty_span), + const_body, + ); let const_item = if is_stmt { Annotatable::Stmt(Box::new(ecx.stmt_item(span, const_item))) } else { diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index e30d506a31b9e..fa1e815fcb87a 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -389,12 +389,8 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> Box { cx.block(span, thin_vec![cx.stmt_item(span, krate), cx.stmt_item(span, decls_static)]), )); - let anon_constant = cx.item_const( - span, - Ident::new(kw::Underscore, span), - cx.ty(span, ast::TyKind::Tup(ThinVec::new())), - block, - ); + let anon_constant = + cx.item_const(span, Ident::new(kw::Underscore, span), ast::FnRetTy::Default(span), block); // Integrate the new item into existing module structures. let items = AstFragment::Items(smallvec![anon_constant]); diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs index 16adaab15c525..92ce870c65e18 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::{AllowConstBlockItems, 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, AllowConstBlockItems::Yes) { Err(err) => { err.emit(); break; diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index f31ad4f591b1e..73437f20ce09f 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -286,7 +286,9 @@ pub(crate) fn expand_test_or_bench( defaultness: ast::Defaultness::Final, ident: Ident::new(fn_.ident.name, sp), generics: ast::Generics::default(), - ty: cx.ty(sp, ast::TyKind::Path(None, test_path("TestDescAndFn"))), + ty: ast::FnRetTy::Ty( + cx.ty(sp, ast::TyKind::Path(None, test_path("TestDescAndFn"))), + ), define_opaque: None, // test::TestDescAndFn { rhs: Some(ast::ConstItemRhs::Body( diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 946f17943fe3d..b30d94a237896 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::{AllowConstBlockItems, 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, AllowConstBlockItems::No) .expect("failed to reparse item") .expect("an actual item") } diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 6be65b0fff16f..cdaca87e8b9e3 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -725,7 +725,7 @@ impl<'a> ExtCtxt<'a> { &self, span: Span, ident: Ident, - ty: Box, + ty: ast::FnRetTy, rhs: ast::ConstItemRhs, ) -> Box { let defaultness = ast::Defaultness::Final; diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 20fb321307ac5..8e85c251a575b 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, + AllowConstBlockItems, AttemptLocalParseRecovery, CommaRecoveryMode, 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, AllowConstBlockItems::Yes)? { 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..23fe2e86d44e8 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::{AllowConstBlockItems, ForceCollect, Parser}; use rustc_session::config::ProcMacroExecutionStrategy; use rustc_span::Span; use rustc_span::profiling::SpannedEventArgRecorder; @@ -156,7 +156,10 @@ impl MultiItemModifier for DeriveProcMacro { let mut items = vec![]; loop { - match parser.parse_item(ForceCollect::No) { + match parser.parse_item( + ForceCollect::No, + if is_stmt { AllowConstBlockItems::No } else { AllowConstBlockItems::Yes }, + ) { 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 3ef4eb00c3546..0aa2e44359ae2 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -443,12 +443,16 @@ 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", Some(149226)), /// 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. (unstable, const_destruct, "1.85.0", Some(133214)), /// Allows `for _ in _` loops in const contexts. (unstable, const_for, "1.56.0", Some(87575)), + /// Allows to omit `: ()` type in `const FOO: () = ...` similarly to `-> ()` in functions. + (unstable, const_items_unit_type_default, "CURRENT_RUSTC_VERSION", Some(149226)), /// Be more precise when looking for live drops in a const context. (unstable, const_precise_live_drops, "1.46.0", Some(73255)), /// Allows `impl const Trait for T` syntax. 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..0d3f904285887 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, + AllowConstBlockItems, AttrWrapper, Capturing, 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, + AllowConstBlockItems::Yes, ) { Ok(Some(item)) => { // FIXME(#100717) diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index abc0ffa87d3d0..a50d249ecada4 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, + AllowConstBlockItems, AttrWrapper, 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, AllowConstBlockItems::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, + allow_const_block_items: AllowConstBlockItems, + ) -> 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, allow_const_block_items) + .map(|i| i.map(Box::new)) } fn parse_item_( &mut self, fn_parse_mode: FnParseMode, force_collect: ForceCollect, + const_block_items_allowed: AllowConstBlockItems, ) -> 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, + allow_const_block_items: AllowConstBlockItems, ) -> 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, allow_const_block_items) + }) { 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, + allow_const_block_items, lo, &vis, &mut def, @@ -204,6 +219,7 @@ impl<'a> Parser<'a> { &mut self, attrs: &mut AttrVec, macros_allowed: bool, + allow_const_block_items: AllowConstBlockItems, lo: Span, vis: &Visibility, def: &mut Defaultness, @@ -251,6 +267,17 @@ impl<'a> Parser<'a> { } else if self.check_impl_frontmatter() { // IMPL ITEM self.parse_item_impl(attrs, def_())? + } else if let AllowConstBlockItems::Yes | AllowConstBlockItems::DoesNotMatter = + allow_const_block_items + && 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); + if let AllowConstBlockItems::DoesNotMatter = allow_const_block_items { + debug!("Parsing a const block item that does not matter: {:?}", self.token.span); + }; + ItemKind::ConstBlock(ConstBlockItem { body: self.parse_expr()? }) } else if let Const::Yes(const_span) = self.parse_constness(case) { // CONST ITEM self.recover_const_mut(const_span); @@ -310,6 +337,7 @@ impl<'a> Parser<'a> { return self.parse_item_kind( attrs, macros_allowed, + allow_const_block_items, lo, vis, def, @@ -990,8 +1018,13 @@ impl<'a> Parser<'a> { fn_parse_mode: FnParseMode, force_collect: ForceCollect, ) -> PResult<'a, Option>>> { - Ok(self.parse_item_(fn_parse_mode, force_collect)?.map( - |Item { attrs, id, span, vis, kind, tokens }| { + Ok(self + .parse_item_( + fn_parse_mode, + force_collect, + AllowConstBlockItems::DoesNotMatter, // due to `AssocItemKind::try_from` below + )? + .map(|Item { attrs, id, span, vis, kind, tokens }| { let kind = match AssocItemKind::try_from(kind) { Ok(kind) => kind, Err(kind) => match kind { @@ -1009,7 +1042,7 @@ impl<'a> Parser<'a> { defaultness: Defaultness::Final, ident, generics: Generics::default(), - ty, + ty: FnRetTy::Ty(ty), rhs, define_opaque, })) @@ -1018,8 +1051,7 @@ impl<'a> Parser<'a> { }, }; Some(Box::new(Item { attrs, id, span, vis, kind, tokens })) - }, - )) + })) } /// Parses a `type` alias with the following grammar: @@ -1242,8 +1274,13 @@ impl<'a> Parser<'a> { context: FnContext::Free, req_body: false, }; - Ok(self.parse_item_(fn_parse_mode, force_collect)?.map( - |Item { attrs, id, span, vis, kind, tokens }| { + Ok(self + .parse_item_( + fn_parse_mode, + force_collect, + AllowConstBlockItems::DoesNotMatter, // due to `ForeignItemKind::try_from` below + )? + .map(|Item { attrs, id, span, vis, kind, tokens }| { let kind = match ForeignItemKind::try_from(kind) { Ok(kind) => kind, Err(kind) => match kind { @@ -1256,7 +1293,12 @@ impl<'a> Parser<'a> { }); ForeignItemKind::Static(Box::new(StaticItem { ident, - ty, + ty: match ty { + FnRetTy::Default(span) => { + Self::default_ty_for_static_items(span) + } + FnRetTy::Ty(ty) => ty, + }, mutability: Mutability::Not, expr: rhs.map(|b| match b { ConstItemRhs::TypeConst(anon_const) => anon_const.value, @@ -1270,8 +1312,7 @@ impl<'a> Parser<'a> { }, }; Some(Box::new(Item { attrs, id, span, vis, kind, tokens })) - }, - )) + })) } fn error_bad_item_kind(&self, span: Span, kind: &ItemKind, ctx: &'static str) -> Option { @@ -1359,6 +1400,10 @@ impl<'a> Parser<'a> { } } + fn default_ty_for_static_items(span: Span) -> Box { + Box::new(Ty { kind: TyKind::Infer, span, id: ast::DUMMY_NODE_ID, tokens: None }) + } + /// Parse a static item with the prefix `"static" "mut"?` already parsed and stored in /// `mutability`. /// @@ -1377,13 +1422,29 @@ impl<'a> Parser<'a> { self.dcx().emit_err(errors::StaticWithGenerics { span: generics.span }); } - // Parse the type of a static item. That is, the `":" $ty` fragment. - // FIXME: This could maybe benefit from `.may_recover()`? - let ty = match (self.eat(exp!(Colon)), self.check(exp!(Eq)) | self.check(exp!(Semi))) { - (true, false) => self.parse_ty()?, - // If there wasn't a `:` or the colon was followed by a `=` or `;`, recover a missing - // type. - (colon, _) => self.recover_missing_global_item_type(colon, Some(mutability)), + let ty = match self.parse_global_item_type(false)? { + Ok(ty) => ty, + Err((span, colon_present)) => { + // Construct the error and stash it away with the hope + // that typeck will later enrich the error with a type. + self.dcx() + .create_err(errors::MissingConstType { + span, + colon: match colon_present { + true => "", + false => ":", + }, + kind: match mutability { + Mutability::Mut => "static mut", + Mutability::Not => "static", + }, + }) + .stash(span, StashKey::ItemNoType); + + // The user intended that the type be inferred, + // so treat this as if the user wrote e.g. `static A: _ = expr;`. + Self::default_ty_for_static_items(span) + } }; let expr = if self.eat(exp!(Eq)) { Some(self.parse_expr()?) } else { None }; @@ -1402,7 +1463,7 @@ impl<'a> Parser<'a> { fn parse_const_item( &mut self, attrs: &[Attribute], - ) -> PResult<'a, (Ident, Generics, Box, Option)> { + ) -> PResult<'a, (Ident, Generics, FnRetTy, Option)> { let ident = self.parse_ident_or_underscore()?; let mut generics = self.parse_generics()?; @@ -1413,15 +1474,12 @@ impl<'a> Parser<'a> { self.psess.gated_spans.gate(sym::generic_const_items, generics.span); } - // Parse the type of a constant item. That is, the `":" $ty` fragment. - // FIXME: This could maybe benefit from `.may_recover()`? - let ty = match ( - self.eat(exp!(Colon)), - self.check(exp!(Eq)) | self.check(exp!(Semi)) | self.check_keyword(exp!(Where)), - ) { - (true, false) => self.parse_ty()?, - // If there wasn't a `:` or the colon was followed by a `=`, `;` or `where`, recover a missing type. - (colon, _) => self.recover_missing_global_item_type(colon, None), + let ty = match self.parse_global_item_type(true)? { + Ok(ty) => FnRetTy::Ty(ty), + Err((span, _)) => { + self.psess.gated_spans.gate(sym::const_items_unit_type_default, span); + FnRetTy::Default(span) + } }; // Proactively parse a where-clause to be able to provide a good error message in case we @@ -1497,33 +1555,24 @@ impl<'a> Parser<'a> { Ok((ident, generics, ty, rhs)) } - /// We were supposed to parse `":" $ty` but the `:` or the type was missing. - /// This means that the type is missing. - fn recover_missing_global_item_type( + // Parse the type of a constant item. That is, the `":" $ty` fragment. + // FIXME: This could maybe benefit from `.may_recover()`? + fn parse_global_item_type( &mut self, - colon_present: bool, - m: Option, - ) -> Box { - // Construct the error and stash it away with the hope - // that typeck will later enrich the error with a type. - let kind = match m { - Some(Mutability::Mut) => "static mut", - Some(Mutability::Not) => "static", - None => "const", - }; - - let colon = match colon_present { - true => "", - false => ":", - }; - - let span = self.prev_token.span.shrink_to_hi(); - let err = self.dcx().create_err(errors::MissingConstType { span, colon, kind }); - err.stash(span, StashKey::ItemNoType); - - // The user intended that the type be inferred, - // so treat this as if the user wrote e.g. `const A: _ = expr;`. - Box::new(Ty { kind: TyKind::Infer, span, id: ast::DUMMY_NODE_ID, tokens: None }) + allow_where: bool, + ) -> PResult<'a, Result, (Span, bool)>> { + Ok( + match ( + self.eat(exp!(Colon)), + self.check(exp!(Eq)) + | self.check(exp!(Semi)) + | (allow_where && self.check_keyword(exp!(Where))), + ) { + (true, false) => Ok(self.parse_ty()?), + // If there wasn't a `:` or the colon was followed by a `=`, `;` or `where`, recover a missing type. + (colon_present, _) => Err((self.prev_token.span.shrink_to_hi(), colon_present)), + }, + ) } /// Parses an enum declaration. @@ -2307,7 +2356,10 @@ 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, + AllowConstBlockItems::DoesNotMatter, // self.token != kw::Const + )?; 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 8577ea40589a8..48569257b9bb1 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -145,6 +145,14 @@ pub enum ForceCollect { No, } +/// Whether to accept `const { ... }` as a shorthand for `const _: () = const { ... }`. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum AllowConstBlockItems { + Yes, + No, + DoesNotMatter, +} + /// 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..706b454835fab 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::{ + AllowConstBlockItems, 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, AllowConstBlockItems::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 26393bf61a32e..3c6629572ae50 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, + AllowConstBlockItems, AttrWrapper, BlockMode, 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, + AllowConstBlockItems::No, )? { self.mk_stmt(lo.to(item.span), StmtKind::Item(Box::new(item))) } else if self.eat(exp!(Semi)) { diff --git a/compiler/rustc_parse/src/parser/tests.rs b/compiler/rustc_parse/src/parser/tests.rs index 9b157cb6c7bf9..9819489e9bba7 100644 --- a/compiler/rustc_parse/src/parser/tests.rs +++ b/compiler/rustc_parse/src/parser/tests.rs @@ -22,7 +22,7 @@ use rustc_span::{ }; use crate::lexer::StripTokens; -use crate::parser::{ForceCollect, Parser}; +use crate::parser::{AllowConstBlockItems, ForceCollect, Parser}; use crate::{new_parser_from_source_str, source_str_to_stream, unwrap_or_emit_fatal}; fn psess() -> ParseSess { @@ -2239,7 +2239,7 @@ fn parse_item_from_source_str( psess: &ParseSess, ) -> PResult<'_, Option>> { unwrap_or_emit_fatal(new_parser_from_source_str(psess, name, source, StripTokens::Nothing)) - .parse_item(ForceCollect::No) + .parse_item(ForceCollect::No, AllowConstBlockItems::Yes) } // Produces a `rustc_span::span`. @@ -2254,7 +2254,9 @@ fn string_to_expr(source_str: String) -> Box { /// Parses a string, returns an item. fn string_to_item(source_str: String) -> Option> { - with_error_checking_parse(source_str, &psess(), |p| p.parse_item(ForceCollect::No)) + with_error_checking_parse(source_str, &psess(), |p| { + p.parse_item(ForceCollect::No, AllowConstBlockItems::Yes) + }) } #[test] diff --git a/compiler/rustc_passes/src/input_stats.rs b/compiler/rustc_passes/src/input_stats.rs index 35101624bd68e..23fbb9ab3a2b7 100644 --- a/compiler/rustc_passes/src/input_stats.rs +++ b/compiler/rustc_passes/src/input_stats.rs @@ -572,6 +572,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..af4e7eb2dd830 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -925,7 +925,10 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } // These items do not add names to modules. - ItemKind::Impl { .. } | ItemKind::ForeignMod(..) | ItemKind::GlobalAsm(..) => {} + ItemKind::Impl { .. } + | ItemKind::ForeignMod(..) + | ItemKind::GlobalAsm(..) + | ItemKind::ConstBlock(..) => {} ItemKind::MacroDef(..) | ItemKind::MacCall(_) | ItemKind::DelegationMac(..) => { unreachable!() 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 f1a03d5a06109..32d7640aa7479 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2702,8 +2702,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), @@ -2714,7 +2714,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), @@ -2726,19 +2726,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, @@ -2751,7 +2745,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, @@ -2770,7 +2764,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, @@ -2810,13 +2804,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); @@ -2824,7 +2812,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); @@ -2832,11 +2820,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, @@ -2856,21 +2844,38 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { this.with_lifetime_rib( LifetimeRibKind::Elided(LifetimeRes::Static), - |this| this.visit_ty(ty), + |this| this.visit_fn_ret_ty(ty), ); 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), @@ -2880,7 +2885,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 { @@ -2893,7 +2898,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( &[], @@ -3199,7 +3204,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { }, |this| { this.visit_generics(generics); - this.visit_ty(ty); + this.visit_fn_ret_ty(ty); // Only impose the restrictions of `ConstRibKind` for an // actual constant expression in a provided default. @@ -3429,7 +3434,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ); this.visit_generics(generics); - this.visit_ty(ty); + this.visit_fn_ret_ty(ty); if let Some(rhs) = rhs { // We allow arbitrary const expressions inside of associated consts, // even if they are potentially not const evaluatable. @@ -5342,6 +5347,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 7e513160de0c3..9aae6d79847f7 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, @@ -740,6 +741,7 @@ symbols! { const_impl_trait, const_in_array_repeat_expressions, const_indexing, + const_items_unit_type_default, const_let, const_loop, const_make_global, diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs index e9f5024e494d1..00e3d93b3436b 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::AllowConstBlockItems::No, + ); let result = match parsed { Ok(Some(ref item)) diff --git a/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs b/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs index b4e1f70d1535b..feb2cab2a0df5 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs @@ -2,7 +2,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs::{self, MsrvStack}; use clippy_utils::source::snippet; -use rustc_ast::ast::{ConstItem, Item, ItemKind, StaticItem, Ty, TyKind}; +use rustc_ast::ast::{ConstItem, FnRetTy, Item, ItemKind, StaticItem, Ty, TyKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::impl_lint_pass; @@ -103,7 +103,9 @@ impl EarlyLintPass for RedundantStaticLifetimes { } if !item.span.from_expansion() { - if let ItemKind::Const(box ConstItem { ty: ref var_type, .. }) = item.kind { + if let ItemKind::Const(box ConstItem { ty: ref var_type, .. }) = item.kind + && let FnRetTy::Ty(var_type) = var_type + { Self::visit_type(var_type, cx, "constants have by default a `'static` lifetime"); // Don't check associated consts because `'static` cannot be elided on those (issue // #2438) diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs index 27b5a57c737d3..5948ca144b21b 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -370,7 +370,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { eq_defaultness(*ld, *rd) && eq_id(*li, *ri) && eq_generics(lg, rg) - && eq_ty(lt, rt) + && eq_fn_ret_ty(lt, rt) && both(lb.as_ref(), rb.as_ref(), eq_const_item_rhs) }, ( @@ -626,7 +626,7 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool { eq_defaultness(*ld, *rd) && eq_id(*li, *ri) && eq_generics(lg, rg) - && eq_ty(lt, rt) + && eq_fn_ret_ty(lt, rt) && both(lb.as_ref(), rb.as_ref(), eq_const_item_rhs) }, ( diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs index 975f9be44e4d3..0a8039968c6ae 100644 --- a/src/tools/rustfmt/src/expr.rs +++ b/src/tools/rustfmt/src/expr.rs @@ -2177,7 +2177,7 @@ pub(crate) fn rewrite_assign_rhs_with_comments, R: Rewrite + Spa } else { shape }; - let rhs = rewrite_assign_rhs_expr(context, &lhs, ex, shape, rhs_kind, rhs_tactics)?; + let rhs: String = rewrite_assign_rhs_expr(context, &lhs, ex, shape, rhs_kind, rhs_tactics)?; if contains_comment { let rhs = rhs.trim_start(); combine_strs_with_missing_comments(context, &lhs, rhs, between_span, shape, allow_extend) diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs index d1778f324c6aa..50733bcaaac64 100644 --- a/src/tools/rustfmt/src/items.rs +++ b/src/tools/rustfmt/src/items.rs @@ -1999,56 +1999,63 @@ pub(crate) fn rewrite_struct_field( combine_strs_with_missing_comments(context, &attrs_str, field_str, missing_span, shape, false) } -pub(crate) struct StaticParts<'a> { +pub(crate) struct StaticPartsLhs<'a> { prefix: &'a str, safety: ast::Safety, vis: &'a ast::Visibility, ident: symbol::Ident, generics: Option<&'a ast::Generics>, - ty: &'a ast::Ty, + ty: Option<&'a ast::Ty>, mutability: ast::Mutability, - expr_opt: Option<&'a ast::Expr>, defaultness: Option, +} + +pub(crate) struct StaticParts<'a> { + lhs: Option>, + rhs: Option<&'a ast::Expr>, span: Span, } impl<'a> StaticParts<'a> { pub(crate) fn from_item(item: &'a ast::Item) -> Self { - let (defaultness, prefix, safety, ident, ty, mutability, expr_opt, generics) = - match &item.kind { - ast::ItemKind::Static(s) => ( - None, - "static", - s.safety, - s.ident, - &s.ty, - s.mutability, - s.expr.as_deref(), - None, - ), - ast::ItemKind::Const(c) => ( - Some(c.defaultness), - "const", - ast::Safety::Default, - c.ident, - &c.ty, - ast::Mutability::Not, - c.rhs.as_ref().map(|rhs| rhs.expr()), - Some(&c.generics), - ), - _ => unreachable!(), - }; - StaticParts { - prefix, - safety, - vis: &item.vis, - ident, - generics, - ty, - mutability, - expr_opt, - defaultness, - span: item.span, + match &item.kind { + ast::ItemKind::Static(s) => StaticParts { + lhs: Some(StaticPartsLhs { + prefix: "static", + safety: s.safety, + vis: &item.vis, + ident: s.ident, + generics: None, + ty: Some(&s.ty), + mutability: s.mutability, + defaultness: None, + }), + rhs: s.expr.as_deref(), + span: item.span, + }, + ast::ItemKind::Const(c) => StaticParts { + lhs: Some(StaticPartsLhs { + prefix: "const", + safety: ast::Safety::Default, + vis: &item.vis, + ident: c.ident, + generics: Some(&c.generics), + ty: match &c.ty { + ast::FnRetTy::Default(_) => None, + ast::FnRetTy::Ty(ty) => Some(ty), + }, + mutability: ast::Mutability::Not, + defaultness: Some(c.defaultness), + }), + rhs: c.rhs.as_ref().map(|rhs| rhs.expr()), + span: item.span, + }, + ast::ItemKind::ConstBlock(b) => StaticParts { + lhs: None, + rhs: Some(&b.body), + span: item.span, + }, + _ => unreachable!(), } } @@ -2063,15 +2070,20 @@ impl<'a> StaticParts<'a> { _ => unreachable!(), }; StaticParts { - prefix: "const", - safety: ast::Safety::Default, - vis: &ti.vis, - ident, - generics, - ty, - mutability: ast::Mutability::Not, - expr_opt, - defaultness: Some(defaultness), + lhs: Some(StaticPartsLhs { + prefix: "const", + safety: ast::Safety::Default, + vis: &ti.vis, + ident, + generics, + ty: match ty { + ast::FnRetTy::Default(_) => None, + ast::FnRetTy::Ty(ty) => Some(ty), + }, + mutability: ast::Mutability::Not, + defaultness: Some(defaultness), + }), + rhs: expr_opt, span: ti.span, } } @@ -2087,88 +2099,149 @@ impl<'a> StaticParts<'a> { _ => unreachable!(), }; StaticParts { - prefix: "const", - safety: ast::Safety::Default, - vis: &ii.vis, - ident, - generics, - ty, - mutability: ast::Mutability::Not, - expr_opt, - defaultness: Some(defaultness), + lhs: Some(StaticPartsLhs { + prefix: "const", + safety: ast::Safety::Default, + vis: &ii.vis, + ident, + generics, + ty: match ty { + ast::FnRetTy::Default(_) => None, + ast::FnRetTy::Ty(ty) => Some(&ty), + }, + mutability: ast::Mutability::Not, + defaultness: Some(defaultness), + }), + rhs: expr_opt, span: ii.span, } } } -fn rewrite_static( +fn rewrite_static_lhs( context: &RewriteContext<'_>, - static_parts: &StaticParts<'_>, + lhs: &StaticPartsLhs<'_>, offset: Indent, -) -> Option { +) -> Option<[String; 2]> { + let StaticPartsLhs { + prefix, + safety, + vis, + ident, + generics, + ty, + mutability, + defaultness, + } = *lhs; + // For now, if this static (or const) has generics, then bail. - if static_parts - .generics - .is_some_and(|g| !g.params.is_empty() || !g.where_clause.is_empty()) - { + if generics.is_some_and(|g| !g.params.is_empty() || !g.where_clause.is_empty()) { return None; } - let colon = colon_spaces(context.config); let mut prefix = format!( - "{}{}{}{} {}{}{}", - format_visibility(context, static_parts.vis), - static_parts.defaultness.map_or("", format_defaultness), - format_safety(static_parts.safety), - static_parts.prefix, - format_mutability(static_parts.mutability), - rewrite_ident(context, static_parts.ident), - colon, + "{}{}{}{} {}{}", + format_visibility(context, vis), + defaultness.map_or("", format_defaultness), + format_safety(safety), + prefix, + format_mutability(mutability), + rewrite_ident(context, ident), ); - // 2 = " =".len() - let ty_shape = - Shape::indented(offset.block_only(), context.config).offset_left(prefix.len() + 2)?; - let ty_str = match static_parts.ty.rewrite(context, ty_shape) { - Some(ty_str) => ty_str, - None => { - if prefix.ends_with(' ') { - prefix.pop(); + let ty_str = match ty { + Some(ty) => { + prefix.push_str(colon_spaces(context.config)); + let ty_shape = Shape::indented(offset.block_only(), context.config) + .offset_left(prefix.len() + const { " =".len() })?; + match ty.rewrite(context, ty_shape) { + Some(ty_str) => ty_str, + None => { + if prefix.ends_with(' ') { + prefix.pop(); + } + let nested_indent = offset.block_indent(context.config); + let nested_shape = Shape::indented(nested_indent, context.config); + let ty_str = ty.rewrite(context, nested_shape)?; + format!( + "{}{}", + nested_indent.to_string_with_newline(context.config), + ty_str + ) + } } - let nested_indent = offset.block_indent(context.config); - let nested_shape = Shape::indented(nested_indent, context.config); - let ty_str = static_parts.ty.rewrite(context, nested_shape)?; - format!( - "{}{}", - nested_indent.to_string_with_newline(context.config), - ty_str - ) } + None => "".to_string(), }; + Some([prefix, ty_str]) +} - if let Some(expr) = static_parts.expr_opt { - let comments_lo = context.snippet_provider.span_after(static_parts.span, "="); - let expr_lo = expr.span.lo(); - let comments_span = mk_sp(comments_lo, expr_lo); +fn rewrite_static_rhs( + context: &RewriteContext<'_>, + lhs: String, + rhs: &ast::Expr, + span: Span, + offset: Indent, + end: &'static str, +) -> Option { + let comments_lo = context.snippet_provider.span_after(span, "="); + let expr_lo = rhs.span.lo(); + let comments_span = mk_sp(comments_lo, expr_lo); - let lhs = format!("{prefix}{ty_str} ="); + let remaining_width = context.budget(offset.block_indent + end.len()); + rewrite_assign_rhs_with_comments( + context, + &lhs, + rhs, + Shape::legacy(remaining_width, offset.block_only()), + &RhsAssignKind::Expr(&rhs.kind, rhs.span), + RhsTactics::Default, + comments_span, + true, + ) + .ok() + .map(|res| recover_comment_removed(res, span, context)) + .map(|s| if s.ends_with(end) { s } else { s + end }) +} - // 1 = ; - let remaining_width = context.budget(offset.block_indent + 1); - rewrite_assign_rhs_with_comments( - context, - &lhs, - expr, - Shape::legacy(remaining_width, offset.block_only()), - &RhsAssignKind::Expr(&expr.kind, expr.span), - RhsTactics::Default, - comments_span, - true, - ) - .ok() - .map(|res| recover_comment_removed(res, static_parts.span, context)) - .map(|s| if s.ends_with(';') { s } else { s + ";" }) - } else { - Some(format!("{prefix}{ty_str};")) +fn rewrite_static( + context: &RewriteContext<'_>, + static_parts: &StaticParts<'_>, + offset: Indent, +) -> Option { + match *static_parts { + StaticParts { + lhs: Some(ref lhs), + rhs: None, + span: _, + } => { + let [prefix, ty] = rewrite_static_lhs(context, lhs, offset)?; + Some(format!("{prefix}{ty};")) + } + StaticParts { + lhs: Some(ref lhs), + rhs: Some(rhs), + span, + } => { + let [prefix, ty] = rewrite_static_lhs(context, lhs, offset)?; + let lhs = format!("{prefix}{ty} ="); + rewrite_static_rhs(context, lhs, rhs, span, offset, ";") + } + StaticParts { + lhs: None, + rhs: Some(rhs), + span, + } => rhs + .rewrite_result( + context, + Shape::legacy(context.budget(offset.block_indent), offset.block_only()), + ) + .ok() + .map(|res| recover_comment_removed(res, span, context)), + StaticParts { + lhs: None, + rhs: None, + span: _, + } => unreachable!(), } } diff --git a/src/tools/rustfmt/src/parse/macros/cfg_if.rs b/src/tools/rustfmt/src/parse/macros/cfg_if.rs index 26bf6c5326f5f..495f12c8f5d5d 100644 --- a/src/tools/rustfmt/src/parse/macros/cfg_if.rs +++ b/src/tools/rustfmt/src/parse/macros/cfg_if.rs @@ -3,7 +3,7 @@ use std::panic::{AssertUnwindSafe, catch_unwind}; use rustc_ast::ast; use rustc_ast::token::TokenKind; use rustc_parse::exp; -use rustc_parse::parser::ForceCollect; +use rustc_parse::parser::{AllowConstBlockItems, ForceCollect}; use rustc_span::symbol::kw; use crate::parse::macros::build_stream_parser; @@ -61,7 +61,7 @@ fn parse_cfg_if_inner<'a>( } while parser.token != TokenKind::CloseBrace && parser.token.kind != TokenKind::Eof { - let item = match parser.parse_item(ForceCollect::No) { + let item = match parser.parse_item(ForceCollect::No, AllowConstBlockItems::Yes) { Ok(Some(item_ptr)) => *item_ptr, Ok(None) => continue, Err(err) => { diff --git a/src/tools/rustfmt/src/parse/macros/mod.rs b/src/tools/rustfmt/src/parse/macros/mod.rs index c063990dfa0b1..552300b1b8284 100644 --- a/src/tools/rustfmt/src/parse/macros/mod.rs +++ b/src/tools/rustfmt/src/parse/macros/mod.rs @@ -2,7 +2,7 @@ use rustc_ast::ast; use rustc_ast::token::{Delimiter, NonterminalKind, NtExprKind::*, NtPatKind::*, TokenKind}; use rustc_ast::tokenstream::TokenStream; use rustc_parse::MACRO_ARGUMENTS; -use rustc_parse::parser::{ForceCollect, Parser, Recovery}; +use rustc_parse::parser::{AllowConstBlockItems, ForceCollect, Parser, Recovery}; use rustc_session::parse::ParseSess; use rustc_span::symbol; @@ -67,7 +67,7 @@ fn parse_macro_arg<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option { parse_macro_arg!( Item, NonterminalKind::Item, - |parser: &mut Parser<'b>| parser.parse_item(ForceCollect::No), + |parser: &mut Parser<'b>| parser.parse_item(ForceCollect::No, AllowConstBlockItems::Yes), |x: Option>| x ); diff --git a/src/tools/rustfmt/src/visitor.rs b/src/tools/rustfmt/src/visitor.rs index c521b497a2d99..79dd311fdbd71 100644 --- a/src/tools/rustfmt/src/visitor.rs +++ b/src/tools/rustfmt/src/visitor.rs @@ -530,7 +530,9 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { self.format_missing_with_indent(source!(self, item.span).lo()); self.format_foreign_mod(foreign_mod, item.span); } - ast::ItemKind::Static(..) | ast::ItemKind::Const(..) => { + ast::ItemKind::Static(..) + | ast::ItemKind::Const(..) + | ast::ItemKind::ConstBlock(..) => { self.visit_static(&StaticParts::from_item(item)); } ast::ItemKind::Fn(ref fn_kind) => { diff --git a/src/tools/rustfmt/tests/source/const-block-items.rs b/src/tools/rustfmt/tests/source/const-block-items.rs new file mode 100644 index 0000000000000..77cfe8b1c55fb --- /dev/null +++ b/src/tools/rustfmt/tests/source/const-block-items.rs @@ -0,0 +1,24 @@ +#![feature(const_block_items)] + + const { + + + assert!(true) + } + + #[cfg(false)] const { assert!(false) } + + + #[cfg(false)] +// foo + const + + { + // bar + assert!(false) + // baz + } + + + #[expect(unused)] +const { let a = 1; assert!(true); } diff --git a/src/tools/rustfmt/tests/source/const-no-type.rs b/src/tools/rustfmt/tests/source/const-no-type.rs new file mode 100644 index 0000000000000..5944f5250e2ad --- /dev/null +++ b/src/tools/rustfmt/tests/source/const-no-type.rs @@ -0,0 +1,29 @@ +#![feature(const_items_unit_type_default)] + + const FOO = { + + + assert!(true) + }; + + #[cfg(false)] const BAR = assert!(false); + + + #[cfg(false)] +// foo + const +// foo 2 +BAZ +// baz += +// baz 2 + + { + // bar + assert!(false) + // baz + } ; + + + #[expect(unused)] +const _ = { let a = 1; assert!(true); } ; diff --git a/src/tools/rustfmt/tests/target/const-block-items.rs b/src/tools/rustfmt/tests/target/const-block-items.rs new file mode 100644 index 0000000000000..d68ea7d9c7265 --- /dev/null +++ b/src/tools/rustfmt/tests/target/const-block-items.rs @@ -0,0 +1,20 @@ +#![feature(const_block_items)] + +const { assert!(true) } + +#[cfg(false)] +const { assert!(false) } + +#[cfg(false)] +// foo +const { + // bar + assert!(false) + // baz +} + +#[expect(unused)] +const { + let a = 1; + assert!(true); +} diff --git a/src/tools/rustfmt/tests/target/const-no-type.rs b/src/tools/rustfmt/tests/target/const-no-type.rs new file mode 100644 index 0000000000000..002f262be1948 --- /dev/null +++ b/src/tools/rustfmt/tests/target/const-no-type.rs @@ -0,0 +1,27 @@ +#![feature(const_items_unit_type_default)] + +const FOO = { assert!(true) }; + +#[cfg(false)] +const BAR = assert!(false); + +#[cfg(false)] +// foo +const +// foo 2 +BAZ +// baz += +// baz 2 + + { + // bar + assert!(false) + // baz + } ; + +#[expect(unused)] +const _ = { + let a = 1; + assert!(true); +}; diff --git a/tests/ui/consts/const-block-items/assert-fail.rs b/tests/ui/consts/const-block-items/assert-fail.rs new file mode 100644 index 0000000000000..a7e3478666ef8 --- /dev/null +++ b/tests/ui/consts/const-block-items/assert-fail.rs @@ -0,0 +1,10 @@ +//@ check-fail + +#![feature(const_block_items)] + +const { assert!(false) } +//~^ ERROR: evaluation panicked: assertion failed: false [E0080] +const { assert!(2 + 2 == 5) } +//~^ ERROR: evaluation panicked: assertion failed: 2 + 2 == 5 [E0080] + +fn main() {} diff --git a/tests/ui/consts/const-block-items/assert-fail.stderr b/tests/ui/consts/const-block-items/assert-fail.stderr new file mode 100644 index 0000000000000..78bd89478541e --- /dev/null +++ b/tests/ui/consts/const-block-items/assert-fail.stderr @@ -0,0 +1,27 @@ +error[E0080]: evaluation panicked: assertion failed: false + --> $DIR/assert-fail.rs:5:9 + | +LL | const { assert!(false) } + | ^^^^^^^^^^^^^^ evaluation of `_::{constant#0}` failed here + +note: erroneous constant encountered + --> $DIR/assert-fail.rs:5:1 + | +LL | const { assert!(false) } + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0080]: evaluation panicked: assertion failed: 2 + 2 == 5 + --> $DIR/assert-fail.rs:7:9 + | +LL | const { assert!(2 + 2 == 5) } + | ^^^^^^^^^^^^^^^^^^^ evaluation of `_::{constant#0}` failed here + +note: erroneous constant encountered + --> $DIR/assert-fail.rs:7:1 + | +LL | const { assert!(2 + 2 == 5) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-block-items/assert-pass.rs b/tests/ui/consts/const-block-items/assert-pass.rs new file mode 100644 index 0000000000000..c409cc5b91f7d --- /dev/null +++ b/tests/ui/consts/const-block-items/assert-pass.rs @@ -0,0 +1,7 @@ +//@ check-pass +#![feature(const_block_items)] + +const { assert!(true) } +const { assert!(2 + 2 == 4) } + +fn main() {} diff --git a/tests/ui/consts/const-block-items/typecheck.rs b/tests/ui/consts/const-block-items/typecheck.rs new file mode 100644 index 0000000000000..2e521cbfda05d --- /dev/null +++ b/tests/ui/consts/const-block-items/typecheck.rs @@ -0,0 +1,20 @@ +//@ check-fail + +#![feature(const_block_items)] + +const { + assert!(true); + 2 + 2 //~ ERROR: mismatched types [E0308] +} + + +const fn id(t: T) -> T { + t +} + +const { id(2) } +//~^ ERROR: mismatched types [E0308] +const { id(()) } + + +fn main() {} diff --git a/tests/ui/consts/const-block-items/typecheck.stderr b/tests/ui/consts/const-block-items/typecheck.stderr new file mode 100644 index 0000000000000..93d1eb1bc9e42 --- /dev/null +++ b/tests/ui/consts/const-block-items/typecheck.stderr @@ -0,0 +1,30 @@ +error[E0308]: mismatched types + --> $DIR/typecheck.rs:7:5 + | +LL | 2 + 2 + | ^^^^^ expected `()`, found integer + +error[E0308]: mismatched types + --> $DIR/typecheck.rs:15:12 + | +LL | const { id(2) } + | -- ^ expected `()`, found integer + | | + | arguments to this function are incorrect + | +help: the return type of this call is `{integer}` due to the type of the argument passed + --> $DIR/typecheck.rs:15:9 + | +LL | const { id(2) } + | ^^^-^ + | | + | this argument influences the return type of `id` +note: function defined here + --> $DIR/typecheck.rs:11:10 + | +LL | const fn id(t: T) -> T { + | ^^ ---- + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/consts/const-block-item-macro-codegen.rs b/tests/ui/consts/const-item-with-block-body/macro-codegen.rs similarity index 100% rename from tests/ui/consts/const-block-item-macro-codegen.rs rename to tests/ui/consts/const-item-with-block-body/macro-codegen.rs diff --git a/tests/ui/consts/const-block-item.rs b/tests/ui/consts/const-item-with-block-body/static.rs similarity index 100% rename from tests/ui/consts/const-block-item.rs rename to tests/ui/consts/const-item-with-block-body/static.rs diff --git a/tests/ui/consts/const-block-item.stderr b/tests/ui/consts/const-item-with-block-body/static.stderr similarity index 84% rename from tests/ui/consts/const-block-item.stderr rename to tests/ui/consts/const-item-with-block-body/static.stderr index b325976a60b69..feaabb92803fc 100644 --- a/tests/ui/consts/const-block-item.stderr +++ b/tests/ui/consts/const-item-with-block-body/static.stderr @@ -1,5 +1,5 @@ warning: trait `Value` is never used - --> $DIR/const-block-item.rs:5:15 + --> $DIR/static.rs:5:15 | LL | pub trait Value { | ^^^^^ diff --git a/tests/ui/consts/const-item-without-ty/assert-fail.rs b/tests/ui/consts/const-item-without-ty/assert-fail.rs new file mode 100644 index 0000000000000..3528ee3f920d6 --- /dev/null +++ b/tests/ui/consts/const-item-without-ty/assert-fail.rs @@ -0,0 +1,10 @@ +//@ check-fail + +#![feature(const_items_unit_type_default)] + +const _ = assert!(false); +//~^ ERROR: evaluation panicked: assertion failed: false [E0080] +const _ = assert!(2 + 2 == 5); +//~^ ERROR: evaluation panicked: assertion failed: 2 + 2 == 5 [E0080] + +fn main() {} diff --git a/tests/ui/consts/const-item-without-ty/assert-fail.stderr b/tests/ui/consts/const-item-without-ty/assert-fail.stderr new file mode 100644 index 0000000000000..1eb534397c1a1 --- /dev/null +++ b/tests/ui/consts/const-item-without-ty/assert-fail.stderr @@ -0,0 +1,15 @@ +error[E0080]: evaluation panicked: assertion failed: false + --> $DIR/assert-fail.rs:5:11 + | +LL | const _ = assert!(false); + | ^^^^^^^^^^^^^^ evaluation of `_` failed here + +error[E0080]: evaluation panicked: assertion failed: 2 + 2 == 5 + --> $DIR/assert-fail.rs:7:11 + | +LL | const _ = assert!(2 + 2 == 5); + | ^^^^^^^^^^^^^^^^^^^ evaluation of `_` failed here + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-item-without-ty/assert-pass.rs b/tests/ui/consts/const-item-without-ty/assert-pass.rs new file mode 100644 index 0000000000000..d911a6250f726 --- /dev/null +++ b/tests/ui/consts/const-item-without-ty/assert-pass.rs @@ -0,0 +1,7 @@ +//@ check-pass +#![feature(const_items_unit_type_default)] + +const _ = assert!(true); +const _ = assert!(2 + 2 == 4); + +fn main() {} diff --git a/tests/ui/consts/const-item-without-ty/typecheck.rs b/tests/ui/consts/const-item-without-ty/typecheck.rs new file mode 100644 index 0000000000000..4f0f7ce7cb549 --- /dev/null +++ b/tests/ui/consts/const-item-without-ty/typecheck.rs @@ -0,0 +1,19 @@ +//@ check-fail + +#![feature(const_items_unit_type_default)] + +const _ = { + assert!(true); + 2 + 2 //~ ERROR: mismatched types [E0308] +}; + +const fn id(t: T) -> T { + t +} + +const _ = id(2); +//~^ ERROR: mismatched types [E0308] +const _ = id(()); + + +fn main() {} diff --git a/tests/ui/consts/const-item-without-ty/typecheck.stderr b/tests/ui/consts/const-item-without-ty/typecheck.stderr new file mode 100644 index 0000000000000..f19383a0451e9 --- /dev/null +++ b/tests/ui/consts/const-item-without-ty/typecheck.stderr @@ -0,0 +1,30 @@ +error[E0308]: mismatched types + --> $DIR/typecheck.rs:7:5 + | +LL | 2 + 2 + | ^^^^^ expected `()`, found integer + +error[E0308]: mismatched types + --> $DIR/typecheck.rs:14:14 + | +LL | const _ = id(2); + | -- ^ expected `()`, found integer + | | + | arguments to this function are incorrect + | +help: the return type of this call is `{integer}` due to the type of the argument passed + --> $DIR/typecheck.rs:14:11 + | +LL | const _ = id(2); + | ^^^-^ + | | + | this argument influences the return type of `id` +note: function defined here + --> $DIR/typecheck.rs:10:10 + | +LL | const fn id(t: T) -> T { + | ^^ ---- + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/consts/missing_assoc_const_type.rs b/tests/ui/consts/missing_assoc_const_type.rs index 61042bfa96d08..653c2f5b6b89d 100644 --- a/tests/ui/consts/missing_assoc_const_type.rs +++ b/tests/ui/consts/missing_assoc_const_type.rs @@ -9,7 +9,8 @@ trait Range { struct TwoDigits; impl Range for TwoDigits { - const FIRST: = 10; //~ ERROR missing type for `const` item + const FIRST: _ = 10; + //~^ ERROR: the placeholder `_` is not allowed within types on item signatures for associated constants [E0121] const LAST: u8 = 99; } diff --git a/tests/ui/consts/missing_assoc_const_type.stderr b/tests/ui/consts/missing_assoc_const_type.stderr index 28af1f0f321e6..e8dec67139908 100644 --- a/tests/ui/consts/missing_assoc_const_type.stderr +++ b/tests/ui/consts/missing_assoc_const_type.stderr @@ -1,8 +1,15 @@ -error: missing type for `const` item - --> $DIR/missing_assoc_const_type.rs:12:17 +error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated constants + --> $DIR/missing_assoc_const_type.rs:12:18 + | +LL | const FIRST: _ = 10; + | ^ not allowed in type signatures + | +help: replace this with a fully-specified type + | +LL - const FIRST: _ = 10; +LL + const FIRST: u8 = 10; | -LL | const FIRST: = 10; - | ^ help: provide a type for the associated constant: `u8` error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0121`. diff --git a/tests/ui/consts/missing_assoc_const_type2.rs b/tests/ui/consts/missing_assoc_const_type2.rs index baf236700a396..7b8c31950c298 100644 --- a/tests/ui/consts/missing_assoc_const_type2.rs +++ b/tests/ui/consts/missing_assoc_const_type2.rs @@ -9,8 +9,8 @@ trait Range { struct TwoDigits; impl Range for TwoDigits { - const FIRST: = 10; - //~^ ERROR: missing type + const FIRST: _ = 10; + //~^ ERROR: the placeholder `_` is not allowed within types on item signatures for associated constants [E0121] const LAST: u8 = 99; } diff --git a/tests/ui/consts/missing_assoc_const_type2.stderr b/tests/ui/consts/missing_assoc_const_type2.stderr index 1255ca2d102b5..1c5f6044c88f9 100644 --- a/tests/ui/consts/missing_assoc_const_type2.stderr +++ b/tests/ui/consts/missing_assoc_const_type2.stderr @@ -1,8 +1,15 @@ -error: missing type for `const` item - --> $DIR/missing_assoc_const_type2.rs:12:17 +error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated constants + --> $DIR/missing_assoc_const_type2.rs:12:18 + | +LL | const FIRST: _ = 10; + | ^ not allowed in type signatures + | +help: replace this with a fully-specified type + | +LL - const FIRST: _ = 10; +LL + const FIRST: u8 = 10; | -LL | const FIRST: = 10; - | ^ help: provide a type for the associated constant: `u8` error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0121`. 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..60a724f907120 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-const-block-items.stderr @@ -0,0 +1,13 @@ +error[E0658]: const block items are experimental + --> $DIR/feature-gate-const-block-items.rs:3:1 + | +LL | const { + | ^^^^^ + | + = note: see issue #149226 for more information + = 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/feature-gates/feature-gate-const-items-unit-type-default.rs b/tests/ui/feature-gates/feature-gate-const-items-unit-type-default.rs new file mode 100644 index 0000000000000..6a4f7aef67379 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-const-items-unit-type-default.rs @@ -0,0 +1,3 @@ +const _ = {}; +//~^ ERROR omitting type on const item declaration is experimental +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-const-items-unit-type-default.stderr b/tests/ui/feature-gates/feature-gate-const-items-unit-type-default.stderr new file mode 100644 index 0000000000000..853c765c607de --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-const-items-unit-type-default.stderr @@ -0,0 +1,14 @@ +error[E0658]: omitting type on const item declaration is experimental + --> $DIR/feature-gate-const-items-unit-type-default.rs:1:8 + | +LL | const _ = {}; + | ^ + | + = note: see issue #149226 for more information + = help: add `#![feature(const_items_unit_type_default)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: consider specifying the type explicitly + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/generic-const-items/assoc-const-missing-type.rs b/tests/ui/generic-const-items/assoc-const-missing-type.rs index dde47cf993ea0..8db3e5b1cf029 100644 --- a/tests/ui/generic-const-items/assoc-const-missing-type.rs +++ b/tests/ui/generic-const-items/assoc-const-missing-type.rs @@ -10,11 +10,12 @@ trait Trait { impl Trait for () { const K = (); - //~^ ERROR missing type for `const` item - //~| ERROR mismatched types + //~^ ERROR omitting type on const item declaration is experimental [E0658] + //~| ERROR implemented const `K` has an incompatible type for trait [E0326] const Q = ""; - //~^ ERROR missing type for `const` item + //~^ ERROR omitting type on const item declaration is experimental [E0658] //~| ERROR lifetime parameters or bounds on associated const `Q` do not match the trait declaration + //~| ERROR mismatched types } fn main() {} diff --git a/tests/ui/generic-const-items/assoc-const-missing-type.stderr b/tests/ui/generic-const-items/assoc-const-missing-type.stderr index 9f6db575ec239..08498fcf45516 100644 --- a/tests/ui/generic-const-items/assoc-const-missing-type.stderr +++ b/tests/ui/generic-const-items/assoc-const-missing-type.stderr @@ -1,19 +1,40 @@ -error[E0308]: mismatched types - --> $DIR/assoc-const-missing-type.rs:12:18 +error[E0658]: omitting type on const item declaration is experimental + --> $DIR/assoc-const-missing-type.rs:12:15 | LL | const K = (); - | - ^^ expected type parameter `T`, found `()` - | | - | expected this type parameter + | ^ | - = note: expected type parameter `T` - found unit type `()` + = note: see issue #149226 for more information + = help: add `#![feature(const_items_unit_type_default)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: consider specifying the type explicitly -error: missing type for `const` item +error[E0658]: omitting type on const item declaration is experimental + --> $DIR/assoc-const-missing-type.rs:15:12 + | +LL | const Q = ""; + | ^ + | + = note: see issue #149226 for more information + = help: add `#![feature(const_items_unit_type_default)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: consider specifying the type explicitly + +error[E0326]: implemented const `K` has an incompatible type for trait --> $DIR/assoc-const-missing-type.rs:12:15 | LL | const K = (); - | ^ help: provide a type for the associated constant: `()` + | - ^ expected type parameter `T`, found `()` + | | + | expected this type parameter + | +note: type in trait + --> $DIR/assoc-const-missing-type.rs:7:17 + | +LL | const K: T; + | ^ + = note: expected type parameter `T` + found unit type `()` error[E0195]: lifetime parameters or bounds on associated const `Q` do not match the trait declaration --> $DIR/assoc-const-missing-type.rs:15:12 @@ -24,13 +45,13 @@ LL | const Q<'a>: &'a str; LL | const Q = ""; | ^ lifetimes do not match associated const in trait -error: missing type for `const` item - --> $DIR/assoc-const-missing-type.rs:15:12 +error[E0308]: mismatched types + --> $DIR/assoc-const-missing-type.rs:15:15 | LL | const Q = ""; - | ^ help: provide a type for the associated constant: `: &str` + | ^^ expected `()`, found `&str` -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors -Some errors have detailed explanations: E0195, E0308. +Some errors have detailed explanations: E0195, E0308, E0326, E0658. For more information about an error, try `rustc --explain E0195`. diff --git a/tests/ui/macros/issue-69396-const-no-type-in-macro.rs b/tests/ui/macros/issue-69396-const-no-type-in-macro.rs index c200a1fd0b41e..e5bee1650fd0b 100644 --- a/tests/ui/macros/issue-69396-const-no-type-in-macro.rs +++ b/tests/ui/macros/issue-69396-const-no-type-in-macro.rs @@ -1,9 +1,9 @@ macro_rules! suite { ( $( $fn:ident; )* ) => { $( - const A = "A".$fn(); + static A = "A".$fn(); //~^ ERROR the name `A` is defined multiple times - //~| ERROR missing type for `const` item + //~| ERROR missing type for `static` item //~| ERROR missing type for item )* } diff --git a/tests/ui/macros/issue-69396-const-no-type-in-macro.stderr b/tests/ui/macros/issue-69396-const-no-type-in-macro.stderr index 4342d7d88f54b..e4007b0daf045 100644 --- a/tests/ui/macros/issue-69396-const-no-type-in-macro.stderr +++ b/tests/ui/macros/issue-69396-const-no-type-in-macro.stderr @@ -1,8 +1,8 @@ error[E0428]: the name `A` is defined multiple times --> $DIR/issue-69396-const-no-type-in-macro.rs:4:13 | -LL | const A = "A".$fn(); - | ^^^^^^^^^^^^^^^^^^^^ `A` redefined here +LL | static A = "A".$fn(); + | ^^^^^^^^^^^^^^^^^^^^^ `A` redefined here ... LL | / suite! { LL | | len; @@ -13,11 +13,11 @@ LL | | } = note: `A` must be defined only once in the value namespace of this module = note: this error originates in the macro `suite` (in Nightly builds, run with -Z macro-backtrace for more info) -error: missing type for `const` item - --> $DIR/issue-69396-const-no-type-in-macro.rs:4:20 +error: missing type for `static` item + --> $DIR/issue-69396-const-no-type-in-macro.rs:4:21 | -LL | const A = "A".$fn(); - | ^ help: provide a type for the constant: `: usize` +LL | static A = "A".$fn(); + | ^ help: provide a type for the static variable: `: usize` ... LL | / suite! { LL | | len; @@ -28,10 +28,10 @@ LL | | } = note: this error originates in the macro `suite` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0121]: missing type for item - --> $DIR/issue-69396-const-no-type-in-macro.rs:4:20 + --> $DIR/issue-69396-const-no-type-in-macro.rs:4:21 | -LL | const A = "A".$fn(); - | ^ not allowed in type signatures +LL | static A = "A".$fn(); + | ^ not allowed in type signatures ... LL | / suite! { LL | | len; diff --git a/tests/ui/macros/stringify.rs b/tests/ui/macros/stringify.rs index fa06da5cbfbc6..0367b8c2d023c 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() {} ], diff --git a/tests/ui/parser/const-block-items/attrs.rs b/tests/ui/parser/const-block-items/attrs.rs new file mode 100644 index 0000000000000..eb7a0554ea9c6 --- /dev/null +++ b/tests/ui/parser/const-block-items/attrs.rs @@ -0,0 +1,14 @@ +//@ check-pass + +#![feature(const_block_items)] + +#[cfg(false)] +const { assert!(false) } + +#[expect(unused)] +const { + let a = 1; + assert!(true); +} + +fn main() {} diff --git a/tests/ui/parser/const-block-items/macro-item.rs b/tests/ui/parser/const-block-items/macro-item.rs new file mode 100644 index 0000000000000..0c07bfc203d25 --- /dev/null +++ b/tests/ui/parser/const-block-items/macro-item.rs @@ -0,0 +1,12 @@ +//@ check-pass +#![feature(const_block_items)] + +macro_rules! foo { + ($item:item) => { + $item + }; +} + +foo!(const {}); + +fn main() {} diff --git a/tests/ui/parser/const-block-items/macro-stmt.rs b/tests/ui/parser/const-block-items/macro-stmt.rs new file mode 100644 index 0000000000000..38632d2eec337 --- /dev/null +++ b/tests/ui/parser/const-block-items/macro-stmt.rs @@ -0,0 +1,14 @@ +//@ check-fail + +#![feature(const_block_items)] + +macro_rules! foo { + ($item:item) => { + $item + //~^ ERROR: expected expression, found `` + }; +} + +fn main() { + foo!(const {}); +} diff --git a/tests/ui/parser/const-block-items/macro-stmt.stderr b/tests/ui/parser/const-block-items/macro-stmt.stderr new file mode 100644 index 0000000000000..dce90e5daa4ca --- /dev/null +++ b/tests/ui/parser/const-block-items/macro-stmt.stderr @@ -0,0 +1,13 @@ +error: expected expression, found `` + --> $DIR/macro-stmt.rs:7:9 + | +LL | $item + | ^^^^^ expected expression +... +LL | foo!(const {}); + | -------------- in this macro invocation + | + = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/const-block-items/mod-in-fn.rs b/tests/ui/parser/const-block-items/mod-in-fn.rs new file mode 100644 index 0000000000000..ec98f95a84485 --- /dev/null +++ b/tests/ui/parser/const-block-items/mod-in-fn.rs @@ -0,0 +1,9 @@ +//@ check-pass + +#![feature(const_block_items)] + +fn main() { + mod foo { + const { assert!(true) } + } +} diff --git a/tests/ui/parser/const-item-without-ty/attrs.rs b/tests/ui/parser/const-item-without-ty/attrs.rs new file mode 100644 index 0000000000000..098d97cf70e7a --- /dev/null +++ b/tests/ui/parser/const-item-without-ty/attrs.rs @@ -0,0 +1,13 @@ +//@ check-pass +#![feature(const_items_unit_type_default)] + +#[cfg(false)] +const _ = assert!(false); + +#[expect(unused)] +const _ = { + let a = 1; + assert!(true); +}; + +fn main() {} diff --git a/tests/ui/parser/const-item-without-ty/macro.rs b/tests/ui/parser/const-item-without-ty/macro.rs new file mode 100644 index 0000000000000..36f449985b9a3 --- /dev/null +++ b/tests/ui/parser/const-item-without-ty/macro.rs @@ -0,0 +1,14 @@ +//@ check-pass +#![feature(const_items_unit_type_default)] + +macro_rules! foo { + ($item:item) => { + $item + }; +} + +foo!(const _ = {};); + +fn main() { + foo!(const _ = {};); +} diff --git a/tests/ui/parser/issues/issue-89574.rs b/tests/ui/parser/issues/issue-89574.rs index 4d28ad051dfaf..3915b25d39eee 100644 --- a/tests/ui/parser/issues/issue-89574.rs +++ b/tests/ui/parser/issues/issue-89574.rs @@ -1,5 +1,5 @@ fn main() { - const EMPTY_ARRAY = []; - //~^ ERROR missing type for `const` item + const EMPTY_ARRAY: _ = []; + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants [E0121] //~| ERROR type annotations needed } diff --git a/tests/ui/parser/issues/issue-89574.stderr b/tests/ui/parser/issues/issue-89574.stderr index f40f5aded8ef1..7c651cb8566ad 100644 --- a/tests/ui/parser/issues/issue-89574.stderr +++ b/tests/ui/parser/issues/issue-89574.stderr @@ -1,20 +1,16 @@ error[E0282]: type annotations needed - --> $DIR/issue-89574.rs:2:25 + --> $DIR/issue-89574.rs:2:28 | -LL | const EMPTY_ARRAY = []; - | ^^ cannot infer type +LL | const EMPTY_ARRAY: _ = []; + | ^^ cannot infer type -error: missing type for `const` item - --> $DIR/issue-89574.rs:2:22 +error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants + --> $DIR/issue-89574.rs:2:24 | -LL | const EMPTY_ARRAY = []; - | ^ - | -help: provide a type for the item - | -LL | const EMPTY_ARRAY: = []; - | ++++++++ +LL | const EMPTY_ARRAY: _ = []; + | ^ not allowed in type signatures error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0282`. +Some errors have detailed explanations: E0121, E0282. +For more information about an error, try `rustc --explain E0121`. diff --git a/tests/ui/parser/item-free-const-no-body-semantic-fail.rs b/tests/ui/parser/item-free-const-no-body-semantic-fail.rs index 613b3c9856171..2438c9a49d820 100644 --- a/tests/ui/parser/item-free-const-no-body-semantic-fail.rs +++ b/tests/ui/parser/item-free-const-no-body-semantic-fail.rs @@ -4,4 +4,4 @@ fn main() {} const A: u8; //~ ERROR free constant item without body const B; //~ ERROR free constant item without body -//~^ ERROR missing type for `const` item +//~^ ERROR omitting type on const item declaration is experimental [E0658] diff --git a/tests/ui/parser/item-free-const-no-body-semantic-fail.stderr b/tests/ui/parser/item-free-const-no-body-semantic-fail.stderr index 1ecf9912e9b11..c071867d8e3e9 100644 --- a/tests/ui/parser/item-free-const-no-body-semantic-fail.stderr +++ b/tests/ui/parser/item-free-const-no-body-semantic-fail.stderr @@ -14,16 +14,17 @@ LL | const B; | | | help: provide a definition for the constant: `= ;` -error: missing type for `const` item +error[E0658]: omitting type on const item declaration is experimental --> $DIR/item-free-const-no-body-semantic-fail.rs:6:8 | LL | const B; | ^ | -help: provide a type for the item - | -LL | const B: ; - | ++++++++ + = note: see issue #149226 for more information + = help: add `#![feature(const_items_unit_type_default)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: consider specifying the type explicitly error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/proc-macro/quote/debug.stdout b/tests/ui/proc-macro/quote/debug.stdout index 77c52f02a33c1..a51870946ca76 100644 --- a/tests/ui/proc-macro/quote/debug.stdout +++ b/tests/ui/proc-macro/quote/debug.stdout @@ -63,7 +63,7 @@ fn main() { ts } } -const _: () = +const _ = { extern crate proc_macro; #[rustc_proc_macro_decls] diff --git a/tests/ui/typeck/do-not-suggest-placeholder-to-const-static-without-type.rs b/tests/ui/typeck/do-not-suggest-placeholder-to-const-static-without-type.rs index 97e0b213f2e79..1e7586c0934cf 100644 --- a/tests/ui/typeck/do-not-suggest-placeholder-to-const-static-without-type.rs +++ b/tests/ui/typeck/do-not-suggest-placeholder-to-const-static-without-type.rs @@ -1,5 +1,5 @@ trait Foo { - const A; //~ ERROR missing type for `const` item + const A; //~ ERROR omitting type on const item declaration is experimental [E0658] static B; //~^ ERROR associated `static` items are not allowed //~| ERROR missing type for `static` item diff --git a/tests/ui/typeck/do-not-suggest-placeholder-to-const-static-without-type.stderr b/tests/ui/typeck/do-not-suggest-placeholder-to-const-static-without-type.stderr index 4450aa66c1322..a9ef7d3f00cf8 100644 --- a/tests/ui/typeck/do-not-suggest-placeholder-to-const-static-without-type.stderr +++ b/tests/ui/typeck/do-not-suggest-placeholder-to-const-static-without-type.stderr @@ -4,16 +4,16 @@ error: associated `static` items are not allowed LL | static B; | ^^^^^^^^^ -error: missing type for `const` item +error[E0658]: omitting type on const item declaration is experimental --> $DIR/do-not-suggest-placeholder-to-const-static-without-type.rs:2:12 | LL | const A; | ^ | -help: provide a type for the item - | -LL | const A: ; - | ++++++++ + = note: see issue #149226 for more information + = help: add `#![feature(const_items_unit_type_default)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: consider specifying the type explicitly error: missing type for `static` item --> $DIR/do-not-suggest-placeholder-to-const-static-without-type.rs:3:13 @@ -28,3 +28,4 @@ LL | static B: ; error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/typeck/issue-79040.rs b/tests/ui/typeck/issue-79040.rs index fe8dc45346186..1ba6b82f0981c 100644 --- a/tests/ui/typeck/issue-79040.rs +++ b/tests/ui/typeck/issue-79040.rs @@ -1,6 +1,6 @@ fn main() { - const FOO = "hello" + 1; + const FOO: _ = "hello" + 1; //~^ ERROR cannot add `{integer}` to `&str` - //~| ERROR missing type for `const` item + //~| ERROR the placeholder `_` is not allowed within types on item signatures for constants [E0121] println!("{}", FOO); } diff --git a/tests/ui/typeck/issue-79040.stderr b/tests/ui/typeck/issue-79040.stderr index 4ab8df8f6c936..04a5f8c4b5bc2 100644 --- a/tests/ui/typeck/issue-79040.stderr +++ b/tests/ui/typeck/issue-79040.stderr @@ -1,22 +1,18 @@ error[E0369]: cannot add `{integer}` to `&str` - --> $DIR/issue-79040.rs:2:25 + --> $DIR/issue-79040.rs:2:28 | -LL | const FOO = "hello" + 1; - | ------- ^ - {integer} - | | - | &str +LL | const FOO: _ = "hello" + 1; + | ------- ^ - {integer} + | | + | &str -error: missing type for `const` item - --> $DIR/issue-79040.rs:2:14 +error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants + --> $DIR/issue-79040.rs:2:16 | -LL | const FOO = "hello" + 1; - | ^ - | -help: provide a type for the item - | -LL | const FOO: = "hello" + 1; - | ++++++++ +LL | const FOO: _ = "hello" + 1; + | ^ not allowed in type signatures error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0369`. +Some errors have detailed explanations: E0121, E0369. +For more information about an error, try `rustc --explain E0121`.