Skip to content

Commit

Permalink
Rollup merge of #118419 - compiler-errors:await-span2, r=cjgillot
Browse files Browse the repository at this point in the history
Eagerly return `ExprKind::Err` on `yield`/`await` in wrong coroutine context

This PR does 2 things:
1. Refuses to lower `.await` or `yield` when we are outside of the right coroutine context for the operator. Instead, we lower to `hir::ExprKind::Err`, to silence subsequent redundant errors.
2. Reworks a bit of the span tracking in `LoweringContext` to fix a bad span when we have something like `let x = [0; async_fn().await]` where the `await` is inside of an anon const. The span for the "item" still kinda sucks, since it overlaps with the `await` span, but at least it's accurate.
  • Loading branch information
matthiaskrgr committed Nov 29, 2023
2 parents b7016ae + dd5abb5 commit 8cfdccf
Show file tree
Hide file tree
Showing 11 changed files with 36 additions and 85 deletions.
23 changes: 11 additions & 12 deletions compiler/rustc_ast_lowering/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let kind = match &e.kind {
ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)),
ExprKind::ConstBlock(c) => {
let c = self.with_new_scopes(|this| hir::ConstBlock {
let c = self.with_new_scopes(c.value.span, |this| hir::ConstBlock {
def_id: this.local_def_id(c.id),
hir_id: this.lower_node_id(c.id),
body: this.lower_const_body(c.value.span, Some(&c.value)),
Expand Down Expand Up @@ -189,7 +189,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
None,
e.span,
hir::CoroutineSource::Block,
|this| this.with_new_scopes(|this| this.lower_block_expr(block)),
|this| this.with_new_scopes(e.span, |this| this.lower_block_expr(block)),
),
ExprKind::Await(expr, await_kw_span) => self.lower_expr_await(*await_kw_span, expr),
ExprKind::Closure(box Closure {
Expand Down Expand Up @@ -323,7 +323,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
None,
e.span,
hir::CoroutineSource::Block,
|this| this.with_new_scopes(|this| this.lower_block_expr(block)),
|this| this.with_new_scopes(e.span, |this| this.lower_block_expr(block)),
),
ExprKind::Yield(opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()),
ExprKind::Err => hir::ExprKind::Err(
Expand Down Expand Up @@ -756,10 +756,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
match self.coroutine_kind {
Some(hir::CoroutineKind::Async(_)) => {}
Some(hir::CoroutineKind::Coroutine) | Some(hir::CoroutineKind::Gen(_)) | None => {
self.tcx.sess.emit_err(AwaitOnlyInAsyncFnAndBlocks {
return hir::ExprKind::Err(self.tcx.sess.emit_err(AwaitOnlyInAsyncFnAndBlocks {
await_kw_span,
item_span: self.current_item,
});
}));
}
}
let span = self.mark_span_with_reason(DesugaringKind::Await, await_kw_span, None);
Expand Down Expand Up @@ -919,9 +919,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
) -> hir::ExprKind<'hir> {
let (binder_clause, generic_params) = self.lower_closure_binder(binder);

let (body_id, coroutine_option) = self.with_new_scopes(move |this| {
let prev = this.current_item;
this.current_item = Some(fn_decl_span);
let (body_id, coroutine_option) = self.with_new_scopes(fn_decl_span, move |this| {
let mut coroutine_kind = None;
let body_id = this.lower_fn_body(decl, |this| {
let e = this.lower_expr_mut(body);
Expand All @@ -930,7 +928,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
});
let coroutine_option =
this.coroutine_movability_for_fn(decl, fn_decl_span, coroutine_kind, movability);
this.current_item = prev;
(body_id, coroutine_option)
});

Expand Down Expand Up @@ -1016,7 +1013,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let outer_decl =
FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) };

let body = self.with_new_scopes(|this| {
let body = self.with_new_scopes(fn_decl_span, |this| {
// FIXME(cramertj): allow `async` non-`move` closures with arguments.
if capture_clause == CaptureBy::Ref && !decl.inputs.is_empty() {
this.tcx.sess.emit_err(AsyncNonMoveClosureNotSupported { fn_decl_span });
Expand All @@ -1038,7 +1035,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
async_ret_ty,
body.span,
hir::CoroutineSource::Closure,
|this| this.with_new_scopes(|this| this.lower_expr_mut(body)),
|this| this.with_new_scopes(fn_decl_span, |this| this.lower_expr_mut(body)),
);
let hir_id = this.lower_node_id(inner_closure_id);
this.maybe_forward_track_caller(body.span, closure_hir_id, hir_id);
Expand Down Expand Up @@ -1478,7 +1475,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
match self.coroutine_kind {
Some(hir::CoroutineKind::Gen(_)) => {}
Some(hir::CoroutineKind::Async(_)) => {
self.tcx.sess.emit_err(AsyncCoroutinesNotSupported { span });
return hir::ExprKind::Err(
self.tcx.sess.emit_err(AsyncCoroutinesNotSupported { span }),
);
}
Some(hir::CoroutineKind::Coroutine) | None => {
if !self.tcx.features().coroutines {
Expand Down
5 changes: 1 addition & 4 deletions compiler/rustc_ast_lowering/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -268,9 +268,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
body,
..
}) => {
self.with_new_scopes(|this| {
this.current_item = Some(ident.span);

self.with_new_scopes(ident.span, |this| {
// Note: we don't need to change the return type from `T` to
// `impl Future<Output = T>` here because lower_body
// only cares about the input argument patterns in the function
Expand Down Expand Up @@ -867,7 +865,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
},
),
AssocItemKind::Fn(box Fn { sig, generics, body, .. }) => {
self.current_item = Some(i.span);
let asyncness = sig.header.asyncness;
let body_id = self.lower_maybe_async_body(
i.span,
Expand Down
11 changes: 8 additions & 3 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -839,7 +839,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
result
}

fn with_new_scopes<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> T {
fn with_new_scopes<T>(&mut self, scope_span: Span, f: impl FnOnce(&mut Self) -> T) -> T {
let current_item = self.current_item;
self.current_item = Some(scope_span);

let was_in_loop_condition = self.is_in_loop_condition;
self.is_in_loop_condition = false;

Expand All @@ -851,6 +854,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {

self.is_in_loop_condition = was_in_loop_condition;

self.current_item = current_item;

ret
}

Expand Down Expand Up @@ -1200,7 +1205,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
tokens: None,
};

let ct = self.with_new_scopes(|this| hir::AnonConst {
let ct = self.with_new_scopes(span, |this| hir::AnonConst {
def_id,
hir_id: this.lower_node_id(node_id),
body: this.lower_const_body(path_expr.span, Some(&path_expr)),
Expand Down Expand Up @@ -2207,7 +2212,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}

fn lower_anon_const(&mut self, c: &AnonConst) -> hir::AnonConst {
self.with_new_scopes(|this| hir::AnonConst {
self.with_new_scopes(c.value.span, |this| hir::AnonConst {
def_id: this.local_def_id(c.id),
hir_id: this.lower_node_id(c.id),
body: this.lower_const_body(c.value.span, Some(&c.value)),
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_error_codes/src/error_codes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -653,3 +653,4 @@ E0795: include_str!("./error_codes/E0795.md"),
// E0721, // `await` keyword
// E0723, // unstable feature in `const` context
// E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`.
// E0744, // merged into E0728
4 changes: 3 additions & 1 deletion compiler/rustc_error_codes/src/error_codes/E0744.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
#### Note: this error code is no longer emitted by the compiler.

An unsupported expression was used inside a const context.

Erroneous code example:

```compile_fail,edition2018,E0744
```ignore (removed error code)
const _: i32 = {
async { 0 }.await
};
Expand Down
9 changes: 4 additions & 5 deletions compiler/rustc_passes/src/check_const.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use rustc_middle::ty::TyCtxt;
use rustc_session::parse::feature_err;
use rustc_span::{sym, Span, Symbol};

use crate::errors::{ExprNotAllowedInContext, SkippingConstChecks};
use crate::errors::SkippingConstChecks;

/// An expression that is not *always* legal in a const context.
#[derive(Clone, Copy)]
Expand Down Expand Up @@ -138,11 +138,10 @@ impl<'tcx> CheckConstVisitor<'tcx> {

match missing_gates.as_slice() {
[] => {
tcx.sess.emit_err(ExprNotAllowedInContext {
span_bug!(
span,
expr: expr.name(),
context: const_kind.keyword_name(),
});
"we should not have reached this point, since `.await` is denied earlier"
);
}

[missing_primary, ref missing_secondary @ ..] => {
Expand Down
9 changes: 0 additions & 9 deletions compiler/rustc_passes/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1005,15 +1005,6 @@ pub struct FeaturePreviouslyDeclared<'a, 'b> {
pub prev_declared: &'b str,
}

#[derive(Diagnostic)]
#[diag(passes_expr_not_allowed_in_context, code = "E0744")]
pub struct ExprNotAllowedInContext<'a> {
#[primary_span]
pub span: Span,
pub expr: String,
pub context: &'a str,
}

pub struct BreakNonLoop<'a> {
pub span: Span,
pub head: Option<Span>,
Expand Down
3 changes: 0 additions & 3 deletions tests/ui/async-await/issue-70594.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@
async fn fun() {
[1; ().await];
//~^ error: `await` is only allowed inside `async` functions and blocks
//~| error: `.await` is not allowed in a `const`
//~| error: `.await` is not allowed in a `const`
//~| error: `()` is not a future
}

fn main() {}
37 changes: 6 additions & 31 deletions tests/ui/async-await/issue-70594.stderr
Original file line number Diff line number Diff line change
@@ -1,37 +1,12 @@
error[E0728]: `await` is only allowed inside `async` functions and blocks
--> $DIR/issue-70594.rs:4:12
|
LL | async fn fun() {
| --- this is not `async`
LL | [1; ().await];
| ^^^^^ only allowed inside `async` functions and blocks
| ---^^^^^
| | |
| | only allowed inside `async` functions and blocks
| this is not `async`

error[E0744]: `.await` is not allowed in a `const`
--> $DIR/issue-70594.rs:4:9
|
LL | [1; ().await];
| ^^^^^^^^

error[E0744]: `.await` is not allowed in a `const`
--> $DIR/issue-70594.rs:4:12
|
LL | [1; ().await];
| ^^^^^

error[E0277]: `()` is not a future
--> $DIR/issue-70594.rs:4:12
|
LL | [1; ().await];
| -^^^^^
| ||
| |`()` is not a future
| help: remove the `.await`
|
= help: the trait `Future` is not implemented for `()`
= note: () must be a future or must implement `IntoFuture` to be awaited
= note: required for `()` to implement `IntoFuture`

error: aborting due to 4 previous errors
error: aborting due to 1 previous error

Some errors have detailed explanations: E0277, E0728, E0744.
For more information about an error, try `rustc --explain E0277`.
For more information about this error, try `rustc --explain E0728`.
1 change: 0 additions & 1 deletion tests/ui/async-await/issues/issue-62009-1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,4 @@ fn main() {
//~^ ERROR `await` is only allowed inside `async` functions and blocks
(|_| 2333).await;
//~^ ERROR `await` is only allowed inside `async` functions and blocks
//~| ERROR is not a future
}
18 changes: 2 additions & 16 deletions tests/ui/async-await/issues/issue-62009-1.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,6 @@ LL | fn main() {
LL | (|_| 2333).await;
| ^^^^^ only allowed inside `async` functions and blocks

error[E0277]: `{closure@$DIR/issue-62009-1.rs:12:6: 12:9}` is not a future
--> $DIR/issue-62009-1.rs:12:16
|
LL | (|_| 2333).await;
| -^^^^^
| ||
| |`{closure@$DIR/issue-62009-1.rs:12:6: 12:9}` is not a future
| help: remove the `.await`
|
= help: the trait `Future` is not implemented for closure `{closure@$DIR/issue-62009-1.rs:12:6: 12:9}`
= note: {closure@$DIR/issue-62009-1.rs:12:6: 12:9} must be a future or must implement `IntoFuture` to be awaited
= note: required for `{closure@$DIR/issue-62009-1.rs:12:6: 12:9}` to implement `IntoFuture`

error: aborting due to 4 previous errors
error: aborting due to 3 previous errors

Some errors have detailed explanations: E0277, E0728.
For more information about an error, try `rustc --explain E0277`.
For more information about this error, try `rustc --explain E0728`.

0 comments on commit 8cfdccf

Please sign in to comment.