Skip to content
Merged
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
0e6049a
Fix dark css rule
GuillaumeGomez Apr 9, 2019
e3fb331
Temporarily accept [i|u][32|size] suffixes on a tuple index and warn
estebank Apr 22, 2019
61fcbfc
rustc_mir: don't rely on mir::UpvarDecl in the MIR borrowck.
eddyb May 16, 2018
82bd719
rustc: don't track var_hir_id or mutability in mir::UpvarDecl.
eddyb May 16, 2018
c1ec45f
rustc_mir: don't use upvar_decls in the generator state transform.
eddyb May 16, 2018
2384e98
rustc_mir: don't use upvar_decls in the miri validity checks.
eddyb Nov 26, 2018
e6ec968
rustc_codegen_ssa: rename debuginfo_upvar_decls_ops_sequence to debug…
eddyb Nov 26, 2018
1525dc2
rustc: dissuade compiler developers from misusing upvar debuginfo.
eddyb Nov 26, 2018
d20da13
rustc_mir: don't rely on mir::LocalDecl `visibility_scope`s in the MI…
eddyb Nov 27, 2018
9260305
rustc_mir: pretty-print all locals into their respective scopes.
eddyb May 17, 2018
c3ca9a3
rustc_mir: create the `let` and "remainder" scopes in source order.
eddyb Jun 1, 2018
4c01573
review comment: change linked ticket
estebank Apr 23, 2019
e617025
Add rustc_allow_const_fn_ptr
cramertj Apr 5, 2019
3f966dc
Stabilize futures_api
cramertj Apr 5, 2019
3fc0936
Don't generate unnecessary rmeta files.
nnethercote Apr 23, 2019
5f82b5b
Rollup merge of #56278 - eddyb:mir-debuginfo-proof, r=nikomatsakis
Centril Apr 24, 2019
48cb6be
Rollup merge of #59739 - cramertj:stabilize, r=withoutboats
Centril Apr 24, 2019
31a5371
Rollup merge of #59822 - GuillaumeGomez:fix-dark-theme-css, r=Manishe…
Centril Apr 24, 2019
eb4860c
Rollup merge of #60186 - estebank:accept-suffix, r=nikomatsakis
Centril Apr 24, 2019
7304e96
Rollup merge of #60190 - nnethercote:less-metadata-gen, r=alexcrichton
Centril Apr 24, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/liballoc/boxed.rs
Original file line number Diff line number Diff line change
@@ -911,7 +911,7 @@ impl<G: ?Sized + Generator> Generator for Pin<Box<G>> {
}
}

#[unstable(feature = "futures_api", issue = "50547")]
#[stable(feature = "futures_api", since = "1.36.0")]
impl<F: ?Sized + Future + Unpin> Future for Box<F> {
type Output = F::Output;

1 change: 0 additions & 1 deletion src/liballoc/lib.rs
Original file line number Diff line number Diff line change
@@ -85,7 +85,6 @@
#![feature(fmt_internals)]
#![feature(fn_traits)]
#![feature(fundamental)]
#![feature(futures_api)]
#![feature(lang_items)]
#![feature(libc)]
#![feature(needs_allocator)]
9 changes: 6 additions & 3 deletions src/libcore/future/future.rs
Original file line number Diff line number Diff line change
@@ -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<Self::Output>;
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl<F: ?Sized + Future + Unpin> Future for &mut F {
type Output = F::Output;

@@ -103,6 +105,7 @@ impl<F: ?Sized + Future + Unpin> Future for &mut F {
}
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl<P> Future for Pin<P>
where
P: Unpin + ops::DerefMut,
5 changes: 2 additions & 3 deletions src/libcore/future/mod.rs
Original file line number Diff line number Diff line change
@@ -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;
6 changes: 3 additions & 3 deletions src/libcore/task/mod.rs
Original file line number Diff line number Diff line change
@@ -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};
20 changes: 16 additions & 4 deletions src/libcore/task/poll.rs
Original file line number Diff line number Diff line change
@@ -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<T> {
/// 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<T> Poll<T> {
/// Changes the ready value of this `Poll` with the closure provided.
#[stable(feature = "futures_api", since = "1.36.0")]
pub fn map<U, F>(self, f: F) -> Poll<U>
where F: FnOnce(T) -> U
{
@@ -34,6 +39,7 @@ impl<T> Poll<T> {

/// 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,13 +49,15 @@ impl<T> Poll<T> {

/// 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()
}
}

impl<T, E> Poll<Result<T, E>> {
/// Changes the success value of this `Poll` with the closure provided.
#[stable(feature = "futures_api", since = "1.36.0")]
pub fn map_ok<U, F>(self, f: F) -> Poll<Result<U, E>>
where F: FnOnce(T) -> U
{
@@ -61,6 +69,7 @@ impl<T, E> Poll<Result<T, E>> {
}

/// Changes the error value of this `Poll` with the closure provided.
#[stable(feature = "futures_api", since = "1.36.0")]
pub fn map_err<U, F>(self, f: F) -> Poll<Result<T, U>>
where F: FnOnce(E) -> U
{
@@ -72,12 +81,14 @@ impl<T, E> Poll<Result<T, E>> {
}
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl<T> From<T> for Poll<T> {
fn from(t: T) -> Poll<T> {
Poll::Ready(t)
}
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl<T, E> Try for Poll<Result<T, E>> {
type Ok = Poll<T>;
type Error = E;
@@ -102,6 +113,7 @@ impl<T, E> Try for Poll<Result<T, E>> {
}
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl<T, E> Try for Poll<Option<Result<T, E>>> {
type Ok = Poll<Option<T>>;
type Error = E;
36 changes: 27 additions & 9 deletions src/libcore/task/wake.rs
Original file line number Diff line number Diff line change
@@ -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,13 +267,15 @@ 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,
}
}
}

#[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;
1 change: 1 addition & 0 deletions src/librustc/ich/impls_syntax.rs
Original file line number Diff line number Diff line change
@@ -121,6 +121,7 @@ impl_stable_hash_for!(struct ::syntax::attr::Stability {
feature,
rustc_depr,
promotable,
allow_const_fn_ptr,
const_stability
});

1 change: 1 addition & 0 deletions src/librustc/middle/stability.rs
Original file line number Diff line number Diff line change
@@ -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);
}
31 changes: 15 additions & 16 deletions src/librustc/mir/mod.rs
Original file line number Diff line number Diff line change
@@ -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<UpvarDecl>,

/// 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<Local>,

/// 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<UpvarDebuginfo>,

/// 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<UpvarDecl>,
__upvar_debuginfo_codegen_only_do_not_use: Vec<UpvarDebuginfo>,
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<HirId>,

/// 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,
35 changes: 0 additions & 35 deletions src/librustc/mir/tcx.rs
Original file line number Diff line number Diff line change
@@ -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<Field> {
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 {
2 changes: 2 additions & 0 deletions src/librustc/query/mod.rs
Original file line number Diff line number Diff line change
@@ -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 {}

7 changes: 7 additions & 0 deletions src/librustc/ty/constness.rs
Original file line number Diff line number Diff line change
@@ -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
};
}
2 changes: 1 addition & 1 deletion src/librustc_codegen_llvm/debuginfo/mod.rs
Original file line number Diff line number Diff line change
@@ -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(),
19 changes: 12 additions & 7 deletions src/librustc_codegen_ssa/back/link.rs
Original file line number Diff line number Diff line change
@@ -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);
}
}
11 changes: 5 additions & 6 deletions src/librustc_codegen_ssa/back/write.rs
Original file line number Diff line number Diff line change
@@ -350,7 +350,7 @@ fn generate_lto_work<B: ExtraBackendMethods>(

pub struct CompiledModules {
pub modules: Vec<CompiledModule>,
pub metadata_module: CompiledModule,
pub metadata_module: Option<CompiledModule>,
pub allocator_module: Option<CompiledModule>,
}

@@ -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<B: ExtraBackendMethods>(
// 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,
28 changes: 19 additions & 9 deletions src/librustc_codegen_ssa/base.rs
Original file line number Diff line number Diff line change
@@ -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<B: ExtraBackendMethods>(
});
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<B: ExtraBackendMethods>(
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<B: ExtraBackendMethods>(
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.
2 changes: 1 addition & 1 deletion src/librustc_codegen_ssa/lib.rs
Original file line number Diff line number Diff line change
@@ -154,7 +154,7 @@ pub struct CodegenResults {
pub crate_name: Symbol,
pub modules: Vec<CompiledModule>,
pub allocator_module: Option<CompiledModule>,
pub metadata_module: CompiledModule,
pub metadata_module: Option<CompiledModule>,
pub crate_hash: Svh,
pub metadata: rustc::middle::cstore::EncodedMetadata,
pub windows_subsystem: Option<String>,
13 changes: 7 additions & 6 deletions src/librustc_codegen_ssa/mir/mod.rs
Original file line number Diff line number Diff line change
@@ -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..] };
2 changes: 1 addition & 1 deletion src/librustc_codegen_ssa/traits/debuginfo.rs
Original file line number Diff line number Diff line change
@@ -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 {
12 changes: 6 additions & 6 deletions src/librustc_mir/borrow_check/error_reporting.rs
Original file line number Diff line number Diff line change
@@ -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);
110 changes: 94 additions & 16 deletions src/librustc_mir/borrow_check/mod.rs
Original file line number Diff line number Diff line change
@@ -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<BasicBlock>,

/// Information about upvars not necessarily preserved in types or MIR
upvars: Vec<Upvar>,
}

// 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<Field> {
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)]
14 changes: 5 additions & 9 deletions src/librustc_mir/borrow_check/move_errors.rs
Original file line number Diff line number Diff line change
@@ -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,16 +269,15 @@ 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(..) =>
self.infcx.tcx.cannot_move_out_of_interior_noncopy(
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");
15 changes: 6 additions & 9 deletions src/librustc_mir/borrow_check/mutability_errors.rs
Original file line number Diff line number Diff line change
@@ -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(
7 changes: 2 additions & 5 deletions src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs
Original file line number Diff line number Diff line change
@@ -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,
5 changes: 4 additions & 1 deletion src/librustc_mir/borrow_check/nll/mod.rs
Original file line number Diff line number Diff line change
@@ -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.
Original file line number Diff line number Diff line change
@@ -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<Diagnostic>,
) {
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)
}

Original file line number Diff line number Diff line change
@@ -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<RegionName> {
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 {
Original file line number Diff line number Diff line change
@@ -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<Symbol>, 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);
14 changes: 12 additions & 2 deletions src/librustc_mir/borrow_check/nll/region_infer/mod.rs
Original file line number Diff line number Diff line change
@@ -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,21 +401,23 @@ impl<'tcx> RegionInferenceContext<'tcx> {
&mut self,
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
mir: &Mir<'tcx>,
upvars: &[Upvar],
mir_def_id: DefId,
errors_buffer: &mut Vec<Diagnostic>,
) -> Option<ClosureRegionRequirements<'gcx>> {
common::time_ext(
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),
)
}

fn solve_inner<'gcx>(
&mut self,
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
mir: &Mir<'tcx>,
upvars: &[Upvar],
mir_def_id: DefId,
errors_buffer: &mut Vec<Diagnostic>,
) -> Option<ClosureRegionRequirements<'gcx>> {
@@ -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<ClosureOutlivesRequirement<'gcx>>>,
errors_buffer: &mut Vec<Diagnostic>,
@@ -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<ClosureOutlivesRequirement<'gcx>>>,
@@ -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<ClosureOutlivesRequirement<'gcx>>>,
errors_buffer: &mut Vec<Diagnostic>,
@@ -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)
}

2 changes: 1 addition & 1 deletion src/librustc_mir/borrow_check/nll/universal_regions.rs
Original file line number Diff line number Diff line change
@@ -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<Item = Ty<'tcx>> + 'tcx {
match self {
DefiningTy::Closure(def_id, substs) => Either::Left(substs.upvar_tys(def_id, tcx)),
4 changes: 2 additions & 2 deletions src/librustc_mir/build/expr/as_rvalue.rs
Original file line number Diff line number Diff line change
@@ -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"),
};
5 changes: 3 additions & 2 deletions src/librustc_mir/build/matches/mod.rs
Original file line number Diff line number Diff line change
@@ -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();
35 changes: 20 additions & 15 deletions src/librustc_mir/build/mod.rs
Original file line number Diff line number Diff line change
@@ -375,7 +375,8 @@ struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
var_indices: HirIdMap<LocalsForNode>,
local_decls: IndexVec<Local, LocalDecl<'tcx>>,
canonical_user_type_annotations: ty::CanonicalUserTypeAnnotations<'tcx>,
upvar_decls: Vec<UpvarDecl>,
__upvar_debuginfo_codegen_only_do_not_use: Vec<UpvarDebuginfo>,
upvar_mutbls: Vec<Mutability>,
unit_temp: Option<Place<'tcx>>,

/// 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<UpvarDecl>)
__upvar_debuginfo_codegen_only_do_not_use: Vec<UpvarDebuginfo>,
upvar_mutbls: Vec<Mutability>)
-> 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(),
)
28 changes: 22 additions & 6 deletions src/librustc_mir/interpret/validity.rs
Original file line number Diff line number Diff line change
@@ -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
10 changes: 5 additions & 5 deletions src/librustc_mir/transform/generator.rs
Original file line number Diff line number Diff line change
@@ -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<Ty<'tcx>>,
upvars: &Vec<Ty<'tcx>>,
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`.
6 changes: 3 additions & 3 deletions src/librustc_mir/transform/inline.rs
Original file line number Diff line number Diff line change
@@ -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;
}

8 changes: 6 additions & 2 deletions src/librustc_mir/transform/qualify_min_const_fn.rs
Original file line number Diff line number Diff line change
@@ -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() {
126 changes: 52 additions & 74 deletions src/librustc_mir/util/pretty.rs
Original file line number Diff line number Diff line change
@@ -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")?;
4 changes: 2 additions & 2 deletions src/librustdoc/html/static/themes/dark.css
Original file line number Diff line number Diff line change
@@ -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;
}

2 changes: 1 addition & 1 deletion src/librustdoc/html/static/themes/light.css
Original file line number Diff line number Diff line change
@@ -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;
}

1 change: 1 addition & 0 deletions src/libstd/future.rs
Original file line number Diff line number Diff line change
@@ -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.
10 changes: 3 additions & 7 deletions src/libstd/lib.rs
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion src/libstd/panic.rs
Original file line number Diff line number Diff line change
@@ -319,7 +319,7 @@ impl<T: fmt::Debug> fmt::Debug for AssertUnwindSafe<T> {
}
}

#[unstable(feature = "futures_api", issue = "50547")]
#[stable(feature = "futures_api", since = "1.36.0")]
impl<F: Future> Future for AssertUnwindSafe<F> {
type Output = F::Output;

18 changes: 14 additions & 4 deletions src/libsyntax/attr/builtin.rs
Original file line number Diff line number Diff line change
@@ -114,6 +114,8 @@ pub struct Stability {
pub const_stability: Option<Symbol>,
/// 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<RustcDeprecation> = None;
let mut rustc_const_unstable: Option<Symbol> = 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");
}
}

34 changes: 31 additions & 3 deletions src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
@@ -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<S: Into<MultiSpan>>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> {
self.sess.span_diagnostic.struct_span_err(sp, m)
}
fn struct_span_warn<S: Into<MultiSpan>>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> {
self.sess.span_diagnostic.struct_span_warn(sp, m)
}
crate fn span_bug<S: Into<MultiSpan>>(&self, sp: S, m: &str) -> ! {
self.sess.span_diagnostic.span_bug(sp, m)
}
2 changes: 1 addition & 1 deletion src/test/compile-fail/must_use-in-stdlib-traits.rs
Original file line number Diff line number Diff line change
@@ -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;
9 changes: 4 additions & 5 deletions src/test/mir-opt/box_expr.rs
Original file line number Diff line number Diff line change
@@ -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<S>;
// let mut _3: ();
// let mut _4: std::boxed::Box<S>;
// scope 1 {
// let _1: std::boxed::Box<S>;
// }
// scope 2 {
// let _1: std::boxed::Box<S>;
// }
// let mut _2: std::boxed::Box<S>;
// let mut _3: ();
// let mut _4: std::boxed::Box<S>;
//
// bb0: {
// StorageLive(_1);
// StorageLive(_2);
21 changes: 11 additions & 10 deletions src/test/mir-opt/issue-41110.rs
Original file line number Diff line number Diff line change
@@ -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
10 changes: 5 additions & 5 deletions src/test/mir-opt/issue-49232.rs
Original file line number Diff line number Diff line change
@@ -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;
// }
4 changes: 2 additions & 2 deletions src/test/mir-opt/nll/region-subtyping-basic.rs
Original file line number Diff line number Diff line change
@@ -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;
10 changes: 5 additions & 5 deletions src/test/mir-opt/packed-struct-drop-aligned.rs
Original file line number Diff line number Diff line change
@@ -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);
2 changes: 1 addition & 1 deletion src/test/run-pass/async-await.rs
Original file line number Diff line number Diff line change
@@ -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;

2 changes: 0 additions & 2 deletions src/test/run-pass/auxiliary/arc_wake.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
// edition:2018

#![feature(futures_api)]

use std::sync::Arc;
use std::task::{
Waker, RawWaker, RawWakerVTable,
2 changes: 0 additions & 2 deletions src/test/run-pass/futures-api.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
// aux-build:arc_wake.rs

#![feature(futures_api)]

extern crate arc_wake;

use std::future::Future;
2 changes: 1 addition & 1 deletion src/test/run-pass/issue-54716.rs
Original file line number Diff line number Diff line change
@@ -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;

2 changes: 1 addition & 1 deletion src/test/run-pass/issue-55809.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// edition:2018
// run-pass

#![feature(async_await, await_macro, futures_api)]
#![feature(async_await, await_macro)]

trait Foo { }

2 changes: 1 addition & 1 deletion src/test/rustdoc/async-fn.rs
Original file line number Diff line number Diff line change
@@ -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<Foo>'
pub async fn foo() -> Option<Foo> {
2 changes: 1 addition & 1 deletion src/test/ui/async-fn-multiple-lifetimes.rs
Original file line number Diff line number Diff line change
@@ -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;

10 changes: 10 additions & 0 deletions src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs
Original file line number Diff line number Diff line change
@@ -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() {}
12 changes: 12 additions & 0 deletions src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr
Original file line number Diff line number Diff line change
@@ -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`.
11 changes: 11 additions & 0 deletions src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.rs
Original file line number Diff line number Diff line change
@@ -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() {}
Original file line number Diff line number Diff line change
@@ -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`.
18 changes: 18 additions & 0 deletions src/test/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs
Original file line number Diff line number Diff line change
@@ -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();
}
2 changes: 1 addition & 1 deletion src/test/ui/editions/edition-deny-async-fns-2015.rs
Original file line number Diff line number Diff line change
@@ -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

Original file line number Diff line number Diff line change
@@ -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

Original file line number Diff line number Diff line change
@@ -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() {}
| ^^^^^^^^^^^^^^^^^
2 changes: 0 additions & 2 deletions src/test/ui/feature-gates/feature-gate-async-await.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
// edition:2018

#![feature(futures_api)]

struct S;

impl S {
12 changes: 6 additions & 6 deletions src/test/ui/feature-gates/feature-gate-async-await.stderr
Original file line number Diff line number Diff line change
@@ -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 || {};
| ^^^^^^^^^^^
2 changes: 1 addition & 1 deletion src/test/ui/impl-trait/recursive-async-impl-trait-type.rs
Original file line number Diff line number Diff line change
@@ -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());
2 changes: 1 addition & 1 deletion src/test/ui/impl-trait/recursive-impl-trait-type.rs
Original file line number Diff line number Diff line change
@@ -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 {
2 changes: 1 addition & 1 deletion src/test/ui/issues/issue-54974.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// compile-pass
// edition:2018

#![feature(async_await, await_macro, futures_api)]
#![feature(async_await, await_macro)]

use std::sync::Arc;

2 changes: 1 addition & 1 deletion src/test/ui/issues/issue-55324.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// compile-pass
// edition:2018

#![feature(async_await, await_macro, futures_api)]
#![feature(async_await, await_macro)]

use std::future::Future;

2 changes: 1 addition & 1 deletion src/test/ui/issues/issue-58885.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// compile-pass
// edition:2018

#![feature(async_await, await_macro, futures_api)]
#![feature(async_await, await_macro)]

struct Xyz {
a: u64,
2 changes: 1 addition & 1 deletion src/test/ui/issues/issue-59001.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// compile-pass
// edition:2018

#![feature(async_await, await_macro, futures_api)]
#![feature(async_await, await_macro)]

use std::future::Future;

2 changes: 1 addition & 1 deletion src/test/ui/no-args-non-move-async-closure.rs
Original file line number Diff line number Diff line change
@@ -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| {};
1 change: 0 additions & 1 deletion src/test/ui/try-poll.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// compile-pass

#![allow(dead_code, unused)]
#![feature(futures_api)]

use std::task::Poll;