Skip to content

Commit 56f216d

Browse files
committed
Syntatically accept become expressions
1 parent 5a65be8 commit 56f216d

File tree

14 files changed

+69
-2
lines changed

14 files changed

+69
-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(waffle): this is obviously wrong
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
@@ -154,6 +154,8 @@ declare_features! (
154154
(active, compiler_builtins, "1.13.0", None, None),
155155
/// Allows writing custom MIR
156156
(active, custom_mir, "1.65.0", None, None),
157+
/// Allows `become` expression aka explicit tail calls (internal because no TI yet).
158+
(active, explicit_tail_calls, "CURRENT_RUSTC_VERSION", None, None),
157159
/// Outputs useful `assert!` messages
158160
(active, generic_assert, "1.63.0", None, None),
159161
/// Allows using the `rust-intrinsic`'s "ABI".

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

compiler/rustc_passes/src/hir_stats.rs

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,7 @@ symbols! {
687687
expf32,
688688
expf64,
689689
explicit_generic_args_with_impl_trait,
690+
explicit_tail_calls,
690691
export_name,
691692
expr,
692693
extended_key_value_attributes,
Lines changed: 9 additions & 0 deletions
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() {}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
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+
= help: add `#![feature(explicit_tail_calls)]` to the crate attributes to enable
8+
9+
error[E0658]: `become` expression is experimental
10+
--> $DIR/feature-gate-explicit_tail_calls.rs:6:5
11+
|
12+
LL | become you();
13+
| ^^^^^^^^^^^^
14+
|
15+
= help: add `#![feature(explicit_tail_calls)]` to the crate attributes to enable
16+
17+
error: aborting due to 2 previous errors
18+
19+
For more information about this error, try `rustc --explain E0658`.

0 commit comments

Comments
 (0)