提交 35bf1ae2 编写于 作者: B bors

Auto merge of #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 https://github.com/rust-lang/rust/issues/52604~~ That was fixed by PR https://github.com/rust-lang/rust/pull/53135
cc https://github.com/rust-lang/rust/issues/31436 https://github.com/rust-lang/rust/issues/50412
# `catch_expr`
# `try_blocks`
The tracking issue for this feature is: [#31436]
......@@ -6,22 +6,24 @@ The tracking issue for this feature is: [#31436]
------------------------
The `catch_expr` feature adds support for a `catch` expression. The `catch`
expression creates a new scope one can use the `?` operator in.
The `try_blocks` feature adds support for `try` blocks. A `try`
block creates a new scope one can use the `?` operator in.
```rust
#![feature(catch_expr)]
```rust,ignore
// This code needs the 2018 edition
#![feature(try_blocks)]
use std::num::ParseIntError;
let result: Result<i32, ParseIntError> = do catch {
let result: Result<i32, ParseIntError> = try {
"1".parse::<i32>()?
+ "2".parse::<i32>()?
+ "3".parse::<i32>()?
};
assert_eq!(result, Ok(6));
let result: Result<i32, ParseIntError> = do catch {
let result: Result<i32, ParseIntError> = try {
"1".parse::<i32>()?
+ "foo".parse::<i32>()?
+ "3".parse::<i32>()?
......
......@@ -3613,10 +3613,10 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
hir::LoopSource::Loop,
)
}),
ExprKind::Catch(ref body) => {
ExprKind::TryBlock(ref body) => {
self.with_catch_scope(body.id, |this| {
let unstable_span =
this.allow_internal_unstable(CompilerDesugaringKind::Catch, body.span);
this.allow_internal_unstable(CompilerDesugaringKind::TryBlock, body.span);
let mut block = this.lower_block(body, true).into_inner();
let tail = block.expr.take().map_or_else(
|| {
......
......@@ -412,7 +412,7 @@ fn hash_token<'a, 'gcx, W: StableHasherResult>(
QuestionMark,
ExistentialReturnType,
ForLoop,
Catch
TryBlock
});
impl_stable_hash_for!(enum ::syntax_pos::FileName {
......
......@@ -65,7 +65,6 @@
#![feature(trace_macros)]
#![feature(trusted_len)]
#![feature(vec_remove_item)]
#![feature(catch_expr)]
#![feature(step_trait)]
#![feature(integer_atomics)]
#![feature(test)]
......
......@@ -312,14 +312,14 @@ fn dump_mir_results<'a, 'gcx, 'tcx>(
);
// Also dump the inference graph constraints as a graphviz file.
let _: io::Result<()> = do catch {
let _: io::Result<()> = try_block! {
let mut file =
pretty::create_dump_file(infcx.tcx, "regioncx.all.dot", None, "nll", &0, source)?;
regioncx.dump_graphviz_raw_constraints(&mut file)?;
};
// Also dump the inference graph constraints as a graphviz file.
let _: io::Result<()> = do catch {
let _: io::Result<()> = try_block! {
let mut file =
pretty::create_dump_file(infcx.tcx, "regioncx.scc.dot", None, "nll", &0, source)?;
regioncx.dump_graphviz_scc_constraints(&mut file)?;
......
......@@ -21,7 +21,6 @@
#![feature(slice_sort_by_cached_key)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(catch_expr)]
#![feature(crate_visibility_modifier)]
#![feature(const_fn)]
#![feature(core_intrinsics)]
......@@ -63,6 +62,14 @@
extern crate byteorder;
extern crate core;
// Once we can use edition 2018 in the compiler,
// replace this with real try blocks.
macro_rules! try_block {
($($inside:tt)*) => (
(||{ ::std::ops::Try::from_ok({ $($inside)* }) })()
)
}
mod diagnostics;
mod borrow_check;
......
......@@ -140,7 +140,7 @@ fn dump_matched_mir_node<'a, 'gcx, 'tcx, F>(
) where
F: FnMut(PassWhere, &mut dyn Write) -> io::Result<()>,
{
let _: io::Result<()> = do catch {
let _: io::Result<()> = try_block! {
let mut file = create_dump_file(tcx, "mir", pass_num, pass_name, disambiguator, source)?;
writeln!(file, "// MIR for `{}`", node_path)?;
writeln!(file, "// source = {:?}", source)?;
......@@ -156,7 +156,7 @@ fn dump_matched_mir_node<'a, 'gcx, 'tcx, F>(
};
if tcx.sess.opts.debugging_opts.dump_mir_graphviz {
let _: io::Result<()> = do catch {
let _: io::Result<()> = try_block! {
let mut file =
create_dump_file(tcx, "dot", pass_num, pass_name, disambiguator, source)?;
write_mir_fn_graphviz(tcx, source.def_id, mir, &mut file)?;
......
......@@ -4471,7 +4471,7 @@ fn check_block_with_expected(&self,
// In some cases, blocks have just one exit, but other blocks
// can be targeted by multiple breaks. This can happen both
// with labeled blocks as well as when we desugar
// a `do catch { ... }` expression.
// a `try { ... }` expression.
//
// Example 1:
//
......
......@@ -987,7 +987,7 @@ pub fn precedence(&self) -> ExprPrecedence {
ExprKind::Match(..) => ExprPrecedence::Match,
ExprKind::Closure(..) => ExprPrecedence::Closure,
ExprKind::Block(..) => ExprPrecedence::Block,
ExprKind::Catch(..) => ExprPrecedence::Catch,
ExprKind::TryBlock(..) => ExprPrecedence::TryBlock,
ExprKind::Async(..) => ExprPrecedence::Async,
ExprKind::Assign(..) => ExprPrecedence::Assign,
ExprKind::AssignOp(..) => ExprPrecedence::AssignOp,
......@@ -1108,8 +1108,8 @@ pub enum ExprKind {
/// created during lowering cannot be made the parent of any other
/// preexisting defs.
Async(CaptureBy, NodeId, P<Block>),
/// A catch block (`catch { ... }`)
Catch(P<Block>),
/// A try block (`try { ... }`)
TryBlock(P<Block>),
/// An assignment (`a = foo()`)
Assign(P<Expr>, P<Expr>),
......
......@@ -333,8 +333,8 @@ pub fn walk_feature_fields<F>(&self, mut f: F)
// `extern "x86-interrupt" fn()`
(active, abi_x86_interrupt, "1.17.0", Some(40180), None),
// Allows the `catch {...}` expression
(active, catch_expr, "1.17.0", Some(31436), None),
// Allows the `try {...}` expression
(active, try_blocks, "1.29.0", Some(31436), None),
// Used to preserve symbols (see llvm.used)
(active, used, "1.18.0", Some(40289), None),
......@@ -1734,8 +1734,8 @@ fn visit_expr(&mut self, e: &'a ast::Expr) {
e.span,
"yield syntax is experimental");
}
ast::ExprKind::Catch(_) => {
gate_feature_post!(&self, catch_expr, e.span, "`catch` expression is experimental");
ast::ExprKind::TryBlock(_) => {
gate_feature_post!(&self, try_blocks, e.span, "`try` expression is experimental");
}
ast::ExprKind::IfLet(ref pats, ..) | ast::ExprKind::WhileLet(ref pats, ..) => {
if pats.len() > 1 {
......
......@@ -1351,7 +1351,7 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu
}
ExprKind::Yield(ex) => ExprKind::Yield(ex.map(|x| folder.fold_expr(x))),
ExprKind::Try(ex) => ExprKind::Try(folder.fold_expr(ex)),
ExprKind::Catch(body) => ExprKind::Catch(folder.fold_block(body)),
ExprKind::TryBlock(body) => ExprKind::TryBlock(folder.fold_block(body)),
},
id: folder.new_id(id),
span: folder.new_span(span),
......
......@@ -26,8 +26,8 @@
#![feature(rustc_diagnostic_macros)]
#![feature(slice_sort_by_cached_key)]
#![feature(str_escape)]
#![feature(try_trait)]
#![feature(unicode_internals)]
#![feature(catch_expr)]
#![recursion_limit="256"]
......
......@@ -31,7 +31,7 @@ pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool {
ast::ExprKind::WhileLet(..) |
ast::ExprKind::Loop(..) |
ast::ExprKind::ForLoop(..) |
ast::ExprKind::Catch(..) => false,
ast::ExprKind::TryBlock(..) => false,
_ => true,
}
}
......
......@@ -1757,9 +1757,17 @@ fn parse_arg_general(&mut self, require_name: bool) -> PResult<'a, Arg> {
let parser_snapshot_before_pat = self.clone();
// Once we can use edition 2018 in the compiler,
// replace this with real try blocks.
macro_rules! try_block {
($($inside:tt)*) => (
(||{ ::std::ops::Try::from_ok({ $($inside)* }) })()
)
}
// We're going to try parsing the argument as a pattern (even though it's not
// allowed). This way we can provide better errors to the user.
let pat_arg: PResult<'a, _> = do catch {
let pat_arg: PResult<'a, _> = try_block! {
let pat = self.parse_pat()?;
self.expect(&token::Colon)?;
(pat, self.parse_ty()?)
......@@ -2387,11 +2395,15 @@ fn parse_bottom_expr(&mut self) -> PResult<'a, P<Expr>> {
BlockCheckMode::Unsafe(ast::UserProvided),
attrs);
}
if self.is_catch_expr() {
if self.is_do_catch_block() {
let mut db = self.fatal("found removed `do catch` syntax");
db.help("Following RFC #2388, the new non-placeholder syntax is `try`");
return Err(db);
}
if self.is_try_block() {
let lo = self.span;
assert!(self.eat_keyword(keywords::Do));
assert!(self.eat_keyword(keywords::Catch));
return self.parse_catch_expr(lo, attrs);
assert!(self.eat_keyword(keywords::Try));
return self.parse_try_block(lo, attrs);
}
if self.eat_keyword(keywords::Return) {
if self.token.can_begin_expr() {
......@@ -3453,13 +3465,13 @@ pub fn parse_async_block(&mut self, mut attrs: ThinVec<Attribute>)
ExprKind::Async(capture_clause, ast::DUMMY_NODE_ID, body), attrs))
}
/// Parse a `do catch {...}` expression (`do catch` token already eaten)
fn parse_catch_expr(&mut self, span_lo: Span, mut attrs: ThinVec<Attribute>)
/// Parse a `try {...}` expression (`try` token already eaten)
fn parse_try_block(&mut self, span_lo: Span, mut attrs: ThinVec<Attribute>)
-> PResult<'a, P<Expr>>
{
let (iattrs, body) = self.parse_inner_attrs_and_block()?;
attrs.extend(iattrs);
Ok(self.mk_expr(span_lo.to(body.span), ExprKind::Catch(body), attrs))
Ok(self.mk_expr(span_lo.to(body.span), ExprKind::TryBlock(body), attrs))
}
// `match` token already eaten
......@@ -4408,12 +4420,20 @@ fn is_async_block(&mut self) -> bool {
)
}
fn is_catch_expr(&mut self) -> bool {
fn is_do_catch_block(&mut self) -> bool {
self.token.is_keyword(keywords::Do) &&
self.look_ahead(1, |t| t.is_keyword(keywords::Catch)) &&
self.look_ahead(2, |t| *t == token::OpenDelim(token::Brace)) &&
!self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
}
fn is_try_block(&mut self) -> bool {
self.token.is_keyword(keywords::Try) &&
self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace)) &&
self.span.edition() >= Edition::Edition2018 &&
// prevent `while catch {} {}`, `if catch {} {} else {}`, etc.
// prevent `while try {} {}`, `if try {} {} else {}`, etc.
!self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
}
......
......@@ -2379,8 +2379,8 @@ fn print_expr_outer_attr_style(&mut self,
self.print_expr_maybe_paren(e, parser::PREC_POSTFIX)?;
self.s.word("?")?
}
ast::ExprKind::Catch(ref blk) => {
self.head("do catch")?;
ast::ExprKind::TryBlock(ref blk) => {
self.head("try")?;
self.s.space()?;
self.print_block_with_attrs(blk, attrs)?
}
......
......@@ -273,7 +273,7 @@ pub enum ExprPrecedence {
Loop,
Match,
Block,
Catch,
TryBlock,
Struct,
Async,
}
......@@ -332,7 +332,7 @@ pub fn order(self) -> i8 {
ExprPrecedence::Loop |
ExprPrecedence::Match |
ExprPrecedence::Block |
ExprPrecedence::Catch |
ExprPrecedence::TryBlock |
ExprPrecedence::Async |
ExprPrecedence::Struct => PREC_PAREN,
}
......
......@@ -809,7 +809,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
ExprKind::Try(ref subexpression) => {
visitor.visit_expr(subexpression)
}
ExprKind::Catch(ref body) => {
ExprKind::TryBlock(ref body) => {
visitor.visit_block(body)
}
}
......
......@@ -595,7 +595,7 @@ pub fn name(&self) -> Symbol {
#[derive(Clone, Copy, Hash, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
pub enum CompilerDesugaringKind {
QuestionMark,
Catch,
TryBlock,
/// Desugaring of an `impl Trait` in return type position
/// to an `existential type Foo: Trait;` + replacing the
/// `impl Trait` with `Foo`.
......@@ -609,7 +609,7 @@ pub fn name(self) -> Symbol {
Symbol::intern(match self {
CompilerDesugaringKind::Async => "async",
CompilerDesugaringKind::QuestionMark => "?",
CompilerDesugaringKind::Catch => "do catch",
CompilerDesugaringKind::TryBlock => "try block",
CompilerDesugaringKind::ExistentialReturnType => "existential type",
CompilerDesugaringKind::ForLoop => "for loop",
})
......
......@@ -415,23 +415,25 @@ pub fn fresh() -> Self {
// Edition-specific keywords reserved for future use.
(51, Async, "async") // >= 2018 Edition Only
(52, Try, "try") // >= 2018 Edition Only
// Special lifetime names
(52, UnderscoreLifetime, "'_")
(53, StaticLifetime, "'static")
(53, UnderscoreLifetime, "'_")
(54, StaticLifetime, "'static")
// Weak keywords, have special meaning only in specific contexts.
(54, Auto, "auto")
(55, Catch, "catch")
(56, Default, "default")
(57, Dyn, "dyn")
(58, Union, "union")
(59, Existential, "existential")
(55, Auto, "auto")
(56, Catch, "catch")
(57, Default, "default")
(58, Dyn, "dyn")
(59, Union, "union")
(60, Existential, "existential")
}
impl Symbol {
fn is_unused_keyword_2018(self) -> bool {
self == keywords::Async.name()
self >= keywords::Async.name() &&
self <= keywords::Try.name()
}
}
......
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Z parse-only
fn main() {
let _: Option<()> = do catch {};
//~^ ERROR found removed `do catch` syntax
//~^^ HELP Following RFC #2388, the new non-placeholder syntax is `try`
}
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Z parse-only --edition 2018
fn main() {
let try = "foo"; //~ error: expected pattern, found reserved keyword `try`
}
......@@ -8,12 +8,14 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(catch_expr)]
// compile-flags: --edition 2018
#![feature(try_blocks)]
fn main() {
let mut a = 0;
let () = {
let _: Result<(), ()> = do catch {
let _: Result<(), ()> = try {
let _ = Err(())?;
return
};
......
......@@ -8,12 +8,14 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(catch_expr)]
// compile-flags: --edition 2018
#![feature(try_blocks)]
struct catch {}
pub fn main() {
let catch_result: Option<_> = do catch {
let catch_result: Option<_> = try {
let x = 5;
x
};
......@@ -30,20 +32,20 @@ pub fn main() {
_ => {}
};
let catch_err: Result<_, i32> = do catch {
let catch_err: Result<_, i32> = try {
Err(22)?;
1
};
assert_eq!(catch_err, Err(22));
let catch_okay: Result<i32, i32> = do catch {
let catch_okay: Result<i32, i32> = try {
if false { Err(25)?; }
Ok::<(), i32>(())?;
28
};
assert_eq!(catch_okay, Ok(28));
let catch_from_loop: Result<i32, i32> = do catch {
let catch_from_loop: Result<i32, i32> = try {
for i in 0..10 {
if i < 5 { Ok::<i32, i32>(i)?; } else { Err(i)?; }
}
......@@ -52,28 +54,28 @@ pub fn main() {
assert_eq!(catch_from_loop, Err(5));
let cfg_init;
let _res: Result<(), ()> = do catch {
let _res: Result<(), ()> = try {
cfg_init = 5;
};
assert_eq!(cfg_init, 5);
let cfg_init_2;
let _res: Result<(), ()> = do catch {
let _res: Result<(), ()> = try {
cfg_init_2 = 6;
Err(())?;
};
assert_eq!(cfg_init_2, 6);
let my_string = "test".to_string();
let res: Result<&str, ()> = do catch {
let res: Result<&str, ()> = try {
// Unfortunately, deref doesn't fire here (#49356)
&my_string[..]
};
assert_eq!(res, Ok("test"));
let my_opt: Option<_> = do catch { () };
let my_opt: Option<_> = try { () };
assert_eq!(my_opt, Some(()));
let my_opt: Option<_> = do catch { };
let my_opt: Option<_> = try { };
assert_eq!(my_opt, Some(()));
}
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: --edition 2015
fn main() {
let try = 2;
struct try { try: u32 };
let try: try = try { try };
assert_eq!(try.try, 2);
}
error[E0597]: `my_string` does not live long enough
--> $DIR/catch-bad-lifetime.rs:20:35
|
LL | let my_str: & str = & my_string;
| ^^^^^^^^^ borrowed value does not live long enough
...
LL | };
| - `my_string` dropped here while still borrowed
LL | }
| - borrowed value needs to live until here
error[E0506]: cannot assign to `i` because it is borrowed
--> $DIR/catch-bad-lifetime.rs:33:13
|
LL | let k = &mut i;
| - borrow of `i` occurs here
...
LL | i = 10; //~ ERROR cannot assign to `i` because it is borrowed
| ^^^^^^ assignment to borrowed `i` occurs here
error[E0382]: use of moved value: `k`
--> $DIR/catch-bad-lifetime.rs:35:26
|
LL | Err(k) ?;
| - value moved here
...
LL | ::std::mem::drop(k); //~ ERROR use of moved value: `k`
| ^ value used here after move
|
= note: move occurs because `k` has type `&mut i32`, which does not implement the `Copy` trait
error[E0506]: cannot assign to `i` because it is borrowed
--> $DIR/catch-bad-lifetime.rs:36:9
|
LL | let k = &mut i;
| - borrow of `i` occurs here
...
LL | i = 40; //~ ERROR cannot assign to `i` because it is borrowed
| ^^^^^^ assignment to borrowed `i` occurs here
error: aborting due to 4 previous errors
Some errors occurred: E0382, E0506, E0597.
For more information about an error, try `rustc --explain E0382`.
error: expected expression, found reserved keyword `do`
--> $DIR/catch-in-match.rs:14:11
|
LL | match do catch { false } { _ => {} } //~ ERROR expected expression, found reserved keyword `do`
| ^^ expected expression
error: aborting due to previous error
error: expected expression, found reserved keyword `do`
--> $DIR/catch-in-while.rs:14:11
|
LL | while do catch { false } {} //~ ERROR expected expression, found reserved keyword `do`
| ^^ expected expression
error: aborting due to previous error
error[E0382]: borrow of moved value: `x`
--> $DIR/catch-maybe-bad-lifetime.rs:33:24
|
LL | ::std::mem::drop(x);
| - value moved here
LL | };
LL | println!("{}", x); //~ ERROR use of moved value: `x`
| ^ value borrowed here after move
|
= note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
error: aborting due to previous error
For more information about this error, try `rustc --explain E0382`.
error[E0381]: use of possibly uninitialized variable: `cfg_res`
--> $DIR/catch-opt-init.rs:23:16
|
LL | assert_eq!(cfg_res, 5); //~ ERROR use of possibly uninitialized variable
| ^^^^^^^ use of possibly uninitialized `cfg_res`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0381`.
......@@ -8,10 +8,12 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: --edition 2018
pub fn main() {
let catch_result = do catch { //~ ERROR `catch` expression is experimental
let try_result: Option<_> = try { //~ ERROR `try` expression is experimental
let x = 5;
x
};
assert_eq!(catch_result, 5);
assert_eq!(try_result, Some(5));
}
error[E0658]: `catch` expression is experimental (see issue #31436)
--> $DIR/feature-gate-catch_expr.rs:12:24
error[E0658]: `try` expression is experimental (see issue #31436)
--> $DIR/feature-gate-try_blocks.rs:14:33
|
LL | let catch_result = do catch { //~ ERROR `catch` expression is experimental
| ________________________^
LL | let try_result: Option<_> = try { //~ ERROR `try` expression is experimental
| _________________________________^
LL | | let x = 5;
LL | | x
LL | | };
| |_____^
|
= help: add #![feature(catch_expr)] to the crate attributes to enable
= help: add #![feature(try_blocks)] to the crate attributes to enable
error: aborting due to previous error
......
......@@ -8,27 +8,33 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(catch_expr)]
// compile-flags: --edition 2018
// This test checks that borrows made and returned inside catch blocks are properly constrained
#![feature(try_blocks)]
#![inline(never)]
fn do_something_with<T>(_x: T) {}
// This test checks that borrows made and returned inside try blocks are properly constrained
pub fn main() {
{
// Test that borrows returned from a catch block must be valid for the lifetime of the
// Test that borrows returned from a try block must be valid for the lifetime of the
// result variable
let _result: Result<(), &str> = do catch {
let result: Result<(), &str> = try {
let my_string = String::from("");
let my_str: & str = & my_string;
//~^ ERROR `my_string` does not live long enough
Err(my_str) ?;
Err("") ?;
};
do_something_with(result);
}
{
// Test that borrows returned from catch blocks freeze their referent
// Test that borrows returned from try blocks freeze their referent
let mut i = 5;
let k = &mut i;
let mut j: Result<(), &mut i32> = do catch {
let mut j: Result<(), &mut i32> = try {
Err(k) ?;
i = 10; //~ ERROR cannot assign to `i` because it is borrowed
};
......
error[E0597]: `my_string` does not live long enough
--> $DIR/try-block-bad-lifetime.rs:25:33
|
LL | let my_str: & str = & my_string;
| ^^^^^^^^^^^ borrowed value does not live long enough
...
LL | };
| - `my_string` dropped here while still borrowed
LL | do_something_with(result);
| ------ borrow later used here
error[E0506]: cannot assign to `i` because it is borrowed
--> $DIR/catch-bad-lifetime.rs:33:13
--> $DIR/try-block-bad-lifetime.rs:39:13
|
LL | let k = &mut i;
| ------ borrow of `i` occurs here
......@@ -11,7 +22,7 @@ LL | ::std::mem::drop(k); //~ ERROR use of moved value: `k`
| - borrow later used here
error[E0382]: use of moved value: `k`
--> $DIR/catch-bad-lifetime.rs:35:26
--> $DIR/try-block-bad-lifetime.rs:41:26
|
LL | Err(k) ?;
| - value moved here
......@@ -22,7 +33,7 @@ LL | ::std::mem::drop(k); //~ ERROR use of moved value: `k`
= note: move occurs because `k` has type `&mut i32`, which does not implement the `Copy` trait
error[E0506]: cannot assign to `i` because it is borrowed
--> $DIR/catch-bad-lifetime.rs:36:9
--> $DIR/try-block-bad-lifetime.rs:42:9
|
LL | let k = &mut i;
| ------ borrow of `i` occurs here
......@@ -33,7 +44,7 @@ LL |
LL | let i_ptr = if let Err(i_ptr) = j { i_ptr } else { panic ! ("") };
| - borrow later used here
error: aborting due to 3 previous errors
error: aborting due to 4 previous errors
Some errors occurred: E0382, E0506.
Some errors occurred: E0382, E0506, E0597.
For more information about an error, try `rustc --explain E0382`.
......@@ -8,21 +8,23 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(catch_expr)]
// compile-flags: --edition 2018
#![feature(try_blocks)]
pub fn main() {
let res: Result<u32, i32> = do catch {
let res: Result<u32, i32> = try {
Err("")?; //~ ERROR the trait bound `i32: std::convert::From<&str>` is not satisfied
5
};
let res: Result<i32, i32> = do catch {
let res: Result<i32, i32> = try {
"" //~ ERROR type mismatch
};
let res: Result<i32, i32> = do catch { }; //~ ERROR type mismatch
let res: Result<i32, i32> = try { }; //~ ERROR type mismatch
let res: () = do catch { }; //~ the trait bound `(): std::ops::Try` is not satisfied
let res: () = try { }; //~ the trait bound `(): std::ops::Try` is not satisfied
let res: i32 = do catch { 5 }; //~ ERROR the trait bound `i32: std::ops::Try` is not satisfied
let res: i32 = try { 5 }; //~ ERROR the trait bound `i32: std::ops::Try` is not satisfied
}
error[E0277]: the trait bound `i32: std::convert::From<&str>` is not satisfied
--> $DIR/catch-bad-type.rs:15:9
--> $DIR/try-block-bad-type.rs:17:9
|
LL | Err("")?; //~ ERROR the trait bound `i32: std::convert::From<&str>` is not satisfied
| ^^^^^^^^ the trait `std::convert::From<&str>` is not implemented for `i32`
......@@ -13,7 +13,7 @@ LL | Err("")?; //~ ERROR the trait bound `i32: std::convert::From<&str>`
= note: required by `std::convert::From::from`
error[E0271]: type mismatch resolving `<std::result::Result<i32, i32> as std::ops::Try>::Ok == &str`
--> $DIR/catch-bad-type.rs:20:9
--> $DIR/try-block-bad-type.rs:22:9
|
LL | "" //~ ERROR type mismatch
| ^^ expected i32, found &str
......@@ -22,27 +22,27 @@ LL | "" //~ ERROR type mismatch
found type `&str`
error[E0271]: type mismatch resolving `<std::result::Result<i32, i32> as std::ops::Try>::Ok == ()`
--> $DIR/catch-bad-type.rs:23:44
--> $DIR/try-block-bad-type.rs:25:39
|
LL | let res: Result<i32, i32> = do catch { }; //~ ERROR type mismatch
| ^ expected i32, found ()
LL | let res: Result<i32, i32> = try { }; //~ ERROR type mismatch
| ^ expected i32, found ()
|
= note: expected type `i32`
found type `()`
error[E0277]: the trait bound `(): std::ops::Try` is not satisfied
--> $DIR/catch-bad-type.rs:25:28
--> $DIR/try-block-bad-type.rs:27:23
|
LL | let res: () = do catch { }; //~ the trait bound `(): std::ops::Try` is not satisfied
| ^^^ the trait `std::ops::Try` is not implemented for `()`
LL | let res: () = try { }; //~ the trait bound `(): std::ops::Try` is not satisfied
| ^^^ the trait `std::ops::Try` is not implemented for `()`
|
= note: required by `std::ops::Try::from_ok`
error[E0277]: the trait bound `i32: std::ops::Try` is not satisfied
--> $DIR/catch-bad-type.rs:27:29
--> $DIR/try-block-bad-type.rs:29:24
|
LL | let res: i32 = do catch { 5 }; //~ ERROR the trait bound `i32: std::ops::Try` is not satisfied
| ^^^^^ the trait `std::ops::Try` is not implemented for `i32`
LL | let res: i32 = try { 5 }; //~ ERROR the trait bound `i32: std::ops::Try` is not satisfied
| ^^^^^ the trait `std::ops::Try` is not implemented for `i32`
|
= note: required by `std::ops::Try::from_ok`
......
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: --edition 2015
pub fn main() {
let try_result: Option<_> = try {
//~^ ERROR expected struct, variant or union type, found macro `try`
let x = 5; //~ ERROR expected identifier, found keyword
x
};
assert_eq!(try_result, Some(5));
}
error: expected identifier, found keyword `let`
--> $DIR/try-block-in-edition2015.rs:16:9
|
LL | let try_result: Option<_> = try {
| --- while parsing this struct
LL | //~^ ERROR expected struct, variant or union type, found macro `try`
LL | let x = 5; //~ ERROR expected identifier, found keyword
| ^^^ expected identifier, found keyword
error[E0574]: expected struct, variant or union type, found macro `try`
--> $DIR/try-block-in-edition2015.rs:14:33
|
LL | let try_result: Option<_> = try {
| ^^^ did you mean `try!(...)`?
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0574`.
......@@ -8,8 +8,10 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(catch_expr)]
// compile-flags: --edition 2018
#![feature(try_blocks)]
fn main() {
while do catch { false } {} //~ ERROR expected expression, found reserved keyword `do`
match try { false } { _ => {} } //~ ERROR expected expression, found reserved keyword `try`
}
error: expected expression, found reserved keyword `try`
--> $DIR/try-block-in-match.rs:16:11
|
LL | match try { false } { _ => {} } //~ ERROR expected expression, found reserved keyword `try`
| ^^^ expected expression
error: aborting due to previous error
......@@ -8,8 +8,10 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(catch_expr)]
// compile-flags: --edition 2018
#![feature(try_blocks)]
fn main() {
match do catch { false } { _ => {} } //~ ERROR expected expression, found reserved keyword `do`
while try { false } {} //~ ERROR expected expression, found reserved keyword `try`
}
error: expected expression, found reserved keyword `try`
--> $DIR/try-block-in-while.rs:16:11
|
LL | while try { false } {} //~ ERROR expected expression, found reserved keyword `try`
| ^^^ expected expression
error: aborting due to previous error
......@@ -8,42 +8,48 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(catch_expr)]
// compile-flags: --edition 2018
// This test checks that borrows made and returned inside catch blocks are properly constrained
#![feature(try_blocks)]
#![inline(never)]
fn do_something_with<T>(_x: T) {}
// This test checks that borrows made and returned inside try blocks are properly constrained
pub fn main() {
{
// Test that a borrow which *might* be returned still freezes its referent
let mut i = 222;
let x: Result<&i32, ()> = do catch {
let x: Result<&i32, ()> = try {
Err(())?;
&i
};
x.ok().cloned();
i = 0; //~ ERROR cannot assign to `i` because it is borrowed
let _ = i;
do_something_with(x);
}
{
let x = String::new();
let _y: Result<(), ()> = do catch {
let _y: Result<(), ()> = try {
Err(())?;
::std::mem::drop(x);
};
println!("{}", x); //~ ERROR use of moved value: `x`
println!("{}", x); //~ ERROR borrow of moved value: `x`
}
{
// Test that a borrow which *might* be assigned to an outer variable still freezes
// its referent
let mut i = 222;
let j;
let x: Result<(), ()> = do catch {
let mut j = &-1;
let _x: Result<(), ()> = try {
Err(())?;
j = &i;
};
i = 0; //~ ERROR cannot assign to `i` because it is borrowed
let _ = i;
do_something_with(j);
}
}
error[E0506]: cannot assign to `i` because it is borrowed
--> $DIR/catch-maybe-bad-lifetime.rs:23:9
--> $DIR/try-block-maybe-bad-lifetime.rs:27:9
|
LL | &i
| - borrow of `i` occurs here
...
| -- borrow of `i` occurs here
LL | };
LL | i = 0; //~ ERROR cannot assign to `i` because it is borrowed
| ^^^^^ assignment to borrowed `i` occurs here
LL | let _ = i;
LL | do_something_with(x);
| - borrow later used here
error[E0382]: use of moved value: `x`
--> $DIR/catch-maybe-bad-lifetime.rs:33:24
error[E0382]: borrow of moved value: `x`
--> $DIR/try-block-maybe-bad-lifetime.rs:38:24
|
LL | ::std::mem::drop(x);
| - value moved here
LL | };
LL | println!("{}", x); //~ ERROR use of moved value: `x`
| ^ value used here after move
LL | println!("{}", x); //~ ERROR borrow of moved value: `x`
| ^ value borrowed here after move
|
= note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
error[E0506]: cannot assign to `i` because it is borrowed
--> $DIR/catch-maybe-bad-lifetime.rs:45:9
--> $DIR/try-block-maybe-bad-lifetime.rs:50:9
|
LL | j = &i;
| - borrow of `i` occurs here
| -- borrow of `i` occurs here
LL | };
LL | i = 0; //~ ERROR cannot assign to `i` because it is borrowed
| ^^^^^ assignment to borrowed `i` occurs here
LL | let _ = i;
LL | do_something_with(j);
| - borrow later used here
error: aborting due to 3 previous errors
......
......@@ -8,18 +8,20 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(catch_expr)]
// compile-flags: --edition 2018
#![feature(try_blocks)]
fn use_val<T: Sized>(_x: T) {}
pub fn main() {
let cfg_res;
let _: Result<(), ()> = do catch {
let _: Result<(), ()> = try {
Err(())?;
cfg_res = 5;
Ok::<(), ()>(())?;
use_val(cfg_res);
};
assert_eq!(cfg_res, 5); //~ ERROR use of possibly uninitialized variable
assert_eq!(cfg_res, 5); //~ ERROR borrow of possibly uninitialized variable: `cfg_res`
}
error[E0381]: borrow of possibly uninitialized variable: `cfg_res`
--> $DIR/catch-opt-init.rs:23:5
--> $DIR/try-block-opt-init.rs:25:5
|
LL | assert_eq!(cfg_res, 5); //~ ERROR use of possibly uninitialized variable
LL | assert_eq!(cfg_res, 5); //~ ERROR borrow of possibly uninitialized variable: `cfg_res`
| ^^^^^^^^^^^^^^^^^^^^^^^ use of possibly uninitialized `cfg_res`
|
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
......
......@@ -8,18 +8,20 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(catch_expr)]
// compile-flags: --edition 2018
#![feature(try_blocks)]
fn foo() -> Option<()> { Some(()) }
fn main() {
let _: Option<f32> = do catch {
let _: Option<f32> = try {
foo()?;
42
//~^ ERROR type mismatch
};
let _: Option<i32> = do catch {
let _: Option<i32> = try {
foo()?;
};
//~^ ERROR type mismatch
......
error[E0271]: type mismatch resolving `<std::option::Option<f32> as std::ops::Try>::Ok == {integer}`
--> $DIR/catch-block-type-error.rs:18:9
--> $DIR/try-block-type-error.rs:20:9
|
LL | 42
| ^^
......@@ -11,7 +11,7 @@ LL | 42
found type `{integer}`
error[E0271]: type mismatch resolving `<std::option::Option<i32> as std::ops::Try>::Ok == ()`
--> $DIR/catch-block-type-error.rs:24:5
--> $DIR/try-block-type-error.rs:26:5
|
LL | };
| ^ expected i32, found ()
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册