Auto merge of #60224 - Centril:rollup-lfuhhsk, r=Centril

Rollup of 5 pull requests

Successful merges:

 - #56278 (Future-proof MIR for dedicated debuginfo.)
 - #59739 (Stabilize futures_api)
 - #59822 (Fix dark css rule)
 - #60186 (Temporarily accept [i|u][32|size] suffixes on a tuple index and warn)
 - #60190 (Don't generate unnecessary rmeta files.)

Failed merges:

r? @ghost
This commit is contained in:
bors 2019-04-24 03:16:47 +00:00
commit 8a44125f55
77 changed files with 568 additions and 355 deletions

View file

@ -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;

View file

@ -85,7 +85,6 @@
#![feature(fmt_internals)]
#![feature(fn_traits)]
#![feature(fundamental)]
#![feature(futures_api)]
#![feature(lang_items)]
#![feature(libc)]
#![feature(needs_allocator)]

View file

@ -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,

View file

@ -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;

View file

@ -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};

View file

@ -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,6 +49,7 @@ 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()
}
@ -50,6 +57,7 @@ impl<T> Poll<T> {
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;

View file

@ -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;

View file

@ -121,6 +121,7 @@ impl_stable_hash_for!(struct ::syntax::attr::Stability {
feature,
rustc_depr,
promotable,
allow_const_fn_ptr,
const_stability
});

View file

@ -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);
}

View file

@ -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,

View file

@ -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 {

View file

@ -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 {}

View file

@ -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
};
}

View file

@ -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(),

View file

@ -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 bc) = allocator.bytecode_compressed {
}
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_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);
}
}

View file

@ -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,

View file

@ -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.

View file

@ -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>,

View file

@ -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..] };

View file

@ -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 {

View file

@ -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);

View file

@ -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)]

View file

@ -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");

View file

@ -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(

View file

@ -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,

View file

@ -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.

View file

@ -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)
}

View file

@ -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 {

View file

@ -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);

View file

@ -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<Diagnostic>,
) -> Option<ClosureRegionRequirements<'gcx>> {
@ -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<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)
}

View file

@ -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)),

View file

@ -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"),
};

View file

@ -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();

View file

@ -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(),
)

View file

@ -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

View file

@ -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`.

View file

@ -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;
}

View file

@ -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() {

View file

@ -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")?;

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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.

View file

@ -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

View file

@ -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;

View file

@ -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");
}
}

View file

@ -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)
}

View file

@ -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;

View file

@ -22,15 +22,14 @@ impl Drop for S {
// END RUST SOURCE
// START rustc.main.ElaborateDrops.before.mir
// let mut _0: ();
// scope 1 {
// }
// 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>;
//
// scope 1 {
// let _1: std::boxed::Box<S>;
// }
// scope 2 {
// }
// bb0: {
// StorageLive(_1);
// StorageLive(_2);

View file

@ -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

View file

@ -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;
// }

View file

@ -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;

View file

@ -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);

View file

@ -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;

View file

@ -1,7 +1,5 @@
// edition:2018
#![feature(futures_api)]
use std::sync::Arc;
use std::task::{
Waker, RawWaker, RawWakerVTable,

View file

@ -1,7 +1,5 @@
// aux-build:arc_wake.rs
#![feature(futures_api)]
extern crate arc_wake;
use std::future::Future;

View file

@ -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;

View file

@ -1,7 +1,7 @@
// edition:2018
// run-pass
#![feature(async_await, await_macro, futures_api)]
#![feature(async_await, await_macro)]
trait Foo { }

View file

@ -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> {

View file

@ -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;

View file

@ -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() {}

View file

@ -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`.

View file

@ -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() {}

View file

@ -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`.

View file

@ -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();
}

View file

@ -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

View file

@ -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

View file

@ -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() {}
| ^^^^^^^^^^^^^^^^^

View file

@ -1,7 +1,5 @@
// edition:2018
#![feature(futures_api)]
struct S;
impl S {

View file

@ -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 || {};
| ^^^^^^^^^^^

View file

@ -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());

View file

@ -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 {

View file

@ -1,7 +1,7 @@
// compile-pass
// edition:2018
#![feature(async_await, await_macro, futures_api)]
#![feature(async_await, await_macro)]
use std::sync::Arc;

View file

@ -1,7 +1,7 @@
// compile-pass
// edition:2018
#![feature(async_await, await_macro, futures_api)]
#![feature(async_await, await_macro)]
use std::future::Future;

View file

@ -1,7 +1,7 @@
// compile-pass
// edition:2018
#![feature(async_await, await_macro, futures_api)]
#![feature(async_await, await_macro)]
struct Xyz {
a: u64,

View file

@ -1,7 +1,7 @@
// compile-pass
// edition:2018
#![feature(async_await, await_macro, futures_api)]
#![feature(async_await, await_macro)]
use std::future::Future;

View file

@ -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| {};

View file

@ -1,7 +1,6 @@
// compile-pass
#![allow(dead_code, unused)]
#![feature(futures_api)]
use std::task::Poll;