diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 8a3950718d7d2..207359ed6968f 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -911,7 +911,7 @@ impl Generator for Pin> { } } -#[unstable(feature = "futures_api", issue = "50547")] +#[stable(feature = "futures_api", since = "1.36.0")] impl Future for Box { type Output = F::Output; diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 63b3fbbdaefe1..eb673488170b6 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -85,7 +85,6 @@ #![feature(fmt_internals)] #![feature(fn_traits)] #![feature(fundamental)] -#![feature(futures_api)] #![feature(lang_items)] #![feature(libc)] #![feature(needs_allocator)] diff --git a/src/libcore/future/future.rs b/src/libcore/future/future.rs index e1ab67873a025..504330a023b31 100644 --- a/src/libcore/future/future.rs +++ b/src/libcore/future/future.rs @@ -1,6 +1,4 @@ -#![unstable(feature = "futures_api", - reason = "futures in libcore are unstable", - issue = "50547")] +#![stable(feature = "futures_api", since = "1.36.0")] use crate::marker::Unpin; use crate::ops; @@ -26,8 +24,10 @@ use crate::task::{Context, Poll}; /// `await!` the value. #[doc(spotlight)] #[must_use = "futures do nothing unless polled"] +#[stable(feature = "futures_api", since = "1.36.0")] pub trait Future { /// The type of value produced on completion. + #[stable(feature = "futures_api", since = "1.36.0")] type Output; /// Attempt to resolve the future to a final value, registering @@ -92,9 +92,11 @@ pub trait Future { /// [`Context`]: ../task/struct.Context.html /// [`Waker`]: ../task/struct.Waker.html /// [`Waker::wake`]: ../task/struct.Waker.html#method.wake + #[stable(feature = "futures_api", since = "1.36.0")] fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll; } +#[stable(feature = "futures_api", since = "1.36.0")] impl Future for &mut F { type Output = F::Output; @@ -103,6 +105,7 @@ impl Future for &mut F { } } +#[stable(feature = "futures_api", since = "1.36.0")] impl

Future for Pin

where P: Unpin + ops::DerefMut, diff --git a/src/libcore/future/mod.rs b/src/libcore/future/mod.rs index 6693ecbac41fa..89ea4713cfdaa 100644 --- a/src/libcore/future/mod.rs +++ b/src/libcore/future/mod.rs @@ -1,8 +1,7 @@ -#![unstable(feature = "futures_api", - reason = "futures in libcore are unstable", - issue = "50547")] +#![stable(feature = "futures_api", since = "1.36.0")] //! Asynchronous values. mod future; +#[stable(feature = "futures_api", since = "1.36.0")] pub use self::future::Future; diff --git a/src/libcore/task/mod.rs b/src/libcore/task/mod.rs index 29bae69ea83c1..ef090928392cd 100644 --- a/src/libcore/task/mod.rs +++ b/src/libcore/task/mod.rs @@ -1,11 +1,11 @@ -#![unstable(feature = "futures_api", - reason = "futures in libcore are unstable", - issue = "50547")] +#![stable(feature = "futures_api", since = "1.36.0")] //! Types and Traits for working with asynchronous tasks. mod poll; +#[stable(feature = "futures_api", since = "1.36.0")] pub use self::poll::Poll; mod wake; +#[stable(feature = "futures_api", since = "1.36.0")] pub use self::wake::{Context, Waker, RawWaker, RawWakerVTable}; diff --git a/src/libcore/task/poll.rs b/src/libcore/task/poll.rs index ecf03afb88e2a..3db70d5e7645f 100644 --- a/src/libcore/task/poll.rs +++ b/src/libcore/task/poll.rs @@ -1,6 +1,4 @@ -#![unstable(feature = "futures_api", - reason = "futures in libcore are unstable", - issue = "50547")] +#![stable(feature = "futures_api", since = "1.36.0")] use crate::ops::Try; use crate::result::Result; @@ -9,20 +7,27 @@ use crate::result::Result; /// scheduled to receive a wakeup instead. #[must_use = "this `Poll` may be a `Pending` variant, which should be handled"] #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[stable(feature = "futures_api", since = "1.36.0")] pub enum Poll { /// Represents that a value is immediately ready. - Ready(T), + #[stable(feature = "futures_api", since = "1.36.0")] + Ready( + #[stable(feature = "futures_api", since = "1.36.0")] + T + ), /// Represents that a value is not ready yet. /// /// When a function returns `Pending`, the function *must* also /// ensure that the current task is scheduled to be awoken when /// progress can be made. + #[stable(feature = "futures_api", since = "1.36.0")] Pending, } impl Poll { /// Changes the ready value of this `Poll` with the closure provided. + #[stable(feature = "futures_api", since = "1.36.0")] pub fn map(self, f: F) -> Poll where F: FnOnce(T) -> U { @@ -34,6 +39,7 @@ impl Poll { /// Returns `true` if this is `Poll::Ready` #[inline] + #[stable(feature = "futures_api", since = "1.36.0")] pub fn is_ready(&self) -> bool { match *self { Poll::Ready(_) => true, @@ -43,6 +49,7 @@ impl Poll { /// Returns `true` if this is `Poll::Pending` #[inline] + #[stable(feature = "futures_api", since = "1.36.0")] pub fn is_pending(&self) -> bool { !self.is_ready() } @@ -50,6 +57,7 @@ impl Poll { impl Poll> { /// Changes the success value of this `Poll` with the closure provided. + #[stable(feature = "futures_api", since = "1.36.0")] pub fn map_ok(self, f: F) -> Poll> where F: FnOnce(T) -> U { @@ -61,6 +69,7 @@ impl Poll> { } /// Changes the error value of this `Poll` with the closure provided. + #[stable(feature = "futures_api", since = "1.36.0")] pub fn map_err(self, f: F) -> Poll> where F: FnOnce(E) -> U { @@ -72,12 +81,14 @@ impl Poll> { } } +#[stable(feature = "futures_api", since = "1.36.0")] impl From for Poll { fn from(t: T) -> Poll { Poll::Ready(t) } } +#[stable(feature = "futures_api", since = "1.36.0")] impl Try for Poll> { type Ok = Poll; type Error = E; @@ -102,6 +113,7 @@ impl Try for Poll> { } } +#[stable(feature = "futures_api", since = "1.36.0")] impl Try for Poll>> { type Ok = Poll>; type Error = E; diff --git a/src/libcore/task/wake.rs b/src/libcore/task/wake.rs index 94e31054a5812..b4e9124983205 100644 --- a/src/libcore/task/wake.rs +++ b/src/libcore/task/wake.rs @@ -1,6 +1,4 @@ -#![unstable(feature = "futures_api", - reason = "futures in libcore are unstable", - issue = "50547")] +#![stable(feature = "futures_api", since = "1.36.0")] use crate::fmt; use crate::marker::{PhantomData, Unpin}; @@ -13,6 +11,7 @@ use crate::marker::{PhantomData, Unpin}; /// It consists of a data pointer and a [virtual function pointer table (vtable)][vtable] that /// customizes the behavior of the `RawWaker`. #[derive(PartialEq, Debug)] +#[stable(feature = "futures_api", since = "1.36.0")] pub struct RawWaker { /// A data pointer, which can be used to store arbitrary data as required /// by the executor. This could be e.g. a type-erased pointer to an `Arc` @@ -37,9 +36,7 @@ impl RawWaker { /// from a `RawWaker`. For each operation on the `Waker`, the associated /// function in the `vtable` of the underlying `RawWaker` will be called. #[rustc_promotable] - #[unstable(feature = "futures_api", - reason = "futures in libcore are unstable", - issue = "50547")] + #[stable(feature = "futures_api", since = "1.36.0")] pub const fn new(data: *const (), vtable: &'static RawWakerVTable) -> RawWaker { RawWaker { data, @@ -58,6 +55,7 @@ impl RawWaker { /// pointer of a properly constructed [`RawWaker`] object from inside the /// [`RawWaker`] implementation. Calling one of the contained functions using /// any other `data` pointer will cause undefined behavior. +#[stable(feature = "futures_api", since = "1.36.0")] #[derive(PartialEq, Copy, Clone, Debug)] pub struct RawWakerVTable { /// This function will be called when the [`RawWaker`] gets cloned, e.g. when @@ -131,9 +129,14 @@ impl RawWakerVTable { /// resources that are associated with this instance of a [`RawWaker`] and /// associated task. #[rustc_promotable] - #[unstable(feature = "futures_api", - reason = "futures in libcore are unstable", - issue = "50547")] + #[cfg_attr(stage0, unstable(feature = "futures_api_const_fn_ptr", issue = "50547"))] + #[cfg_attr(not(stage0), stable(feature = "futures_api", since = "1.36.0"))] + // `rustc_allow_const_fn_ptr` is a hack that should not be used anywhere else + // without first consulting with T-Lang. + // + // FIXME: remove whenever we have a stable way to accept fn pointers from const fn + // (see https://github.com/rust-rfcs/const-eval/issues/19#issuecomment-472799062) + #[cfg_attr(not(stage0), rustc_allow_const_fn_ptr)] pub const fn new( clone: unsafe fn(*const ()) -> RawWaker, wake: unsafe fn(*const ()), @@ -153,6 +156,7 @@ impl RawWakerVTable { /// /// Currently, `Context` only serves to provide access to a `&Waker` /// which can be used to wake the current task. +#[stable(feature = "futures_api", since = "1.36.0")] pub struct Context<'a> { waker: &'a Waker, // Ensure we future-proof against variance changes by forcing @@ -164,6 +168,7 @@ pub struct Context<'a> { impl<'a> Context<'a> { /// Create a new `Context` from a `&Waker`. + #[stable(feature = "futures_api", since = "1.36.0")] #[inline] pub fn from_waker(waker: &'a Waker) -> Self { Context { @@ -173,12 +178,14 @@ impl<'a> Context<'a> { } /// Returns a reference to the `Waker` for the current task. + #[stable(feature = "futures_api", since = "1.36.0")] #[inline] pub fn waker(&self) -> &'a Waker { &self.waker } } +#[stable(feature = "futures_api", since = "1.36.0")] impl fmt::Debug for Context<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Context") @@ -195,17 +202,22 @@ impl fmt::Debug for Context<'_> { /// /// Implements [`Clone`], [`Send`], and [`Sync`]. #[repr(transparent)] +#[stable(feature = "futures_api", since = "1.36.0")] pub struct Waker { waker: RawWaker, } +#[stable(feature = "futures_api", since = "1.36.0")] impl Unpin for Waker {} +#[stable(feature = "futures_api", since = "1.36.0")] unsafe impl Send for Waker {} +#[stable(feature = "futures_api", since = "1.36.0")] unsafe impl Sync for Waker {} impl Waker { /// Wake up the task associated with this `Waker`. #[inline] + #[stable(feature = "futures_api", since = "1.36.0")] pub fn wake(self) { // The actual wakeup call is delegated through a virtual function call // to the implementation which is defined by the executor. @@ -227,6 +239,7 @@ impl Waker { /// where an owned `Waker` is available. This method should be preferred to /// calling `waker.clone().wake()`. #[inline] + #[stable(feature = "futures_api", since = "1.36.0")] pub fn wake_by_ref(&self) { // The actual wakeup call is delegated through a virtual function call // to the implementation which is defined by the executor. @@ -243,6 +256,7 @@ impl Waker { /// /// This function is primarily used for optimization purposes. #[inline] + #[stable(feature = "futures_api", since = "1.36.0")] pub fn will_wake(&self, other: &Waker) -> bool { self.waker == other.waker } @@ -253,6 +267,7 @@ impl Waker { /// in [`RawWaker`]'s and [`RawWakerVTable`]'s documentation is not upheld. /// Therefore this method is unsafe. #[inline] + #[stable(feature = "futures_api", since = "1.36.0")] pub unsafe fn from_raw(waker: RawWaker) -> Waker { Waker { waker, @@ -260,6 +275,7 @@ impl Waker { } } +#[stable(feature = "futures_api", since = "1.36.0")] impl Clone for Waker { #[inline] fn clone(&self) -> Self { @@ -272,6 +288,7 @@ impl Clone for Waker { } } +#[stable(feature = "futures_api", since = "1.36.0")] impl Drop for Waker { #[inline] fn drop(&mut self) { @@ -282,6 +299,7 @@ impl Drop for Waker { } } +#[stable(feature = "futures_api", since = "1.36.0")] impl fmt::Debug for Waker { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let vtable_ptr = self.waker.vtable as *const RawWakerVTable; diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index 496ccc888b61a..40cce8e77c0e0 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -121,6 +121,7 @@ impl_stable_hash_for!(struct ::syntax::attr::Stability { feature, rustc_depr, promotable, + allow_const_fn_ptr, const_stability }); diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index ef1270d304523..8ce86f70a551f 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -441,6 +441,7 @@ impl<'a, 'tcx> Index<'tcx> { rustc_depr: None, const_stability: None, promotable: false, + allow_const_fn_ptr: false, }); annotator.parent_stab = Some(stability); } diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 555374a138c43..bf2a1eaafd664 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -4,7 +4,7 @@ use crate::hir::def::{CtorKind, Namespace}; use crate::hir::def_id::DefId; -use crate::hir::{self, HirId, InlineAsm as HirInlineAsm}; +use crate::hir::{self, InlineAsm as HirInlineAsm}; use crate::mir::interpret::{ConstValue, InterpError, Scalar}; use crate::mir::visit::MirVisitable; use rustc_apfloat::ieee::{Double, Single}; @@ -138,16 +138,20 @@ pub struct Mir<'tcx> { /// If this MIR was built for a constant, this will be 0. pub arg_count: usize, - /// Names and capture modes of all the closure upvars, assuming - /// the first argument is either the closure or a reference to it. - pub upvar_decls: Vec, - /// Mark an argument local (which must be a tuple) as getting passed as /// its individual components at the LLVM level. /// /// This is used for the "rust-call" ABI. pub spread_arg: Option, + /// Names and capture modes of all the closure upvars, assuming + /// the first argument is either the closure or a reference to it. + // NOTE(eddyb) This is *strictly* a temporary hack for codegen + // debuginfo generation, and will be removed at some point. + // Do **NOT** use it for anything else, upvar information should not be + // in the MIR, please rely on local crate HIR or other side-channels. + pub __upvar_debuginfo_codegen_only_do_not_use: Vec, + /// Mark this MIR of a const context other than const functions as having converted a `&&` or /// `||` expression into `&` or `|` respectively. This is problematic because if we ever stop /// this conversion from happening and use short circuiting, we will cause the following code @@ -173,7 +177,7 @@ impl<'tcx> Mir<'tcx> { local_decls: LocalDecls<'tcx>, user_type_annotations: CanonicalUserTypeAnnotations<'tcx>, arg_count: usize, - upvar_decls: Vec, + __upvar_debuginfo_codegen_only_do_not_use: Vec, span: Span, control_flow_destroyed: Vec<(Span, String)>, ) -> Self { @@ -197,7 +201,7 @@ impl<'tcx> Mir<'tcx> { local_decls, user_type_annotations, arg_count, - upvar_decls, + __upvar_debuginfo_codegen_only_do_not_use, spread_arg: None, span, cache: cache::Cache::new(), @@ -431,7 +435,7 @@ impl_stable_hash_for!(struct Mir<'tcx> { local_decls, user_type_annotations, arg_count, - upvar_decls, + __upvar_debuginfo_codegen_only_do_not_use, spread_arg, control_flow_destroyed, span, @@ -983,16 +987,11 @@ impl<'tcx> LocalDecl<'tcx> { /// A closure capture, with its name and mode. #[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] -pub struct UpvarDecl { +pub struct UpvarDebuginfo { pub debug_name: Name, - /// `HirId` of the captured variable - pub var_hir_id: ClearCrossCrate, - /// If true, the capture is behind a reference. pub by_ref: bool, - - pub mutability: Mutability, } /////////////////////////////////////////////////////////////////////////// @@ -3156,7 +3155,7 @@ CloneTypeFoldableAndLiftImpls! { MirPhase, Mutability, SourceInfo, - UpvarDecl, + UpvarDebuginfo, FakeReadCause, RetagKind, SourceScope, @@ -3178,7 +3177,7 @@ BraceStructTypeFoldableImpl! { local_decls, user_type_annotations, arg_count, - upvar_decls, + __upvar_debuginfo_codegen_only_do_not_use, spread_arg, control_flow_destroyed, span, diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index 23be1bbf6c687..04b763f773d9e 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -133,41 +133,6 @@ impl<'tcx> Place<'tcx> { proj.base.ty(local_decls, tcx).projection_ty(tcx, &proj.elem), } } - - /// If this is a field projection, and the field is being projected from a closure type, - /// then returns the index of the field being projected. Note that this closure will always - /// be `self` in the current MIR, because that is the only time we directly access the fields - /// of a closure type. - pub fn is_upvar_field_projection<'cx, 'gcx>(&self, mir: &'cx Mir<'tcx>, - tcx: &TyCtxt<'cx, 'gcx, 'tcx>) -> Option { - let (place, by_ref) = if let Place::Projection(ref proj) = self { - if let ProjectionElem::Deref = proj.elem { - (&proj.base, true) - } else { - (self, false) - } - } else { - (self, false) - }; - - match place { - Place::Projection(ref proj) => match proj.elem { - ProjectionElem::Field(field, _ty) => { - let base_ty = proj.base.ty(mir, *tcx).ty; - - if (base_ty.is_closure() || base_ty.is_generator()) && - (!by_ref || mir.upvar_decls[field.index()].by_ref) - { - Some(field) - } else { - None - } - }, - _ => None, - } - _ => None, - } - } } pub enum RvalueInitializationState { diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index 8c1e345cdaec5..1861420b408b6 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -235,6 +235,8 @@ rustc_queries! { /// constructor function). query is_promotable_const_fn(_: DefId) -> bool {} + query const_fn_is_allowed_fn_ptr(_: DefId) -> bool {} + /// True if this is a foreign item (i.e., linked via `extern { ... }`). query is_foreign_item(_: DefId) -> bool {} diff --git a/src/librustc/ty/constness.rs b/src/librustc/ty/constness.rs index e33d0a74ea013..7298b548f3197 100644 --- a/src/librustc/ty/constness.rs +++ b/src/librustc/ty/constness.rs @@ -95,9 +95,16 @@ pub fn provide<'tcx>(providers: &mut Providers<'tcx>) { } } + fn const_fn_is_allowed_fn_ptr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool { + tcx.is_const_fn(def_id) && + tcx.lookup_stability(def_id) + .map(|stab| stab.allow_const_fn_ptr).unwrap_or(false) + } + *providers = Providers { is_const_fn_raw, is_promotable_const_fn, + const_fn_is_allowed_fn_ptr, ..*providers }; } diff --git a/src/librustc_codegen_llvm/debuginfo/mod.rs b/src/librustc_codegen_llvm/debuginfo/mod.rs index ae498673c1d84..cb00cca0f9c96 100644 --- a/src/librustc_codegen_llvm/debuginfo/mod.rs +++ b/src/librustc_codegen_llvm/debuginfo/mod.rs @@ -542,7 +542,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { finalize(self) } - fn debuginfo_upvar_decls_ops_sequence(&self, byte_offset_of_var_in_env: u64) -> [i64; 4] { + fn debuginfo_upvar_ops_sequence(&self, byte_offset_of_var_in_env: u64) -> [i64; 4] { unsafe { [llvm::LLVMRustDIBuilderCreateOpDeref(), llvm::LLVMRustDIBuilderCreateOpPlusUconst(), diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs index 166234c83fca5..fe703ff4d25dd 100644 --- a/src/librustc_codegen_ssa/back/link.rs +++ b/src/librustc_codegen_ssa/back/link.rs @@ -83,14 +83,16 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(sess: &'a Session, for obj in codegen_results.modules.iter().filter_map(|m| m.bytecode_compressed.as_ref()) { remove(sess, obj); } - if let Some(ref obj) = codegen_results.metadata_module.object { - remove(sess, obj); - } - if let Some(ref allocator) = codegen_results.allocator_module { - if let Some(ref obj) = allocator.object { + if let Some(ref metadata_module) = codegen_results.metadata_module { + if let Some(ref obj) = metadata_module.object { + remove(sess, obj); + } + } + if let Some(ref allocator_module) = codegen_results.allocator_module { + if let Some(ref obj) = allocator_module.object { remove(sess, obj); } - if let Some(ref bc) = allocator.bytecode_compressed { + if let Some(ref bc) = allocator_module.bytecode_compressed { remove(sess, bc); } } @@ -1067,7 +1069,10 @@ fn link_args<'a, B: ArchiveBuilder<'a>>(cmd: &mut dyn Linker, // object file, so we link that in here. if crate_type == config::CrateType::Dylib || crate_type == config::CrateType::ProcMacro { - if let Some(obj) = codegen_results.metadata_module.object.as_ref() { + let obj = codegen_results.metadata_module + .as_ref() + .and_then(|m| m.object.as_ref()); + if let Some(obj) = obj { cmd.add_object(obj); } } diff --git a/src/librustc_codegen_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs index 4b02425d40d65..88a5e5a1aec3b 100644 --- a/src/librustc_codegen_ssa/back/write.rs +++ b/src/librustc_codegen_ssa/back/write.rs @@ -350,7 +350,7 @@ fn generate_lto_work( pub struct CompiledModules { pub modules: Vec, - pub metadata_module: CompiledModule, + pub metadata_module: Option, pub allocator_module: Option, } @@ -682,8 +682,10 @@ fn produce_final_output_artifacts(sess: &Session, } if !user_wants_bitcode { - if let Some(ref path) = compiled_modules.metadata_module.bytecode { - remove(sess, &path); + if let Some(ref metadata_module) = compiled_modules.metadata_module { + if let Some(ref path) = metadata_module.bytecode { + remove(sess, &path); + } } if let Some(ref allocator_module) = compiled_modules.allocator_module { @@ -1564,9 +1566,6 @@ fn start_executing_work( // out deterministic results. compiled_modules.sort_by(|a, b| a.name.cmp(&b.name)); - let compiled_metadata_module = compiled_metadata_module - .expect("Metadata module not compiled?"); - Ok(CompiledModules { modules: compiled_modules, metadata_module: compiled_metadata_module, diff --git a/src/librustc_codegen_ssa/base.rs b/src/librustc_codegen_ssa/base.rs index 6cb54831a0743..3046c069981cb 100644 --- a/src/librustc_codegen_ssa/base.rs +++ b/src/librustc_codegen_ssa/base.rs @@ -25,7 +25,7 @@ use rustc::ty::layout::{self, Align, TyLayout, LayoutOf, VariantIdx, HasTyCtxt}; use rustc::ty::query::Providers; use rustc::middle::cstore::{self, LinkagePreference}; use rustc::util::common::{time, print_time_passes_entry}; -use rustc::session::config::{self, EntryFnType, Lto}; +use rustc::session::config::{self, CrateType, EntryFnType, Lto}; use rustc::session::Session; use rustc_mir::monomorphize::item::DefPathBasedNames; use rustc_mir::monomorphize::Instance; @@ -550,12 +550,6 @@ pub fn codegen_crate( }); tcx.sess.profiler(|p| p.end_activity("codegen crate metadata")); - let metadata_module = ModuleCodegen { - name: metadata_cgu_name, - module_llvm: metadata_llvm_module, - kind: ModuleKind::Metadata, - }; - // Skip crate items and just output metadata in -Z no-codegen mode. if tcx.sess.opts.debugging_opts.no_codegen || !tcx.sess.opts.output_types.should_codegen() { @@ -566,7 +560,6 @@ pub fn codegen_crate( rx, 1); - ongoing_codegen.submit_pre_codegened_module_to_llvm(tcx, metadata_module); ongoing_codegen.codegen_finished(tcx); assert_and_save_dep_graph(tcx); @@ -639,7 +632,24 @@ pub fn codegen_crate( ongoing_codegen.submit_pre_codegened_module_to_llvm(tcx, allocator_module); } - ongoing_codegen.submit_pre_codegened_module_to_llvm(tcx, metadata_module); + let needs_metadata_module = tcx.sess.crate_types.borrow().iter().any(|ct| { + match *ct { + CrateType::Dylib | + CrateType::ProcMacro => true, + CrateType::Executable | + CrateType::Rlib | + CrateType::Staticlib | + CrateType::Cdylib => false, + } + }); + if needs_metadata_module { + let metadata_module = ModuleCodegen { + name: metadata_cgu_name, + module_llvm: metadata_llvm_module, + kind: ModuleKind::Metadata, + }; + ongoing_codegen.submit_pre_codegened_module_to_llvm(tcx, metadata_module); + } // We sort the codegen units by size. This way we can schedule work for LLVM // a bit more efficiently. diff --git a/src/librustc_codegen_ssa/lib.rs b/src/librustc_codegen_ssa/lib.rs index 9d3d6ef854990..4d7af7a643b66 100644 --- a/src/librustc_codegen_ssa/lib.rs +++ b/src/librustc_codegen_ssa/lib.rs @@ -154,7 +154,7 @@ pub struct CodegenResults { pub crate_name: Symbol, pub modules: Vec, pub allocator_module: Option, - pub metadata_module: CompiledModule, + pub metadata_module: Option, pub crate_hash: Svh, pub metadata: rustc::middle::cstore::EncodedMetadata, pub windows_subsystem: Option, diff --git a/src/librustc_codegen_ssa/mir/mod.rs b/src/librustc_codegen_ssa/mir/mod.rs index 91aa9bcc7808b..621c4e5d4488e 100644 --- a/src/librustc_codegen_ssa/mir/mod.rs +++ b/src/librustc_codegen_ssa/mir/mod.rs @@ -598,9 +598,10 @@ fn arg_local_refs<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( tmp } }; + let upvar_debuginfo = &mir.__upvar_debuginfo_codegen_only_do_not_use; arg_scope.map(|scope| { // Is this a regular argument? - if arg_index > 0 || mir.upvar_decls.is_empty() { + if arg_index > 0 || upvar_debuginfo.is_empty() { // The Rust ABI passes indirect variables using a pointer and a manual copy, so we // need to insert a deref here, but the C ABI uses a pointer and a copy using the // byval attribute, for which LLVM always does the deref itself, @@ -638,16 +639,16 @@ fn arg_local_refs<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( let (def_id, upvar_substs) = match closure_layout.ty.sty { ty::Closure(def_id, substs) => (def_id, UpvarSubsts::Closure(substs)), ty::Generator(def_id, substs, _) => (def_id, UpvarSubsts::Generator(substs)), - _ => bug!("upvar_decls with non-closure arg0 type `{}`", closure_layout.ty) + _ => bug!("upvar debuginfo with non-closure arg0 type `{}`", closure_layout.ty) }; let upvar_tys = upvar_substs.upvar_tys(def_id, tcx); let extra_locals = { - let upvars = mir.upvar_decls + let upvars = upvar_debuginfo .iter() .zip(upvar_tys) .enumerate() - .map(|(i, (decl, ty))| (i, decl.debug_name, decl.by_ref, ty)); + .map(|(i, (upvar, ty))| (i, upvar.debug_name, upvar.by_ref, ty)); let generator_fields = mir.generator_layout.as_ref().map(|generator_layout| { let (def_id, gen_substs) = match closure_layout.ty.sty { @@ -656,7 +657,7 @@ fn arg_local_refs<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( }; let state_tys = gen_substs.state_tys(def_id, tcx); - let upvar_count = mir.upvar_decls.len(); + let upvar_count = upvar_debuginfo.len(); generator_layout.fields .iter() .zip(state_tys) @@ -673,7 +674,7 @@ fn arg_local_refs<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( for (field, name, by_ref, ty) in extra_locals { let byte_offset_of_var_in_env = closure_layout.fields.offset(field).bytes(); - let ops = bx.debuginfo_upvar_decls_ops_sequence(byte_offset_of_var_in_env); + let ops = bx.debuginfo_upvar_ops_sequence(byte_offset_of_var_in_env); // The environment and the capture can each be indirect. let mut ops = if env_ref { &ops[..] } else { &ops[1..] }; diff --git a/src/librustc_codegen_ssa/traits/debuginfo.rs b/src/librustc_codegen_ssa/traits/debuginfo.rs index a0b53fde09c4d..aadffc5932ba8 100644 --- a/src/librustc_codegen_ssa/traits/debuginfo.rs +++ b/src/librustc_codegen_ssa/traits/debuginfo.rs @@ -37,7 +37,7 @@ pub trait DebugInfoMethods<'tcx>: BackendTypes { defining_crate: CrateNum, ) -> Self::DIScope; fn debuginfo_finalize(&self); - fn debuginfo_upvar_decls_ops_sequence(&self, byte_offset_of_var_in_env: u64) -> [i64; 4]; + fn debuginfo_upvar_ops_sequence(&self, byte_offset_of_var_in_env: u64) -> [i64; 4]; } pub trait DebugInfoBuilderMethods<'tcx>: BackendTypes { diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index 3ab0996d3a17f..12dcea7bd5981 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -1088,7 +1088,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { | LocalKind::Temp => bug!("temporary or return pointer with a name"), LocalKind::Var => "local variable ", LocalKind::Arg - if !self.mir.upvar_decls.is_empty() + if !self.upvars.is_empty() && local == Local::new(1) => { "variable captured by `move` " } @@ -1632,11 +1632,11 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { match proj.elem { ProjectionElem::Deref => { let upvar_field_projection = - place.is_upvar_field_projection(self.mir, &self.infcx.tcx); + self.is_upvar_field_projection(place); if let Some(field) = upvar_field_projection { let var_index = field.index(); - let name = self.mir.upvar_decls[var_index].debug_name.to_string(); - if self.mir.upvar_decls[var_index].by_ref { + let name = self.upvars[var_index].name.to_string(); + if self.upvars[var_index].by_ref { buf.push_str(&name); } else { buf.push_str(&format!("*{}", &name)); @@ -1694,10 +1694,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { autoderef = true; let upvar_field_projection = - place.is_upvar_field_projection(self.mir, &self.infcx.tcx); + self.is_upvar_field_projection(place); if let Some(field) = upvar_field_projection { let var_index = field.index(); - let name = self.mir.upvar_decls[var_index].debug_name.to_string(); + let name = self.upvars[var_index].name.to_string(); buf.push_str(&name); } else { let field_name = self.describe_field(&proj.base, field); diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 4a3159d8a9dc3..14cafdef67d7d 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -1,7 +1,7 @@ //! This query borrow-checks the MIR to (further) ensure it is not broken. use crate::borrow_check::nll::region_infer::RegionInferenceContext; -use rustc::hir; +use rustc::hir::{self, HirId}; use rustc::hir::Node; use rustc::hir::def_id::DefId; use rustc::infer::InferCtxt; @@ -27,6 +27,7 @@ use std::collections::BTreeMap; use std::mem; use std::rc::Rc; +use syntax::ast::Name; use syntax_pos::{Span, DUMMY_SP}; use crate::dataflow::indexes::{BorrowIndex, InitIndex, MoveOutIndex, MovePathIndex}; @@ -63,6 +64,19 @@ mod used_muts; pub(crate) mod nll; +// FIXME(eddyb) perhaps move this somewhere more centrally. +#[derive(Debug)] +crate struct Upvar { + name: Name, + + var_hir_id: HirId, + + /// If true, the capture is behind a reference. + by_ref: bool, + + mutability: Mutability, +} + pub fn provide(providers: &mut Providers<'_>) { *providers = Providers { mir_borrowck, @@ -126,6 +140,36 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( .as_local_hir_id(def_id) .expect("do_mir_borrowck: non-local DefId"); + // Gather the upvars of a closure, if any. + let tables = tcx.typeck_tables_of(def_id); + let upvars: Vec<_> = tables + .upvar_list + .get(&def_id) + .into_iter() + .flatten() + .map(|upvar_id| { + let var_hir_id = upvar_id.var_path.hir_id; + let var_node_id = tcx.hir().hir_to_node_id(var_hir_id); + let capture = tables.upvar_capture(*upvar_id); + let by_ref = match capture { + ty::UpvarCapture::ByValue => false, + ty::UpvarCapture::ByRef(..) => true, + }; + let mut upvar = Upvar { + name: tcx.hir().name(var_node_id), + var_hir_id, + by_ref, + mutability: Mutability::Not, + }; + let bm = *tables.pat_binding_modes().get(var_hir_id) + .expect("missing binding mode"); + if bm == ty::BindByValue(hir::MutMutable) { + upvar.mutability = Mutability::Mut; + } + upvar + }) + .collect(); + // Replace all regions with fresh inference variables. This // requires first making our own copy of the MIR. This copy will // be modified (in place) to contain non-lexical lifetimes. It @@ -168,6 +212,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( def_id, free_regions, mir, + &upvars, location_table, param_env, &mut flow_inits, @@ -240,6 +285,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( used_mut_upvars: SmallVec::new(), borrow_set, dominators, + upvars, }; let mut state = Flows::new( @@ -475,6 +521,9 @@ pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> { /// Dominators for MIR dominators: Dominators, + + /// Information about upvars not necessarily preserved in types or MIR + upvars: Vec, } // Check that: @@ -1287,8 +1336,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { let propagate_closure_used_mut_place = |this: &mut Self, place: &Place<'tcx>| { match *place { Place::Projection { .. } => { - if let Some(field) = place.is_upvar_field_projection( - this.mir, &this.infcx.tcx) { + if let Some(field) = this.is_upvar_field_projection(place) { this.used_mut_upvars.push(field); } } @@ -2057,7 +2105,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { place: place @ Place::Projection(_), is_local_mutation_allowed: _, } => { - if let Some(field) = place.is_upvar_field_projection(self.mir, &self.infcx.tcx) { + if let Some(field) = self.is_upvar_field_projection(place) { self.used_mut_upvars.push(field); } } @@ -2127,13 +2175,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // Mutably borrowed data is mutable, but only if we have a // unique path to the `&mut` hir::MutMutable => { - let mode = match place.is_upvar_field_projection( - self.mir, &self.infcx.tcx) - { + let mode = match self.is_upvar_field_projection(place) { Some(field) - if { - self.mir.upvar_decls[field.index()].by_ref - } => + if self.upvars[field.index()].by_ref => { is_local_mutation_allowed } @@ -2173,15 +2217,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } | ProjectionElem::Downcast(..) => { - let upvar_field_projection = place.is_upvar_field_projection( - self.mir, &self.infcx.tcx); + let upvar_field_projection = self.is_upvar_field_projection(place); if let Some(field) = upvar_field_projection { - let decl = &self.mir.upvar_decls[field.index()]; + let upvar = &self.upvars[field.index()]; debug!( - "decl.mutability={:?} local_mutation_is_allowed={:?} place={:?}", - decl, is_local_mutation_allowed, place + "upvar.mutability={:?} local_mutation_is_allowed={:?} place={:?}", + upvar, is_local_mutation_allowed, place ); - match (decl.mutability, is_local_mutation_allowed) { + match (upvar.mutability, is_local_mutation_allowed) { (Mutability::Not, LocalMutationIsAllowed::No) | (Mutability::Not, LocalMutationIsAllowed::ExceptUpvars) => { Err(place) @@ -2229,6 +2272,41 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } } } + + /// If `place` is a field projection, and the field is being projected from a closure type, + /// then returns the index of the field being projected. Note that this closure will always + /// be `self` in the current MIR, because that is the only time we directly access the fields + /// of a closure type. + pub fn is_upvar_field_projection(&self, place: &Place<'tcx>) -> Option { + let (place, by_ref) = if let Place::Projection(ref proj) = place { + if let ProjectionElem::Deref = proj.elem { + (&proj.base, true) + } else { + (place, false) + } + } else { + (place, false) + }; + + match place { + Place::Projection(ref proj) => match proj.elem { + ProjectionElem::Field(field, _ty) => { + let tcx = self.infcx.tcx; + let base_ty = proj.base.ty(self.mir, tcx).ty; + + if (base_ty.is_closure() || base_ty.is_generator()) && + (!by_ref || self.upvars[field.index()].by_ref) + { + Some(field) + } else { + None + } + }, + _ => None, + } + _ => None, + } + } } #[derive(Copy, Clone, PartialEq, Eq, Debug)] diff --git a/src/librustc_mir/borrow_check/move_errors.rs b/src/librustc_mir/borrow_check/move_errors.rs index 7efe1d83c2e5f..a7bad44c42c7f 100644 --- a/src/librustc_mir/borrow_check/move_errors.rs +++ b/src/librustc_mir/borrow_check/move_errors.rs @@ -256,7 +256,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { let origin = Origin::Mir; debug!("report: original_path={:?} span={:?}, kind={:?} \ original_path.is_upvar_field_projection={:?}", original_path, span, kind, - original_path.is_upvar_field_projection(self.mir, &self.infcx.tcx)); + self.is_upvar_field_projection(original_path)); ( match kind { IllegalMoveOriginKind::Static => { @@ -269,8 +269,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { let ty = place.ty(self.mir, self.infcx.tcx).ty; let is_upvar_field_projection = self.prefixes(&original_path, PrefixSet::All) - .any(|p| p.is_upvar_field_projection(self.mir, &self.infcx.tcx) - .is_some()); + .any(|p| self.is_upvar_field_projection(p).is_some()); debug!("report: ty={:?}", ty); match ty.sty { ty::Array(..) | ty::Slice(..) => @@ -278,7 +277,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { span, ty, None, origin ), ty::Closure(def_id, closure_substs) - if !self.mir.upvar_decls.is_empty() && is_upvar_field_projection + if def_id == self.mir_def_id && is_upvar_field_projection => { let closure_kind_ty = closure_substs.closure_kind_ty(def_id, self.infcx.tcx); @@ -303,11 +302,8 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { span, place_description, origin); for prefix in self.prefixes(&original_path, PrefixSet::All) { - if let Some(field) = prefix.is_upvar_field_projection( - self.mir, &self.infcx.tcx) { - let upvar_decl = &self.mir.upvar_decls[field.index()]; - let upvar_hir_id = - upvar_decl.var_hir_id.assert_crate_local(); + if let Some(field) = self.is_upvar_field_projection(prefix) { + let upvar_hir_id = self.upvars[field.index()].var_hir_id; let upvar_span = self.infcx.tcx.hir().span_by_hir_id( upvar_hir_id); diag.span_label(upvar_span, "captured outer variable"); diff --git a/src/librustc_mir/borrow_check/mutability_errors.rs b/src/librustc_mir/borrow_check/mutability_errors.rs index b780511315d81..c5ad2b18c23fc 100644 --- a/src/librustc_mir/borrow_check/mutability_errors.rs +++ b/src/librustc_mir/borrow_check/mutability_errors.rs @@ -68,10 +68,10 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { )); item_msg = format!("`{}`", access_place_desc.unwrap()); - if access_place.is_upvar_field_projection(self.mir, &self.infcx.tcx).is_some() { + if self.is_upvar_field_projection(access_place).is_some() { reason = ", as it is not declared as mutable".to_string(); } else { - let name = self.mir.upvar_decls[upvar_index.index()].debug_name; + let name = self.upvars[upvar_index.index()].name; reason = format!(", as `{}` is not declared as mutable", name); } } @@ -81,15 +81,14 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { elem: ProjectionElem::Deref, }) => { if *base == Place::Base(PlaceBase::Local(Local::new(1))) && - !self.mir.upvar_decls.is_empty() { + !self.upvars.is_empty() { item_msg = format!("`{}`", access_place_desc.unwrap()); debug_assert!(self.mir.local_decls[Local::new(1)].ty.is_region_ptr()); debug_assert!(is_closure_or_generator( the_place_err.ty(self.mir, self.infcx.tcx).ty )); - reason = if access_place.is_upvar_field_projection(self.mir, - &self.infcx.tcx).is_some() { + reason = if self.is_upvar_field_projection(access_place).is_some() { ", as it is a captured variable in a `Fn` closure".to_string() } else { ", as `Fn` closures cannot mutate their captured variables".to_string() @@ -309,9 +308,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { err.span_label(span, format!("cannot {ACT}", ACT = act)); - let upvar_hir_id = self.mir.upvar_decls[upvar_index.index()] - .var_hir_id - .assert_crate_local(); + let upvar_hir_id = self.upvars[upvar_index.index()].var_hir_id; let upvar_node_id = self.infcx.tcx.hir().hir_to_node_id(upvar_hir_id); if let Some(Node::Binding(pat)) = self.infcx.tcx.hir().find(upvar_node_id) { if let hir::PatKind::Binding( @@ -452,7 +449,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { base, elem: ProjectionElem::Deref, }) if *base == Place::Base(PlaceBase::Local(Local::new(1))) && - !self.mir.upvar_decls.is_empty() => + !self.upvars.is_empty() => { err.span_label(span, format!("cannot {ACT}", ACT = act)); err.span_help( diff --git a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs index 5ad54080c5a61..89f85a941d386 100644 --- a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs +++ b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs @@ -273,11 +273,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { if mir.local_decls[local].name.is_some() { if let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place { if let Place::Base(PlaceBase::Local(borrowed_local)) = place { - let dropped_local_scope = mir.local_decls[local].visibility_scope; - let borrowed_local_scope = - mir.local_decls[*borrowed_local].visibility_scope; - - if mir.is_sub_scope(borrowed_local_scope, dropped_local_scope) + if mir.local_decls[*borrowed_local].name.is_some() && local != *borrowed_local { should_note_order = true; @@ -298,6 +294,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { let (category, from_closure, span, region_name) = self.nonlexical_regioncx.free_region_constraint_info( self.mir, + &self.upvars, self.mir_def_id, self.infcx, borrow_region_vid, diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs index 3e1b93fb4170a..ad43c8ef66f42 100644 --- a/src/librustc_mir/borrow_check/nll/mod.rs +++ b/src/librustc_mir/borrow_check/nll/mod.rs @@ -8,6 +8,7 @@ use crate::dataflow::move_paths::MoveData; use crate::dataflow::FlowAtLocation; use crate::dataflow::MaybeInitializedPlaces; use crate::transform::MirSource; +use crate::borrow_check::Upvar; use rustc::hir::def_id::DefId; use rustc::infer::InferCtxt; use rustc::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, Mir}; @@ -72,6 +73,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>( def_id: DefId, universal_regions: UniversalRegions<'tcx>, mir: &Mir<'tcx>, + upvars: &[Upvar], location_table: &LocationTable, param_env: ty::ParamEnv<'gcx>, flow_inits: &mut FlowAtLocation<'tcx, MaybeInitializedPlaces<'cx, 'gcx, 'tcx>>, @@ -187,7 +189,8 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>( }); // Solve the region constraints. - let closure_region_requirements = regioncx.solve(infcx, &mir, def_id, errors_buffer); + let closure_region_requirements = + regioncx.solve(infcx, &mir, upvars, def_id, errors_buffer); // Dump MIR results into a file, if that is enabled. This let us // write unit-tests, as well as helping with debugging. diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs index 917e383cae827..abb30d042ca4c 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs @@ -4,6 +4,7 @@ use crate::borrow_check::nll::type_check::Locations; use crate::borrow_check::nll::universal_regions::DefiningTy; use crate::borrow_check::nll::ConstraintDescription; use crate::util::borrowck_errors::{BorrowckErrors, Origin}; +use crate::borrow_check::Upvar; use rustc::hir::def_id::DefId; use rustc::infer::error_reporting::nice_region_error::NiceRegionError; use rustc::infer::InferCtxt; @@ -237,6 +238,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { pub(super) fn report_error( &self, mir: &Mir<'tcx>, + upvars: &[Upvar], infcx: &InferCtxt<'_, '_, 'tcx>, mir_def_id: DefId, fr: RegionVid, @@ -273,6 +275,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { (ConstraintCategory::Return, true, false) if self.is_closure_fn_mut(infcx, fr) => { self.report_fnmut_error( mir, + upvars, infcx, mir_def_id, fr, @@ -284,6 +287,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { (ConstraintCategory::Assignment, true, false) | (ConstraintCategory::CallArgument, true, false) => self.report_escaping_data_error( mir, + upvars, infcx, mir_def_id, fr, @@ -294,6 +298,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { ), _ => self.report_general_error( mir, + upvars, infcx, mir_def_id, fr, @@ -353,6 +358,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { fn report_fnmut_error( &self, mir: &Mir<'tcx>, + upvars: &[Upvar], infcx: &InferCtxt<'_, '_, 'tcx>, mir_def_id: DefId, _fr: RegionVid, @@ -377,7 +383,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { diag.span_label(span, message); - match self.give_region_a_name(infcx, mir, mir_def_id, outlived_fr, &mut 1).unwrap().source { + match self.give_region_a_name(infcx, mir, upvars, mir_def_id, outlived_fr, &mut 1) + .unwrap().source + { RegionNameSource::NamedEarlyBoundRegion(fr_span) | RegionNameSource::NamedFreeRegion(fr_span) | RegionNameSource::SynthesizedFreeEnvRegion(fr_span, _) @@ -415,6 +423,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { fn report_escaping_data_error( &self, mir: &Mir<'tcx>, + upvars: &[Upvar], infcx: &InferCtxt<'_, '_, 'tcx>, mir_def_id: DefId, fr: RegionVid, @@ -423,9 +432,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { span: Span, errors_buffer: &mut Vec, ) { - let fr_name_and_span = self.get_var_name_and_span_for_region(infcx.tcx, mir, fr); + let fr_name_and_span = + self.get_var_name_and_span_for_region(infcx.tcx, mir, upvars, fr); let outlived_fr_name_and_span = - self.get_var_name_and_span_for_region(infcx.tcx, mir, outlived_fr); + self.get_var_name_and_span_for_region(infcx.tcx, mir, upvars, outlived_fr); let escapes_from = match self.universal_regions.defining_ty { DefiningTy::Closure(..) => "closure", @@ -442,6 +452,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { { return self.report_general_error( mir, + upvars, infcx, mir_def_id, fr, @@ -504,6 +515,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { fn report_general_error( &self, mir: &Mir<'tcx>, + upvars: &[Upvar], infcx: &InferCtxt<'_, '_, 'tcx>, mir_def_id: DefId, fr: RegionVid, @@ -520,10 +532,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { ); let counter = &mut 1; - let fr_name = self.give_region_a_name(infcx, mir, mir_def_id, fr, counter).unwrap(); + let fr_name = self.give_region_a_name(infcx, mir, upvars, mir_def_id, fr, counter).unwrap(); fr_name.highlight_region_name(&mut diag); let outlived_fr_name = - self.give_region_a_name(infcx, mir, mir_def_id, outlived_fr, counter).unwrap(); + self.give_region_a_name(infcx, mir, upvars, mir_def_id, outlived_fr, counter).unwrap(); outlived_fr_name.highlight_region_name(&mut diag); let mir_def_name = if infcx.tcx.is_closure(mir_def_id) { @@ -656,6 +668,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { crate fn free_region_constraint_info( &self, mir: &Mir<'tcx>, + upvars: &[Upvar], mir_def_id: DefId, infcx: &InferCtxt<'_, '_, 'tcx>, borrow_region: RegionVid, @@ -664,7 +677,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { let (category, from_closure, span) = self.best_blame_constraint(mir, borrow_region, |r| r == outlived_region); let outlived_fr_name = - self.give_region_a_name(infcx, mir, mir_def_id, outlived_region, &mut 1); + self.give_region_a_name(infcx, mir, upvars, mir_def_id, outlived_region, &mut 1); (category, from_closure, span, outlived_fr_name) } diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs index 362214d325712..680e7ce576af0 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs @@ -2,6 +2,7 @@ use std::fmt::{self, Display}; use crate::borrow_check::nll::region_infer::RegionInferenceContext; use crate::borrow_check::nll::universal_regions::DefiningTy; use crate::borrow_check::nll::ToRegionVid; +use crate::borrow_check::Upvar; use rustc::hir; use rustc::hir::def_id::DefId; use rustc::infer::InferCtxt; @@ -144,6 +145,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { &self, infcx: &InferCtxt<'_, '_, 'tcx>, mir: &Mir<'tcx>, + upvars: &[Upvar], mir_def_id: DefId, fr: RegionVid, counter: &mut usize, @@ -160,7 +162,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { }) .or_else(|| { self.give_name_if_anonymous_region_appears_in_upvars( - infcx.tcx, mir, fr, counter, + infcx.tcx, upvars, fr, counter, ) }) .or_else(|| { @@ -639,13 +641,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { fn give_name_if_anonymous_region_appears_in_upvars( &self, tcx: TyCtxt<'_, '_, 'tcx>, - mir: &Mir<'tcx>, + upvars: &[Upvar], fr: RegionVid, counter: &mut usize, ) -> Option { let upvar_index = self.get_upvar_index_for_region(tcx, fr)?; let (upvar_name, upvar_span) = - self.get_upvar_name_and_span_for_region(tcx, mir, upvar_index); + self.get_upvar_name_and_span_for_region(tcx, upvars, upvar_index); let region_name = self.synthesize_region_name(counter); Some(RegionName { diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/var_name.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/var_name.rs index f6bbaf2db0383..d8f34233839b9 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/var_name.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/var_name.rs @@ -1,5 +1,6 @@ use crate::borrow_check::nll::region_infer::RegionInferenceContext; use crate::borrow_check::nll::ToRegionVid; +use crate::borrow_check::Upvar; use rustc::mir::{Local, Mir}; use rustc::ty::{RegionVid, TyCtxt}; use rustc_data_structures::indexed_vec::Idx; @@ -11,6 +12,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { &self, tcx: TyCtxt<'_, '_, 'tcx>, mir: &Mir<'tcx>, + upvars: &[Upvar], fr: RegionVid, ) -> Option<(Option, Span)> { debug!("get_var_name_and_span_for_region(fr={:?})", fr); @@ -19,7 +21,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { debug!("get_var_name_and_span_for_region: attempting upvar"); self.get_upvar_index_for_region(tcx, fr) .map(|index| { - let (name, span) = self.get_upvar_name_and_span_for_region(tcx, mir, index); + let (name, span) = + self.get_upvar_name_and_span_for_region(tcx, upvars, index); (Some(name), span) }) .or_else(|| { @@ -67,10 +70,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { crate fn get_upvar_name_and_span_for_region( &self, tcx: TyCtxt<'_, '_, 'tcx>, - mir: &Mir<'tcx>, + upvars: &[Upvar], upvar_index: usize, ) -> (Symbol, Span) { - let upvar_hir_id = mir.upvar_decls[upvar_index].var_hir_id.assert_crate_local(); + let upvar_hir_id = upvars[upvar_index].var_hir_id; debug!("get_upvar_name_and_span_for_region: upvar_hir_id={:?}", upvar_hir_id); let upvar_name = tcx.hir().name_by_hir_id(upvar_hir_id); diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs index ac10683598aa7..9dd18ab76a5f2 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -4,6 +4,7 @@ use crate::borrow_check::nll::constraints::{ConstraintSccIndex, ConstraintSet, O use crate::borrow_check::nll::region_infer::values::{ PlaceholderIndices, RegionElement, ToElementIndex }; +use crate::borrow_check::Upvar; use crate::borrow_check::nll::type_check::free_region_relations::UniversalRegionRelations; use crate::borrow_check::nll::type_check::Locations; use rustc::hir::def_id::DefId; @@ -400,6 +401,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { &mut self, infcx: &InferCtxt<'_, 'gcx, 'tcx>, mir: &Mir<'tcx>, + upvars: &[Upvar], mir_def_id: DefId, errors_buffer: &mut Vec, ) -> Option> { @@ -407,7 +409,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { infcx.tcx.sess.time_extended(), Some(infcx.tcx.sess), &format!("solve_nll_region_constraints({:?})", mir_def_id), - || self.solve_inner(infcx, mir, mir_def_id, errors_buffer), + || self.solve_inner(infcx, mir, upvars, mir_def_id, errors_buffer), ) } @@ -415,6 +417,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { &mut self, infcx: &InferCtxt<'_, 'gcx, 'tcx>, mir: &Mir<'tcx>, + upvars: &[Upvar], mir_def_id: DefId, errors_buffer: &mut Vec, ) -> Option> { @@ -442,6 +445,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { self.check_universal_regions( infcx, mir, + upvars, mir_def_id, outlives_requirements.as_mut(), errors_buffer, @@ -1102,6 +1106,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { &self, infcx: &InferCtxt<'_, 'gcx, 'tcx>, mir: &Mir<'tcx>, + upvars: &[Upvar], mir_def_id: DefId, mut propagated_outlives_requirements: Option<&mut Vec>>, errors_buffer: &mut Vec, @@ -1115,6 +1120,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { self.check_universal_region( infcx, mir, + upvars, mir_def_id, fr, &mut propagated_outlives_requirements, @@ -1145,6 +1151,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { &self, infcx: &InferCtxt<'_, 'gcx, 'tcx>, mir: &Mir<'tcx>, + upvars: &[Upvar], mir_def_id: DefId, longer_fr: RegionVid, propagated_outlives_requirements: &mut Option<&mut Vec>>, @@ -1177,6 +1184,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { representative, infcx, mir, + upvars, mir_def_id, propagated_outlives_requirements, errors_buffer, @@ -1192,6 +1200,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { shorter_fr, infcx, mir, + upvars, mir_def_id, propagated_outlives_requirements, errors_buffer, @@ -1208,6 +1217,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { shorter_fr: RegionVid, infcx: &InferCtxt<'_, 'gcx, 'tcx>, mir: &Mir<'tcx>, + upvars: &[Upvar], mir_def_id: DefId, propagated_outlives_requirements: &mut Option<&mut Vec>>, errors_buffer: &mut Vec, @@ -1265,7 +1275,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // // Note: in this case, we use the unapproximated regions to report the // error. This gives better error messages in some cases. - self.report_error(mir, infcx, mir_def_id, longer_fr, shorter_fr, errors_buffer); + self.report_error(mir, upvars, infcx, mir_def_id, longer_fr, shorter_fr, errors_buffer); Some(ErrorReported) } diff --git a/src/librustc_mir/borrow_check/nll/universal_regions.rs b/src/librustc_mir/borrow_check/nll/universal_regions.rs index ae8dfa8144fd9..d3cef46b4022d 100644 --- a/src/librustc_mir/borrow_check/nll/universal_regions.rs +++ b/src/librustc_mir/borrow_check/nll/universal_regions.rs @@ -105,7 +105,7 @@ impl<'tcx> DefiningTy<'tcx> { /// Returns a list of all the upvar types for this MIR. If this is /// not a closure or generator, there are no upvars, and hence it /// will be an empty list. The order of types in this list will - /// match up with the `upvar_decls` field of `Mir`. + /// match up with the upvar order in the HIR, typesystem, and MIR. pub fn upvar_tys(self, tcx: TyCtxt<'_, '_, 'tcx>) -> impl Iterator> + 'tcx { match self { DefiningTy::Closure(def_id, substs) => Either::Left(substs.upvar_tys(def_id, tcx)), diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index b9fec22da63ca..c58b570d8fc9f 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -556,10 +556,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ); // Not in a closure debug_assert!( - this.upvar_decls.len() > upvar_index.index(), + this.upvar_mutbls.len() > upvar_index.index(), "Unexpected capture place" ); - this.upvar_decls[upvar_index.index()].mutability + this.upvar_mutbls[upvar_index.index()] } _ => bug!("Unexpected capture place"), }; diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index b5b2d78f1bd67..5e15d98e246b7 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -505,14 +505,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { UserTypeProjections::none(), &mut |this, mutability, name, mode, var, span, ty, user_ty| { if visibility_scope.is_none() { - visibility_scope = - Some(this.new_source_scope(scope_span, LintLevel::Inherited, None)); // If we have lints, create a new source scope // that marks the lints for the locals. See the comment // on the `source_info` field for why this is needed. if lint_level.is_explicit() { scope = this.new_source_scope(scope_span, lint_level, None); } + visibility_scope = Some(this.new_source_scope(scope_span, + LintLevel::Inherited, + None)); } let source_info = SourceInfo { span, scope }; let visibility_scope = visibility_scope.unwrap(); diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 7fe86d11c9ee4..79e1d5daae194 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -375,7 +375,8 @@ struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { var_indices: HirIdMap, local_decls: IndexVec>, canonical_user_type_annotations: ty::CanonicalUserTypeAnnotations<'tcx>, - upvar_decls: Vec, + __upvar_debuginfo_codegen_only_do_not_use: Vec, + upvar_mutbls: Vec, unit_temp: Option>, /// Cached block with the `RESUME` terminator; this is created @@ -625,11 +626,12 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, let fn_def_id = tcx_hir.local_def_id_from_hir_id(fn_id); // Gather the upvars of a closure, if any. + let mut upvar_mutbls = vec![]; // In analyze_closure() in upvar.rs we gathered a list of upvars used by a // closure and we stored in a map called upvar_list in TypeckTables indexed // with the closure's DefId. Here, we run through that vec of UpvarIds for // the given closure and use the necessary information to create UpvarDecl. - let upvar_decls: Vec<_> = hir_tables + let upvar_debuginfo: Vec<_> = hir_tables .upvar_list .get(&fn_def_id) .into_iter() @@ -642,27 +644,27 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, ty::UpvarCapture::ByValue => false, ty::UpvarCapture::ByRef(..) => true, }; - let mut decl = UpvarDecl { + let mut debuginfo = UpvarDebuginfo { debug_name: keywords::Invalid.name(), - var_hir_id: ClearCrossCrate::Set(var_hir_id), by_ref, - mutability: Mutability::Not, }; + let mut mutability = Mutability::Not; if let Some(Node::Binding(pat)) = tcx_hir.find(var_node_id) { if let hir::PatKind::Binding(_, _, ident, _) = pat.node { - decl.debug_name = ident.name; + debuginfo.debug_name = ident.name; if let Some(&bm) = hir.tables.pat_binding_modes().get(pat.hir_id) { if bm == ty::BindByValue(hir::MutMutable) { - decl.mutability = Mutability::Mut; + mutability = Mutability::Mut; } else { - decl.mutability = Mutability::Not; + mutability = Mutability::Not; } } else { tcx.sess.delay_span_bug(pat.span, "missing binding mode"); } } } - decl + upvar_mutbls.push(mutability); + debuginfo }) .collect(); @@ -672,7 +674,8 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, safety, return_ty, return_ty_span, - upvar_decls); + upvar_debuginfo, + upvar_mutbls); let call_site_scope = region::Scope { id: body.value.hir_id.local_id, @@ -734,7 +737,7 @@ fn construct_const<'a, 'gcx, 'tcx>( let ty = hir.tables().expr_ty_adjusted(ast_expr); let owner_id = tcx.hir().body_owner(body_id); let span = tcx.hir().span(owner_id); - let mut builder = Builder::new(hir, span, 0, Safety::Safe, ty, ty_span,vec![]); + let mut builder = Builder::new(hir, span, 0, Safety::Safe, ty, ty_span, vec![], vec![]); let mut block = START_BLOCK; let expr = builder.hir.mirror(ast_expr); @@ -762,7 +765,7 @@ fn construct_error<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>, let owner_id = hir.tcx().hir().body_owner(body_id); let span = hir.tcx().hir().span(owner_id); let ty = hir.tcx().types.err; - let mut builder = Builder::new(hir, span, 0, Safety::Safe, ty, span, vec![]); + let mut builder = Builder::new(hir, span, 0, Safety::Safe, ty, span, vec![], vec![]); let source_info = builder.source_info(span); builder.cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable); builder.finish(None) @@ -775,7 +778,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { safety: Safety, return_ty: Ty<'tcx>, return_span: Span, - upvar_decls: Vec) + __upvar_debuginfo_codegen_only_do_not_use: Vec, + upvar_mutbls: Vec) -> Builder<'a, 'gcx, 'tcx> { let lint_level = LintLevel::Explicit(hir.root_lint_level); let mut builder = Builder { @@ -797,7 +801,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { 1, ), canonical_user_type_annotations: IndexVec::new(), - upvar_decls, + __upvar_debuginfo_codegen_only_do_not_use, + upvar_mutbls, var_indices: Default::default(), unit_temp: None, cached_resume_block: None, @@ -832,7 +837,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { self.local_decls, self.canonical_user_type_annotations, self.arg_count, - self.upvar_decls, + self.__upvar_debuginfo_codegen_only_do_not_use, self.fn_span, self.hir.control_flow_destroyed(), ) diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index 11e4ffe19da62..bd6f005e8736c 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -3,6 +3,7 @@ use std::hash::Hash; use std::ops::RangeInclusive; use syntax_pos::symbol::Symbol; +use rustc::hir; use rustc::ty::layout::{self, Size, Align, TyLayout, LayoutOf, VariantIdx}; use rustc::ty; use rustc_data_structures::fx::FxHashSet; @@ -165,13 +166,28 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> ValidityVisitor<'rt, 'a, ' match layout.ty.sty { // generators and closures. ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => { - if let Some(upvar) = self.ecx.tcx.optimized_mir(def_id).upvar_decls.get(field) { - PathElem::ClosureVar(upvar.debug_name) - } else { - // Sometimes the index is beyond the number of freevars (seen - // for a generator). - PathElem::ClosureVar(Symbol::intern(&field.to_string())) + let mut name = None; + if def_id.is_local() { + let tables = self.ecx.tcx.typeck_tables_of(def_id); + if let Some(upvars) = tables.upvar_list.get(&def_id) { + // Sometimes the index is beyond the number of freevars (seen + // for a generator). + if let Some(upvar_id) = upvars.get(field) { + let var_hir_id = upvar_id.var_path.hir_id; + let var_node_id = self.ecx.tcx.hir().hir_to_node_id(var_hir_id); + if let hir::Node::Binding(pat) = self.ecx.tcx.hir().get(var_node_id) { + if let hir::PatKind::Binding(_, _, ident, _) = pat.node { + name = Some(ident.name); + } + } + } + } } + + PathElem::ClosureVar(name.unwrap_or_else(|| { + // Fall back to showing the field index. + Symbol::intern(&field.to_string()) + })) } // tuples diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index e63c1899fe583..2b909feb9603f 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -490,7 +490,7 @@ fn locals_live_across_suspend_points( fn compute_layout<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, source: MirSource<'tcx>, - upvars: Vec>, + upvars: &Vec>, interior: Ty<'tcx>, movable: bool, mir: &mut Mir<'tcx>) @@ -505,7 +505,7 @@ fn compute_layout<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, movable); // Erase regions from the types passed in from typeck so we can compare them with // MIR types - let allowed_upvars = tcx.erase_regions(&upvars); + let allowed_upvars = tcx.erase_regions(upvars); let allowed = match interior.sty { ty::GeneratorWitness(s) => tcx.erase_late_bound_regions(&s), _ => bug!(), @@ -528,7 +528,7 @@ fn compute_layout<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } - let upvar_len = mir.upvar_decls.len(); + let upvar_len = upvars.len(); let dummy_local = LocalDecl::new_internal(tcx.mk_unit(), mir.span); // Gather live locals and their indices replacing values in mir.local_decls with a dummy @@ -917,12 +917,12 @@ impl MirPass for StateTransform { let (remap, layout, storage_liveness) = compute_layout( tcx, source, - upvars, + &upvars, interior, movable, mir); - let state_field = mir.upvar_decls.len(); + let state_field = upvars.len(); // Run the transformation which converts Places from Local to generator struct // accesses for locals in `remap`. diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 027ae70b06a17..e96a40ad2f036 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -222,10 +222,10 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { debug!("should_inline({:?})", callsite); let tcx = self.tcx; - // Don't inline closures that have captures + // Don't inline closures that have capture debuginfo // FIXME: Handle closures better - if callee_mir.upvar_decls.len() > 0 { - debug!(" upvar decls present - not inlining"); + if callee_mir.__upvar_debuginfo_codegen_only_do_not_use.len() > 0 { + debug!(" upvar debuginfo present - not inlining"); return false; } diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index 776985ab79802..d5f04ca64e4c4 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -60,13 +60,14 @@ pub fn is_min_const_fn( } for local in &mir.local_decls { - check_ty(tcx, local.ty, local.source_info.span)?; + check_ty(tcx, local.ty, local.source_info.span, def_id)?; } // impl trait is gone in MIR, so check the return type manually check_ty( tcx, tcx.fn_sig(def_id).output().skip_binder(), mir.local_decls.iter().next().unwrap().source_info.span, + def_id, )?; for bb in mir.basic_blocks() { @@ -82,6 +83,7 @@ fn check_ty( tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: ty::Ty<'tcx>, span: Span, + fn_def_id: DefId, ) -> McfResult { for ty in ty.walk() { match ty.sty { @@ -91,7 +93,9 @@ fn check_ty( )), ty::Opaque(..) => return Err((span, "`impl Trait` in const fn is unstable".into())), ty::FnPtr(..) => { - return Err((span, "function pointers in const fn are unstable".into())) + if !tcx.const_fn_is_allowed_fn_ptr(fn_def_id) { + return Err((span, "function pointers in const fn are unstable".into())) + } } ty::Dynamic(preds, _) => { for pred in preds.iter() { diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index efae1e56f4dc6..1f55a728f9c72 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -461,9 +461,7 @@ fn comment(tcx: TyCtxt<'_, '_, '_>, SourceInfo { span, scope }: SourceInfo) -> S ) } -/// Prints user-defined variables in a scope tree. -/// -/// Returns the total number of variables printed. +/// Prints local variables in a scope tree. fn write_scope_tree( tcx: TyCtxt<'_, '_, '_>, mir: &Mir<'_>, @@ -474,57 +472,64 @@ fn write_scope_tree( ) -> io::Result<()> { let indent = depth * INDENT.len(); + // Local variable types (including the user's name in a comment). + for (local, local_decl) in mir.local_decls.iter_enumerated() { + if (1..mir.arg_count+1).contains(&local.index()) { + // Skip over argument locals, they're printed in the signature. + continue; + } + + if local_decl.source_info.scope != parent { + // Not declared in this scope. + continue; + } + + let mut_str = if local_decl.mutability == Mutability::Mut { + "mut " + } else { + "" + }; + + let mut indented_decl = format!( + "{0:1$}let {2}{3:?}: {4:?}", + INDENT, + indent, + mut_str, + local, + local_decl.ty + ); + for user_ty in local_decl.user_ty.projections() { + write!(indented_decl, " as {:?}", user_ty).unwrap(); + } + indented_decl.push_str(";"); + + let local_name = if local == RETURN_PLACE { + format!(" return place") + } else if let Some(name) = local_decl.name { + format!(" \"{}\"", name) + } else { + String::new() + }; + + writeln!( + w, + "{0:1$} //{2} in {3}", + indented_decl, + ALIGN, + local_name, + comment(tcx, local_decl.source_info), + )?; + } + let children = match scope_tree.get(&parent) { - Some(children) => children, + Some(childs) => childs, None => return Ok(()), }; for &child in children { - let data = &mir.source_scopes[child]; - assert_eq!(data.parent_scope, Some(parent)); + assert_eq!(mir.source_scopes[child].parent_scope, Some(parent)); writeln!(w, "{0:1$}scope {2} {{", "", indent, child.index())?; - - // User variable types (including the user's name in a comment). - for local in mir.vars_iter() { - let var = &mir.local_decls[local]; - let (name, source_info) = if var.source_info.scope == child { - (var.name.unwrap(), var.source_info) - } else { - // Not a variable or not declared in this scope. - continue; - }; - - let mut_str = if var.mutability == Mutability::Mut { - "mut " - } else { - "" - }; - - let indent = indent + INDENT.len(); - let mut indented_var = format!( - "{0:1$}let {2}{3:?}: {4:?}", - INDENT, - indent, - mut_str, - local, - var.ty - ); - for user_ty in var.user_ty.projections() { - write!(indented_var, " as {:?}", user_ty).unwrap(); - } - indented_var.push_str(";"); - writeln!( - w, - "{0:1$} // \"{2}\" in {3}", - indented_var, - ALIGN, - name, - comment(tcx, source_info) - )?; - } - write_scope_tree(tcx, mir, scope_tree, w, child, depth + 1)?; - writeln!(w, "{0:1$}}}", "", depth * INDENT.len())?; } @@ -556,19 +561,8 @@ pub fn write_mir_intro<'a, 'gcx, 'tcx>( } } - // Print return place - let indented_retptr = format!("{}let mut {:?}: {};", - INDENT, - RETURN_PLACE, - mir.local_decls[RETURN_PLACE].ty); - writeln!(w, "{0:1$} // return place", - indented_retptr, - ALIGN)?; - write_scope_tree(tcx, mir, &scope_tree, w, OUTERMOST_SOURCE_SCOPE, 1)?; - write_temp_decls(mir, w)?; - // Add an empty line before the first block is printed. writeln!(w, "")?; @@ -632,22 +626,6 @@ fn write_mir_sig( Ok(()) } -fn write_temp_decls(mir: &Mir<'_>, w: &mut dyn Write) -> io::Result<()> { - // Compiler-introduced temporary types. - for temp in mir.temps_iter() { - writeln!( - w, - "{}let {}{:?}: {};", - INDENT, - if mir.local_decls[temp].mutability == Mutability::Mut {"mut "} else {""}, - temp, - mir.local_decls[temp].ty - )?; - } - - Ok(()) -} - fn write_user_type_annotations(mir: &Mir<'_>, w: &mut dyn Write) -> io::Result<()> { if !mir.user_type_annotations.is_empty() { writeln!(w, "| User Type Annotations")?; diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css index e3bb41ae672f4..f1255f5224737 100644 --- a/src/librustdoc/html/static/themes/dark.css +++ b/src/librustdoc/html/static/themes/dark.css @@ -184,12 +184,12 @@ a.test-arrow { color: #ddd; } -.stab.unstable {background: #FFF5D6; border-color: #FFC600; color: #2f2f2f; } +.stab.unstable { background: #FFF5D6; border-color: #FFC600; color: #2f2f2f; } .stab.internal { background: #FFB9B3; border-color: #B71C1C; color: #2f2f2f; } .stab.deprecated { background: #F3DFFF; border-color: #7F0087; color: #2f2f2f; } .stab.portability { background: #C4ECFF; border-color: #7BA5DB; color: #2f2f2f; } -.stab > code { +.stab.portability > code { color: #ddd; } diff --git a/src/librustdoc/html/static/themes/light.css b/src/librustdoc/html/static/themes/light.css index dd4d028c6c9be..c052e6b37ade7 100644 --- a/src/librustdoc/html/static/themes/light.css +++ b/src/librustdoc/html/static/themes/light.css @@ -190,7 +190,7 @@ a.test-arrow { .stab.deprecated { background: #F3DFFF; border-color: #7F0087; } .stab.portability { background: #C4ECFF; border-color: #7BA5DB; } -.stab > code { +.stab.portability > code { color: #000; } diff --git a/src/libstd/future.rs b/src/libstd/future.rs index 898387cb9f56d..c18a314116bf0 100644 --- a/src/libstd/future.rs +++ b/src/libstd/future.rs @@ -9,6 +9,7 @@ use core::task::{Context, Poll}; use core::ops::{Drop, Generator, GeneratorState}; #[doc(inline)] +#[stable(feature = "futures_api", since = "1.36.0")] pub use core::future::*; /// Wrap a generator in a future. diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 62bc1991cc93c..bdec0c347f546 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -263,7 +263,6 @@ #![feature(fixed_size_array)] #![feature(fn_traits)] #![feature(fnbox)] -#![feature(futures_api)] #![feature(generator_trait)] #![feature(hash_raw_entry)] #![feature(hashmap_internals)] @@ -458,18 +457,15 @@ pub mod process; pub mod sync; pub mod time; -#[unstable(feature = "futures_api", - reason = "futures in libcore are unstable", - issue = "50547")] +#[stable(feature = "futures_api", since = "1.36.0")] pub mod task { //! Types and Traits for working with asynchronous tasks. #[doc(inline)] + #[stable(feature = "futures_api", since = "1.36.0")] pub use core::task::*; } -#[unstable(feature = "futures_api", - reason = "futures in libcore are unstable", - issue = "50547")] +#[stable(feature = "futures_api", since = "1.36.0")] pub mod future; // Platform-abstraction modules diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs index 5a8101e230119..7a3b5d30500a9 100644 --- a/src/libstd/panic.rs +++ b/src/libstd/panic.rs @@ -319,7 +319,7 @@ impl fmt::Debug for AssertUnwindSafe { } } -#[unstable(feature = "futures_api", issue = "50547")] +#[stable(feature = "futures_api", since = "1.36.0")] impl Future for AssertUnwindSafe { type Output = F::Output; diff --git a/src/libsyntax/attr/builtin.rs b/src/libsyntax/attr/builtin.rs index 74c952b076cd7..db821f4e5369d 100644 --- a/src/libsyntax/attr/builtin.rs +++ b/src/libsyntax/attr/builtin.rs @@ -114,6 +114,8 @@ pub struct Stability { pub const_stability: Option, /// whether the function has a `#[rustc_promotable]` attribute pub promotable: bool, + /// whether the function has a `#[rustc_allow_const_fn_ptr]` attribute + pub allow_const_fn_ptr: bool, } /// The available stability levels. @@ -178,6 +180,7 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, let mut rustc_depr: Option = None; let mut rustc_const_unstable: Option = None; let mut promotable = false; + let mut allow_const_fn_ptr = false; let diagnostic = &sess.span_diagnostic; 'outer: for attr in attrs_iter { @@ -187,6 +190,7 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, "unstable", "stable", "rustc_promotable", + "rustc_allow_const_fn_ptr", ].iter().any(|&s| attr.path == s) { continue // not a stability level } @@ -198,6 +202,9 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, if attr.path == "rustc_promotable" { promotable = true; } + if attr.path == "rustc_allow_const_fn_ptr" { + allow_const_fn_ptr = true; + } // attributes with data else if let Some(MetaItem { node: MetaItemKind::List(ref metas), .. }) = meta { let meta = meta.as_ref().unwrap(); @@ -354,6 +361,7 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, rustc_depr: None, const_stability: None, promotable: false, + allow_const_fn_ptr: false, }) } (None, _, _) => { @@ -418,6 +426,7 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, rustc_depr: None, const_stability: None, promotable: false, + allow_const_fn_ptr: false, }) } (None, _) => { @@ -458,13 +467,14 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, } // Merge the const-unstable info into the stability info - if promotable { + if promotable || allow_const_fn_ptr { if let Some(ref mut stab) = stab { - stab.promotable = true; + stab.promotable = promotable; + stab.allow_const_fn_ptr = allow_const_fn_ptr; } else { span_err!(diagnostic, item_sp, E0717, - "rustc_promotable attribute must be paired with \ - either stable or unstable attribute"); + "rustc_promotable and rustc_allow_const_fn_ptr attributes \ + must be paired with either stable or unstable attribute"); } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 53dab510ac39f..75d687be28003 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1145,9 +1145,34 @@ impl<'a> Parser<'a> { if text.is_empty() { self.span_bug(sp, "found empty literal suffix in Some") } - self.struct_span_err(sp, &format!("suffixes on {} are invalid", kind)) - .span_label(sp, format!("invalid suffix `{}`", text)) - .emit(); + let mut err = if kind == "a tuple index" && + ["i32", "u32", "isize", "usize"].contains(&text.to_string().as_str()) + { + // #59553: warn instead of reject out of hand to allow the fix to percolate + // through the ecosystem when people fix their macros + let mut err = self.struct_span_warn( + sp, + &format!("suffixes on {} are invalid", kind), + ); + err.note(&format!( + "`{}` is *temporarily* accepted on tuple index fields as it was \ + incorrectly accepted on stable for a few releases", + text, + )); + err.help( + "on proc macros, you'll want to use `syn::Index::from` or \ + `proc_macro::Literal::*_unsuffixed` for code that will desugar \ + to tuple field access", + ); + err.note( + "for more context, see https://github.com/rust-lang/rust/issues/60210", + ); + err + } else { + self.struct_span_err(sp, &format!("suffixes on {} are invalid", kind)) + }; + err.span_label(sp, format!("invalid suffix `{}`", text)); + err.emit(); } } } @@ -1455,6 +1480,9 @@ impl<'a> Parser<'a> { fn struct_span_err>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> { self.sess.span_diagnostic.struct_span_err(sp, m) } + fn struct_span_warn>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> { + self.sess.span_diagnostic.struct_span_warn(sp, m) + } crate fn span_bug>(&self, sp: S, m: &str) -> ! { self.sess.span_diagnostic.span_bug(sp, m) } diff --git a/src/test/compile-fail/must_use-in-stdlib-traits.rs b/src/test/compile-fail/must_use-in-stdlib-traits.rs index 503b39e181ab7..39472ae11fbc5 100644 --- a/src/test/compile-fail/must_use-in-stdlib-traits.rs +++ b/src/test/compile-fail/must_use-in-stdlib-traits.rs @@ -1,5 +1,5 @@ #![deny(unused_must_use)] -#![feature(arbitrary_self_types, futures_api)] +#![feature(arbitrary_self_types)] use std::iter::Iterator; use std::future::Future; diff --git a/src/test/mir-opt/box_expr.rs b/src/test/mir-opt/box_expr.rs index 14d302f0eea72..d4852db6d475e 100644 --- a/src/test/mir-opt/box_expr.rs +++ b/src/test/mir-opt/box_expr.rs @@ -22,15 +22,14 @@ impl Drop for S { // END RUST SOURCE // START rustc.main.ElaborateDrops.before.mir // let mut _0: (); +// let mut _2: std::boxed::Box; +// let mut _3: (); +// let mut _4: std::boxed::Box; // scope 1 { +// let _1: std::boxed::Box; // } // scope 2 { -// let _1: std::boxed::Box; // } -// let mut _2: std::boxed::Box; -// let mut _3: (); -// let mut _4: std::boxed::Box; -// // bb0: { // StorageLive(_1); // StorageLive(_2); diff --git a/src/test/mir-opt/issue-41110.rs b/src/test/mir-opt/issue-41110.rs index 31ad1ebd9ff62..023440af0eb10 100644 --- a/src/test/mir-opt/issue-41110.rs +++ b/src/test/mir-opt/issue-41110.rs @@ -29,27 +29,28 @@ impl S { // END RUST SOURCE // START rustc.main.ElaborateDrops.after.mir // let mut _0: (); -// scope 1 { -// } -// scope 2 { -// let _1: (); -// } // let mut _2: S; // let mut _3: S; // let mut _4: S; // let mut _5: bool; +// scope 1 { +// let _1: (); +// } +// scope 2 { +// } +// ... // bb0: { // END rustc.main.ElaborateDrops.after.mir // START rustc.test.ElaborateDrops.after.mir // let mut _0: (); -// ... -// let mut _2: S; -// ... -// let _1: S; -// ... // let mut _3: (); // let mut _4: S; // let mut _5: S; // let mut _6: bool; +// ... +// let _1: S; +// ... +// let mut _2: S; +// ... // bb0: { // END rustc.test.ElaborateDrops.after.mir diff --git a/src/test/mir-opt/issue-49232.rs b/src/test/mir-opt/issue-49232.rs index 5f4f4ab82af24..29446d2ecc23e 100644 --- a/src/test/mir-opt/issue-49232.rs +++ b/src/test/mir-opt/issue-49232.rs @@ -17,16 +17,16 @@ fn main() { // START rustc.main.mir_map.0.mir // fn main() -> (){ // let mut _0: (); -// scope 1 { -// } -// scope 2 { -// let _2: i32; -// } // let mut _1: (); // let mut _3: bool; // let mut _4: !; // let mut _5: (); // let mut _6: &i32; +// scope 1 { +// let _2: i32; +// } +// scope 2 { +// } // bb0: { // goto -> bb1; // } diff --git a/src/test/mir-opt/nll/region-subtyping-basic.rs b/src/test/mir-opt/nll/region-subtyping-basic.rs index c2dda680b739d..bb27461bb1e0f 100644 --- a/src/test/mir-opt/nll/region-subtyping-basic.rs +++ b/src/test/mir-opt/nll/region-subtyping-basic.rs @@ -27,10 +27,10 @@ fn main() { // | '_#4r | U0 | {bb2[4..=5], bb3[0..=1]} // END rustc.main.nll.0.mir // START rustc.main.nll.0.mir -// let _6: &'_#4r usize; -// ... // let _2: &'_#3r usize; // ... +// let _6: &'_#4r usize; +// ... // _2 = &'_#2r _1[_3]; // ... // _6 = _2; diff --git a/src/test/mir-opt/packed-struct-drop-aligned.rs b/src/test/mir-opt/packed-struct-drop-aligned.rs index 167a6eb349eb2..7e8c58e64c28d 100644 --- a/src/test/mir-opt/packed-struct-drop-aligned.rs +++ b/src/test/mir-opt/packed-struct-drop-aligned.rs @@ -18,16 +18,16 @@ impl Drop for Droppy { // START rustc.main.EraseRegions.before.mir // fn main() -> () { // let mut _0: (); -// scope 1 { -// } -// scope 2 { -// let mut _1: Packed; -// } // let mut _2: Aligned; // let mut _3: Droppy; // let mut _4: Aligned; // let mut _5: Droppy; // let mut _6: Aligned; +// scope 1 { +// let mut _1: Packed; +// } +// scope 2 { +// } // // bb0: { // StorageLive(_1); diff --git a/src/test/run-pass/async-await.rs b/src/test/run-pass/async-await.rs index 518452aefc152..e1b4328debd9a 100644 --- a/src/test/run-pass/async-await.rs +++ b/src/test/run-pass/async-await.rs @@ -1,7 +1,7 @@ // edition:2018 // aux-build:arc_wake.rs -#![feature(async_await, await_macro, futures_api)] +#![feature(async_await, await_macro)] extern crate arc_wake; diff --git a/src/test/run-pass/auxiliary/arc_wake.rs b/src/test/run-pass/auxiliary/arc_wake.rs index 93e074e7ee55c..c21886f26f467 100644 --- a/src/test/run-pass/auxiliary/arc_wake.rs +++ b/src/test/run-pass/auxiliary/arc_wake.rs @@ -1,7 +1,5 @@ // edition:2018 -#![feature(futures_api)] - use std::sync::Arc; use std::task::{ Waker, RawWaker, RawWakerVTable, diff --git a/src/test/run-pass/futures-api.rs b/src/test/run-pass/futures-api.rs index 6094f15569bb6..ee77053fd5b6a 100644 --- a/src/test/run-pass/futures-api.rs +++ b/src/test/run-pass/futures-api.rs @@ -1,7 +1,5 @@ // aux-build:arc_wake.rs -#![feature(futures_api)] - extern crate arc_wake; use std::future::Future; diff --git a/src/test/run-pass/issue-54716.rs b/src/test/run-pass/issue-54716.rs index ea4f5e076b005..961c412f5ecb2 100644 --- a/src/test/run-pass/issue-54716.rs +++ b/src/test/run-pass/issue-54716.rs @@ -3,7 +3,7 @@ // run-pass #![allow(unused_variables)] -#![feature(async_await, await_macro, futures_api)] +#![feature(async_await, await_macro)] extern crate arc_wake; diff --git a/src/test/run-pass/issue-55809.rs b/src/test/run-pass/issue-55809.rs index 86b0977bebe1d..12be6582a21e8 100644 --- a/src/test/run-pass/issue-55809.rs +++ b/src/test/run-pass/issue-55809.rs @@ -1,7 +1,7 @@ // edition:2018 // run-pass -#![feature(async_await, await_macro, futures_api)] +#![feature(async_await, await_macro)] trait Foo { } diff --git a/src/test/rustdoc/async-fn.rs b/src/test/rustdoc/async-fn.rs index ba4997a7f9b5b..7384f7027d185 100644 --- a/src/test/rustdoc/async-fn.rs +++ b/src/test/rustdoc/async-fn.rs @@ -1,6 +1,6 @@ // edition:2018 -#![feature(async_await, futures_api)] +#![feature(async_await)] // @has async_fn/fn.foo.html '//pre[@class="rust fn"]' 'pub async fn foo() -> Option' pub async fn foo() -> Option { diff --git a/src/test/ui/async-fn-multiple-lifetimes.rs b/src/test/ui/async-fn-multiple-lifetimes.rs index fccc4fdb91725..e3ac817b15ca5 100644 --- a/src/test/ui/async-fn-multiple-lifetimes.rs +++ b/src/test/ui/async-fn-multiple-lifetimes.rs @@ -1,6 +1,6 @@ // edition:2018 -#![feature(arbitrary_self_types, async_await, await_macro, futures_api, pin)] +#![feature(arbitrary_self_types, async_await, await_macro, pin)] use std::ops::Add; diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs new file mode 100644 index 0000000000000..3992607c387e1 --- /dev/null +++ b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs @@ -0,0 +1,10 @@ +#![feature(rustc_attrs, staged_api)] + +#[stable(feature = "rust1", since = "1.0.0")] +const fn error(_: fn()) {} //~ ERROR function pointers in const fn are unstable + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_allow_const_fn_ptr] +const fn compiles(_: fn()) {} + +fn main() {} diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr new file mode 100644 index 0000000000000..e6e1ced6592a2 --- /dev/null +++ b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr @@ -0,0 +1,12 @@ +error[E0723]: function pointers in const fn are unstable + --> $DIR/allow_const_fn_ptr.rs:4:16 + | +LL | const fn error(_: fn()) {} + | ^ + | + = note: for more information, see issue https://github.com/rust-lang/rust/issues/57563 + = help: add #![feature(const_fn)] to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0723`. diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.rs b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.rs new file mode 100644 index 0000000000000..0395795ef7bfe --- /dev/null +++ b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.rs @@ -0,0 +1,11 @@ +#![feature(staged_api)] + +#[stable(feature = "rust1", since = "1.0.0")] +const fn error(_: fn()) {} + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_allow_const_fn_ptr] +//~^ ERROR unless otherwise specified, attributes with the prefix `rustc_` are reserved +const fn compiles(_: fn()) {} + +fn main() {} diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.stderr b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.stderr new file mode 100644 index 0000000000000..c934307e918b9 --- /dev/null +++ b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.stderr @@ -0,0 +1,12 @@ +error[E0658]: unless otherwise specified, attributes with the prefix `rustc_` are reserved for internal compiler diagnostics + --> $DIR/allow_const_fn_ptr_feature_gate.rs:7:3 + | +LL | #[rustc_allow_const_fn_ptr] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 + = help: add #![feature(rustc_attrs)] to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs new file mode 100644 index 0000000000000..1d8b95ab1a2fd --- /dev/null +++ b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs @@ -0,0 +1,18 @@ +// run-pass + +#![feature(rustc_attrs, staged_api)] +#![stable(feature = "rust1", since = "1.0.0")] + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_allow_const_fn_ptr] +const fn takes_fn_ptr(_: fn()) {} + +const FN: fn() = || (); + +const fn gives_fn_ptr() { + takes_fn_ptr(FN) +} + +fn main() { + gives_fn_ptr(); +} diff --git a/src/test/ui/editions/edition-deny-async-fns-2015.rs b/src/test/ui/editions/edition-deny-async-fns-2015.rs index 2105aa5835d0d..e1111f9e0e4b9 100644 --- a/src/test/ui/editions/edition-deny-async-fns-2015.rs +++ b/src/test/ui/editions/edition-deny-async-fns-2015.rs @@ -1,6 +1,6 @@ // edition:2015 -#![feature(futures_api, async_await)] +#![feature(async_await)] async fn foo() {} //~ ERROR `async fn` is not permitted in the 2015 edition diff --git a/src/test/ui/feature-gates/feature-gate-async-await-2015-edition.rs b/src/test/ui/feature-gates/feature-gate-async-await-2015-edition.rs index b6ab8ae0a9bc7..801aeb82aa266 100644 --- a/src/test/ui/feature-gates/feature-gate-async-await-2015-edition.rs +++ b/src/test/ui/feature-gates/feature-gate-async-await-2015-edition.rs @@ -1,7 +1,5 @@ // edition:2015 -#![feature(futures_api)] - async fn foo() {} //~ ERROR `async fn` is not permitted in the 2015 edition //~^ ERROR async fn is unstable diff --git a/src/test/ui/feature-gates/feature-gate-async-await-2015-edition.stderr b/src/test/ui/feature-gates/feature-gate-async-await-2015-edition.stderr index cec211fef1351..b419f1232dfab 100644 --- a/src/test/ui/feature-gates/feature-gate-async-await-2015-edition.stderr +++ b/src/test/ui/feature-gates/feature-gate-async-await-2015-edition.stderr @@ -1,23 +1,23 @@ error[E0670]: `async fn` is not permitted in the 2015 edition - --> $DIR/feature-gate-async-await-2015-edition.rs:5:1 + --> $DIR/feature-gate-async-await-2015-edition.rs:3:1 | LL | async fn foo() {} | ^^^^^ error[E0422]: cannot find struct, variant or union type `async` in this scope - --> $DIR/feature-gate-async-await-2015-edition.rs:9:13 + --> $DIR/feature-gate-async-await-2015-edition.rs:7:13 | LL | let _ = async {}; | ^^^^^ not found in this scope error[E0425]: cannot find value `async` in this scope - --> $DIR/feature-gate-async-await-2015-edition.rs:10:13 + --> $DIR/feature-gate-async-await-2015-edition.rs:8:13 | LL | let _ = async || { true }; | ^^^^^ not found in this scope error[E0658]: async fn is unstable - --> $DIR/feature-gate-async-await-2015-edition.rs:5:1 + --> $DIR/feature-gate-async-await-2015-edition.rs:3:1 | LL | async fn foo() {} | ^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/feature-gates/feature-gate-async-await.rs b/src/test/ui/feature-gates/feature-gate-async-await.rs index 1fdaec75e9d5a..9cfefef4129de 100644 --- a/src/test/ui/feature-gates/feature-gate-async-await.rs +++ b/src/test/ui/feature-gates/feature-gate-async-await.rs @@ -1,7 +1,5 @@ // edition:2018 -#![feature(futures_api)] - struct S; impl S { diff --git a/src/test/ui/feature-gates/feature-gate-async-await.stderr b/src/test/ui/feature-gates/feature-gate-async-await.stderr index 1fa21f52045fc..43e41b4545869 100644 --- a/src/test/ui/feature-gates/feature-gate-async-await.stderr +++ b/src/test/ui/feature-gates/feature-gate-async-await.stderr @@ -1,11 +1,11 @@ error[E0706]: trait fns cannot be declared `async` - --> $DIR/feature-gate-async-await.rs:12:5 + --> $DIR/feature-gate-async-await.rs:10:5 | LL | async fn foo(); | ^^^^^^^^^^^^^^^ error[E0658]: async fn is unstable - --> $DIR/feature-gate-async-await.rs:8:5 + --> $DIR/feature-gate-async-await.rs:6:5 | LL | async fn foo() {} | ^^^^^^^^^^^^^^^^^ @@ -14,7 +14,7 @@ LL | async fn foo() {} = help: add #![feature(async_await)] to the crate attributes to enable error[E0658]: async fn is unstable - --> $DIR/feature-gate-async-await.rs:12:5 + --> $DIR/feature-gate-async-await.rs:10:5 | LL | async fn foo(); | ^^^^^^^^^^^^^^^ @@ -23,7 +23,7 @@ LL | async fn foo(); = help: add #![feature(async_await)] to the crate attributes to enable error[E0658]: async fn is unstable - --> $DIR/feature-gate-async-await.rs:16:1 + --> $DIR/feature-gate-async-await.rs:14:1 | LL | async fn foo() {} | ^^^^^^^^^^^^^^^^^ @@ -32,7 +32,7 @@ LL | async fn foo() {} = help: add #![feature(async_await)] to the crate attributes to enable error[E0658]: async blocks are unstable - --> $DIR/feature-gate-async-await.rs:19:13 + --> $DIR/feature-gate-async-await.rs:17:13 | LL | let _ = async {}; | ^^^^^^^^ @@ -41,7 +41,7 @@ LL | let _ = async {}; = help: add #![feature(async_await)] to the crate attributes to enable error[E0658]: async closures are unstable - --> $DIR/feature-gate-async-await.rs:20:13 + --> $DIR/feature-gate-async-await.rs:18:13 | LL | let _ = async || {}; | ^^^^^^^^^^^ diff --git a/src/test/ui/impl-trait/recursive-async-impl-trait-type.rs b/src/test/ui/impl-trait/recursive-async-impl-trait-type.rs index 40642523be255..a4e080119345e 100644 --- a/src/test/ui/impl-trait/recursive-async-impl-trait-type.rs +++ b/src/test/ui/impl-trait/recursive-async-impl-trait-type.rs @@ -2,7 +2,7 @@ // Test that impl trait does not allow creating recursive types that are // otherwise forbidden when using `async` and `await`. -#![feature(await_macro, async_await, futures_api, generators)] +#![feature(await_macro, async_await, generators)] async fn recursive_async_function() -> () { //~ ERROR await!(recursive_async_function()); diff --git a/src/test/ui/impl-trait/recursive-impl-trait-type.rs b/src/test/ui/impl-trait/recursive-impl-trait-type.rs index 869876dc6a88a..2428b560b7001 100644 --- a/src/test/ui/impl-trait/recursive-impl-trait-type.rs +++ b/src/test/ui/impl-trait/recursive-impl-trait-type.rs @@ -1,7 +1,7 @@ // Test that impl trait does not allow creating recursive types that are // otherwise forbidden. -#![feature(futures_api, generators)] +#![feature(generators)] fn option(i: i32) -> impl Sized { //~ ERROR if i < 0 { diff --git a/src/test/ui/issues/issue-54974.rs b/src/test/ui/issues/issue-54974.rs index b2624ec92a184..d6f18875c9e3a 100644 --- a/src/test/ui/issues/issue-54974.rs +++ b/src/test/ui/issues/issue-54974.rs @@ -1,7 +1,7 @@ // compile-pass // edition:2018 -#![feature(async_await, await_macro, futures_api)] +#![feature(async_await, await_macro)] use std::sync::Arc; diff --git a/src/test/ui/issues/issue-55324.rs b/src/test/ui/issues/issue-55324.rs index 6160fbabd96d7..4572e543f22de 100644 --- a/src/test/ui/issues/issue-55324.rs +++ b/src/test/ui/issues/issue-55324.rs @@ -1,7 +1,7 @@ // compile-pass // edition:2018 -#![feature(async_await, await_macro, futures_api)] +#![feature(async_await, await_macro)] use std::future::Future; diff --git a/src/test/ui/issues/issue-58885.rs b/src/test/ui/issues/issue-58885.rs index 559899194fbe7..99d87b2273c2f 100644 --- a/src/test/ui/issues/issue-58885.rs +++ b/src/test/ui/issues/issue-58885.rs @@ -1,7 +1,7 @@ // compile-pass // edition:2018 -#![feature(async_await, await_macro, futures_api)] +#![feature(async_await, await_macro)] struct Xyz { a: u64, diff --git a/src/test/ui/issues/issue-59001.rs b/src/test/ui/issues/issue-59001.rs index a310653fbce48..c758244002ff6 100644 --- a/src/test/ui/issues/issue-59001.rs +++ b/src/test/ui/issues/issue-59001.rs @@ -1,7 +1,7 @@ // compile-pass // edition:2018 -#![feature(async_await, await_macro, futures_api)] +#![feature(async_await, await_macro)] use std::future::Future; diff --git a/src/test/ui/no-args-non-move-async-closure.rs b/src/test/ui/no-args-non-move-async-closure.rs index 4f5b2ea3783aa..345f19b06233b 100644 --- a/src/test/ui/no-args-non-move-async-closure.rs +++ b/src/test/ui/no-args-non-move-async-closure.rs @@ -1,6 +1,6 @@ // edition:2018 -#![feature(arbitrary_self_types, async_await, await_macro, futures_api, pin)] +#![feature(async_await, await_macro)] fn main() { let _ = async |x: u8| {}; diff --git a/src/test/ui/try-poll.rs b/src/test/ui/try-poll.rs index 3d7115c522346..f63950ad5e905 100644 --- a/src/test/ui/try-poll.rs +++ b/src/test/ui/try-poll.rs @@ -1,7 +1,6 @@ // compile-pass #![allow(dead_code, unused)] -#![feature(futures_api)] use std::task::Poll;