diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs index 015a4aa94cd42..963654e466b58 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -7,6 +7,7 @@ use rustc_hir::LangItem; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::mir; use rustc_middle::mir::*; +use rustc_middle::ty::TypeVisitableExt; use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty}; use rustc_trait_selection::traits::{ self, ImplSource, Obligation, ObligationCause, ObligationCtxt, SelectionContext, @@ -91,7 +92,8 @@ impl Qualif for HasMutInterior { } fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool { - !ty.is_freeze(cx.tcx, cx.param_env) + // Pessimistically assume opaque types are `!Freeze` + ty.has_opaque_types() || !ty.is_freeze(cx.tcx, cx.param_env) } fn in_adt_inherently<'tcx>( diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index fa8257cf9849c..e703b2f518e6a 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -19,6 +19,7 @@ extern crate tracing; #[macro_use] extern crate rustc_middle; +use hir::ConstContext; use required_consts::RequiredConstsVisitor; use rustc_const_eval::util; use rustc_data_structures::fx::FxIndexSet; @@ -231,8 +232,12 @@ fn mir_const_qualif(tcx: TyCtxt<'_>, def: LocalDefId) -> ConstQualifs { let const_kind = tcx.hir().body_const_context(def); // No need to const-check a non-const `fn`. - if const_kind.is_none() { - return Default::default(); + match const_kind { + Some(ConstContext::Const | ConstContext::Static(_)) | Some(ConstContext::ConstFn) => {} + None => span_bug!( + tcx.def_span(def), + "`mir_const_qualif` should only be called on const fns and const items" + ), } // N.B., this `borrow()` is guaranteed to be valid (i.e., the value @@ -297,7 +302,21 @@ fn mir_promoted( // Ensure that we compute the `mir_const_qualif` for constants at // this point, before we steal the mir-const result. // Also this means promotion can rely on all const checks having been done. - let const_qualifs = tcx.mir_const_qualif(def); + + let const_qualifs = match tcx.def_kind(def) { + DefKind::Fn | DefKind::AssocFn | DefKind::Closure + if tcx.constness(def) == hir::Constness::Const + || tcx.is_const_default_method(def.to_def_id()) => + { + tcx.mir_const_qualif(def) + } + DefKind::AssocConst + | DefKind::Const + | DefKind::Static(_) + | DefKind::InlineConst + | DefKind::AnonConst => tcx.mir_const_qualif(def), + _ => ConstQualifs::default(), + }; let mut body = tcx.mir_const(def).steal(); if let Some(error_reported) = const_qualifs.tainted_by_errors { body.tainted_by_errors = Some(error_reported); diff --git a/tests/ui/consts/const-fn-cycle-tait.rs b/tests/ui/consts/const-fn-cycle-tait.rs new file mode 100644 index 0000000000000..f8a63ea00c961 --- /dev/null +++ b/tests/ui/consts/const-fn-cycle-tait.rs @@ -0,0 +1,17 @@ +#![feature(type_alias_impl_trait)] + +//! Test that we pessimistically assume the `Drop` impl of +//! a hidden type is not const. + +pub struct Parser(H); + +type Tait = impl Sized; + +const fn constrain() -> Tait {} + +pub const fn take(_: Tait) {} +//~^ ERROR: destructor of `Tait` cannot be evaluated at compile-time + +fn main() { + println!("Hello, world!"); +} diff --git a/tests/ui/consts/const-fn-cycle-tait.stderr b/tests/ui/consts/const-fn-cycle-tait.stderr new file mode 100644 index 0000000000000..3e025178a25bc --- /dev/null +++ b/tests/ui/consts/const-fn-cycle-tait.stderr @@ -0,0 +1,11 @@ +error[E0493]: destructor of `Tait` cannot be evaluated at compile-time + --> $DIR/const-fn-cycle-tait.rs:12:19 + | +LL | pub const fn take(_: Tait) {} + | ^ - value is dropped here + | | + | the destructor for this type cannot be evaluated in constant functions + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0493`. diff --git a/tests/ui/consts/const-fn-cycle.rs b/tests/ui/consts/const-fn-cycle.rs new file mode 100644 index 0000000000000..033f9f0a1a735 --- /dev/null +++ b/tests/ui/consts/const-fn-cycle.rs @@ -0,0 +1,29 @@ +//! Discovered in https://github.com/rust-lang/rust/issues/112602. +//! This caused a cycle error, which made no sense. +//! Removing the `const` part of the `many` function would make the +//! test pass again. +//! The issue was that we were running const qualif checks on +//! `const fn`s, but never using them. During const qualif checks we tend +//! to end up revealing opaque types (the RPIT in `many`'s return type), +//! which can quickly lead to cycles. + +// check-pass + +pub struct Parser(H); + +impl Parser +where + H: for<'a> Fn(&'a str) -> T, +{ + pub const fn new(handler: H) -> Parser { + Parser(handler) + } + + pub const fn many<'s>(&'s self) -> Parser Fn(&'a str) -> Vec + 's> { + Parser::new(|_| unimplemented!()) + } +} + +fn main() { + println!("Hello, world!"); +} diff --git a/tests/ui/consts/const-promoted-opaque.atomic.stderr b/tests/ui/consts/const-promoted-opaque.atomic.stderr new file mode 100644 index 0000000000000..38c3cadab056a --- /dev/null +++ b/tests/ui/consts/const-promoted-opaque.atomic.stderr @@ -0,0 +1,41 @@ +error[E0493]: destructor of `Foo` cannot be evaluated at compile-time + --> $DIR/const-promoted-opaque.rs:25:26 + | +LL | let _: &'static _ = &FOO; + | ^^^ the destructor for this type cannot be evaluated in constants +... +LL | }; + | - value is dropped here + +error[E0716]: temporary value dropped while borrowed + --> $DIR/const-promoted-opaque.rs:25:26 + | +LL | let _: &'static _ = &FOO; + | ---------- ^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | }; + | - temporary value is freed at the end of this statement + +error[E0492]: constants cannot refer to interior mutable data + --> $DIR/const-promoted-opaque.rs:30:19 + | +LL | const BAZ: &Foo = &FOO; + | ^^^^ this borrow of an interior mutable value may end up in the final value + +error[E0716]: temporary value dropped while borrowed + --> $DIR/const-promoted-opaque.rs:34:26 + | +LL | let _: &'static _ = &FOO; + | ---------- ^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | +LL | } + | - temporary value is freed at the end of this statement + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0492, E0493, E0716. +For more information about an error, try `rustc --explain E0492`. diff --git a/tests/ui/consts/const-promoted-opaque.rs b/tests/ui/consts/const-promoted-opaque.rs new file mode 100644 index 0000000000000..265cfa44b2f55 --- /dev/null +++ b/tests/ui/consts/const-promoted-opaque.rs @@ -0,0 +1,36 @@ +// revisions: string unit atomic +#![feature(type_alias_impl_trait)] + +//! Check that we do not cause cycle errors when trying to +//! obtain information about interior mutability of an opaque type. +//! This used to happen, because when the body-analysis failed, we +//! checked the type instead, but the constant was also defining the +//! hidden type of the opaque type. Thus we ended up relying on the +//! result of our analysis to compute the result of our analysis. + +//[unit] check-pass + +type Foo = impl Sized; + +#[cfg(string)] +const FOO: Foo = String::new(); + +#[cfg(atomic)] +const FOO: Foo = std::sync::atomic::AtomicU8::new(42); + +#[cfg(unit)] +const FOO: Foo = (); + +const BAR: () = { + let _: &'static _ = &FOO; + //[string,atomic]~^ ERROR: destructor of `Foo` cannot be evaluated at compile-time + //[string,atomic]~| ERROR: temporary value dropped while borrowed +}; + +const BAZ: &Foo = &FOO; +//[string,atomic]~^ ERROR: constants cannot refer to interior mutable data + +fn main() { + let _: &'static _ = &FOO; + //[string,atomic]~^ ERROR: temporary value dropped while borrowed +} diff --git a/tests/ui/consts/const-promoted-opaque.string.stderr b/tests/ui/consts/const-promoted-opaque.string.stderr new file mode 100644 index 0000000000000..38c3cadab056a --- /dev/null +++ b/tests/ui/consts/const-promoted-opaque.string.stderr @@ -0,0 +1,41 @@ +error[E0493]: destructor of `Foo` cannot be evaluated at compile-time + --> $DIR/const-promoted-opaque.rs:25:26 + | +LL | let _: &'static _ = &FOO; + | ^^^ the destructor for this type cannot be evaluated in constants +... +LL | }; + | - value is dropped here + +error[E0716]: temporary value dropped while borrowed + --> $DIR/const-promoted-opaque.rs:25:26 + | +LL | let _: &'static _ = &FOO; + | ---------- ^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | }; + | - temporary value is freed at the end of this statement + +error[E0492]: constants cannot refer to interior mutable data + --> $DIR/const-promoted-opaque.rs:30:19 + | +LL | const BAZ: &Foo = &FOO; + | ^^^^ this borrow of an interior mutable value may end up in the final value + +error[E0716]: temporary value dropped while borrowed + --> $DIR/const-promoted-opaque.rs:34:26 + | +LL | let _: &'static _ = &FOO; + | ---------- ^^^ creates a temporary value which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | +LL | } + | - temporary value is freed at the end of this statement + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0492, E0493, E0716. +For more information about an error, try `rustc --explain E0492`.