Skip to content

Commit c6710d1

Browse files
authored
Rollup merge of #112790 - WaffleLapkin:syntactically, r=Nilstrieb
Syntactically accept `become` expressions (explicit tail calls experiment) This adds `ast::ExprKind::Become`, implements parsing and properly gates the feature. cc `@scottmcm`
2 parents a98c14f + b967f5c commit c6710d1

File tree

17 files changed

+74
-2
lines changed

17 files changed

+74
-2
lines changed

compiler/rustc_ast/src/ast.rs

+6
Original file line numberDiff line numberDiff line change
@@ -1295,6 +1295,7 @@ impl Expr {
12951295
ExprKind::Yield(..) => ExprPrecedence::Yield,
12961296
ExprKind::Yeet(..) => ExprPrecedence::Yeet,
12971297
ExprKind::FormatArgs(..) => ExprPrecedence::FormatArgs,
1298+
ExprKind::Become(..) => ExprPrecedence::Become,
12981299
ExprKind::Err => ExprPrecedence::Err,
12991300
}
13001301
}
@@ -1515,6 +1516,11 @@ pub enum ExprKind {
15151516
/// with an optional value to be returned.
15161517
Yeet(Option<P<Expr>>),
15171518

1519+
/// A tail call return, with the value to be returned.
1520+
///
1521+
/// While `.0` must be a function call, we check this later, after parsing.
1522+
Become(P<Expr>),
1523+
15181524
/// Bytes included via `include_bytes!`
15191525
/// Added for optimization purposes to avoid the need to escape
15201526
/// large binary blobs - should always behave like [`ExprKind::Lit`]

compiler/rustc_ast/src/mut_visit.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1457,6 +1457,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
14571457
ExprKind::Yeet(expr) => {
14581458
visit_opt(expr, |expr| vis.visit_expr(expr));
14591459
}
1460+
ExprKind::Become(expr) => vis.visit_expr(expr),
14601461
ExprKind::InlineAsm(asm) => vis.visit_inline_asm(asm),
14611462
ExprKind::FormatArgs(fmt) => vis.visit_format_args(fmt),
14621463
ExprKind::OffsetOf(container, fields) => {

compiler/rustc_ast/src/util/parser.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ pub enum ExprPrecedence {
245245
Ret,
246246
Yield,
247247
Yeet,
248+
Become,
248249

249250
Range,
250251

@@ -298,7 +299,8 @@ impl ExprPrecedence {
298299
| ExprPrecedence::Continue
299300
| ExprPrecedence::Ret
300301
| ExprPrecedence::Yield
301-
| ExprPrecedence::Yeet => PREC_JUMP,
302+
| ExprPrecedence::Yeet
303+
| ExprPrecedence::Become => PREC_JUMP,
302304

303305
// `Range` claims to have higher precedence than `Assign`, but `x .. x = x` fails to
304306
// parse, instead of parsing as `(x .. x) = x`. Giving `Range` a lower precedence

compiler/rustc_ast/src/visit.rs

+1
Original file line numberDiff line numberDiff line change
@@ -908,6 +908,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
908908
ExprKind::Yeet(optional_expression) => {
909909
walk_list!(visitor, visit_expr, optional_expression);
910910
}
911+
ExprKind::Become(expr) => visitor.visit_expr(expr),
911912
ExprKind::MacCall(mac) => visitor.visit_mac_call(mac),
912913
ExprKind::Paren(subexpression) => visitor.visit_expr(subexpression),
913914
ExprKind::InlineAsm(asm) => visitor.visit_inline_asm(asm),

compiler/rustc_ast_lowering/src/expr.rs

+6
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
275275
hir::ExprKind::Ret(e)
276276
}
277277
ExprKind::Yeet(sub_expr) => self.lower_expr_yeet(e.span, sub_expr.as_deref()),
278+
ExprKind::Become(sub_expr) => {
279+
let sub_expr = self.lower_expr(sub_expr);
280+
281+
// FIXME(explicit_tail_calls): Use `hir::ExprKind::Become` once we implemented it
282+
hir::ExprKind::Ret(Some(sub_expr))
283+
}
278284
ExprKind::InlineAsm(asm) => {
279285
hir::ExprKind::InlineAsm(self.lower_inline_asm(e.span, asm))
280286
}

compiler/rustc_ast_passes/src/feature_gate.rs

+1
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
555555
gate_all!(dyn_star, "`dyn*` trait objects are experimental");
556556
gate_all!(const_closures, "const closures are experimental");
557557
gate_all!(builtin_syntax, "`builtin #` syntax is unstable");
558+
gate_all!(explicit_tail_calls, "`become` expression is experimental");
558559

559560
if !visitor.features.negative_bounds {
560561
for &span in spans.get(&sym::negative_bounds).iter().copied().flatten() {

compiler/rustc_ast_pretty/src/pprust/state/expr.rs

+5
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,11 @@ impl<'a> State<'a> {
537537
self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
538538
}
539539
}
540+
ast::ExprKind::Become(result) => {
541+
self.word("become");
542+
self.word(" ");
543+
self.print_expr_maybe_paren(result, parser::PREC_JUMP);
544+
}
540545
ast::ExprKind::InlineAsm(a) => {
541546
// FIXME: This should have its own syntax, distinct from a macro invocation.
542547
self.word("asm!");

compiler/rustc_builtin_macros/src/assert/context.rs

+1
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
320320
| ExprKind::Underscore
321321
| ExprKind::While(_, _, _)
322322
| ExprKind::Yeet(_)
323+
| ExprKind::Become(_)
323324
| ExprKind::Yield(_) => {}
324325
}
325326
}

compiler/rustc_feature/src/active.rs

+2
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,8 @@ declare_features! (
395395
(active, exclusive_range_pattern, "1.11.0", Some(37854), None),
396396
/// Allows exhaustive pattern matching on types that contain uninhabited types.
397397
(active, exhaustive_patterns, "1.13.0", Some(51085), None),
398+
/// Allows explicit tail calls via `become` expression.
399+
(incomplete, explicit_tail_calls, "CURRENT_RUSTC_VERSION", Some(112788), None),
398400
/// Allows using `efiapi`, `sysv64` and `win64` as calling convention
399401
/// for functions with varargs.
400402
(active, extended_varargs_abi_support, "1.65.0", Some(100189), None),

compiler/rustc_parse/src/parser/expr.rs

+12
Original file line numberDiff line numberDiff line change
@@ -1430,6 +1430,8 @@ impl<'a> Parser<'a> {
14301430
self.parse_expr_yield()
14311431
} else if self.is_do_yeet() {
14321432
self.parse_expr_yeet()
1433+
} else if self.eat_keyword(kw::Become) {
1434+
self.parse_expr_become()
14331435
} else if self.check_keyword(kw::Let) {
14341436
self.parse_expr_let()
14351437
} else if self.eat_keyword(kw::Underscore) {
@@ -1746,6 +1748,16 @@ impl<'a> Parser<'a> {
17461748
self.maybe_recover_from_bad_qpath(expr)
17471749
}
17481750

1751+
/// Parse `"become" expr`, with `"become"` token already eaten.
1752+
fn parse_expr_become(&mut self) -> PResult<'a, P<Expr>> {
1753+
let lo = self.prev_token.span;
1754+
let kind = ExprKind::Become(self.parse_expr()?);
1755+
let span = lo.to(self.prev_token.span);
1756+
self.sess.gated_spans.gate(sym::explicit_tail_calls, span);
1757+
let expr = self.mk_expr(span, kind);
1758+
self.maybe_recover_from_bad_qpath(expr)
1759+
}
1760+
17491761
/// Parse `"break" (('label (:? expr)?) | expr?)` with `"break"` token already eaten.
17501762
/// If the label is followed immediately by a `:` token, the label and `:` are
17511763
/// parsed as part of the expression (i.e. a labeled loop). The language team has

compiler/rustc_passes/src/hir_stats.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -569,7 +569,8 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
569569
Array, ConstBlock, Call, MethodCall, Tup, Binary, Unary, Lit, Cast, Type, Let,
570570
If, While, ForLoop, Loop, Match, Closure, Block, Async, Await, TryBlock, Assign,
571571
AssignOp, Field, Index, Range, Underscore, Path, AddrOf, Break, Continue, Ret,
572-
InlineAsm, FormatArgs, OffsetOf, MacCall, Struct, Repeat, Paren, Try, Yield, Yeet, IncludedBytes, Err
572+
InlineAsm, FormatArgs, OffsetOf, MacCall, Struct, Repeat, Paren, Try, Yield, Yeet,
573+
Become, IncludedBytes, Err
573574
]
574575
);
575576
ast_visit::walk_expr(self, e)

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -686,6 +686,7 @@ symbols! {
686686
expf32,
687687
expf64,
688688
explicit_generic_args_with_impl_trait,
689+
explicit_tail_calls,
689690
export_name,
690691
expr,
691692
extended_key_value_attributes,

src/tools/clippy/clippy_utils/src/sugg.rs

+1
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ impl<'a> Sugg<'a> {
211211
| ast::ExprKind::Path(..)
212212
| ast::ExprKind::Repeat(..)
213213
| ast::ExprKind::Ret(..)
214+
| ast::ExprKind::Become(..)
214215
| ast::ExprKind::Yeet(..)
215216
| ast::ExprKind::FormatArgs(..)
216217
| ast::ExprKind::Struct(..)

src/tools/rustfmt/src/expr.rs

+1
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ pub(crate) fn format_expr(
232232
ast::ExprKind::Ret(Some(ref expr)) => {
233233
rewrite_unary_prefix(context, "return ", &**expr, shape)
234234
}
235+
ast::ExprKind::Become(ref expr) => rewrite_unary_prefix(context, "become ", &**expr, shape),
235236
ast::ExprKind::Yeet(None) => Some("do yeet".to_owned()),
236237
ast::ExprKind::Yeet(Some(ref expr)) => {
237238
rewrite_unary_prefix(context, "do yeet ", &**expr, shape)

src/tools/rustfmt/src/utils.rs

+1
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,7 @@ pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr
505505
| ast::ExprKind::Range(..)
506506
| ast::ExprKind::Repeat(..)
507507
| ast::ExprKind::Ret(..)
508+
| ast::ExprKind::Become(..)
508509
| ast::ExprKind::Yeet(..)
509510
| ast::ExprKind::Tup(..)
510511
| ast::ExprKind::Type(..)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
pub fn you<T>() -> T {
2+
become bottom(); //~ error: `become` expression is experimental
3+
}
4+
5+
pub fn bottom<T>() -> T {
6+
become you(); //~ error: `become` expression is experimental
7+
}
8+
9+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
error[E0658]: `become` expression is experimental
2+
--> $DIR/feature-gate-explicit_tail_calls.rs:2:5
3+
|
4+
LL | become bottom();
5+
| ^^^^^^^^^^^^^^^
6+
|
7+
= note: see issue #112788 <https://github.com/rust-lang/rust/issues/112788> for more information
8+
= help: add `#![feature(explicit_tail_calls)]` to the crate attributes to enable
9+
10+
error[E0658]: `become` expression is experimental
11+
--> $DIR/feature-gate-explicit_tail_calls.rs:6:5
12+
|
13+
LL | become you();
14+
| ^^^^^^^^^^^^
15+
|
16+
= note: see issue #112788 <https://github.com/rust-lang/rust/issues/112788> for more information
17+
= help: add `#![feature(explicit_tail_calls)]` to the crate attributes to enable
18+
19+
error: aborting due to 2 previous errors
20+
21+
For more information about this error, try `rustc --explain E0658`.

0 commit comments

Comments
 (0)