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

Lines changed: 6 additions & 0 deletions
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

Lines changed: 1 addition & 0 deletions
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

Lines changed: 3 additions & 1 deletion
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

Lines changed: 1 addition & 0 deletions
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

Lines changed: 6 additions & 0 deletions
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

Lines changed: 1 addition & 0 deletions
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

Lines changed: 5 additions & 0 deletions
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

Lines changed: 1 addition & 0 deletions
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

Lines changed: 2 additions & 0 deletions
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

Lines changed: 12 additions & 0 deletions
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

0 commit comments

Comments
 (0)