Skip to content
40 changes: 35 additions & 5 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(_)
Expand Down Expand Up @@ -3768,7 +3769,7 @@ pub struct ConstItem {
pub defaultness: Defaultness,
pub ident: Ident,
pub generics: Generics,
pub ty: Box<Ty>,
pub ty: FnRetTy,
pub rhs: Option<ConstItemRhs>,
pub define_opaque: Option<ThinVec<(NodeId, Path)>>,
}
Expand All @@ -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<Expr>,
}

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 {
Expand All @@ -3811,6 +3822,11 @@ pub enum ItemKind {
///
/// E.g., `const FOO: i32 = 42;`.
Const(Box<ConstItem>),
/// 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 { .. }`.
Expand Down Expand Up @@ -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(_)
Expand All @@ -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",
}
}
Expand All @@ -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",
Expand Down Expand Up @@ -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,
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_ast/src/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,7 @@ macro_rules! common_visitor_and_walkers {
ByRef,
Closure,
Const,
ConstBlockItem,
ConstItem,
ConstItemRhs,
Defaultness,
Expand Down Expand Up @@ -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) =>
Expand Down
36 changes: 28 additions & 8 deletions compiler/rustc_ast_lowering/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,24 +183,40 @@ 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(
generics,
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)
},
);
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,
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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)
Expand Down
24 changes: 15 additions & 9 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Output = T>`.
fn lower_coroutine_fn_output_type_to_bound(
&mut self,
Expand All @@ -1810,15 +1821,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
itctx: ImplTraitContext,
) -> hir::GenericBound<'hir> {
// Compute the `T` in `Future<Output = T>` 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 {
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_ast_passes/src/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -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) {
Expand Down
25 changes: 18 additions & 7 deletions compiler/rustc_ast_pretty/src/pprust/state/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ impl<'a> State<'a> {
*ident,
Some(*mutability),
&ast::Generics::default(),
ty,
Some(ty),
expr.as_deref(),
vis,
*safety,
Expand Down Expand Up @@ -87,7 +87,7 @@ impl<'a> State<'a> {
ident: Ident,
mutbl: Option<ast::Mutability>,
generics: &ast::Generics,
ty: &ast::Ty,
ty: Option<&ast::Ty>,
body: Option<&ast::Expr>,
vis: &ast::Visibility,
safety: ast::Safety,
Expand All @@ -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();
}
Expand Down Expand Up @@ -197,14 +199,17 @@ impl<'a> State<'a> {
*ident,
Some(*mutbl),
&ast::Generics::default(),
ty,
Some(ty),
body.as_deref(),
&item.vis,
ast::Safety::Default,
ast::Defaultness::Final,
define_opaque.as_deref(),
);
}
ast::ItemKind::ConstBlock(ast::ConstBlockItem { body }) => {
self.print_expr(body, FixupContext::default())
}
ast::ItemKind::Const(box ast::ConstItem {
defaultness,
ident,
Expand All @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
11 changes: 8 additions & 3 deletions compiler/rustc_builtin_macros/src/alloc_error_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 {
Expand Down
5 changes: 3 additions & 2 deletions compiler/rustc_builtin_macros/src/cfg_eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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) => {
Expand Down
8 changes: 6 additions & 2 deletions compiler/rustc_builtin_macros/src/global_allocator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
8 changes: 2 additions & 6 deletions compiler/rustc_builtin_macros/src/proc_macro_harness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -389,12 +389,8 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> Box<ast::Item> {
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]);
Expand Down
Loading
Loading