From ed6c7efd87f17a7d9282f4bc7341cb5cbda8db4d Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 2 Sep 2020 13:25:19 -0700 Subject: [PATCH 1/6] Use enum for status of non-const ops --- .../src/transform/check_consts/ops.rs | 112 ++++++++++-------- 1 file changed, 61 insertions(+), 51 deletions(-) diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs index ea025f208e49d..ff27d0c3a9211 100644 --- a/compiler/rustc_mir/src/transform/check_consts/ops.rs +++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs @@ -14,35 +14,32 @@ use super::ConstCx; pub fn non_const(ccx: &ConstCx<'_, '_>, op: O, span: Span) { debug!("illegal_op: op={:?}", op); - if op.is_allowed_in_item(ccx) { - return; - } + let gate = match op.status_in_item(ccx) { + Status::Allowed => return, + Status::Unstable(gate) if ccx.tcx.features().enabled(gate) => return, + Status::Unstable(gate) => Some(gate), + Status::Forbidden => None, + }; if ccx.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you { - ccx.tcx.sess.miri_unleashed_feature(span, O::feature_gate()); + ccx.tcx.sess.miri_unleashed_feature(span, gate); return; } op.emit_error(ccx, span); } +pub enum Status { + Allowed, + Unstable(Symbol), + Forbidden, +} + /// An operation that is not *always* allowed in a const context. pub trait NonConstOp: std::fmt::Debug { - /// Returns the `Symbol` corresponding to the feature gate that would enable this operation, - /// or `None` if such a feature gate does not exist. - fn feature_gate() -> Option { - None - } - - /// Returns `true` if this operation is allowed in the given item. - /// - /// This check should assume that we are not in a non-const `fn`, where all operations are - /// legal. - /// - /// By default, it returns `true` if and only if this operation has a corresponding feature - /// gate and that gate is enabled. - fn is_allowed_in_item(&self, ccx: &ConstCx<'_, '_>) -> bool { - Self::feature_gate().map_or(false, |gate| ccx.tcx.features().enabled(gate)) + /// Returns an enum indicating whether this operation is allowed within the given item. + fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status { + Status::Forbidden } fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { @@ -53,9 +50,13 @@ pub trait NonConstOp: std::fmt::Debug { "{} contains unimplemented expression type", ccx.const_kind() ); - if let Some(feat) = Self::feature_gate() { - err.help(&format!("add `#![feature({})]` to the crate attributes to enable", feat)); + + if let Status::Unstable(gate) = self.status_in_item(ccx) { + if !ccx.tcx.features().enabled(gate) && nightly_options::is_nightly_build() { + err.help(&format!("add `#![feature({})]` to the crate attributes to enable", gate)); + } } + if ccx.tcx.sess.teach(&err.get_code().unwrap()) { err.note( "A function call isn't allowed in the const's initialization expression \ @@ -182,14 +183,13 @@ impl NonConstOp for CellBorrow { #[derive(Debug)] pub struct MutBorrow; impl NonConstOp for MutBorrow { - fn is_allowed_in_item(&self, ccx: &ConstCx<'_, '_>) -> bool { - // Forbid everywhere except in const fn - ccx.const_kind() == hir::ConstContext::ConstFn - && ccx.tcx.features().enabled(Self::feature_gate().unwrap()) - } - - fn feature_gate() -> Option { - Some(sym::const_mut_refs) + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + // Forbid everywhere except in const fn with a feature gate + if ccx.const_kind() == hir::ConstContext::ConstFn { + Status::Unstable(sym::const_mut_refs) + } else { + Status::Forbidden + } } fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { @@ -201,15 +201,16 @@ impl NonConstOp for MutBorrow { &format!("mutable references are not allowed in {}s", ccx.const_kind()), ) } else { - struct_span_err!( + let mut err = struct_span_err!( ccx.tcx.sess, span, E0764, "mutable references are not allowed in {}s", ccx.const_kind(), - ) + ); + err.span_label(span, format!("`&mut` is only allowed in `const fn`")); + err }; - err.span_label(span, "`&mut` is only allowed in `const fn`".to_string()); if ccx.tcx.sess.teach(&err.get_code().unwrap()) { err.note( "References in statics and constants may only refer \ @@ -226,11 +227,17 @@ impl NonConstOp for MutBorrow { } } +// FIXME(ecstaticmorse): Unify this with `MutBorrow`. It has basically the same issues. #[derive(Debug)] pub struct MutAddressOf; impl NonConstOp for MutAddressOf { - fn feature_gate() -> Option { - Some(sym::const_mut_refs) + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + // Forbid everywhere except in const fn with a feature gate + if ccx.const_kind() == hir::ConstContext::ConstFn { + Status::Unstable(sym::const_mut_refs) + } else { + Status::Forbidden + } } fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { @@ -247,16 +254,16 @@ impl NonConstOp for MutAddressOf { #[derive(Debug)] pub struct MutDeref; impl NonConstOp for MutDeref { - fn feature_gate() -> Option { - Some(sym::const_mut_refs) + fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { + Status::Unstable(sym::const_mut_refs) } } #[derive(Debug)] pub struct Panic; impl NonConstOp for Panic { - fn feature_gate() -> Option { - Some(sym::const_panic) + fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { + Status::Unstable(sym::const_panic) } fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { @@ -289,8 +296,8 @@ impl NonConstOp for RawPtrComparison { #[derive(Debug)] pub struct RawPtrDeref; impl NonConstOp for RawPtrDeref { - fn feature_gate() -> Option { - Some(sym::const_raw_ptr_deref) + fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { + Status::Unstable(sym::const_raw_ptr_deref) } fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { @@ -307,8 +314,8 @@ impl NonConstOp for RawPtrDeref { #[derive(Debug)] pub struct RawPtrToIntCast; impl NonConstOp for RawPtrToIntCast { - fn feature_gate() -> Option { - Some(sym::const_raw_ptr_to_usize_cast) + fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { + Status::Unstable(sym::const_raw_ptr_to_usize_cast) } fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { @@ -326,8 +333,12 @@ impl NonConstOp for RawPtrToIntCast { #[derive(Debug)] pub struct StaticAccess; impl NonConstOp for StaticAccess { - fn is_allowed_in_item(&self, ccx: &ConstCx<'_, '_>) -> bool { - matches!(ccx.const_kind(), hir::ConstContext::Static(_)) + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + if let hir::ConstContext::Static(_) = ccx.const_kind() { + Status::Allowed + } else { + Status::Forbidden + } } fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { @@ -371,14 +382,13 @@ impl NonConstOp for ThreadLocalAccess { #[derive(Debug)] pub struct UnionAccess; impl NonConstOp for UnionAccess { - fn is_allowed_in_item(&self, ccx: &ConstCx<'_, '_>) -> bool { + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { // Union accesses are stable in all contexts except `const fn`. - ccx.const_kind() != hir::ConstContext::ConstFn - || ccx.tcx.features().enabled(Self::feature_gate().unwrap()) - } - - fn feature_gate() -> Option { - Some(sym::const_fn_union) + if ccx.const_kind() != hir::ConstContext::ConstFn { + Status::Allowed + } else { + Status::Unstable(sym::const_fn_union) + } } fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { From c3607bd7dd323a898b8cc9d2c603dfd14172c73c Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 2 Sep 2020 14:35:02 -0700 Subject: [PATCH 2/6] Use helper function for searching `allow_internal_unstable` --- compiler/rustc_mir/src/transform/check_consts/mod.rs | 8 ++++++++ compiler/rustc_mir/src/transform/qualify_min_const_fn.rs | 7 ++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_mir/src/transform/check_consts/mod.rs b/compiler/rustc_mir/src/transform/check_consts/mod.rs index 81c1b0b5bd49f..c1b4cb5f1a8d5 100644 --- a/compiler/rustc_mir/src/transform/check_consts/mod.rs +++ b/compiler/rustc_mir/src/transform/check_consts/mod.rs @@ -4,10 +4,12 @@ //! has interior mutability or needs to be dropped, as well as the visitor that emits errors when //! it finds operations that are invalid in a certain context. +use rustc_attr as attr; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::mir; use rustc_middle::ty::{self, TyCtxt}; +use rustc_span::Symbol; pub use self::qualifs::Qualif; @@ -55,3 +57,9 @@ impl ConstCx<'mir, 'tcx> { pub fn is_lang_panic_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { Some(def_id) == tcx.lang_items().panic_fn() || Some(def_id) == tcx.lang_items().begin_panic_fn() } + +pub fn allow_internal_unstable(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbol) -> bool { + let attrs = tcx.get_attrs(def_id); + attr::allow_internal_unstable(&tcx.sess, attrs) + .map_or(false, |mut features| features.any(|name| name == feature_gate)) +} diff --git a/compiler/rustc_mir/src/transform/qualify_min_const_fn.rs b/compiler/rustc_mir/src/transform/qualify_min_const_fn.rs index 5e102f5151d0c..f15a7f7c2c889 100644 --- a/compiler/rustc_mir/src/transform/qualify_min_const_fn.rs +++ b/compiler/rustc_mir/src/transform/qualify_min_const_fn.rs @@ -1,4 +1,3 @@ -use rustc_attr as attr; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_middle::mir::*; @@ -344,8 +343,7 @@ fn feature_allowed(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbol) -> bo // However, we cannot allow stable `const fn`s to use unstable features without an explicit // opt-in via `allow_internal_unstable`. - attr::allow_internal_unstable(&tcx.sess, &tcx.get_attrs(def_id)) - .map_or(false, |mut features| features.any(|name| name == feature_gate)) + super::check_consts::allow_internal_unstable(tcx, def_id, feature_gate) } /// Returns `true` if the given library feature gate is allowed within the function with the given `DefId`. @@ -364,8 +362,7 @@ pub fn lib_feature_allowed(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbo // However, we cannot allow stable `const fn`s to use unstable features without an explicit // opt-in via `allow_internal_unstable`. - attr::allow_internal_unstable(&tcx.sess, &tcx.get_attrs(def_id)) - .map_or(false, |mut features| features.any(|name| name == feature_gate)) + super::check_consts::allow_internal_unstable(tcx, def_id, feature_gate) } fn check_terminator( From e4edc161f20ccbc77fffb7ceb60ebb6102cbd747 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 2 Sep 2020 14:54:55 -0700 Subject: [PATCH 3/6] Give name to extra `Span` in `LiveDrop` error --- compiler/rustc_mir/src/transform/check_consts/ops.rs | 6 ++++-- .../src/transform/check_consts/post_drop_elaboration.rs | 2 +- compiler/rustc_mir/src/transform/check_consts/validation.rs | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs index ff27d0c3a9211..4af355310ae25 100644 --- a/compiler/rustc_mir/src/transform/check_consts/ops.rs +++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs @@ -148,7 +148,9 @@ pub struct InlineAsm; impl NonConstOp for InlineAsm {} #[derive(Debug)] -pub struct LiveDrop(pub Option); +pub struct LiveDrop { + pub dropped_at: Option, +} impl NonConstOp for LiveDrop { fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { let mut diagnostic = struct_span_err!( @@ -158,7 +160,7 @@ impl NonConstOp for LiveDrop { "destructors cannot be evaluated at compile-time" ); diagnostic.span_label(span, format!("{}s cannot evaluate destructors", ccx.const_kind())); - if let Some(span) = self.0 { + if let Some(span) = self.dropped_at { diagnostic.span_label(span, "value is dropped here"); } diagnostic.emit(); diff --git a/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs b/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs index 55075b3ab5e99..a2e5c905612aa 100644 --- a/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs +++ b/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs @@ -52,7 +52,7 @@ impl std::ops::Deref for CheckLiveDrops<'mir, 'tcx> { impl CheckLiveDrops<'mir, 'tcx> { fn check_live_drop(&self, span: Span) { - ops::non_const(self.ccx, ops::LiveDrop(None), span); + ops::non_const(self.ccx, ops::LiveDrop { dropped_at: None }, span); } } diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index e8411b121e394..ebba7f29663ed 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -576,7 +576,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { if needs_drop { self.check_op_spanned( - ops::LiveDrop(Some(terminator.source_info.span)), + ops::LiveDrop { dropped_at: Some(terminator.source_info.span) }, err_span, ); } From 81b3b66487c7001a0dbadf7f9af41ad714702533 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 2 Sep 2020 17:11:55 -0700 Subject: [PATCH 4/6] Error if an unstable const eval feature is used in a stable const fn --- .../src/transform/check_consts/ops.rs | 26 +++++++++++++++++-- .../check_consts/post_drop_elaboration.rs | 11 +++++--- .../src/transform/check_consts/validation.rs | 2 +- 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs index 4af355310ae25..032cbc23a3f52 100644 --- a/compiler/rustc_mir/src/transform/check_consts/ops.rs +++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs @@ -1,6 +1,6 @@ //! Concrete error types for all operations which may be invalid in a certain const context. -use rustc_errors::struct_span_err; +use rustc_errors::{struct_span_err, Applicability}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_session::config::nightly_options; @@ -16,7 +16,29 @@ pub fn non_const(ccx: &ConstCx<'_, '_>, op: O, span: Span) { let gate = match op.status_in_item(ccx) { Status::Allowed => return, - Status::Unstable(gate) if ccx.tcx.features().enabled(gate) => return, + + Status::Unstable(gate) if ccx.tcx.features().enabled(gate) => { + let unstable_in_stable = ccx.const_kind() == hir::ConstContext::ConstFn + && ccx.tcx.features().enabled(sym::staged_api) + && !ccx.tcx.has_attr(ccx.def_id.to_def_id(), sym::rustc_const_unstable) + && !super::allow_internal_unstable(ccx.tcx, ccx.def_id.to_def_id(), gate); + + if unstable_in_stable { + ccx.tcx.sess + .struct_span_err(span, &format!("`#[feature({})]` cannot be depended on in a const-stable function", gate.as_str())) + .span_suggestion( + ccx.body.span, + "if it is not part of the public API, make this function unstably const", + concat!(r#"#[rustc_const_unstable(feature = "...", issue = "...")]"#, '\n').to_owned(), + Applicability::HasPlaceholders, + ) + .help("otherwise `#[allow_internal_unstable]` can be used to bypass stability checks") + .emit(); + } + + return; + } + Status::Unstable(gate) => Some(gate), Status::Forbidden => None, }; diff --git a/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs b/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs index a2e5c905612aa..0228f2d7de023 100644 --- a/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs +++ b/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs @@ -2,7 +2,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::{self, BasicBlock, Location}; use rustc_middle::ty::TyCtxt; -use rustc_span::Span; +use rustc_span::{sym, Span}; use super::ops; use super::qualifs::{NeedsDrop, Qualif}; @@ -11,7 +11,12 @@ use super::ConstCx; /// Returns `true` if we should use the more precise live drop checker that runs after drop /// elaboration. -pub fn checking_enabled(tcx: TyCtxt<'tcx>) -> bool { +pub fn checking_enabled(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool { + // Const-stable functions must always use the stable live drop checker. + if tcx.features().staged_api && !tcx.has_attr(def_id.to_def_id(), sym::rustc_const_unstable) { + return false; + } + tcx.features().const_precise_live_drops } @@ -25,7 +30,7 @@ pub fn check_live_drops(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &mir::Body< return; } - if !checking_enabled(tcx) { + if !checking_enabled(tcx, def_id) { return; } diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index ebba7f29663ed..0501302b7610a 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -551,7 +551,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { | TerminatorKind::DropAndReplace { place: dropped_place, .. } => { // If we are checking live drops after drop-elaboration, don't emit duplicate // errors here. - if super::post_drop_elaboration::checking_enabled(self.tcx) { + if super::post_drop_elaboration::checking_enabled(self.tcx, self.def_id) { return; } From 1e1257b8f87d1e3073020df27765dc57fcf2c0cd Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 16 Sep 2020 13:09:46 -0700 Subject: [PATCH 5/6] Bless `miri-unleashed` tests `const_mut_refs` doesn't actually work in a `const` or `static` --- src/test/ui/consts/miri_unleashed/box.stderr | 2 +- .../ui/consts/miri_unleashed/mutable_references.stderr | 8 ++++---- .../consts/miri_unleashed/mutable_references_err.stderr | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/test/ui/consts/miri_unleashed/box.stderr b/src/test/ui/consts/miri_unleashed/box.stderr index 768b795ca5b39..66ea9d5924dfb 100644 --- a/src/test/ui/consts/miri_unleashed/box.stderr +++ b/src/test/ui/consts/miri_unleashed/box.stderr @@ -21,7 +21,7 @@ help: skipping check for `const_mut_refs` feature | LL | &mut *(box 0) | ^^^^^^^^^^^^^ -help: skipping check for `const_mut_refs` feature +help: skipping check that does not even have a feature gate --> $DIR/box.rs:10:5 | LL | &mut *(box 0) diff --git a/src/test/ui/consts/miri_unleashed/mutable_references.stderr b/src/test/ui/consts/miri_unleashed/mutable_references.stderr index 7109ffd8b61d7..c6180c1e0041c 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_references.stderr +++ b/src/test/ui/consts/miri_unleashed/mutable_references.stderr @@ -6,17 +6,17 @@ LL | *OH_YES = 99; warning: skipping const checks | -help: skipping check for `const_mut_refs` feature +help: skipping check that does not even have a feature gate --> $DIR/mutable_references.rs:9:26 | LL | static FOO: &&mut u32 = &&mut 42; | ^^^^^^^ -help: skipping check for `const_mut_refs` feature +help: skipping check that does not even have a feature gate --> $DIR/mutable_references.rs:13:23 | LL | static BAR: &mut () = &mut (); | ^^^^^^^ -help: skipping check for `const_mut_refs` feature +help: skipping check that does not even have a feature gate --> $DIR/mutable_references.rs:18:28 | LL | static BOO: &mut Foo<()> = &mut Foo(()); @@ -26,7 +26,7 @@ help: skipping check that does not even have a feature gate | LL | x: &UnsafeCell::new(42), | ^^^^^^^^^^^^^^^^^^^^ -help: skipping check for `const_mut_refs` feature +help: skipping check that does not even have a feature gate --> $DIR/mutable_references.rs:30:27 | LL | static OH_YES: &mut i32 = &mut 42; diff --git a/src/test/ui/consts/miri_unleashed/mutable_references_err.stderr b/src/test/ui/consts/miri_unleashed/mutable_references_err.stderr index 45e7d5a2cc3b3..7647a9ff4f6e4 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_references_err.stderr +++ b/src/test/ui/consts/miri_unleashed/mutable_references_err.stderr @@ -30,7 +30,7 @@ help: skipping check that does not even have a feature gate | LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: skipping check for `const_mut_refs` feature +help: skipping check that does not even have a feature gate --> $DIR/mutable_references_err.rs:30:25 | LL | const BLUNT: &mut i32 = &mut 42; From abc71677da866fd36c70790e768f36d2f809c493 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 16 Sep 2020 13:19:45 -0700 Subject: [PATCH 6/6] Test that `const_precise_live_drops` can't be depended upon stably --- .../stable-precise-live-drops-in-libcore.rs | 22 ++++++++++++++++++ ...table-precise-live-drops-in-libcore.stderr | 12 ++++++++++ .../unstable-precise-live-drops-in-libcore.rs | 23 +++++++++++++++++++ 3 files changed, 57 insertions(+) create mode 100644 src/test/ui/consts/stable-precise-live-drops-in-libcore.rs create mode 100644 src/test/ui/consts/stable-precise-live-drops-in-libcore.stderr create mode 100644 src/test/ui/consts/unstable-precise-live-drops-in-libcore.rs diff --git a/src/test/ui/consts/stable-precise-live-drops-in-libcore.rs b/src/test/ui/consts/stable-precise-live-drops-in-libcore.rs new file mode 100644 index 0000000000000..651462d7ef19c --- /dev/null +++ b/src/test/ui/consts/stable-precise-live-drops-in-libcore.rs @@ -0,0 +1,22 @@ +#![stable(feature = "core", since = "1.6.0")] +#![feature(staged_api)] +#![feature(const_precise_live_drops, const_fn)] + +enum Either { + Left(T), + Right(S), +} + +impl Either { + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "foo", since = "1.0.0")] + pub const fn unwrap(self) -> T { + //~^ ERROR destructors cannot be evaluated at compile-time + match self { + Self::Left(t) => t, + Self::Right(t) => t, + } + } +} + +fn main() {} diff --git a/src/test/ui/consts/stable-precise-live-drops-in-libcore.stderr b/src/test/ui/consts/stable-precise-live-drops-in-libcore.stderr new file mode 100644 index 0000000000000..a3f513541dd6a --- /dev/null +++ b/src/test/ui/consts/stable-precise-live-drops-in-libcore.stderr @@ -0,0 +1,12 @@ +error[E0493]: destructors cannot be evaluated at compile-time + --> $DIR/stable-precise-live-drops-in-libcore.rs:13:25 + | +LL | pub const fn unwrap(self) -> T { + | ^^^^ constant functions cannot evaluate destructors +... +LL | } + | - value is dropped here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0493`. diff --git a/src/test/ui/consts/unstable-precise-live-drops-in-libcore.rs b/src/test/ui/consts/unstable-precise-live-drops-in-libcore.rs new file mode 100644 index 0000000000000..619084eaa517a --- /dev/null +++ b/src/test/ui/consts/unstable-precise-live-drops-in-libcore.rs @@ -0,0 +1,23 @@ +// check-pass + +#![stable(feature = "core", since = "1.6.0")] +#![feature(staged_api)] +#![feature(const_precise_live_drops)] + +enum Either { + Left(T), + Right(S), +} + +impl Either { + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "foo", issue = "none")] + pub const fn unwrap(self) -> T { + match self { + Self::Left(t) => t, + Self::Right(t) => t, + } + } +} + +fn main() {}