diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs index 25ed7859d2187..32e233e337da3 100644 --- a/compiler/rustc_mir/src/transform/check_consts/ops.rs +++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs @@ -151,14 +151,15 @@ impl NonConstOp for FnPtrCast { } #[derive(Debug)] -pub struct Generator; +pub struct Generator(pub hir::GeneratorKind); impl NonConstOp for Generator { fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { Status::Forbidden } fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { - ccx.tcx.sess.struct_span_err(span, "Generators and `async` functions cannot be `const`") + let msg = format!("{}s are not allowed in {}s", self.0, ccx.const_kind()); + ccx.tcx.sess.struct_span_err(span, &msg) } } diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index ab63fd03a336e..4e714bfeed310 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -770,6 +770,14 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { return; } + // `async` blocks get lowered to `std::future::from_generator(/* a closure */)`. + let is_async_block = Some(callee) == tcx.lang_items().from_generator_fn(); + if is_async_block { + let kind = hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block); + self.check_op(ops::Generator(kind)); + return; + } + // HACK: This is to "unstabilize" the `transmute` intrinsic // within const fns. `transmute` is allowed in all other const contexts. // This won't really scale to more intrinsics or functions. Let's allow const @@ -869,7 +877,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { TerminatorKind::Abort => self.check_op(ops::Abort), TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => { - self.check_op(ops::Generator) + self.check_op(ops::Generator(hir::GeneratorKind::Gen)) } TerminatorKind::Assert { .. } diff --git a/src/test/ui/consts/async-block.rs b/src/test/ui/consts/async-block.rs new file mode 100644 index 0000000000000..1fa2a6160913e --- /dev/null +++ b/src/test/ui/consts/async-block.rs @@ -0,0 +1,8 @@ +// From + +// edition:2018 + +const _: i32 = { core::mem::ManuallyDrop::new(async { 0 }); 4 }; +//~^ `async` block + +fn main() {} diff --git a/src/test/ui/consts/async-block.stderr b/src/test/ui/consts/async-block.stderr new file mode 100644 index 0000000000000..99f470623ac32 --- /dev/null +++ b/src/test/ui/consts/async-block.stderr @@ -0,0 +1,8 @@ +error: `async` blocks are not allowed in constants + --> $DIR/async-block.rs:5:47 + | +LL | const _: i32 = { core::mem::ManuallyDrop::new(async { 0 }); 4 }; + | ^^^^^^^^^^^ + +error: aborting due to previous error +