1
Fork 0

Auto merge of #112953 - compiler-errors:interpolated-block-exprs, r=WaffleLapkin

Support interpolated block for `try` and `async`

I'm putting this up for T-lang discussion, to decide whether or not they feel like this should be supported. This was raised in #112952, which surprised me. There doesn't seem to be a *technical* reason why we don't support this.

### Precedent:

This is supported:

```rust
macro_rules! always {
  ($block:block) => {
    if true $block
  }
}

fn main() {
    always!({});
}
```

### Counterpoint:

However, for context, this is *not* supported:

```rust
macro_rules! unsafe_block {
  ($block:block) => {
    unsafe $block
  }
}

fn main() {
    unsafe_block!({});
}
```

If this support for `async` and `try` with interpolated blocks is *not* desirable, then I can convert them to instead the same diagnostic as `unsafe $block` and make this situation a lot less ambiguous.

----

I'll try to write up more before T-lang triage on Tuesday. I couldn't find anything other than #69760 for why something like `unsafe $block` is not supported, and even that PR doesn't have much information.

Fixes #112952
This commit is contained in:
bors 2023-07-22 20:37:44 +00:00
commit 1d56e3a6d9
3 changed files with 45 additions and 4 deletions

View file

@ -3003,7 +3003,8 @@ impl<'a> Parser<'a> {
fn is_do_catch_block(&self) -> bool { fn is_do_catch_block(&self) -> bool {
self.token.is_keyword(kw::Do) self.token.is_keyword(kw::Do)
&& self.is_keyword_ahead(1, &[kw::Catch]) && self.is_keyword_ahead(1, &[kw::Catch])
&& self.look_ahead(2, |t| *t == token::OpenDelim(Delimiter::Brace)) && self
.look_ahead(2, |t| *t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block())
&& !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL) && !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
} }
@ -3013,7 +3014,8 @@ impl<'a> Parser<'a> {
fn is_try_block(&self) -> bool { fn is_try_block(&self) -> bool {
self.token.is_keyword(kw::Try) self.token.is_keyword(kw::Try)
&& self.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace)) && self
.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block())
&& self.token.uninterpolated_span().at_least_rust_2018() && self.token.uninterpolated_span().at_least_rust_2018()
} }
@ -3032,10 +3034,14 @@ impl<'a> Parser<'a> {
&& (( && ((
// `async move {` // `async move {`
self.is_keyword_ahead(1, &[kw::Move]) self.is_keyword_ahead(1, &[kw::Move])
&& self.look_ahead(2, |t| *t == token::OpenDelim(Delimiter::Brace)) && self.look_ahead(2, |t| {
*t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block()
})
) || ( ) || (
// `async {` // `async {`
self.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace)) self.look_ahead(1, |t| {
*t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block()
})
)) ))
} }

View file

@ -0,0 +1,16 @@
// check-pass
// edition:2021
macro_rules! create_async {
($body:block) => {
async $body
};
}
async fn other() {}
fn main() {
let y = create_async! {{
other().await;
}};
}

View file

@ -0,0 +1,19 @@
// check-pass
// edition:2021
#![feature(try_blocks)]
macro_rules! create_try {
($body:block) => {
try $body
};
}
fn main() {
let x: Option<&str> = create_try! {{
None?;
"Hello world"
}};
println!("{x:?}");
}