Skip to content

Commit a632bad

Browse files
committed
redo frontend work
This commit is a port of the changes done by @semtexzv, as described in this comment: rust-lang/rfcs#1888 (comment) All locations that need further work are marked with: FIXME(explicit_tail_calls)
1 parent e49122f commit a632bad

File tree

47 files changed

+248
-7
lines changed

Some content is hidden

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

47 files changed

+248
-7
lines changed

compiler/rustc_ast/src/ast.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1270,6 +1270,7 @@ impl Expr {
12701270
ExprKind::Break(..) => ExprPrecedence::Break,
12711271
ExprKind::Continue(..) => ExprPrecedence::Continue,
12721272
ExprKind::Ret(..) => ExprPrecedence::Ret,
1273+
ExprKind::Become(..) => ExprPrecedence::Ret,
12731274
ExprKind::InlineAsm(..) => ExprPrecedence::InlineAsm,
12741275
ExprKind::MacCall(..) => ExprPrecedence::Mac,
12751276
ExprKind::Struct(..) => ExprPrecedence::Struct,
@@ -1465,6 +1466,8 @@ pub enum ExprKind {
14651466
Continue(Option<Label>),
14661467
/// A `return`, with an optional value to be returned.
14671468
Ret(Option<P<Expr>>),
1469+
/// A `become`, with the required value to be returned.
1470+
Become(P<Expr>),
14681471

14691472
/// Output of the `asm!()` macro.
14701473
InlineAsm(P<InlineAsm>),

compiler/rustc_ast/src/mut_visit.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1451,6 +1451,9 @@ pub fn noop_visit_expr<T: MutVisitor>(
14511451
ExprKind::Ret(expr) => {
14521452
visit_opt(expr, |expr| vis.visit_expr(expr));
14531453
}
1454+
ExprKind::Become(expr) => {
1455+
vis.visit_expr(expr);
1456+
}
14541457
ExprKind::Yeet(expr) => {
14551458
visit_opt(expr, |expr| vis.visit_expr(expr));
14561459
}

compiler/rustc_ast/src/visit.rs

+3
Original file line numberDiff line numberDiff line change
@@ -902,6 +902,9 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
902902
ExprKind::Ret(optional_expression) => {
903903
walk_list!(visitor, visit_expr, optional_expression);
904904
}
905+
ExprKind::Become(expression) => {
906+
visitor.visit_expr(expression);
907+
}
905908
ExprKind::Yeet(optional_expression) => {
906909
walk_list!(visitor, visit_expr, optional_expression);
907910
}

compiler/rustc_ast_lowering/src/expr.rs

+4
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
284284
let e = e.as_ref().map(|x| self.lower_expr(x));
285285
hir::ExprKind::Ret(e)
286286
}
287+
ExprKind::Become(e) => {
288+
let e = self.lower_expr(e);
289+
hir::ExprKind::Become(e)
290+
}
287291
ExprKind::Yeet(sub_expr) => self.lower_expr_yeet(e.span, sub_expr.as_deref()),
288292
ExprKind::InlineAsm(asm) => {
289293
hir::ExprKind::InlineAsm(self.lower_inline_asm(e.span, asm))

compiler/rustc_ast_passes/src/feature_gate.rs

+4
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,10 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
600600
gate_all!(inline_const_pat, "inline-const in pattern position is experimental");
601601
gate_all!(associated_const_equality, "associated const equality is incomplete");
602602
gate_all!(yeet_expr, "`do yeet` expression is experimental");
603+
gate_all!(
604+
explicit_tail_calls,
605+
"explicit tails calls using the `become` keyword is experimental"
606+
);
603607
gate_all!(dyn_star, "`dyn*` trait objects are experimental");
604608
gate_all!(const_closures, "const closures are experimental");
605609

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

+5
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,11 @@ impl<'a> State<'a> {
522522
self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
523523
}
524524
}
525+
ast::ExprKind::Become(expr) => {
526+
self.word("become");
527+
self.word(" ");
528+
self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
529+
}
525530
ast::ExprKind::Yeet(result) => {
526531
self.word("do");
527532
self.word(" ");

compiler/rustc_builtin_macros/src/assert/context.rs

+1
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
308308
| ExprKind::Match(_, _)
309309
| ExprKind::Path(_, _)
310310
| ExprKind::Ret(_)
311+
| ExprKind::Become(_)
311312
| ExprKind::Try(_)
312313
| ExprKind::TryBlock(_)
313314
| ExprKind::Type(_, _)

compiler/rustc_feature/src/active.rs

+2
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,8 @@ declare_features! (
389389
(active, exclusive_range_pattern, "1.11.0", Some(37854), None),
390390
/// Allows exhaustive pattern matching on types that contain uninhabited types.
391391
(active, exhaustive_patterns, "1.13.0", Some(51085), None),
392+
/// Allows guaranteeing tail call elimination using the `become` keyword.
393+
(active, explicit_tail_calls, "1.70.0", Some(66666), None), // FIXME(explicit_tail_calls)
392394
/// Allows using `efiapi`, `sysv64` and `win64` as calling convention
393395
/// for functions with varargs.
394396
(active, extended_varargs_abi_support, "1.65.0", Some(100189), None),

compiler/rustc_hir/src/hir.rs

+5
Original file line numberDiff line numberDiff line change
@@ -1714,6 +1714,7 @@ impl Expr<'_> {
17141714
ExprKind::Break(..) => ExprPrecedence::Break,
17151715
ExprKind::Continue(..) => ExprPrecedence::Continue,
17161716
ExprKind::Ret(..) => ExprPrecedence::Ret,
1717+
ExprKind::Become(..) => ExprPrecedence::Ret,
17171718
ExprKind::InlineAsm(..) => ExprPrecedence::InlineAsm,
17181719
ExprKind::Struct(..) => ExprPrecedence::Struct,
17191720
ExprKind::Repeat(..) => ExprPrecedence::Repeat,
@@ -1770,6 +1771,7 @@ impl Expr<'_> {
17701771
| ExprKind::Break(..)
17711772
| ExprKind::Continue(..)
17721773
| ExprKind::Ret(..)
1774+
| ExprKind::Become(..)
17731775
| ExprKind::Let(..)
17741776
| ExprKind::Loop(..)
17751777
| ExprKind::Assign(..)
@@ -1859,6 +1861,7 @@ impl Expr<'_> {
18591861
| ExprKind::Break(..)
18601862
| ExprKind::Continue(..)
18611863
| ExprKind::Ret(..)
1864+
| ExprKind::Become(..)
18621865
| ExprKind::Let(..)
18631866
| ExprKind::Loop(..)
18641867
| ExprKind::Assign(..)
@@ -2018,6 +2021,8 @@ pub enum ExprKind<'hir> {
20182021
Continue(Destination),
20192022
/// A `return`, with an optional value to be returned.
20202023
Ret(Option<&'hir Expr<'hir>>),
2024+
/// A `become`, with a value to be returned.
2025+
Become(&'hir Expr<'hir>),
20212026

20222027
/// Inline assembly (from `asm!`), with its outputs and inputs.
20232028
InlineAsm(&'hir InlineAsm<'hir>),

compiler/rustc_hir/src/intravisit.rs

+3
Original file line numberDiff line numberDiff line change
@@ -783,6 +783,9 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
783783
ExprKind::Ret(ref optional_expression) => {
784784
walk_list!(visitor, visit_expr, optional_expression);
785785
}
786+
ExprKind::Become(ref expression) => {
787+
visitor.visit_expr(expression);
788+
}
786789
ExprKind::InlineAsm(ref asm) => {
787790
visitor.visit_inline_asm(asm, expression.hir_id);
788791
}

compiler/rustc_hir_pretty/src/lib.rs

+9-3
Original file line numberDiff line numberDiff line change
@@ -1080,9 +1080,10 @@ impl<'a> State<'a> {
10801080
// parses as the erroneous construct `if (return {})`, not `if (return) {}`.
10811081
fn cond_needs_par(expr: &hir::Expr<'_>) -> bool {
10821082
match expr.kind {
1083-
hir::ExprKind::Break(..) | hir::ExprKind::Closure { .. } | hir::ExprKind::Ret(..) => {
1084-
true
1085-
}
1083+
hir::ExprKind::Break(..)
1084+
| hir::ExprKind::Closure { .. }
1085+
| hir::ExprKind::Ret(..)
1086+
| hir::ExprKind::Become(..) => true,
10861087
_ => contains_exterior_struct_lit(expr),
10871088
}
10881089
}
@@ -1547,6 +1548,11 @@ impl<'a> State<'a> {
15471548
self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
15481549
}
15491550
}
1551+
hir::ExprKind::Become(expr) => {
1552+
self.word("become");
1553+
self.word(" ");
1554+
self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
1555+
}
15501556
hir::ExprKind::InlineAsm(asm) => {
15511557
self.word("asm!");
15521558
self.print_inline_asm(asm);

compiler/rustc_hir_typeck/src/expr.rs

+24
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
318318
}
319319
}
320320
ExprKind::Ret(ref expr_opt) => self.check_expr_return(expr_opt.as_deref(), expr),
321+
ExprKind::Become(ref become_expr) => self.check_expr_become(become_expr, expr),
321322
ExprKind::Let(let_expr) => self.check_expr_let(let_expr),
322323
ExprKind::Loop(body, _, source, _) => {
323324
self.check_expr_loop(body, source, expected, expr)
@@ -811,6 +812,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
811812
self.tcx.types.never
812813
}
813814

815+
fn check_expr_become(
816+
&self,
817+
_expr: &'tcx hir::Expr<'tcx>,
818+
_base_expr: &'tcx hir::Expr<'tcx>,
819+
) -> Ty<'tcx> {
820+
bug!("become is not supported yet"); // FIXME(explicit_tail_calls)
821+
// // FIXME: Checks
822+
// // 1: That the the expr is a func call
823+
// // 2: That the calling context is a function, not a closure
824+
// // 3: That the function arguments & ret type match
825+
826+
// match &expr.kind {
827+
// hir::ExprKind::Call(..) => {}
828+
// _ => {
829+
// let mut err = self.tcx.sess.struct_span_err(expr.span, "become must always call a function");
830+
// err.span_label(expr.span, "this is not a function call");
831+
// err.emit();
832+
// }
833+
// }
834+
// // Defer other type checking to return. might not be totally correct, but it'll work for now
835+
// self.check_expr_return(Some(expr), _base_expr)
836+
}
837+
814838
/// `explicit_return` is `true` if we're checking an explicit `return expr`,
815839
/// and `false` if we're checking a trailing expression.
816840
pub(super) fn check_return_expr(

compiler/rustc_hir_typeck/src/expr_use_visitor.rs

+4
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,10 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
325325
}
326326
}
327327

328+
hir::ExprKind::Become(ref expr) => {
329+
self.consume_expr(expr);
330+
}
331+
328332
hir::ExprKind::Assign(lhs, rhs, _) => {
329333
self.mutate_expr(lhs);
330334
self.consume_expr(rhs);

compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs

+2
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
214214
| ExprKind::Break(..)
215215
| ExprKind::Continue(..)
216216
| ExprKind::Ret(..)
217+
| ExprKind::Become(..)
217218
| ExprKind::InlineAsm(..)
218219
| ExprKind::Struct(..)
219220
| ExprKind::Repeat(..)
@@ -490,6 +491,7 @@ impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> {
490491
| ExprKind::Path(..)
491492
| ExprKind::Repeat(..)
492493
| ExprKind::Ret(..)
494+
| ExprKind::Become(..)
493495
| ExprKind::Struct(..)
494496
| ExprKind::Tup(..)
495497
| ExprKind::Type(..)

compiler/rustc_hir_typeck/src/mem_categorization.rs

+1
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
361361
| hir::ExprKind::AssignOp(..)
362362
| hir::ExprKind::Closure { .. }
363363
| hir::ExprKind::Ret(..)
364+
| hir::ExprKind::Become(..)
364365
| hir::ExprKind::Unary(..)
365366
| hir::ExprKind::Yield(..)
366367
| hir::ExprKind::MethodCall(..)

compiler/rustc_middle/src/thir.rs

+4
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,10 @@ pub enum ExprKind<'tcx> {
411411
Return {
412412
value: Option<ExprId>,
413413
},
414+
/// A `become` expression.
415+
Become {
416+
value: ExprId,
417+
},
414418
/// An inline `const` block, e.g. `const {}`.
415419
ConstBlock {
416420
did: DefId,

compiler/rustc_middle/src/thir/visit.rs

+1
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Exp
100100
visitor.visit_expr(&visitor.thir()[value])
101101
}
102102
}
103+
Become { value } => visitor.visit_expr(&visitor.thir()[value]),
103104
ConstBlock { did: _, substs: _ } => {}
104105
Repeat { value, count: _ } => {
105106
visitor.visit_expr(&visitor.thir()[value]);

compiler/rustc_mir_build/src/build/expr/as_place.rs

+1
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
549549
| ExprKind::Break { .. }
550550
| ExprKind::Continue { .. }
551551
| ExprKind::Return { .. }
552+
| ExprKind::Become { .. }
552553
| ExprKind::Literal { .. }
553554
| ExprKind::NamedConst { .. }
554555
| ExprKind::NonHirLiteral { .. }

compiler/rustc_mir_build/src/build/expr/as_rvalue.rs

+1
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
513513
| ExprKind::Break { .. }
514514
| ExprKind::Continue { .. }
515515
| ExprKind::Return { .. }
516+
| ExprKind::Become { .. }
516517
| ExprKind::InlineAsm { .. }
517518
| ExprKind::PlaceTypeAscription { .. }
518519
| ExprKind::ValueTypeAscription { .. } => {

compiler/rustc_mir_build/src/build/expr/category.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ impl Category {
8181
| ExprKind::Block { .. }
8282
| ExprKind::Break { .. }
8383
| ExprKind::Continue { .. }
84-
| ExprKind::Return { .. } =>
84+
| ExprKind::Return { .. }
85+
| ExprKind::Become { .. } =>
8586
// FIXME(#27840) these probably want their own
8687
// category, like "nonterminating"
8788
{

compiler/rustc_mir_build/src/build/expr/into.rs

+4
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
495495
block.unit()
496496
}
497497

498+
ExprKind::Become { .. } => {
499+
bug!("expr_into_dest not yet implemented for `become`."); // FIXME(explicit_tail_calls)
500+
}
501+
498502
// Avoid creating a temporary
499503
ExprKind::VarRef { .. }
500504
| ExprKind::UpvarRef { .. }

compiler/rustc_mir_build/src/check_unsafety.rs

+1
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
316316
| ExprKind::Closure { .. }
317317
| ExprKind::Continue { .. }
318318
| ExprKind::Return { .. }
319+
| ExprKind::Become { .. }
319320
| ExprKind::Yield { .. }
320321
| ExprKind::Loop { .. }
321322
| ExprKind::Let { .. }

compiler/rustc_mir_build/src/thir/cx/expr.rs

+1
Original file line numberDiff line numberDiff line change
@@ -686,6 +686,7 @@ impl<'tcx> Cx<'tcx> {
686686
ExprKind::Repeat { value: self.mirror_expr(v), count: *count }
687687
}
688688
hir::ExprKind::Ret(ref v) => ExprKind::Return { value: v.map(|v| self.mirror_expr(v)) },
689+
hir::ExprKind::Become(v) => ExprKind::Become { value: self.mirror_expr(v) },
689690
hir::ExprKind::Break(dest, ref value) => match dest.target_id {
690691
Ok(target_id) => ExprKind::Break {
691692
label: region::Scope { id: target_id.local_id, data: region::ScopeData::Node },

compiler/rustc_mir_build/src/thir/print.rs

+9
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,15 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
421421

422422
print_indented!(self, "}", depth_lvl);
423423
}
424+
Become { .. } => {
425+
bug!("print_expr: `Become` is not implemented yet."); // FIXME(explicit_tail_calls)
426+
// print_indented!(self, "Become {", depth_lvl);
427+
// print_indented!(self, "value:", depth_lvl + 1);
428+
429+
// self.print_expr(*value, depth_lvl + 2);
430+
431+
// print_indented!(self, "}", depth_lvl);
432+
}
424433
ConstBlock { did, substs } => {
425434
print_indented!(self, "ConstBlock {", depth_lvl);
426435
print_indented!(self, format!("did: {:?}", did), depth_lvl + 1);

compiler/rustc_parse/src/parser/expr.rs

+11
Original file line numberDiff line numberDiff line change
@@ -1400,6 +1400,9 @@ impl<'a> Parser<'a> {
14001400
self.parse_try_block(lo)
14011401
} else if self.eat_keyword(kw::Return) {
14021402
self.parse_expr_return()
1403+
} else if self.eat_keyword(kw::Become) {
1404+
self.sess.gated_spans.gate(sym::explicit_tail_calls, self.prev_token.span);
1405+
self.parse_expr_become()
14031406
} else if self.eat_keyword(kw::Continue) {
14041407
self.parse_expr_continue(lo)
14051408
} else if self.eat_keyword(kw::Break) {
@@ -1699,6 +1702,14 @@ impl<'a> Parser<'a> {
16991702
self.maybe_recover_from_bad_qpath(expr)
17001703
}
17011704

1705+
/// Parse `"become" expr?`.
1706+
fn parse_expr_become(&mut self) -> PResult<'a, P<Expr>> {
1707+
let lo = self.prev_token.span;
1708+
let kind = ExprKind::Become(self.parse_expr()?);
1709+
let expr = self.mk_expr(lo.to(self.prev_token.span), kind);
1710+
self.maybe_recover_from_bad_qpath(expr)
1711+
}
1712+
17021713
/// Parse `"do" "yeet" expr?`.
17031714
fn parse_expr_yeet(&mut self) -> PResult<'a, P<Expr>> {
17041715
let lo = self.token.span;

compiler/rustc_passes/src/hir_stats.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
302302
[
303303
ConstBlock, Array, Call, MethodCall, Tup, Binary, Unary, Lit, Cast, Type,
304304
DropTemps, Let, If, Loop, Match, Closure, Block, Assign, AssignOp, Field, Index,
305-
Path, AddrOf, Break, Continue, Ret, InlineAsm, Struct, Repeat, Yield, Err
305+
Path, AddrOf, Break, Continue, Ret, Become, InlineAsm, Struct, Repeat, Yield, Err
306306
]
307307
);
308308
hir_visit::walk_expr(self, e)
@@ -567,7 +567,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
567567
[
568568
Array, ConstBlock, Call, MethodCall, Tup, Binary, Unary, Lit, Cast, Type, Let,
569569
If, While, ForLoop, Loop, Match, Closure, Block, Async, Await, TryBlock, Assign,
570-
AssignOp, Field, Index, Range, Underscore, Path, AddrOf, Break, Continue, Ret,
570+
AssignOp, Field, Index, Range, Underscore, Path, AddrOf, Break, Continue, Ret, Become,
571571
InlineAsm, FormatArgs, MacCall, Struct, Repeat, Paren, Try, Yield, Yeet, IncludedBytes, Err
572572
]
573573
);

compiler/rustc_passes/src/liveness.rs

+7
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,7 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
467467
| hir::ExprKind::Lit(_)
468468
| hir::ExprKind::ConstBlock(..)
469469
| hir::ExprKind::Ret(..)
470+
| hir::ExprKind::Become(..)
470471
| hir::ExprKind::Block(..)
471472
| hir::ExprKind::Assign(..)
472473
| hir::ExprKind::AssignOp(..)
@@ -965,6 +966,11 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
965966
self.propagate_through_opt_expr(o_e.as_deref(), self.exit_ln)
966967
}
967968

969+
hir::ExprKind::Become(ref expr) => {
970+
// Ignore succ and subst exit_ln.
971+
self.propagate_through_expr(expr, self.exit_ln)
972+
}
973+
968974
hir::ExprKind::Break(label, ref opt_expr) => {
969975
// Find which label this break jumps to
970976
let target = match label.target_id {
@@ -1412,6 +1418,7 @@ fn check_expr<'tcx>(this: &mut Liveness<'_, 'tcx>, expr: &'tcx Expr<'tcx>) {
14121418
| hir::ExprKind::DropTemps(..)
14131419
| hir::ExprKind::Unary(..)
14141420
| hir::ExprKind::Ret(..)
1421+
| hir::ExprKind::Become(..)
14151422
| hir::ExprKind::Break(..)
14161423
| hir::ExprKind::Continue(..)
14171424
| hir::ExprKind::Lit(_)

compiler/rustc_passes/src/naked_functions.rs

+1
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
203203
| ExprKind::Break(..)
204204
| ExprKind::Continue(..)
205205
| ExprKind::Ret(..)
206+
| ExprKind::Become(..)
206207
| ExprKind::Struct(..)
207208
| ExprKind::Repeat(..)
208209
| ExprKind::Yield(..) => {

0 commit comments

Comments
 (0)