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... ~~Fixes 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
This commit is contained in:
commit
35bf1ae257
@ -1,4 +1,4 @@
|
||||
# `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 @@ impl<'a> LoweringContext<'a> {
|
||||
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 @@ impl_stable_hash_for!(enum ::syntax_pos::hygiene::CompilerDesugaringKind {
|
||||
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 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
|
||||
#![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 rustc_apfloat;
|
||||
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 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
// 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 @@ impl Expr {
|
||||
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 @@ declare_features! (
|
||||
// `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 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
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 @@ impl<'a> Parser<'a> {
|
||||
|
||||
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 @@ impl<'a> Parser<'a> {
|
||||
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 @@ impl<'a> Parser<'a> {
|
||||
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 @@ impl<'a> Parser<'a> {
|
||||
)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
// prevent `while catch {} {}`, `if catch {} {} else {}`, etc.
|
||||
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 try {} {}`, `if try {} {} else {}`, etc.
|
||||
!self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
|
||||
}
|
||||
|
||||
|
@ -2379,8 +2379,8 @@ impl<'a> State<'a> {
|
||||
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 @@ impl ExprPrecedence {
|
||||
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 @@ impl ExpnFormat {
|
||||
#[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 @@ impl CompilerDesugaringKind {
|
||||
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 @@ declare_keywords! {
|
||||
|
||||
// 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()
|
||||
}
|
||||
}
|
||||
|
||||
|
17
src/test/parse-fail/do-catch-suggests-try.rs
Normal file
17
src/test/parse-fail/do-catch-suggests-try.rs
Normal file
@ -0,0 +1,17 @@
|
||||
// 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`
|
||||
}
|
15
src/test/parse-fail/keyword-try-as-identifier-edition2018.rs
Normal file
15
src/test/parse-fail/keyword-try-as-identifier-edition2018.rs
Normal file
@ -0,0 +1,15 @@
|
||||
// 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(()));
|
||||
}
|
18
src/test/run-pass/try-is-identifier-edition2015.rs
Normal file
18
src/test/run-pass/try-is-identifier-edition2015.rs
Normal file
@ -0,0 +1,18 @@
|
||||
// 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);
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
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`.
|
@ -1,8 +0,0 @@
|
||||
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
|
||||
|
@ -1,8 +0,0 @@
|
||||
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
|
||||
|
@ -1,14 +0,0 @@
|
||||
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`.
|
@ -1,9 +0,0 @@
|
||||
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`.
|
@ -1,15 +0,0 @@
|
||||
error[E0658]: `catch` expression is experimental (see issue #31436)
|
||||
--> $DIR/feature-gate-catch_expr.rs:12:24
|
||||
|
|
||||
LL | let catch_result = do catch { //~ ERROR `catch` expression is experimental
|
||||
| ________________________^
|
||||
LL | | let x = 5;
|
||||
LL | | x
|
||||
LL | | };
|
||||
| |_____^
|
||||
|
|
||||
= help: add #![feature(catch_expr)] to the crate attributes to enable
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
@ -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));
|
||||
}
|
15
src/test/ui/feature-gates/feature-gate-try_blocks.stderr
Normal file
15
src/test/ui/feature-gates/feature-gate-try_blocks.stderr
Normal file
@ -0,0 +1,15 @@
|
||||
error[E0658]: `try` expression is experimental (see issue #31436)
|
||||
--> $DIR/feature-gate-try_blocks.rs:14:33
|
||||
|
|
||||
LL | let try_result: Option<_> = try { //~ ERROR `try` expression is experimental
|
||||
| _________________________________^
|
||||
LL | | let x = 5;
|
||||
LL | | x
|
||||
LL | | };
|
||||
| |_____^
|
||||
|
|
||||
= help: add #![feature(try_blocks)] to the crate attributes to enable
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
@ -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
|
||||
};
|
@ -1,5 +1,16 @@
|
||||
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
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
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`
|
||||
|
20
src/test/ui/try-block/try-block-in-edition2015.rs
Normal file
20
src/test/ui/try-block/try-block-in-edition2015.rs
Normal file
@ -0,0 +1,20 @@
|
||||
// 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));
|
||||
}
|
18
src/test/ui/try-block/try-block-in-edition2015.stderr
Normal file
18
src/test/ui/try-block/try-block-in-edition2015.stderr
Normal file
@ -0,0 +1,18 @@
|
||||
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() {
|
||||
match do catch { false } { _ => {} } //~ ERROR expected expression, found reserved keyword `do`
|
||||
match try { false } { _ => {} } //~ ERROR expected expression, found reserved keyword `try`
|
||||
}
|
8
src/test/ui/try-block/try-block-in-match.stderr
Normal file
8
src/test/ui/try-block/try-block-in-match.stderr
Normal file
@ -0,0 +1,8 @@
|
||||
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() {
|
||||
while do catch { false } {} //~ ERROR expected expression, found reserved keyword `do`
|
||||
while try { false } {} //~ ERROR expected expression, found reserved keyword `try`
|
||||
}
|
8
src/test/ui/try-block/try-block-in-while.stderr
Normal file
8
src/test/ui/try-block/try-block-in-while.stderr
Normal file
@ -0,0 +1,8 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -1,31 +1,37 @@
|
||||
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`
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
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
|
@ -1,5 +1,5 @@
|
||||
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 ()
|
Loading…
x
Reference in New Issue
Block a user