Skip to content

Commit 39fc73f

Browse files
committed
Sugar for const _: () =
1 parent e22dab3 commit 39fc73f

File tree

16 files changed

+115
-29
lines changed

16 files changed

+115
-29
lines changed

compiler/rustc_ast_passes/src/feature_gate.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
525525
gate_all!(super_let, "`super let` is experimental");
526526
gate_all!(frontmatter, "frontmatters are experimental");
527527
gate_all!(coroutines, "coroutine syntax is experimental");
528+
gate_all!(const_block_items, "const block items are experimental");
528529

529530
if !visitor.features.never_patterns() {
530531
if let Some(spans) = spans.get(&sym::never_patterns) {

compiler/rustc_builtin_macros/src/cfg_eval.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use rustc_expand::base::{Annotatable, ExtCtxt};
99
use rustc_expand::config::StripUnconfigured;
1010
use rustc_expand::configure;
1111
use rustc_feature::Features;
12-
use rustc_parse::parser::{ForceCollect, Parser};
12+
use rustc_parse::parser::{ConstBlockItemsAllowed, ForceCollect, Parser};
1313
use rustc_session::Session;
1414
use rustc_span::{Span, sym};
1515
use smallvec::SmallVec;
@@ -113,7 +113,8 @@ impl CfgEval<'_> {
113113
let res: PResult<'_, Annotatable> = try {
114114
match annotatable {
115115
Annotatable::Item(_) => {
116-
let item = parser.parse_item(ForceCollect::Yes)?.unwrap();
116+
let item =
117+
parser.parse_item(ForceCollect::Yes, ConstBlockItemsAllowed::No)?.unwrap();
117118
Annotatable::Item(self.flat_map_item(item).pop().unwrap())
118119
}
119120
Annotatable::AssocItem(_, ctxt) => {

compiler/rustc_builtin_macros/src/source_util.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use rustc_expand::base::{
1313
};
1414
use rustc_expand::module::DirOwnership;
1515
use rustc_parse::lexer::StripTokens;
16-
use rustc_parse::parser::ForceCollect;
16+
use rustc_parse::parser::{ConstBlockItemsAllowed, ForceCollect};
1717
use rustc_parse::{new_parser_from_file, unwrap_or_emit_fatal, utf8_error};
1818
use rustc_session::lint::builtin::INCOMPLETE_INCLUDE;
1919
use rustc_session::parse::ParseSess;
@@ -173,7 +173,7 @@ pub(crate) fn expand_include<'cx>(
173173
));
174174
let mut ret = SmallVec::new();
175175
loop {
176-
match p.parse_item(ForceCollect::No) {
176+
match p.parse_item(ForceCollect::No, ConstBlockItemsAllowed::No) {
177177
Err(err) => {
178178
err.emit();
179179
break;

compiler/rustc_expand/src/base.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use rustc_hir::limit::Limit;
2222
use rustc_hir::{Stability, find_attr};
2323
use rustc_lint_defs::RegisteredTools;
2424
use rustc_parse::MACRO_ARGUMENTS;
25-
use rustc_parse::parser::{ForceCollect, Parser};
25+
use rustc_parse::parser::{ConstBlockItemsAllowed, ForceCollect, Parser};
2626
use rustc_session::Session;
2727
use rustc_session::config::CollapseMacroDebuginfo;
2828
use rustc_session::parse::ParseSess;
@@ -1497,7 +1497,7 @@ pub(crate) fn stream_pretty_printing_compatibility_hack(
14971497
let mut parser = Parser::new(psess, stream.clone(), None);
14981498
// No need to collect tokens for this simple check.
14991499
parser
1500-
.parse_item(ForceCollect::No)
1500+
.parse_item(ForceCollect::No, ConstBlockItemsAllowed::No)
15011501
.expect("failed to reparse item")
15021502
.expect("an actual item")
15031503
}

compiler/rustc_expand/src/expand.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ use rustc_hir::Target;
2121
use rustc_hir::def::MacroKinds;
2222
use rustc_hir::limit::Limit;
2323
use rustc_parse::parser::{
24-
AttemptLocalParseRecovery, CommaRecoveryMode, ForceCollect, Parser, RecoverColon, RecoverComma,
25-
token_descr,
24+
AttemptLocalParseRecovery, CommaRecoveryMode, ConstBlockItemsAllowed, ForceCollect, Parser,
25+
RecoverColon, RecoverComma, token_descr,
2626
};
2727
use rustc_session::Session;
2828
use rustc_session::lint::builtin::{UNUSED_ATTRIBUTES, UNUSED_DOC_COMMENTS};
@@ -1096,7 +1096,7 @@ pub fn parse_ast_fragment<'a>(
10961096
Ok(match kind {
10971097
AstFragmentKind::Items => {
10981098
let mut items = SmallVec::new();
1099-
while let Some(item) = this.parse_item(ForceCollect::No)? {
1099+
while let Some(item) = this.parse_item(ForceCollect::No, ConstBlockItemsAllowed::No)? {
11001100
items.push(item);
11011101
}
11021102
AstFragment::Items(items)

compiler/rustc_expand/src/proc_macro.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use rustc_ast::tokenstream::TokenStream;
22
use rustc_errors::ErrorGuaranteed;
3-
use rustc_parse::parser::{ForceCollect, Parser};
3+
use rustc_parse::parser::{ConstBlockItemsAllowed, ForceCollect, Parser};
44
use rustc_session::config::ProcMacroExecutionStrategy;
55
use rustc_span::Span;
66
use rustc_span::profiling::SpannedEventArgRecorder;
@@ -156,7 +156,7 @@ impl MultiItemModifier for DeriveProcMacro {
156156
let mut items = vec![];
157157

158158
loop {
159-
match parser.parse_item(ForceCollect::No) {
159+
match parser.parse_item(ForceCollect::No, ConstBlockItemsAllowed::No) {
160160
Ok(None) => break,
161161
Ok(Some(item)) => {
162162
if is_stmt {

compiler/rustc_feature/src/unstable.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,8 @@ declare_features! (
445445
(unstable, cmse_nonsecure_entry, "1.48.0", Some(75835)),
446446
/// Allows `async {}` expressions in const contexts.
447447
(unstable, const_async_blocks, "1.53.0", Some(85368)),
448+
/// Allows `const { ... }` as a shorthand for `const _: () = const { ... };` for module items.
449+
(unstable, const_block_items, "CURRENT_RUSTC_VERSION", None),
448450
/// Allows `const || {}` closures in const contexts.
449451
(incomplete, const_closures, "1.68.0", Some(106003)),
450452
/// Allows using `[const] Destruct` bounds and calling drop impls in const contexts.

compiler/rustc_parse/src/parser/attr.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ use thin_vec::ThinVec;
99
use tracing::debug;
1010

1111
use super::{
12-
AttrWrapper, Capturing, FnParseMode, ForceCollect, Parser, PathStyle, Trailing, UsePreAttrPos,
12+
AttrWrapper, Capturing, ConstBlockItemsAllowed, FnParseMode, ForceCollect, Parser, PathStyle,
13+
Trailing, UsePreAttrPos,
1314
};
1415
use crate::parser::FnContext;
1516
use crate::{errors, exp, fluent_generated as fluent};
@@ -203,6 +204,7 @@ impl<'a> Parser<'a> {
203204
false,
204205
FnParseMode { req_name: |_, _| true, context: FnContext::Free, req_body: true },
205206
ForceCollect::No,
207+
ConstBlockItemsAllowed::No,
206208
) {
207209
Ok(Some(item)) => {
208210
// FIXME(#100717)

compiler/rustc_parse/src/parser/item.rs

Lines changed: 57 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ use tracing::debug;
2222
use super::diagnostics::{ConsumeClosingDelim, dummy_arg};
2323
use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
2424
use super::{
25-
AttrWrapper, ExpKeywordPair, ExpTokenPair, FollowedByType, ForceCollect, Parser, PathStyle,
26-
Recovered, Trailing, UsePreAttrPos,
25+
AttrWrapper, ConstBlockItemsAllowed, ExpKeywordPair, ExpTokenPair, FollowedByType,
26+
ForceCollect, Parser, PathStyle, Recovered, Trailing, UsePreAttrPos,
2727
};
2828
use crate::errors::{self, FnPointerCannotBeAsync, FnPointerCannotBeConst, MacroExpandsToAdtField};
2929
use crate::{exp, fluent_generated as fluent};
@@ -69,7 +69,7 @@ impl<'a> Parser<'a> {
6969
// `parse_item` consumes the appropriate semicolons so any leftover is an error.
7070
loop {
7171
while self.maybe_consume_incorrect_semicolon(items.last().map(|x| &**x)) {} // Eat all bad semicolons
72-
let Some(item) = self.parse_item(ForceCollect::No)? else {
72+
let Some(item) = self.parse_item(ForceCollect::No, ConstBlockItemsAllowed::Yes)? else {
7373
break;
7474
};
7575
items.push(item);
@@ -118,21 +118,34 @@ impl<'a> Parser<'a> {
118118
}
119119

120120
impl<'a> Parser<'a> {
121-
pub fn parse_item(&mut self, force_collect: ForceCollect) -> PResult<'a, Option<Box<Item>>> {
121+
pub fn parse_item(
122+
&mut self,
123+
force_collect: ForceCollect,
124+
const_block_items_allowed: ConstBlockItemsAllowed,
125+
) -> PResult<'a, Option<Box<Item>>> {
122126
let fn_parse_mode =
123127
FnParseMode { req_name: |_, _| true, context: FnContext::Free, req_body: true };
124-
self.parse_item_(fn_parse_mode, force_collect).map(|i| i.map(Box::new))
128+
self.parse_item_(fn_parse_mode, force_collect, const_block_items_allowed)
129+
.map(|i| i.map(Box::new))
125130
}
126131

127132
fn parse_item_(
128133
&mut self,
129134
fn_parse_mode: FnParseMode,
130135
force_collect: ForceCollect,
136+
const_block_items_allowed: ConstBlockItemsAllowed,
131137
) -> PResult<'a, Option<Item>> {
132138
self.recover_vcs_conflict_marker();
133139
let attrs = self.parse_outer_attributes()?;
134140
self.recover_vcs_conflict_marker();
135-
self.parse_item_common(attrs, true, false, fn_parse_mode, force_collect)
141+
self.parse_item_common(
142+
attrs,
143+
true,
144+
false,
145+
fn_parse_mode,
146+
force_collect,
147+
const_block_items_allowed,
148+
)
136149
}
137150

138151
pub(super) fn parse_item_common(
@@ -142,10 +155,11 @@ impl<'a> Parser<'a> {
142155
attrs_allowed: bool,
143156
fn_parse_mode: FnParseMode,
144157
force_collect: ForceCollect,
158+
const_block_items_allowed: ConstBlockItemsAllowed,
145159
) -> PResult<'a, Option<Item>> {
146-
if let Some(item) =
147-
self.eat_metavar_seq(MetaVarKind::Item, |this| this.parse_item(ForceCollect::Yes))
148-
{
160+
if let Some(item) = self.eat_metavar_seq(MetaVarKind::Item, |this| {
161+
this.parse_item(ForceCollect::Yes, const_block_items_allowed)
162+
}) {
149163
let mut item = item.expect("an actual item");
150164
attrs.prepend_to_nt_inner(&mut item.attrs);
151165
return Ok(Some(*item));
@@ -158,6 +172,7 @@ impl<'a> Parser<'a> {
158172
let kind = this.parse_item_kind(
159173
&mut attrs,
160174
mac_allowed,
175+
const_block_items_allowed,
161176
lo,
162177
&vis,
163178
&mut def,
@@ -204,6 +219,7 @@ impl<'a> Parser<'a> {
204219
&mut self,
205220
attrs: &mut AttrVec,
206221
macros_allowed: bool,
222+
const_block_items_allowed: ConstBlockItemsAllowed,
207223
lo: Span,
208224
vis: &Visibility,
209225
def: &mut Defaultness,
@@ -253,6 +269,34 @@ impl<'a> Parser<'a> {
253269
} else if self.check_impl_frontmatter() {
254270
// IMPL ITEM
255271
self.parse_item_impl(attrs, def_())?
272+
} else if let ConstBlockItemsAllowed::Yes = const_block_items_allowed
273+
&& self.token.is_keyword(kw::Const)
274+
&& self.look_ahead(1, |t| *t == token::OpenBrace || t.is_metavar_block())
275+
{
276+
// CONST BLOCK ITEM
277+
self.psess.gated_spans.gate(sym::const_block_items, self.token.span);
278+
let block = self.parse_const_block(DUMMY_SP, false)?;
279+
ItemKind::Const(Box::new(ConstItem {
280+
defaultness: Defaultness::Final,
281+
ident: Ident { name: kw::Underscore, span: DUMMY_SP },
282+
generics: Generics {
283+
params: thin_vec![],
284+
where_clause: WhereClause {
285+
has_where_token: false,
286+
predicates: thin_vec![],
287+
span: DUMMY_SP,
288+
},
289+
span: DUMMY_SP,
290+
},
291+
ty: Box::new(Ty {
292+
id: DUMMY_NODE_ID,
293+
kind: TyKind::Tup(thin_vec![]),
294+
span: DUMMY_SP,
295+
tokens: None,
296+
}),
297+
rhs: Some(ConstItemRhs::Body(block)),
298+
define_opaque: None,
299+
}))
256300
} else if let Const::Yes(const_span) = self.parse_constness(Case::Sensitive) {
257301
// CONST ITEM
258302
self.recover_const_mut(const_span);
@@ -312,6 +356,7 @@ impl<'a> Parser<'a> {
312356
return self.parse_item_kind(
313357
attrs,
314358
macros_allowed,
359+
const_block_items_allowed,
315360
lo,
316361
vis,
317362
def,
@@ -992,7 +1037,7 @@ impl<'a> Parser<'a> {
9921037
fn_parse_mode: FnParseMode,
9931038
force_collect: ForceCollect,
9941039
) -> PResult<'a, Option<Option<Box<AssocItem>>>> {
995-
Ok(self.parse_item_(fn_parse_mode, force_collect)?.map(
1040+
Ok(self.parse_item_(fn_parse_mode, force_collect, ConstBlockItemsAllowed::No)?.map(
9961041
|Item { attrs, id, span, vis, kind, tokens }| {
9971042
let kind = match AssocItemKind::try_from(kind) {
9981043
Ok(kind) => kind,
@@ -1244,7 +1289,7 @@ impl<'a> Parser<'a> {
12441289
context: FnContext::Free,
12451290
req_body: false,
12461291
};
1247-
Ok(self.parse_item_(fn_parse_mode, force_collect)?.map(
1292+
Ok(self.parse_item_(fn_parse_mode, force_collect, ConstBlockItemsAllowed::No)?.map(
12481293
|Item { attrs, id, span, vis, kind, tokens }| {
12491294
let kind = match ForeignItemKind::try_from(kind) {
12501295
Ok(kind) => kind,
@@ -2300,7 +2345,7 @@ impl<'a> Parser<'a> {
23002345
{
23012346
let kw_token = self.token;
23022347
let kw_str = pprust::token_to_string(&kw_token);
2303-
let item = self.parse_item(ForceCollect::No)?;
2348+
let item = self.parse_item(ForceCollect::No, ConstBlockItemsAllowed::No)?;
23042349
let mut item = item.unwrap().span;
23052350
if self.token == token::Comma {
23062351
item = item.to(self.token.span);

compiler/rustc_parse/src/parser/mod.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,13 @@ pub enum ForceCollect {
145145
No,
146146
}
147147

148+
/// Whether to accept `const { ... }` as a shorthand for `const _: () = const { ... }`.
149+
#[derive(Clone, Copy, Debug, PartialEq)]
150+
pub enum ConstBlockItemsAllowed {
151+
Yes,
152+
No,
153+
}
154+
148155
/// If the next tokens are ill-formed `$ty::` recover them as `<$ty>::`.
149156
#[macro_export]
150157
macro_rules! maybe_recover_from_interpolated_ty_qpath {

0 commit comments

Comments
 (0)