Skip to content

Commit 9146d03

Browse files
Rollup merge of rust-lang#52602 - scottmcm:tryblock-expr, r=nikomatsakis
Implement try block expressions I noticed that `try` wasn't a keyword yet in Rust 2018, so... ~~Fix​es rust-lang#52604 That was fixed by PR rust-lang#53135 cc rust-lang#31436 rust-lang#50412
2 parents f1b506a + 0095471 commit 9146d03

Some content is hidden

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

48 files changed

+320
-224
lines changed

src/doc/unstable-book/src/language-features/catch-expr.md renamed to src/doc/unstable-book/src/language-features/try-blocks.md

+9-7
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,29 @@
1-
# `catch_expr`
1+
# `try_blocks`
22

33
The tracking issue for this feature is: [#31436]
44

55
[#31436]: https://github.com/rust-lang/rust/issues/31436
66

77
------------------------
88

9-
The `catch_expr` feature adds support for a `catch` expression. The `catch`
10-
expression creates a new scope one can use the `?` operator in.
9+
The `try_blocks` feature adds support for `try` blocks. A `try`
10+
block creates a new scope one can use the `?` operator in.
1111

12-
```rust
13-
#![feature(catch_expr)]
12+
```rust,ignore
13+
// This code needs the 2018 edition
14+
15+
#![feature(try_blocks)]
1416
1517
use std::num::ParseIntError;
1618
17-
let result: Result<i32, ParseIntError> = do catch {
19+
let result: Result<i32, ParseIntError> = try {
1820
"1".parse::<i32>()?
1921
+ "2".parse::<i32>()?
2022
+ "3".parse::<i32>()?
2123
};
2224
assert_eq!(result, Ok(6));
2325
24-
let result: Result<i32, ParseIntError> = do catch {
26+
let result: Result<i32, ParseIntError> = try {
2527
"1".parse::<i32>()?
2628
+ "foo".parse::<i32>()?
2729
+ "3".parse::<i32>()?

src/librustc/hir/lowering.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -3613,10 +3613,10 @@ impl<'a> LoweringContext<'a> {
36133613
hir::LoopSource::Loop,
36143614
)
36153615
}),
3616-
ExprKind::Catch(ref body) => {
3616+
ExprKind::TryBlock(ref body) => {
36173617
self.with_catch_scope(body.id, |this| {
36183618
let unstable_span =
3619-
this.allow_internal_unstable(CompilerDesugaringKind::Catch, body.span);
3619+
this.allow_internal_unstable(CompilerDesugaringKind::TryBlock, body.span);
36203620
let mut block = this.lower_block(body, true).into_inner();
36213621
let tail = block.expr.take().map_or_else(
36223622
|| {

src/librustc/ich/impls_syntax.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,7 @@ impl_stable_hash_for!(enum ::syntax_pos::hygiene::CompilerDesugaringKind {
412412
QuestionMark,
413413
ExistentialReturnType,
414414
ForLoop,
415-
Catch
415+
TryBlock
416416
});
417417

418418
impl_stable_hash_for!(enum ::syntax_pos::FileName {

src/librustc/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@
6565
#![feature(trace_macros)]
6666
#![feature(trusted_len)]
6767
#![feature(vec_remove_item)]
68-
#![feature(catch_expr)]
6968
#![feature(step_trait)]
7069
#![feature(integer_atomics)]
7170
#![feature(test)]

src/librustc_mir/borrow_check/nll/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -312,14 +312,14 @@ fn dump_mir_results<'a, 'gcx, 'tcx>(
312312
);
313313

314314
// Also dump the inference graph constraints as a graphviz file.
315-
let _: io::Result<()> = do catch {
315+
let _: io::Result<()> = try_block! {
316316
let mut file =
317317
pretty::create_dump_file(infcx.tcx, "regioncx.all.dot", None, "nll", &0, source)?;
318318
regioncx.dump_graphviz_raw_constraints(&mut file)?;
319319
};
320320

321321
// Also dump the inference graph constraints as a graphviz file.
322-
let _: io::Result<()> = do catch {
322+
let _: io::Result<()> = try_block! {
323323
let mut file =
324324
pretty::create_dump_file(infcx.tcx, "regioncx.scc.dot", None, "nll", &0, source)?;
325325
regioncx.dump_graphviz_scc_constraints(&mut file)?;

src/librustc_mir/lib.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
2121
#![feature(slice_sort_by_cached_key)]
2222
#![feature(box_patterns)]
2323
#![feature(box_syntax)]
24-
#![feature(catch_expr)]
2524
#![feature(crate_visibility_modifier)]
2625
#![feature(const_fn)]
2726
#![feature(core_intrinsics)]
@@ -63,6 +62,14 @@ extern crate rustc_apfloat;
6362
extern crate byteorder;
6463
extern crate core;
6564

65+
// Once we can use edition 2018 in the compiler,
66+
// replace this with real try blocks.
67+
macro_rules! try_block {
68+
($($inside:tt)*) => (
69+
(||{ ::std::ops::Try::from_ok({ $($inside)* }) })()
70+
)
71+
}
72+
6673
mod diagnostics;
6774

6875
mod borrow_check;

src/librustc_mir/util/pretty.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ fn dump_matched_mir_node<'a, 'gcx, 'tcx, F>(
140140
) where
141141
F: FnMut(PassWhere, &mut dyn Write) -> io::Result<()>,
142142
{
143-
let _: io::Result<()> = do catch {
143+
let _: io::Result<()> = try_block! {
144144
let mut file = create_dump_file(tcx, "mir", pass_num, pass_name, disambiguator, source)?;
145145
writeln!(file, "// MIR for `{}`", node_path)?;
146146
writeln!(file, "// source = {:?}", source)?;
@@ -156,7 +156,7 @@ fn dump_matched_mir_node<'a, 'gcx, 'tcx, F>(
156156
};
157157

158158
if tcx.sess.opts.debugging_opts.dump_mir_graphviz {
159-
let _: io::Result<()> = do catch {
159+
let _: io::Result<()> = try_block! {
160160
let mut file =
161161
create_dump_file(tcx, "dot", pass_num, pass_name, disambiguator, source)?;
162162
write_mir_fn_graphviz(tcx, source.def_id, mir, &mut file)?;

src/librustc_typeck/check/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -4471,7 +4471,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
44714471
// In some cases, blocks have just one exit, but other blocks
44724472
// can be targeted by multiple breaks. This can happen both
44734473
// with labeled blocks as well as when we desugar
4474-
// a `do catch { ... }` expression.
4474+
// a `try { ... }` expression.
44754475
//
44764476
// Example 1:
44774477
//

src/libsyntax/ast.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -987,7 +987,7 @@ impl Expr {
987987
ExprKind::Match(..) => ExprPrecedence::Match,
988988
ExprKind::Closure(..) => ExprPrecedence::Closure,
989989
ExprKind::Block(..) => ExprPrecedence::Block,
990-
ExprKind::Catch(..) => ExprPrecedence::Catch,
990+
ExprKind::TryBlock(..) => ExprPrecedence::TryBlock,
991991
ExprKind::Async(..) => ExprPrecedence::Async,
992992
ExprKind::Assign(..) => ExprPrecedence::Assign,
993993
ExprKind::AssignOp(..) => ExprPrecedence::AssignOp,
@@ -1108,8 +1108,8 @@ pub enum ExprKind {
11081108
/// created during lowering cannot be made the parent of any other
11091109
/// preexisting defs.
11101110
Async(CaptureBy, NodeId, P<Block>),
1111-
/// A catch block (`catch { ... }`)
1112-
Catch(P<Block>),
1111+
/// A try block (`try { ... }`)
1112+
TryBlock(P<Block>),
11131113

11141114
/// An assignment (`a = foo()`)
11151115
Assign(P<Expr>, P<Expr>),

src/libsyntax/feature_gate.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -330,8 +330,8 @@ declare_features! (
330330
// `extern "x86-interrupt" fn()`
331331
(active, abi_x86_interrupt, "1.17.0", Some(40180), None),
332332

333-
// Allows the `catch {...}` expression
334-
(active, catch_expr, "1.17.0", Some(31436), None),
333+
// Allows the `try {...}` expression
334+
(active, try_blocks, "1.29.0", Some(31436), None),
335335

336336
// Used to preserve symbols (see llvm.used)
337337
(active, used, "1.18.0", Some(40289), None),
@@ -1732,8 +1732,8 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
17321732
e.span,
17331733
"yield syntax is experimental");
17341734
}
1735-
ast::ExprKind::Catch(_) => {
1736-
gate_feature_post!(&self, catch_expr, e.span, "`catch` expression is experimental");
1735+
ast::ExprKind::TryBlock(_) => {
1736+
gate_feature_post!(&self, try_blocks, e.span, "`try` expression is experimental");
17371737
}
17381738
ast::ExprKind::IfLet(ref pats, ..) | ast::ExprKind::WhileLet(ref pats, ..) => {
17391739
if pats.len() > 1 {

src/libsyntax/fold.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1351,7 +1351,7 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu
13511351
}
13521352
ExprKind::Yield(ex) => ExprKind::Yield(ex.map(|x| folder.fold_expr(x))),
13531353
ExprKind::Try(ex) => ExprKind::Try(folder.fold_expr(ex)),
1354-
ExprKind::Catch(body) => ExprKind::Catch(folder.fold_block(body)),
1354+
ExprKind::TryBlock(body) => ExprKind::TryBlock(folder.fold_block(body)),
13551355
},
13561356
id: folder.new_id(id),
13571357
span: folder.new_span(span),

src/libsyntax/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@
2626
#![feature(rustc_diagnostic_macros)]
2727
#![feature(slice_sort_by_cached_key)]
2828
#![feature(str_escape)]
29+
#![feature(try_trait)]
2930
#![feature(unicode_internals)]
30-
#![feature(catch_expr)]
3131

3232
#![recursion_limit="256"]
3333

src/libsyntax/parse/classify.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool {
3131
ast::ExprKind::WhileLet(..) |
3232
ast::ExprKind::Loop(..) |
3333
ast::ExprKind::ForLoop(..) |
34-
ast::ExprKind::Catch(..) => false,
34+
ast::ExprKind::TryBlock(..) => false,
3535
_ => true,
3636
}
3737
}

src/libsyntax/parse/parser.rs

+30-10
Original file line numberDiff line numberDiff line change
@@ -1757,9 +1757,17 @@ impl<'a> Parser<'a> {
17571757

17581758
let parser_snapshot_before_pat = self.clone();
17591759

1760+
// Once we can use edition 2018 in the compiler,
1761+
// replace this with real try blocks.
1762+
macro_rules! try_block {
1763+
($($inside:tt)*) => (
1764+
(||{ ::std::ops::Try::from_ok({ $($inside)* }) })()
1765+
)
1766+
}
1767+
17601768
// We're going to try parsing the argument as a pattern (even though it's not
17611769
// allowed). This way we can provide better errors to the user.
1762-
let pat_arg: PResult<'a, _> = do catch {
1770+
let pat_arg: PResult<'a, _> = try_block! {
17631771
let pat = self.parse_pat()?;
17641772
self.expect(&token::Colon)?;
17651773
(pat, self.parse_ty()?)
@@ -2387,11 +2395,15 @@ impl<'a> Parser<'a> {
23872395
BlockCheckMode::Unsafe(ast::UserProvided),
23882396
attrs);
23892397
}
2390-
if self.is_catch_expr() {
2398+
if self.is_do_catch_block() {
2399+
let mut db = self.fatal("found removed `do catch` syntax");
2400+
db.help("Following RFC #2388, the new non-placeholder syntax is `try`");
2401+
return Err(db);
2402+
}
2403+
if self.is_try_block() {
23912404
let lo = self.span;
2392-
assert!(self.eat_keyword(keywords::Do));
2393-
assert!(self.eat_keyword(keywords::Catch));
2394-
return self.parse_catch_expr(lo, attrs);
2405+
assert!(self.eat_keyword(keywords::Try));
2406+
return self.parse_try_block(lo, attrs);
23952407
}
23962408
if self.eat_keyword(keywords::Return) {
23972409
if self.token.can_begin_expr() {
@@ -3453,13 +3465,13 @@ impl<'a> Parser<'a> {
34533465
ExprKind::Async(capture_clause, ast::DUMMY_NODE_ID, body), attrs))
34543466
}
34553467

3456-
/// Parse a `do catch {...}` expression (`do catch` token already eaten)
3457-
fn parse_catch_expr(&mut self, span_lo: Span, mut attrs: ThinVec<Attribute>)
3468+
/// Parse a `try {...}` expression (`try` token already eaten)
3469+
fn parse_try_block(&mut self, span_lo: Span, mut attrs: ThinVec<Attribute>)
34583470
-> PResult<'a, P<Expr>>
34593471
{
34603472
let (iattrs, body) = self.parse_inner_attrs_and_block()?;
34613473
attrs.extend(iattrs);
3462-
Ok(self.mk_expr(span_lo.to(body.span), ExprKind::Catch(body), attrs))
3474+
Ok(self.mk_expr(span_lo.to(body.span), ExprKind::TryBlock(body), attrs))
34633475
}
34643476

34653477
// `match` token already eaten
@@ -4408,12 +4420,20 @@ impl<'a> Parser<'a> {
44084420
)
44094421
}
44104422

4411-
fn is_catch_expr(&mut self) -> bool {
4423+
fn is_do_catch_block(&mut self) -> bool {
44124424
self.token.is_keyword(keywords::Do) &&
44134425
self.look_ahead(1, |t| t.is_keyword(keywords::Catch)) &&
44144426
self.look_ahead(2, |t| *t == token::OpenDelim(token::Brace)) &&
4427+
!self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
4428+
}
4429+
4430+
fn is_try_block(&mut self) -> bool {
4431+
self.token.is_keyword(keywords::Try) &&
4432+
self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace)) &&
4433+
4434+
self.span.edition() >= Edition::Edition2018 &&
44154435

4416-
// prevent `while catch {} {}`, `if catch {} {} else {}`, etc.
4436+
// prevent `while try {} {}`, `if try {} {} else {}`, etc.
44174437
!self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
44184438
}
44194439

src/libsyntax/print/pprust.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -2379,8 +2379,8 @@ impl<'a> State<'a> {
23792379
self.print_expr_maybe_paren(e, parser::PREC_POSTFIX)?;
23802380
self.s.word("?")?
23812381
}
2382-
ast::ExprKind::Catch(ref blk) => {
2383-
self.head("do catch")?;
2382+
ast::ExprKind::TryBlock(ref blk) => {
2383+
self.head("try")?;
23842384
self.s.space()?;
23852385
self.print_block_with_attrs(blk, attrs)?
23862386
}

src/libsyntax/util/parser.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ pub enum ExprPrecedence {
273273
Loop,
274274
Match,
275275
Block,
276-
Catch,
276+
TryBlock,
277277
Struct,
278278
Async,
279279
}
@@ -332,7 +332,7 @@ impl ExprPrecedence {
332332
ExprPrecedence::Loop |
333333
ExprPrecedence::Match |
334334
ExprPrecedence::Block |
335-
ExprPrecedence::Catch |
335+
ExprPrecedence::TryBlock |
336336
ExprPrecedence::Async |
337337
ExprPrecedence::Struct => PREC_PAREN,
338338
}

src/libsyntax/visit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -809,7 +809,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
809809
ExprKind::Try(ref subexpression) => {
810810
visitor.visit_expr(subexpression)
811811
}
812-
ExprKind::Catch(ref body) => {
812+
ExprKind::TryBlock(ref body) => {
813813
visitor.visit_block(body)
814814
}
815815
}

src/libsyntax_pos/hygiene.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -595,7 +595,7 @@ impl ExpnFormat {
595595
#[derive(Clone, Copy, Hash, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
596596
pub enum CompilerDesugaringKind {
597597
QuestionMark,
598-
Catch,
598+
TryBlock,
599599
/// Desugaring of an `impl Trait` in return type position
600600
/// to an `existential type Foo: Trait;` + replacing the
601601
/// `impl Trait` with `Foo`.
@@ -609,7 +609,7 @@ impl CompilerDesugaringKind {
609609
Symbol::intern(match self {
610610
CompilerDesugaringKind::Async => "async",
611611
CompilerDesugaringKind::QuestionMark => "?",
612-
CompilerDesugaringKind::Catch => "do catch",
612+
CompilerDesugaringKind::TryBlock => "try block",
613613
CompilerDesugaringKind::ExistentialReturnType => "existential type",
614614
CompilerDesugaringKind::ForLoop => "for loop",
615615
})

src/libsyntax_pos/symbol.rs

+11-9
Original file line numberDiff line numberDiff line change
@@ -415,23 +415,25 @@ declare_keywords! {
415415

416416
// Edition-specific keywords reserved for future use.
417417
(51, Async, "async") // >= 2018 Edition Only
418+
(52, Try, "try") // >= 2018 Edition Only
418419

419420
// Special lifetime names
420-
(52, UnderscoreLifetime, "'_")
421-
(53, StaticLifetime, "'static")
421+
(53, UnderscoreLifetime, "'_")
422+
(54, StaticLifetime, "'static")
422423

423424
// Weak keywords, have special meaning only in specific contexts.
424-
(54, Auto, "auto")
425-
(55, Catch, "catch")
426-
(56, Default, "default")
427-
(57, Dyn, "dyn")
428-
(58, Union, "union")
429-
(59, Existential, "existential")
425+
(55, Auto, "auto")
426+
(56, Catch, "catch")
427+
(57, Default, "default")
428+
(58, Dyn, "dyn")
429+
(59, Union, "union")
430+
(60, Existential, "existential")
430431
}
431432

432433
impl Symbol {
433434
fn is_unused_keyword_2018(self) -> bool {
434-
self == keywords::Async.name()
435+
self >= keywords::Async.name() &&
436+
self <= keywords::Try.name()
435437
}
436438
}
437439

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// compile-flags: -Z parse-only
12+
13+
fn main() {
14+
let _: Option<()> = do catch {};
15+
//~^ ERROR found removed `do catch` syntax
16+
//~^^ HELP Following RFC #2388, the new non-placeholder syntax is `try`
17+
}

0 commit comments

Comments
 (0)