Skip to content

Commit 2003458

Browse files
committed
Add const effect syntax to the parser for all function headers
1 parent c5c2f2a commit 2003458

File tree

129 files changed

+819
-366
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

129 files changed

+819
-366
lines changed

compiler/rustc_ast/src/ast.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -3010,7 +3010,7 @@ impl BoundPolarity {
30103010
}
30113011
}
30123012

3013-
/// The constness of a trait bound.
3013+
/// The constness of a trait bound or function.
30143014
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, Hash)]
30153015
#[derive(HashStable_Generic)]
30163016
pub enum BoundConstness {
@@ -3462,7 +3462,7 @@ pub struct FnHeader {
34623462
/// Whether this is `async`, `gen`, or nothing.
34633463
pub coroutine_kind: Option<CoroutineKind>,
34643464
/// The `const` keyword, if any
3465-
pub constness: Const,
3465+
pub constness: BoundConstness,
34663466
/// The `extern` keyword and corresponding ABI string, if any.
34673467
pub ext: Extern,
34683468
}
@@ -3473,7 +3473,7 @@ impl FnHeader {
34733473
let Self { safety, coroutine_kind, constness, ext } = self;
34743474
matches!(safety, Safety::Unsafe(_))
34753475
|| coroutine_kind.is_some()
3476-
|| matches!(constness, Const::Yes(_))
3476+
|| !matches!(constness, BoundConstness::Never)
34773477
|| !matches!(ext, Extern::None)
34783478
}
34793479
}
@@ -3483,7 +3483,7 @@ impl Default for FnHeader {
34833483
FnHeader {
34843484
safety: Safety::Default,
34853485
coroutine_kind: None,
3486-
constness: Const::No,
3486+
constness: BoundConstness::Never,
34873487
ext: Extern::None,
34883488
}
34893489
}

compiler/rustc_ast/src/mut_visit.rs

+10-5
Original file line numberDiff line numberDiff line change
@@ -902,6 +902,14 @@ fn visit_constness<T: MutVisitor>(vis: &mut T, constness: &mut Const) {
902902
}
903903
}
904904

905+
// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
906+
fn walk_bound_constness<T: MutVisitor>(vis: &mut T, constness: &mut BoundConstness) {
907+
match constness {
908+
BoundConstness::Never => {}
909+
BoundConstness::Always(span) | BoundConstness::Maybe(span) => vis.visit_span(span),
910+
}
911+
}
912+
905913
fn walk_closure_binder<T: MutVisitor>(vis: &mut T, binder: &mut ClosureBinder) {
906914
match binder {
907915
ClosureBinder::NotPresent => {}
@@ -1131,10 +1139,7 @@ fn walk_poly_trait_ref<T: MutVisitor>(vis: &mut T, p: &mut PolyTraitRef) {
11311139

11321140
fn walk_modifiers<V: MutVisitor>(vis: &mut V, m: &mut TraitBoundModifiers) {
11331141
let TraitBoundModifiers { constness, asyncness, polarity } = m;
1134-
match constness {
1135-
BoundConstness::Never => {}
1136-
BoundConstness::Always(span) | BoundConstness::Maybe(span) => vis.visit_span(span),
1137-
}
1142+
walk_bound_constness(vis, constness);
11381143
match asyncness {
11391144
BoundAsyncness::Normal => {}
11401145
BoundAsyncness::Async(span) => vis.visit_span(span),
@@ -1443,7 +1448,7 @@ fn walk_const_item<T: MutVisitor>(vis: &mut T, item: &mut ConstItem) {
14431448

14441449
fn walk_fn_header<T: MutVisitor>(vis: &mut T, header: &mut FnHeader) {
14451450
let FnHeader { safety, coroutine_kind, constness, ext: _ } = header;
1446-
visit_constness(vis, constness);
1451+
walk_bound_constness(vis, constness);
14471452
coroutine_kind.as_mut().map(|coroutine_kind| vis.visit_coroutine_kind(coroutine_kind));
14481453
visit_safety(vis, safety);
14491454
}

compiler/rustc_ast_lowering/src/item.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1593,7 +1593,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
15931593
hir::FnHeader {
15941594
safety,
15951595
asyncness,
1596-
constness: self.lower_constness(h.constness),
1596+
constness: self.lower_fn_header_constness(h.constness),
15971597
abi: self.lower_extern(h.ext),
15981598
}
15991599
}

compiler/rustc_ast_lowering/src/lib.rs

+9
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
198198
pub(crate) fn dcx(&self) -> DiagCtxtHandle<'hir> {
199199
self.tcx.dcx()
200200
}
201+
202+
fn lower_fn_header_constness(&self, constness: BoundConstness) -> hir::Constness {
203+
match constness {
204+
BoundConstness::Never => hir::Constness::NotConst,
205+
BoundConstness::Always(_) => hir::Constness::Const,
206+
// FIXME(const_trait_impls): support non-const fn and `(const)` fns within the same trait
207+
BoundConstness::Maybe(_) => hir::Constness::NotConst,
208+
}
209+
}
201210
}
202211

203212
#[extension(trait ResolverAstLoweringExt)]

compiler/rustc_ast_passes/messages.ftl

+2
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ ast_passes_const_and_coroutine = functions cannot be both `const` and `{$corouti
4747
4848
ast_passes_const_bound_trait_object = const trait bounds are not allowed in trait object types
4949
50+
ast_passes_const_in_trait = `const fn` in traits is unstable
51+
5052
ast_passes_const_without_body =
5153
free constant item without body
5254
.suggestion = provide a definition for the constant

compiler/rustc_ast_passes/src/ast_validation.rs

+74-18
Original file line numberDiff line numberDiff line change
@@ -253,12 +253,65 @@ impl<'a> AstValidator<'a> {
253253
}
254254
}
255255

256-
fn check_trait_fn_not_const(&self, constness: Const, parent: &TraitOrTraitImpl) {
257-
let Const::Yes(span) = constness else {
258-
return;
256+
fn check_trait_fn_not_const(
257+
&self,
258+
constness: BoundConstness,
259+
sig_span: Span,
260+
parent: &TraitOrTraitImpl,
261+
) {
262+
let const_trait_impl = self.features.const_trait_impl();
263+
264+
let span = match (constness, parent) {
265+
(BoundConstness::Never, toti) => {
266+
// only `(const)` or `const` fn are allowed in traits or impls respectively.
267+
// But for bootstrap purposes we allow the stage1 std and the stage0 std to be the same.
268+
if toti.constness().is_some() && !self.features.staged_api() {
269+
// FIXME(const_trait_impls): allow non-const fns
270+
self.dcx()
271+
.struct_span_err(
272+
sig_span.shrink_to_lo(),
273+
"non-const fn in const traits are not supported yet",
274+
)
275+
.with_span_suggestion(
276+
sig_span.shrink_to_lo(),
277+
"mark the function as const",
278+
match toti {
279+
TraitOrTraitImpl::Trait { .. } => "(const) ",
280+
TraitOrTraitImpl::TraitImpl { .. } => "const ",
281+
},
282+
rustc_errors::Applicability::MachineApplicable,
283+
)
284+
.emit();
285+
}
286+
return;
287+
}
288+
// `(const) fn` in `const Trait` is ok
289+
(
290+
BoundConstness::Always(span),
291+
TraitOrTraitImpl::TraitImpl { constness: Const::Yes(_), .. },
292+
) => {
293+
if !const_trait_impl {
294+
self.sess
295+
.create_feature_err(errors::ConstInTrait { span }, sym::const_trait_impl)
296+
.emit();
297+
}
298+
return;
299+
}
300+
(BoundConstness::Always(span), _) => span,
301+
(
302+
BoundConstness::Maybe(span),
303+
TraitOrTraitImpl::Trait { constness_span: Some(_), .. },
304+
) => {
305+
if !const_trait_impl {
306+
self.sess
307+
.create_feature_err(errors::ConstInTrait { span }, sym::const_trait_impl)
308+
.emit();
309+
}
310+
return;
311+
}
312+
(BoundConstness::Maybe(span), _) => span,
259313
};
260314

261-
let const_trait_impl = self.features.const_trait_impl();
262315
let make_impl_const_sugg = if const_trait_impl
263316
&& let TraitOrTraitImpl::TraitImpl {
264317
constness: Const::No,
@@ -500,8 +553,9 @@ impl<'a> AstValidator<'a> {
500553
None => (),
501554
}
502555
match constness {
503-
Const::Yes(span) => report_err(span, "const"),
504-
Const::No => (),
556+
BoundConstness::Always(span) => report_err(span, "const"),
557+
BoundConstness::Maybe(span) => report_err(span, "~const"),
558+
BoundConstness::Never => (),
505559
}
506560
match ext {
507561
Extern::None => (),
@@ -538,7 +592,9 @@ impl<'a> AstValidator<'a> {
538592
}
539593

540594
if let Some(header) = fk.header() {
541-
if let Const::Yes(const_span) = header.constness {
595+
if let BoundConstness::Always(const_span) | BoundConstness::Maybe(const_span) =
596+
header.constness
597+
{
542598
let mut spans = variadic_spans.clone();
543599
spans.push(const_span);
544600
self.dcx().emit_err(errors::ConstAndCVariadic {
@@ -1347,7 +1403,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
13471403

13481404
// Functions cannot both be `const async` or `const gen`
13491405
if let Some(&FnHeader {
1350-
constness: Const::Yes(const_span),
1406+
constness: BoundConstness::Always(const_span) | BoundConstness::Maybe(const_span),
13511407
coroutine_kind: Some(coroutine_kind),
13521408
..
13531409
}) = fk.header()
@@ -1398,14 +1454,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
13981454
});
13991455
}
14001456

1401-
let tilde_const_allowed =
1402-
matches!(fk.header(), Some(FnHeader { constness: ast::Const::Yes(_), .. }))
1403-
|| matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)))
1404-
&& self
1405-
.outer_trait_or_trait_impl
1406-
.as_ref()
1407-
.and_then(TraitOrTraitImpl::constness)
1408-
.is_some();
1457+
let tilde_const_allowed = matches!(fk.header(), Some(FnHeader { constness: ast::BoundConstness::Always(_) | ast::BoundConstness::Maybe(_), .. }))
1458+
// FIXME(const_trait_impls): remove this, we don't want to allow `~const` trait bounds in non-const methods
1459+
|| matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)))
1460+
&& self
1461+
.outer_trait_or_trait_impl
1462+
.as_ref()
1463+
.and_then(TraitOrTraitImpl::constness)
1464+
.is_some();
14091465

14101466
let disallowed = (!tilde_const_allowed).then(|| match fk {
14111467
FnKind::Fn(_, _, f) => TildeConstReason::Function { ident: f.ident.span },
@@ -1474,7 +1530,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
14741530
if let Some(parent) = &self.outer_trait_or_trait_impl {
14751531
self.visibility_not_permitted(&item.vis, errors::VisibilityNotPermittedNote::TraitImpl);
14761532
if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
1477-
self.check_trait_fn_not_const(sig.header.constness, parent);
1533+
self.check_trait_fn_not_const(sig.header.constness, sig.span, parent);
14781534
}
14791535
}
14801536

@@ -1489,7 +1545,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
14891545
AssocItemKind::Fn(func)
14901546
if parent_is_const
14911547
|| ctxt == AssocCtxt::Trait
1492-
|| matches!(func.sig.header.constness, Const::Yes(_)) =>
1548+
|| !matches!(func.sig.header.constness, ast::BoundConstness::Never) =>
14931549
{
14941550
self.visit_attrs_vis_ident(&item.attrs, &item.vis, &func.ident);
14951551
let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), &item.vis, &*func);

compiler/rustc_ast_passes/src/errors.rs

+7
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,13 @@ pub(crate) struct NestedLifetimes {
569569
pub span: Span,
570570
}
571571

572+
#[derive(Diagnostic)]
573+
#[diag(ast_passes_const_in_trait)]
574+
pub(crate) struct ConstInTrait {
575+
#[primary_span]
576+
pub span: Span,
577+
}
578+
572579
#[derive(Diagnostic)]
573580
#[diag(ast_passes_optional_trait_supertrait)]
574581
#[note]

compiler/rustc_ast_pretty/src/pprust/state.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -1979,7 +1979,7 @@ impl<'a> State<'a> {
19791979
}
19801980

19811981
fn print_fn_header_info(&mut self, header: ast::FnHeader) {
1982-
self.print_constness(header.constness);
1982+
self.print_bound_constness(header.constness);
19831983
header.coroutine_kind.map(|coroutine_kind| self.print_coroutine_kind(coroutine_kind));
19841984
self.print_safety(header.safety);
19851985

@@ -2013,6 +2013,14 @@ impl<'a> State<'a> {
20132013
}
20142014
}
20152015

2016+
fn print_bound_constness(&mut self, s: ast::BoundConstness) {
2017+
match s {
2018+
ast::BoundConstness::Never => {}
2019+
ast::BoundConstness::Always(_) => self.word_nbsp("const"),
2020+
ast::BoundConstness::Maybe(_) => self.word_nbsp("~const"),
2021+
}
2022+
}
2023+
20162024
fn print_is_auto(&mut self, s: ast::IsAuto) {
20172025
match s {
20182026
ast::IsAuto::Yes => self.word_nbsp("auto"),

compiler/rustc_builtin_macros/src/deriving/generic/mod.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -1019,7 +1019,18 @@ impl<'a> MethodDef<'a> {
10191019

10201020
let trait_lo_sp = span.shrink_to_lo();
10211021

1022-
let sig = ast::FnSig { header: ast::FnHeader::default(), decl: fn_decl, span };
1022+
let sig = ast::FnSig {
1023+
header: ast::FnHeader {
1024+
constness: if trait_.is_const {
1025+
ast::BoundConstness::Always(span)
1026+
} else {
1027+
ast::BoundConstness::Never
1028+
},
1029+
..Default::default()
1030+
},
1031+
decl: fn_decl,
1032+
span,
1033+
};
10231034
let defaultness = ast::Defaultness::Final;
10241035

10251036
// Create the method.

compiler/rustc_parse/src/parser/item.rs

+31-5
Original file line numberDiff line numberDiff line change
@@ -2606,6 +2606,10 @@ impl<'a> Parser<'a> {
26062606
// Rule out `async gen {` and `async gen move {`
26072607
&& !self.is_async_gen_block())
26082608
})
2609+
// `(const)`
2610+
|| (self.check(exp!(OpenParen)) &&
2611+
self.look_ahead(1, |t| t.is_keyword(kw::Const)) &&
2612+
self.look_ahead(2, |t| *t == token::CloseDelim(Delimiter::Parenthesis)))
26092613
// `extern ABI fn`
26102614
|| self.check_keyword_case(exp!(Extern), case)
26112615
// Use `tree_look_ahead` because `ABI` might be a metavariable,
@@ -2640,24 +2644,44 @@ impl<'a> Parser<'a> {
26402644
)
26412645
}
26422646

2647+
pub fn parse_fn_constness(&mut self, case: Case) -> PResult<'a, BoundConstness> {
2648+
Ok(if self.eat_keyword_case(exp!(Const), case) {
2649+
BoundConstness::Always(self.prev_token.span)
2650+
} else if self.check(exp!(OpenParen))
2651+
&& self.look_ahead(1, |t| t.is_keyword(kw::Const))
2652+
&& self.look_ahead(2, |t| *t == token::CloseDelim(Delimiter::Parenthesis))
2653+
{
2654+
let start = self.token.span;
2655+
self.bump();
2656+
self.expect_keyword(exp!(Const)).unwrap();
2657+
self.bump();
2658+
let span = start.to(self.prev_token.span);
2659+
self.psess.gated_spans.gate(sym::const_trait_impl, span);
2660+
BoundConstness::Maybe(span)
2661+
} else {
2662+
BoundConstness::Never
2663+
})
2664+
}
2665+
26432666
/// Parses all the "front matter" (or "qualifiers") for a `fn` declaration,
26442667
/// up to and including the `fn` keyword. The formal grammar is:
26452668
///
26462669
/// ```text
26472670
/// Extern = "extern" StringLit? ;
2648-
/// FnQual = "const"? "async"? "unsafe"? Extern? ;
2671+
/// FnQual = "(const)"? "const"? "async"? "unsafe"? Extern? ;
26492672
/// FnFrontMatter = FnQual "fn" ;
26502673
/// ```
26512674
///
26522675
/// `vis` represents the visibility that was already parsed, if any. Use
26532676
/// `Visibility::Inherited` when no visibility is known.
2677+
#[tracing::instrument(skip(self), ret)]
26542678
pub(super) fn parse_fn_front_matter(
26552679
&mut self,
26562680
orig_vis: &Visibility,
26572681
case: Case,
26582682
) -> PResult<'a, FnHeader> {
26592683
let sp_start = self.token.span;
2660-
let constness = self.parse_constness(case);
2684+
let constness = self.parse_fn_constness(case)?;
26612685

26622686
let async_start_sp = self.token.span;
26632687
let coroutine_kind = self.parse_coroutine_kind(case);
@@ -2706,9 +2730,11 @@ impl<'a> Parser<'a> {
27062730
// that the keyword is already present and the second instance should be removed.
27072731
let wrong_kw = if self.check_keyword(exp!(Const)) {
27082732
match constness {
2709-
Const::Yes(sp) => Some(WrongKw::Duplicated(sp)),
2710-
Const::No => {
2711-
recover_constness = Const::Yes(self.token.span);
2733+
BoundConstness::Always(sp) | BoundConstness::Maybe(sp) => {
2734+
Some(WrongKw::Duplicated(sp))
2735+
}
2736+
BoundConstness::Never => {
2737+
recover_constness = BoundConstness::Always(self.token.span);
27122738
Some(WrongKw::Misplaced(async_start_sp))
27132739
}
27142740
}

0 commit comments

Comments
 (0)