Auto merge of #60460 - Centril:rollup-gz5bc8i, r=Centril
Rollup of 7 pull requests Successful merges: - #59634 (Added an explanation for the E0704 error.) - #60348 (move some functions from parser.rs to diagostics.rs) - #60385 (Emit metadata files earlier) - #60428 (Refactor `eval_body_using_ecx` so that it doesn't need to query for MIR) - #60437 (Ensure that drop order of `async fn` matches `fn` and that users cannot refer to generated arguments.) - #60439 (doc: Warn about possible zombie apocalypse) - #60452 (Remove Context and ContextKind) Failed merges: r? @ghost
This commit is contained in:
commit
767f594626
@ -2802,6 +2802,7 @@ dependencies = [
|
|||||||
"rustc-rayon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rustc-rayon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rustc_allocator 0.0.0",
|
"rustc_allocator 0.0.0",
|
||||||
"rustc_borrowck 0.0.0",
|
"rustc_borrowck 0.0.0",
|
||||||
|
"rustc_codegen_ssa 0.0.0",
|
||||||
"rustc_codegen_utils 0.0.0",
|
"rustc_codegen_utils 0.0.0",
|
||||||
"rustc_data_structures 0.0.0",
|
"rustc_data_structures 0.0.0",
|
||||||
"rustc_errors 0.0.0",
|
"rustc_errors 0.0.0",
|
||||||
@ -2821,6 +2822,7 @@ dependencies = [
|
|||||||
"syntax 0.0.0",
|
"syntax 0.0.0",
|
||||||
"syntax_ext 0.0.0",
|
"syntax_ext 0.0.0",
|
||||||
"syntax_pos 0.0.0",
|
"syntax_pos 0.0.0",
|
||||||
|
"tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2996,8 +2996,33 @@ impl<'a> LoweringContext<'a> {
|
|||||||
if let IsAsync::Async { closure_id, ref arguments, .. } = asyncness {
|
if let IsAsync::Async { closure_id, ref arguments, .. } = asyncness {
|
||||||
let mut body = body.clone();
|
let mut body = body.clone();
|
||||||
|
|
||||||
|
// Async function arguments are lowered into the closure body so that they are
|
||||||
|
// captured and so that the drop order matches the equivalent non-async functions.
|
||||||
|
//
|
||||||
|
// async fn foo(<pattern>: <ty>, <pattern>: <ty>, <pattern>: <ty>) {
|
||||||
|
// async move {
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // ...becomes...
|
||||||
|
// fn foo(__arg0: <ty>, __arg1: <ty>, __arg2: <ty>) {
|
||||||
|
// async move {
|
||||||
|
// let __arg2 = __arg2;
|
||||||
|
// let <pattern> = __arg2;
|
||||||
|
// let __arg1 = __arg1;
|
||||||
|
// let <pattern> = __arg1;
|
||||||
|
// let __arg0 = __arg0;
|
||||||
|
// let <pattern> = __arg0;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// If `<pattern>` is a simple ident, then it is lowered to a single
|
||||||
|
// `let <pattern> = <pattern>;` statement as an optimization.
|
||||||
for a in arguments.iter().rev() {
|
for a in arguments.iter().rev() {
|
||||||
body.stmts.insert(0, a.stmt.clone());
|
if let Some(pat_stmt) = a.pat_stmt.clone() {
|
||||||
|
body.stmts.insert(0, pat_stmt);
|
||||||
|
}
|
||||||
|
body.stmts.insert(0, a.move_stmt.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
let async_expr = this.make_async_expr(
|
let async_expr = this.make_async_expr(
|
||||||
@ -3093,7 +3118,11 @@ impl<'a> LoweringContext<'a> {
|
|||||||
let mut decl = decl.clone();
|
let mut decl = decl.clone();
|
||||||
// Replace the arguments of this async function with the generated
|
// Replace the arguments of this async function with the generated
|
||||||
// arguments that will be moved into the closure.
|
// arguments that will be moved into the closure.
|
||||||
decl.inputs = arguments.clone().drain(..).map(|a| a.arg).collect();
|
for (i, a) in arguments.clone().drain(..).enumerate() {
|
||||||
|
if let Some(arg) = a.arg {
|
||||||
|
decl.inputs[i] = arg;
|
||||||
|
}
|
||||||
|
}
|
||||||
lower_fn(&decl)
|
lower_fn(&decl)
|
||||||
} else {
|
} else {
|
||||||
lower_fn(decl)
|
lower_fn(decl)
|
||||||
@ -3590,7 +3619,11 @@ impl<'a> LoweringContext<'a> {
|
|||||||
let mut sig = sig.clone();
|
let mut sig = sig.clone();
|
||||||
// Replace the arguments of this async function with the generated
|
// Replace the arguments of this async function with the generated
|
||||||
// arguments that will be moved into the closure.
|
// arguments that will be moved into the closure.
|
||||||
sig.decl.inputs = arguments.clone().drain(..).map(|a| a.arg).collect();
|
for (i, a) in arguments.clone().drain(..).enumerate() {
|
||||||
|
if let Some(arg) = a.arg {
|
||||||
|
sig.decl.inputs[i] = arg;
|
||||||
|
}
|
||||||
|
}
|
||||||
lower_method(&sig)
|
lower_method(&sig)
|
||||||
} else {
|
} else {
|
||||||
lower_method(sig)
|
lower_method(sig)
|
||||||
|
@ -94,7 +94,9 @@ impl<'a> DefCollector<'a> {
|
|||||||
// Walk the generated arguments for the `async fn`.
|
// Walk the generated arguments for the `async fn`.
|
||||||
for a in arguments {
|
for a in arguments {
|
||||||
use visit::Visitor;
|
use visit::Visitor;
|
||||||
this.visit_ty(&a.arg.ty);
|
if let Some(arg) = &a.arg {
|
||||||
|
this.visit_ty(&arg.ty);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We do not invoke `walk_fn_decl` as this will walk the arguments that are being
|
// We do not invoke `walk_fn_decl` as this will walk the arguments that are being
|
||||||
@ -105,10 +107,13 @@ impl<'a> DefCollector<'a> {
|
|||||||
*closure_id, DefPathData::ClosureExpr, REGULAR_SPACE, span,
|
*closure_id, DefPathData::ClosureExpr, REGULAR_SPACE, span,
|
||||||
);
|
);
|
||||||
this.with_parent(closure_def, |this| {
|
this.with_parent(closure_def, |this| {
|
||||||
|
use visit::Visitor;
|
||||||
|
// Walk each of the generated statements before the regular block body.
|
||||||
for a in arguments {
|
for a in arguments {
|
||||||
use visit::Visitor;
|
this.visit_stmt(&a.move_stmt);
|
||||||
// Walk each of the generated statements before the regular block body.
|
if let Some(pat_stmt) = &a.pat_stmt {
|
||||||
this.visit_stmt(&a.stmt);
|
this.visit_stmt(&pat_stmt);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
visit::walk_block(this, &body);
|
visit::walk_block(this, &body);
|
||||||
|
@ -1334,14 +1334,19 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
|
|||||||
if let ast::IsAsync::Async { ref arguments, .. } = header.asyncness.node {
|
if let ast::IsAsync::Async { ref arguments, .. } = header.asyncness.node {
|
||||||
for a in arguments {
|
for a in arguments {
|
||||||
// Visit the argument..
|
// Visit the argument..
|
||||||
self.visit_pat(&a.arg.pat);
|
if let Some(arg) = &a.arg {
|
||||||
if let ast::ArgSource::AsyncFn(pat) = &a.arg.source {
|
self.visit_pat(&arg.pat);
|
||||||
self.visit_pat(pat);
|
if let ast::ArgSource::AsyncFn(pat) = &arg.source {
|
||||||
|
self.visit_pat(pat);
|
||||||
|
}
|
||||||
|
self.visit_ty(&arg.ty);
|
||||||
}
|
}
|
||||||
self.visit_ty(&a.arg.ty);
|
|
||||||
|
|
||||||
// ..and the statement.
|
// ..and the statement.
|
||||||
self.visit_stmt(&a.stmt);
|
self.visit_stmt(&a.move_stmt);
|
||||||
|
if let Some(pat_stmt) = &a.pat_stmt {
|
||||||
|
self.visit_stmt(&pat_stmt);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ use rustc::mir::mono::{Linkage, Visibility, Stats};
|
|||||||
use rustc::middle::cstore::{EncodedMetadata};
|
use rustc::middle::cstore::{EncodedMetadata};
|
||||||
use rustc::ty::TyCtxt;
|
use rustc::ty::TyCtxt;
|
||||||
use rustc::middle::exported_symbols;
|
use rustc::middle::exported_symbols;
|
||||||
use rustc::session::config::{self, DebugInfo};
|
use rustc::session::config::DebugInfo;
|
||||||
use rustc_codegen_ssa::mono_item::MonoItemExt;
|
use rustc_codegen_ssa::mono_item::MonoItemExt;
|
||||||
use rustc_data_structures::small_c_str::SmallCStr;
|
use rustc_data_structures::small_c_str::SmallCStr;
|
||||||
|
|
||||||
@ -42,47 +42,16 @@ use rustc::hir::CodegenFnAttrs;
|
|||||||
|
|
||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
|
|
||||||
|
pub fn write_compressed_metadata<'a, 'gcx>(
|
||||||
pub fn write_metadata<'a, 'gcx>(
|
|
||||||
tcx: TyCtxt<'a, 'gcx, 'gcx>,
|
tcx: TyCtxt<'a, 'gcx, 'gcx>,
|
||||||
|
metadata: &EncodedMetadata,
|
||||||
llvm_module: &mut ModuleLlvm
|
llvm_module: &mut ModuleLlvm
|
||||||
) -> EncodedMetadata {
|
) {
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use flate2::Compression;
|
use flate2::Compression;
|
||||||
use flate2::write::DeflateEncoder;
|
use flate2::write::DeflateEncoder;
|
||||||
|
|
||||||
let (metadata_llcx, metadata_llmod) = (&*llvm_module.llcx, llvm_module.llmod());
|
let (metadata_llcx, metadata_llmod) = (&*llvm_module.llcx, llvm_module.llmod());
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, PartialOrd, Ord)]
|
|
||||||
enum MetadataKind {
|
|
||||||
None,
|
|
||||||
Uncompressed,
|
|
||||||
Compressed
|
|
||||||
}
|
|
||||||
|
|
||||||
let kind = tcx.sess.crate_types.borrow().iter().map(|ty| {
|
|
||||||
match *ty {
|
|
||||||
config::CrateType::Executable |
|
|
||||||
config::CrateType::Staticlib |
|
|
||||||
config::CrateType::Cdylib => MetadataKind::None,
|
|
||||||
|
|
||||||
config::CrateType::Rlib => MetadataKind::Uncompressed,
|
|
||||||
|
|
||||||
config::CrateType::Dylib |
|
|
||||||
config::CrateType::ProcMacro => MetadataKind::Compressed,
|
|
||||||
}
|
|
||||||
}).max().unwrap_or(MetadataKind::None);
|
|
||||||
|
|
||||||
if kind == MetadataKind::None {
|
|
||||||
return EncodedMetadata::new();
|
|
||||||
}
|
|
||||||
|
|
||||||
let metadata = tcx.encode_metadata();
|
|
||||||
if kind == MetadataKind::Uncompressed {
|
|
||||||
return metadata;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert!(kind == MetadataKind::Compressed);
|
|
||||||
let mut compressed = tcx.metadata_encoding_version();
|
let mut compressed = tcx.metadata_encoding_version();
|
||||||
DeflateEncoder::new(&mut compressed, Compression::fast())
|
DeflateEncoder::new(&mut compressed, Compression::fast())
|
||||||
.write_all(&metadata.raw_data).unwrap();
|
.write_all(&metadata.raw_data).unwrap();
|
||||||
@ -107,7 +76,6 @@ pub fn write_metadata<'a, 'gcx>(
|
|||||||
let directive = CString::new(directive).unwrap();
|
let directive = CString::new(directive).unwrap();
|
||||||
llvm::LLVMSetModuleInlineAsm(metadata_llmod, directive.as_ptr())
|
llvm::LLVMSetModuleInlineAsm(metadata_llmod, directive.as_ptr())
|
||||||
}
|
}
|
||||||
return metadata;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ValueIter<'ll> {
|
pub struct ValueIter<'ll> {
|
||||||
|
@ -110,12 +110,13 @@ impl ExtraBackendMethods for LlvmCodegenBackend {
|
|||||||
ModuleLlvm::new_metadata(tcx, mod_name)
|
ModuleLlvm::new_metadata(tcx, mod_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_metadata<'b, 'gcx>(
|
fn write_compressed_metadata<'b, 'gcx>(
|
||||||
&self,
|
&self,
|
||||||
tcx: TyCtxt<'b, 'gcx, 'gcx>,
|
tcx: TyCtxt<'b, 'gcx, 'gcx>,
|
||||||
metadata: &mut ModuleLlvm
|
metadata: &EncodedMetadata,
|
||||||
) -> EncodedMetadata {
|
llvm_module: &mut ModuleLlvm
|
||||||
base::write_metadata(tcx, metadata)
|
) {
|
||||||
|
base::write_compressed_metadata(tcx, metadata, llvm_module)
|
||||||
}
|
}
|
||||||
fn codegen_allocator<'b, 'gcx>(
|
fn codegen_allocator<'b, 'gcx>(
|
||||||
&self,
|
&self,
|
||||||
@ -289,9 +290,12 @@ impl CodegenBackend for LlvmCodegenBackend {
|
|||||||
fn codegen_crate<'b, 'tcx>(
|
fn codegen_crate<'b, 'tcx>(
|
||||||
&self,
|
&self,
|
||||||
tcx: TyCtxt<'b, 'tcx, 'tcx>,
|
tcx: TyCtxt<'b, 'tcx, 'tcx>,
|
||||||
|
metadata: EncodedMetadata,
|
||||||
|
need_metadata_module: bool,
|
||||||
rx: mpsc::Receiver<Box<dyn Any + Send>>
|
rx: mpsc::Receiver<Box<dyn Any + Send>>
|
||||||
) -> Box<dyn Any> {
|
) -> Box<dyn Any> {
|
||||||
box rustc_codegen_ssa::base::codegen_crate(LlvmCodegenBackend(()), tcx, rx)
|
box rustc_codegen_ssa::base::codegen_crate(
|
||||||
|
LlvmCodegenBackend(()), tcx, metadata, need_metadata_module, rx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn join_codegen_and_link(
|
fn join_codegen_and_link(
|
||||||
|
@ -7,7 +7,7 @@ use rustc::session::config::{
|
|||||||
};
|
};
|
||||||
use rustc::session::search_paths::PathKind;
|
use rustc::session::search_paths::PathKind;
|
||||||
use rustc::middle::dependency_format::Linkage;
|
use rustc::middle::dependency_format::Linkage;
|
||||||
use rustc::middle::cstore::{LibSource, NativeLibrary, NativeLibraryKind};
|
use rustc::middle::cstore::{EncodedMetadata, LibSource, NativeLibrary, NativeLibraryKind};
|
||||||
use rustc::util::common::{time, time_ext};
|
use rustc::util::common::{time, time_ext};
|
||||||
use rustc::hir::def_id::CrateNum;
|
use rustc::hir::def_id::CrateNum;
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
@ -50,9 +50,9 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(sess: &'a Session,
|
|||||||
outputs: &OutputFilenames,
|
outputs: &OutputFilenames,
|
||||||
crate_name: &str,
|
crate_name: &str,
|
||||||
target_cpu: &str) {
|
target_cpu: &str) {
|
||||||
|
let output_metadata = sess.opts.output_types.contains_key(&OutputType::Metadata);
|
||||||
for &crate_type in sess.crate_types.borrow().iter() {
|
for &crate_type in sess.crate_types.borrow().iter() {
|
||||||
// Ignore executable crates if we have -Z no-codegen, as they will error.
|
// Ignore executable crates if we have -Z no-codegen, as they will error.
|
||||||
let output_metadata = sess.opts.output_types.contains_key(&OutputType::Metadata);
|
|
||||||
if (sess.opts.debugging_opts.no_codegen || !sess.opts.output_types.should_codegen()) &&
|
if (sess.opts.debugging_opts.no_codegen || !sess.opts.output_types.should_codegen()) &&
|
||||||
!output_metadata &&
|
!output_metadata &&
|
||||||
crate_type == config::CrateType::Executable {
|
crate_type == config::CrateType::Executable {
|
||||||
@ -63,12 +63,43 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(sess: &'a Session,
|
|||||||
bug!("invalid output type `{:?}` for target os `{}`",
|
bug!("invalid output type `{:?}` for target os `{}`",
|
||||||
crate_type, sess.opts.target_triple);
|
crate_type, sess.opts.target_triple);
|
||||||
}
|
}
|
||||||
link_binary_output::<B>(sess,
|
|
||||||
codegen_results,
|
for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) {
|
||||||
crate_type,
|
check_file_is_writeable(obj, sess);
|
||||||
outputs,
|
}
|
||||||
crate_name,
|
|
||||||
target_cpu);
|
let tmpdir = TempFileBuilder::new().prefix("rustc").tempdir().unwrap_or_else(|err|
|
||||||
|
sess.fatal(&format!("couldn't create a temp dir: {}", err)));
|
||||||
|
|
||||||
|
if outputs.outputs.should_codegen() {
|
||||||
|
let out_filename = out_filename(sess, crate_type, outputs, crate_name);
|
||||||
|
match crate_type {
|
||||||
|
config::CrateType::Rlib => {
|
||||||
|
link_rlib::<B>(sess,
|
||||||
|
codegen_results,
|
||||||
|
RlibFlavor::Normal,
|
||||||
|
&out_filename,
|
||||||
|
&tmpdir).build();
|
||||||
|
}
|
||||||
|
config::CrateType::Staticlib => {
|
||||||
|
link_staticlib::<B>(sess, codegen_results, &out_filename, &tmpdir);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
link_natively::<B>(
|
||||||
|
sess,
|
||||||
|
crate_type,
|
||||||
|
&out_filename,
|
||||||
|
codegen_results,
|
||||||
|
tmpdir.path(),
|
||||||
|
target_cpu,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if sess.opts.cg.save_temps {
|
||||||
|
let _ = tmpdir.into_path();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the temporary object file and metadata if we aren't saving temps
|
// Remove the temporary object file and metadata if we aren't saving temps
|
||||||
@ -85,7 +116,7 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(sess: &'a Session,
|
|||||||
if let Some(ref obj) = metadata_module.object {
|
if let Some(ref obj) = metadata_module.object {
|
||||||
remove(sess, obj);
|
remove(sess, obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(ref allocator_module) = codegen_results.allocator_module {
|
if let Some(ref allocator_module) = codegen_results.allocator_module {
|
||||||
if let Some(ref obj) = allocator_module.object {
|
if let Some(ref obj) = allocator_module.object {
|
||||||
remove(sess, obj);
|
remove(sess, obj);
|
||||||
@ -97,73 +128,6 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(sess: &'a Session,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn link_binary_output<'a, B: ArchiveBuilder<'a>>(sess: &'a Session,
|
|
||||||
codegen_results: &CodegenResults,
|
|
||||||
crate_type: config::CrateType,
|
|
||||||
outputs: &OutputFilenames,
|
|
||||||
crate_name: &str,
|
|
||||||
target_cpu: &str) {
|
|
||||||
for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) {
|
|
||||||
check_file_is_writeable(obj, sess);
|
|
||||||
}
|
|
||||||
|
|
||||||
if outputs.outputs.contains_key(&OutputType::Metadata) {
|
|
||||||
let out_filename = filename_for_metadata(sess, crate_name, outputs);
|
|
||||||
// To avoid races with another rustc process scanning the output directory,
|
|
||||||
// we need to write the file somewhere else and atomically move it to its
|
|
||||||
// final destination, with a `fs::rename` call. In order for the rename to
|
|
||||||
// always succeed, the temporary file needs to be on the same filesystem,
|
|
||||||
// which is why we create it inside the output directory specifically.
|
|
||||||
let metadata_tmpdir = TempFileBuilder::new()
|
|
||||||
.prefix("rmeta")
|
|
||||||
.tempdir_in(out_filename.parent().unwrap())
|
|
||||||
.unwrap_or_else(|err| sess.fatal(&format!("couldn't create a temp dir: {}", err)));
|
|
||||||
let metadata = emit_metadata(sess, codegen_results, &metadata_tmpdir);
|
|
||||||
match fs::rename(&metadata, &out_filename) {
|
|
||||||
Ok(_) => {
|
|
||||||
if sess.opts.debugging_opts.emit_directives {
|
|
||||||
sess.parse_sess.span_diagnostic.maybe_emit_json_directive(
|
|
||||||
format!("metadata file written: {}", out_filename.display()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let tmpdir = TempFileBuilder::new().prefix("rustc").tempdir().unwrap_or_else(|err|
|
|
||||||
sess.fatal(&format!("couldn't create a temp dir: {}", err)));
|
|
||||||
|
|
||||||
if outputs.outputs.should_codegen() {
|
|
||||||
let out_filename = out_filename(sess, crate_type, outputs, crate_name);
|
|
||||||
match crate_type {
|
|
||||||
config::CrateType::Rlib => {
|
|
||||||
link_rlib::<B>(sess,
|
|
||||||
codegen_results,
|
|
||||||
RlibFlavor::Normal,
|
|
||||||
&out_filename,
|
|
||||||
&tmpdir).build();
|
|
||||||
}
|
|
||||||
config::CrateType::Staticlib => {
|
|
||||||
link_staticlib::<B>(sess, codegen_results, &out_filename, &tmpdir);
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
link_natively::<B>(
|
|
||||||
sess,
|
|
||||||
crate_type,
|
|
||||||
&out_filename,
|
|
||||||
codegen_results,
|
|
||||||
tmpdir.path(),
|
|
||||||
target_cpu,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if sess.opts.cg.save_temps {
|
|
||||||
let _ = tmpdir.into_path();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The third parameter is for env vars, used on windows to set up the
|
// The third parameter is for env vars, used on windows to set up the
|
||||||
// path for MSVC to find its DLLs, and gcc to find its bundled
|
// path for MSVC to find its DLLs, and gcc to find its bundled
|
||||||
// toolchain
|
// toolchain
|
||||||
@ -261,13 +225,13 @@ pub fn each_linked_rlib(sess: &Session,
|
|||||||
/// building an `.rlib` (stomping over one another), or writing an `.rmeta` into a
|
/// building an `.rlib` (stomping over one another), or writing an `.rmeta` into a
|
||||||
/// directory being searched for `extern crate` (observing an incomplete file).
|
/// directory being searched for `extern crate` (observing an incomplete file).
|
||||||
/// The returned path is the temporary file containing the complete metadata.
|
/// The returned path is the temporary file containing the complete metadata.
|
||||||
fn emit_metadata<'a>(
|
pub fn emit_metadata<'a>(
|
||||||
sess: &'a Session,
|
sess: &'a Session,
|
||||||
codegen_results: &CodegenResults,
|
metadata: &EncodedMetadata,
|
||||||
tmpdir: &TempDir
|
tmpdir: &TempDir
|
||||||
) -> PathBuf {
|
) -> PathBuf {
|
||||||
let out_filename = tmpdir.path().join(METADATA_FILENAME);
|
let out_filename = tmpdir.path().join(METADATA_FILENAME);
|
||||||
let result = fs::write(&out_filename, &codegen_results.metadata.raw_data);
|
let result = fs::write(&out_filename, &metadata.raw_data);
|
||||||
|
|
||||||
if let Err(e) = result {
|
if let Err(e) = result {
|
||||||
sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e));
|
sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e));
|
||||||
@ -351,7 +315,7 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>(sess: &'a Session,
|
|||||||
RlibFlavor::Normal => {
|
RlibFlavor::Normal => {
|
||||||
// Instead of putting the metadata in an object file section, rlibs
|
// Instead of putting the metadata in an object file section, rlibs
|
||||||
// contain the metadata in a separate file.
|
// contain the metadata in a separate file.
|
||||||
ab.add_file(&emit_metadata(sess, codegen_results, tmpdir));
|
ab.add_file(&emit_metadata(sess, &codegen_results.metadata, tmpdir));
|
||||||
|
|
||||||
// For LTO purposes, the bytecode of this library is also inserted
|
// For LTO purposes, the bytecode of this library is also inserted
|
||||||
// into the archive.
|
// into the archive.
|
||||||
|
@ -17,6 +17,7 @@ use crate::{ModuleCodegen, ModuleKind, CachedModuleCodegen};
|
|||||||
|
|
||||||
use rustc::dep_graph::cgu_reuse_tracker::CguReuse;
|
use rustc::dep_graph::cgu_reuse_tracker::CguReuse;
|
||||||
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
|
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
|
||||||
|
use rustc::middle::cstore::EncodedMetadata;
|
||||||
use rustc::middle::lang_items::StartFnLangItem;
|
use rustc::middle::lang_items::StartFnLangItem;
|
||||||
use rustc::middle::weak_lang_items;
|
use rustc::middle::weak_lang_items;
|
||||||
use rustc::mir::mono::{Stats, CodegenUnitNameBuilder};
|
use rustc::mir::mono::{Stats, CodegenUnitNameBuilder};
|
||||||
@ -25,7 +26,7 @@ use rustc::ty::layout::{self, Align, TyLayout, LayoutOf, VariantIdx, HasTyCtxt};
|
|||||||
use rustc::ty::query::Providers;
|
use rustc::ty::query::Providers;
|
||||||
use rustc::middle::cstore::{self, LinkagePreference};
|
use rustc::middle::cstore::{self, LinkagePreference};
|
||||||
use rustc::util::common::{time, print_time_passes_entry};
|
use rustc::util::common::{time, print_time_passes_entry};
|
||||||
use rustc::session::config::{self, CrateType, EntryFnType, Lto};
|
use rustc::session::config::{self, EntryFnType, Lto};
|
||||||
use rustc::session::Session;
|
use rustc::session::Session;
|
||||||
use rustc_mir::monomorphize::item::DefPathBasedNames;
|
use rustc_mir::monomorphize::item::DefPathBasedNames;
|
||||||
use rustc_mir::monomorphize::Instance;
|
use rustc_mir::monomorphize::Instance;
|
||||||
@ -530,26 +531,13 @@ pub const CODEGEN_WORKER_ID: usize = ::std::usize::MAX;
|
|||||||
pub fn codegen_crate<B: ExtraBackendMethods>(
|
pub fn codegen_crate<B: ExtraBackendMethods>(
|
||||||
backend: B,
|
backend: B,
|
||||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
|
metadata: EncodedMetadata,
|
||||||
|
need_metadata_module: bool,
|
||||||
rx: mpsc::Receiver<Box<dyn Any + Send>>
|
rx: mpsc::Receiver<Box<dyn Any + Send>>
|
||||||
) -> OngoingCodegen<B> {
|
) -> OngoingCodegen<B> {
|
||||||
|
|
||||||
check_for_rustc_errors_attr(tcx);
|
check_for_rustc_errors_attr(tcx);
|
||||||
|
|
||||||
let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx);
|
|
||||||
|
|
||||||
// Codegen the metadata.
|
|
||||||
tcx.sess.profiler(|p| p.start_activity("codegen crate metadata"));
|
|
||||||
|
|
||||||
let metadata_cgu_name = cgu_name_builder.build_cgu_name(LOCAL_CRATE,
|
|
||||||
&["crate"],
|
|
||||||
Some("metadata")).as_str()
|
|
||||||
.to_string();
|
|
||||||
let mut metadata_llvm_module = backend.new_metadata(tcx, &metadata_cgu_name);
|
|
||||||
let metadata = time(tcx.sess, "write metadata", || {
|
|
||||||
backend.write_metadata(tcx, &mut metadata_llvm_module)
|
|
||||||
});
|
|
||||||
tcx.sess.profiler(|p| p.end_activity("codegen crate metadata"));
|
|
||||||
|
|
||||||
// Skip crate items and just output metadata in -Z no-codegen mode.
|
// Skip crate items and just output metadata in -Z no-codegen mode.
|
||||||
if tcx.sess.opts.debugging_opts.no_codegen ||
|
if tcx.sess.opts.debugging_opts.no_codegen ||
|
||||||
!tcx.sess.opts.output_types.should_codegen() {
|
!tcx.sess.opts.output_types.should_codegen() {
|
||||||
@ -569,6 +557,8 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
|
|||||||
return ongoing_codegen;
|
return ongoing_codegen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx);
|
||||||
|
|
||||||
// Run the monomorphization collector and partition the collected items into
|
// Run the monomorphization collector and partition the collected items into
|
||||||
// codegen units.
|
// codegen units.
|
||||||
let codegen_units = tcx.collect_and_partition_mono_items(LOCAL_CRATE).1;
|
let codegen_units = tcx.collect_and_partition_mono_items(LOCAL_CRATE).1;
|
||||||
@ -632,17 +622,21 @@ 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, allocator_module);
|
||||||
}
|
}
|
||||||
|
|
||||||
let needs_metadata_module = tcx.sess.crate_types.borrow().iter().any(|ct| {
|
if need_metadata_module {
|
||||||
match *ct {
|
// Codegen the encoded metadata.
|
||||||
CrateType::Dylib |
|
tcx.sess.profiler(|p| p.start_activity("codegen crate metadata"));
|
||||||
CrateType::ProcMacro => true,
|
|
||||||
CrateType::Executable |
|
let metadata_cgu_name = cgu_name_builder.build_cgu_name(LOCAL_CRATE,
|
||||||
CrateType::Rlib |
|
&["crate"],
|
||||||
CrateType::Staticlib |
|
Some("metadata")).as_str()
|
||||||
CrateType::Cdylib => false,
|
.to_string();
|
||||||
}
|
let mut metadata_llvm_module = backend.new_metadata(tcx, &metadata_cgu_name);
|
||||||
});
|
time(tcx.sess, "write compressed metadata", || {
|
||||||
if needs_metadata_module {
|
backend.write_compressed_metadata(tcx, &ongoing_codegen.metadata,
|
||||||
|
&mut metadata_llvm_module);
|
||||||
|
});
|
||||||
|
tcx.sess.profiler(|p| p.end_activity("codegen crate metadata"));
|
||||||
|
|
||||||
let metadata_module = ModuleCodegen {
|
let metadata_module = ModuleCodegen {
|
||||||
name: metadata_cgu_name,
|
name: metadata_cgu_name,
|
||||||
module_llvm: metadata_llvm_module,
|
module_llvm: metadata_llvm_module,
|
||||||
|
@ -33,11 +33,12 @@ impl<'tcx, T> Backend<'tcx> for T where
|
|||||||
|
|
||||||
pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Send {
|
pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Send {
|
||||||
fn new_metadata(&self, sess: TyCtxt<'_, '_, '_>, mod_name: &str) -> Self::Module;
|
fn new_metadata(&self, sess: TyCtxt<'_, '_, '_>, mod_name: &str) -> Self::Module;
|
||||||
fn write_metadata<'b, 'gcx>(
|
fn write_compressed_metadata<'b, 'gcx>(
|
||||||
&self,
|
&self,
|
||||||
tcx: TyCtxt<'b, 'gcx, 'gcx>,
|
tcx: TyCtxt<'b, 'gcx, 'gcx>,
|
||||||
metadata: &mut Self::Module,
|
metadata: &EncodedMetadata,
|
||||||
) -> EncodedMetadata;
|
llvm_module: &mut Self::Module,
|
||||||
|
);
|
||||||
fn codegen_allocator<'b, 'gcx>(
|
fn codegen_allocator<'b, 'gcx>(
|
||||||
&self,
|
&self,
|
||||||
tcx: TyCtxt<'b, 'gcx, 'gcx>,
|
tcx: TyCtxt<'b, 'gcx, 'gcx>,
|
||||||
|
@ -18,7 +18,7 @@ use rustc::util::common::ErrorReported;
|
|||||||
use rustc::session::config::{OutputFilenames, PrintRequest};
|
use rustc::session::config::{OutputFilenames, PrintRequest};
|
||||||
use rustc::ty::TyCtxt;
|
use rustc::ty::TyCtxt;
|
||||||
use rustc::ty::query::Providers;
|
use rustc::ty::query::Providers;
|
||||||
use rustc::middle::cstore::MetadataLoader;
|
use rustc::middle::cstore::{EncodedMetadata, MetadataLoader};
|
||||||
use rustc::dep_graph::DepGraph;
|
use rustc::dep_graph::DepGraph;
|
||||||
|
|
||||||
pub use rustc_data_structures::sync::MetadataRef;
|
pub use rustc_data_structures::sync::MetadataRef;
|
||||||
@ -37,6 +37,8 @@ pub trait CodegenBackend {
|
|||||||
fn codegen_crate<'a, 'tcx>(
|
fn codegen_crate<'a, 'tcx>(
|
||||||
&self,
|
&self,
|
||||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
|
metadata: EncodedMetadata,
|
||||||
|
need_metadata_module: bool,
|
||||||
rx: mpsc::Receiver<Box<dyn Any + Send>>
|
rx: mpsc::Receiver<Box<dyn Any + Send>>
|
||||||
) -> Box<dyn Any>;
|
) -> Box<dyn Any>;
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@ rustc_borrowck = { path = "../librustc_borrowck" }
|
|||||||
rustc_incremental = { path = "../librustc_incremental" }
|
rustc_incremental = { path = "../librustc_incremental" }
|
||||||
rustc_traits = { path = "../librustc_traits" }
|
rustc_traits = { path = "../librustc_traits" }
|
||||||
rustc_data_structures = { path = "../librustc_data_structures" }
|
rustc_data_structures = { path = "../librustc_data_structures" }
|
||||||
|
rustc_codegen_ssa = { path = "../librustc_codegen_ssa" }
|
||||||
rustc_codegen_utils = { path = "../librustc_codegen_utils" }
|
rustc_codegen_utils = { path = "../librustc_codegen_utils" }
|
||||||
rustc_metadata = { path = "../librustc_metadata" }
|
rustc_metadata = { path = "../librustc_metadata" }
|
||||||
rustc_mir = { path = "../librustc_mir" }
|
rustc_mir = { path = "../librustc_mir" }
|
||||||
@ -34,3 +35,4 @@ rustc_errors = { path = "../librustc_errors" }
|
|||||||
rustc_plugin = { path = "../librustc_plugin" }
|
rustc_plugin = { path = "../librustc_plugin" }
|
||||||
rustc_privacy = { path = "../librustc_privacy" }
|
rustc_privacy = { path = "../librustc_privacy" }
|
||||||
rustc_resolve = { path = "../librustc_resolve" }
|
rustc_resolve = { path = "../librustc_resolve" }
|
||||||
|
tempfile = "3.0.5"
|
||||||
|
@ -16,11 +16,13 @@ use rustc::traits;
|
|||||||
use rustc::util::common::{time, ErrorReported};
|
use rustc::util::common::{time, ErrorReported};
|
||||||
use rustc::util::profiling::ProfileCategory;
|
use rustc::util::profiling::ProfileCategory;
|
||||||
use rustc::session::{CompileResult, CrateDisambiguator, Session};
|
use rustc::session::{CompileResult, CrateDisambiguator, Session};
|
||||||
use rustc::session::config::{self, Input, OutputFilenames, OutputType};
|
use rustc::session::config::{self, CrateType, Input, OutputFilenames, OutputType};
|
||||||
use rustc::session::search_paths::PathKind;
|
use rustc::session::search_paths::PathKind;
|
||||||
use rustc_allocator as allocator;
|
use rustc_allocator as allocator;
|
||||||
use rustc_borrowck as borrowck;
|
use rustc_borrowck as borrowck;
|
||||||
|
use rustc_codegen_ssa::back::link::emit_metadata;
|
||||||
use rustc_codegen_utils::codegen_backend::CodegenBackend;
|
use rustc_codegen_utils::codegen_backend::CodegenBackend;
|
||||||
|
use rustc_codegen_utils::link::filename_for_metadata;
|
||||||
use rustc_data_structures::{box_region_allow_access, declare_box_region_type, parallel};
|
use rustc_data_structures::{box_region_allow_access, declare_box_region_type, parallel};
|
||||||
use rustc_data_structures::fingerprint::Fingerprint;
|
use rustc_data_structures::fingerprint::Fingerprint;
|
||||||
use rustc_data_structures::stable_hasher::StableHasher;
|
use rustc_data_structures::stable_hasher::StableHasher;
|
||||||
@ -50,6 +52,7 @@ use syntax_pos::{FileName, hygiene};
|
|||||||
use syntax_ext;
|
use syntax_ext;
|
||||||
|
|
||||||
use serialize::json;
|
use serialize::json;
|
||||||
|
use tempfile::Builder as TempFileBuilder;
|
||||||
|
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::env;
|
use std::env;
|
||||||
@ -999,6 +1002,68 @@ fn analysis<'tcx>(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn encode_and_write_metadata<'tcx>(
|
||||||
|
tcx: TyCtxt<'_, 'tcx, 'tcx>,
|
||||||
|
outputs: &OutputFilenames,
|
||||||
|
) -> (middle::cstore::EncodedMetadata, bool) {
|
||||||
|
#[derive(PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
enum MetadataKind {
|
||||||
|
None,
|
||||||
|
Uncompressed,
|
||||||
|
Compressed
|
||||||
|
}
|
||||||
|
|
||||||
|
let metadata_kind = tcx.sess.crate_types.borrow().iter().map(|ty| {
|
||||||
|
match *ty {
|
||||||
|
CrateType::Executable |
|
||||||
|
CrateType::Staticlib |
|
||||||
|
CrateType::Cdylib => MetadataKind::None,
|
||||||
|
|
||||||
|
CrateType::Rlib => MetadataKind::Uncompressed,
|
||||||
|
|
||||||
|
CrateType::Dylib |
|
||||||
|
CrateType::ProcMacro => MetadataKind::Compressed,
|
||||||
|
}
|
||||||
|
}).max().unwrap_or(MetadataKind::None);
|
||||||
|
|
||||||
|
let metadata = match metadata_kind {
|
||||||
|
MetadataKind::None => middle::cstore::EncodedMetadata::new(),
|
||||||
|
MetadataKind::Uncompressed |
|
||||||
|
MetadataKind::Compressed => tcx.encode_metadata(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let need_metadata_file = tcx.sess.opts.output_types.contains_key(&OutputType::Metadata);
|
||||||
|
if need_metadata_file {
|
||||||
|
let crate_name = &tcx.crate_name(LOCAL_CRATE).as_str();
|
||||||
|
let out_filename = filename_for_metadata(tcx.sess, crate_name, outputs);
|
||||||
|
// To avoid races with another rustc process scanning the output directory,
|
||||||
|
// we need to write the file somewhere else and atomically move it to its
|
||||||
|
// final destination, with an `fs::rename` call. In order for the rename to
|
||||||
|
// always succeed, the temporary file needs to be on the same filesystem,
|
||||||
|
// which is why we create it inside the output directory specifically.
|
||||||
|
let metadata_tmpdir = TempFileBuilder::new()
|
||||||
|
.prefix("rmeta")
|
||||||
|
.tempdir_in(out_filename.parent().unwrap())
|
||||||
|
.unwrap_or_else(|err| {
|
||||||
|
tcx.sess.fatal(&format!("couldn't create a temp dir: {}", err))
|
||||||
|
});
|
||||||
|
let metadata_filename = emit_metadata(tcx.sess, &metadata, &metadata_tmpdir);
|
||||||
|
match std::fs::rename(&metadata_filename, &out_filename) {
|
||||||
|
Ok(_) => {
|
||||||
|
if tcx.sess.opts.debugging_opts.emit_directives {
|
||||||
|
tcx.sess.parse_sess.span_diagnostic.maybe_emit_json_directive(
|
||||||
|
format!("metadata file written: {}", out_filename.display()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => tcx.sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let need_metadata_module = metadata_kind == MetadataKind::Compressed;
|
||||||
|
|
||||||
|
(metadata, need_metadata_module)
|
||||||
|
}
|
||||||
|
|
||||||
/// Runs the codegen backend, after which the AST and analysis can
|
/// Runs the codegen backend, after which the AST and analysis can
|
||||||
/// be discarded.
|
/// be discarded.
|
||||||
pub fn start_codegen<'tcx>(
|
pub fn start_codegen<'tcx>(
|
||||||
@ -1013,11 +1078,17 @@ pub fn start_codegen<'tcx>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
time(tcx.sess, "resolving dependency formats", || {
|
time(tcx.sess, "resolving dependency formats", || {
|
||||||
::rustc::middle::dependency_format::calculate(tcx)
|
middle::dependency_format::calculate(tcx)
|
||||||
|
});
|
||||||
|
|
||||||
|
let (metadata, need_metadata_module) = time(tcx.sess, "metadata encoding and writing", || {
|
||||||
|
encode_and_write_metadata(tcx, outputs)
|
||||||
});
|
});
|
||||||
|
|
||||||
tcx.sess.profiler(|p| p.start_activity("codegen crate"));
|
tcx.sess.profiler(|p| p.start_activity("codegen crate"));
|
||||||
let codegen = time(tcx.sess, "codegen", move || codegen_backend.codegen_crate(tcx, rx));
|
let codegen = time(tcx.sess, "codegen", move || {
|
||||||
|
codegen_backend.codegen_crate(tcx, metadata, need_metadata_module, rx)
|
||||||
|
});
|
||||||
tcx.sess.profiler(|p| p.end_activity("codegen crate"));
|
tcx.sess.profiler(|p| p.end_activity("codegen crate"));
|
||||||
|
|
||||||
if log_enabled!(::log::Level::Info) {
|
if log_enabled!(::log::Level::Info) {
|
||||||
|
@ -22,7 +22,7 @@ use syntax_pos::Span;
|
|||||||
use syntax::source_map::CompilerDesugaringKind;
|
use syntax::source_map::CompilerDesugaringKind;
|
||||||
|
|
||||||
use super::borrow_set::BorrowData;
|
use super::borrow_set::BorrowData;
|
||||||
use super::{Context, MirBorrowckCtxt};
|
use super::{MirBorrowckCtxt};
|
||||||
use super::{InitializationRequiringAction, PrefixSet};
|
use super::{InitializationRequiringAction, PrefixSet};
|
||||||
use crate::dataflow::drop_flag_effects;
|
use crate::dataflow::drop_flag_effects;
|
||||||
use crate::dataflow::indexes::{MovePathIndex, MoveOutIndex};
|
use crate::dataflow::indexes::{MovePathIndex, MoveOutIndex};
|
||||||
@ -42,22 +42,22 @@ struct MoveSite {
|
|||||||
impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||||
pub(super) fn report_use_of_moved_or_uninitialized(
|
pub(super) fn report_use_of_moved_or_uninitialized(
|
||||||
&mut self,
|
&mut self,
|
||||||
context: Context,
|
location: Location,
|
||||||
desired_action: InitializationRequiringAction,
|
desired_action: InitializationRequiringAction,
|
||||||
(moved_place, used_place, span): (&Place<'tcx>, &Place<'tcx>, Span),
|
(moved_place, used_place, span): (&Place<'tcx>, &Place<'tcx>, Span),
|
||||||
mpi: MovePathIndex,
|
mpi: MovePathIndex,
|
||||||
) {
|
) {
|
||||||
debug!(
|
debug!(
|
||||||
"report_use_of_moved_or_uninitialized: context={:?} desired_action={:?} \
|
"report_use_of_moved_or_uninitialized: location={:?} desired_action={:?} \
|
||||||
moved_place={:?} used_place={:?} span={:?} mpi={:?}",
|
moved_place={:?} used_place={:?} span={:?} mpi={:?}",
|
||||||
context, desired_action, moved_place, used_place, span, mpi
|
location, desired_action, moved_place, used_place, span, mpi
|
||||||
);
|
);
|
||||||
|
|
||||||
let use_spans = self.move_spans(moved_place, context.loc)
|
let use_spans = self.move_spans(moved_place, location)
|
||||||
.or_else(|| self.borrow_spans(span, context.loc));
|
.or_else(|| self.borrow_spans(span, location));
|
||||||
let span = use_spans.args_or_use();
|
let span = use_spans.args_or_use();
|
||||||
|
|
||||||
let move_site_vec = self.get_moved_indexes(context, mpi);
|
let move_site_vec = self.get_moved_indexes(location, mpi);
|
||||||
debug!(
|
debug!(
|
||||||
"report_use_of_moved_or_uninitialized: move_site_vec={:?}",
|
"report_use_of_moved_or_uninitialized: move_site_vec={:?}",
|
||||||
move_site_vec
|
move_site_vec
|
||||||
@ -125,7 +125,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
self.add_moved_or_invoked_closure_note(
|
self.add_moved_or_invoked_closure_note(
|
||||||
context.loc,
|
location,
|
||||||
used_place,
|
used_place,
|
||||||
&mut err,
|
&mut err,
|
||||||
);
|
);
|
||||||
@ -261,13 +261,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
|
|
||||||
pub(super) fn report_move_out_while_borrowed(
|
pub(super) fn report_move_out_while_borrowed(
|
||||||
&mut self,
|
&mut self,
|
||||||
context: Context,
|
location: Location,
|
||||||
(place, span): (&Place<'tcx>, Span),
|
(place, span): (&Place<'tcx>, Span),
|
||||||
borrow: &BorrowData<'tcx>,
|
borrow: &BorrowData<'tcx>,
|
||||||
) {
|
) {
|
||||||
debug!(
|
debug!(
|
||||||
"report_move_out_while_borrowed: context={:?} place={:?} span={:?} borrow={:?}",
|
"report_move_out_while_borrowed: location={:?} place={:?} span={:?} borrow={:?}",
|
||||||
context, place, span, borrow
|
location, place, span, borrow
|
||||||
);
|
);
|
||||||
let tcx = self.infcx.tcx;
|
let tcx = self.infcx.tcx;
|
||||||
let value_msg = match self.describe_place(place) {
|
let value_msg = match self.describe_place(place) {
|
||||||
@ -282,7 +282,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
let borrow_spans = self.retrieve_borrow_spans(borrow);
|
let borrow_spans = self.retrieve_borrow_spans(borrow);
|
||||||
let borrow_span = borrow_spans.args_or_use();
|
let borrow_span = borrow_spans.args_or_use();
|
||||||
|
|
||||||
let move_spans = self.move_spans(place, context.loc);
|
let move_spans = self.move_spans(place, location);
|
||||||
let span = move_spans.args_or_use();
|
let span = move_spans.args_or_use();
|
||||||
|
|
||||||
let mut err = tcx.cannot_move_when_borrowed(
|
let mut err = tcx.cannot_move_when_borrowed(
|
||||||
@ -304,7 +304,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
self.explain_why_borrow_contains_point(
|
self.explain_why_borrow_contains_point(
|
||||||
context,
|
location,
|
||||||
borrow,
|
borrow,
|
||||||
None,
|
None,
|
||||||
).add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, "", Some(borrow_span));
|
).add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, "", Some(borrow_span));
|
||||||
@ -313,7 +313,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
|
|
||||||
pub(super) fn report_use_while_mutably_borrowed(
|
pub(super) fn report_use_while_mutably_borrowed(
|
||||||
&mut self,
|
&mut self,
|
||||||
context: Context,
|
location: Location,
|
||||||
(place, _span): (&Place<'tcx>, Span),
|
(place, _span): (&Place<'tcx>, Span),
|
||||||
borrow: &BorrowData<'tcx>,
|
borrow: &BorrowData<'tcx>,
|
||||||
) -> DiagnosticBuilder<'cx> {
|
) -> DiagnosticBuilder<'cx> {
|
||||||
@ -324,7 +324,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
|
|
||||||
// Conflicting borrows are reported separately, so only check for move
|
// Conflicting borrows are reported separately, so only check for move
|
||||||
// captures.
|
// captures.
|
||||||
let use_spans = self.move_spans(place, context.loc);
|
let use_spans = self.move_spans(place, location);
|
||||||
let span = use_spans.var_or_use();
|
let span = use_spans.var_or_use();
|
||||||
|
|
||||||
let mut err = tcx.cannot_use_when_mutably_borrowed(
|
let mut err = tcx.cannot_use_when_mutably_borrowed(
|
||||||
@ -343,14 +343,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
format!("borrow occurs due to use of `{}`{}", desc_place, borrow_spans.describe())
|
format!("borrow occurs due to use of `{}`{}", desc_place, borrow_spans.describe())
|
||||||
});
|
});
|
||||||
|
|
||||||
self.explain_why_borrow_contains_point(context, borrow, None)
|
self.explain_why_borrow_contains_point(location, borrow, None)
|
||||||
.add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, "", None);
|
.add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, "", None);
|
||||||
err
|
err
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn report_conflicting_borrow(
|
pub(super) fn report_conflicting_borrow(
|
||||||
&mut self,
|
&mut self,
|
||||||
context: Context,
|
location: Location,
|
||||||
(place, span): (&Place<'tcx>, Span),
|
(place, span): (&Place<'tcx>, Span),
|
||||||
gen_borrow_kind: BorrowKind,
|
gen_borrow_kind: BorrowKind,
|
||||||
issued_borrow: &BorrowData<'tcx>,
|
issued_borrow: &BorrowData<'tcx>,
|
||||||
@ -358,7 +358,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
let issued_spans = self.retrieve_borrow_spans(issued_borrow);
|
let issued_spans = self.retrieve_borrow_spans(issued_borrow);
|
||||||
let issued_span = issued_spans.args_or_use();
|
let issued_span = issued_spans.args_or_use();
|
||||||
|
|
||||||
let borrow_spans = self.borrow_spans(span, context.loc);
|
let borrow_spans = self.borrow_spans(span, location);
|
||||||
let span = borrow_spans.args_or_use();
|
let span = borrow_spans.args_or_use();
|
||||||
|
|
||||||
let container_name = if issued_spans.for_generator() || borrow_spans.for_generator() {
|
let container_name = if issued_spans.for_generator() || borrow_spans.for_generator() {
|
||||||
@ -370,7 +370,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
let (desc_place, msg_place, msg_borrow, union_type_name) =
|
let (desc_place, msg_place, msg_borrow, union_type_name) =
|
||||||
self.describe_place_for_conflicting_borrow(place, &issued_borrow.borrowed_place);
|
self.describe_place_for_conflicting_borrow(place, &issued_borrow.borrowed_place);
|
||||||
|
|
||||||
let explanation = self.explain_why_borrow_contains_point(context, issued_borrow, None);
|
let explanation = self.explain_why_borrow_contains_point(location, issued_borrow, None);
|
||||||
let second_borrow_desc = if explanation.is_explained() {
|
let second_borrow_desc = if explanation.is_explained() {
|
||||||
"second "
|
"second "
|
||||||
} else {
|
} else {
|
||||||
@ -671,7 +671,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
/// `Drop::drop` with an aliasing borrow.)
|
/// `Drop::drop` with an aliasing borrow.)
|
||||||
pub(super) fn report_borrowed_value_does_not_live_long_enough(
|
pub(super) fn report_borrowed_value_does_not_live_long_enough(
|
||||||
&mut self,
|
&mut self,
|
||||||
context: Context,
|
location: Location,
|
||||||
borrow: &BorrowData<'tcx>,
|
borrow: &BorrowData<'tcx>,
|
||||||
place_span: (&Place<'tcx>, Span),
|
place_span: (&Place<'tcx>, Span),
|
||||||
kind: Option<WriteKind>,
|
kind: Option<WriteKind>,
|
||||||
@ -680,7 +680,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
"report_borrowed_value_does_not_live_long_enough(\
|
"report_borrowed_value_does_not_live_long_enough(\
|
||||||
{:?}, {:?}, {:?}, {:?}\
|
{:?}, {:?}, {:?}, {:?}\
|
||||||
)",
|
)",
|
||||||
context, borrow, place_span, kind
|
location, borrow, place_span, kind
|
||||||
);
|
);
|
||||||
|
|
||||||
let drop_span = place_span.1;
|
let drop_span = place_span.1;
|
||||||
@ -719,7 +719,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
// destructor conflict.
|
// destructor conflict.
|
||||||
if !borrow.borrowed_place.is_prefix_of(place_span.0) {
|
if !borrow.borrowed_place.is_prefix_of(place_span.0) {
|
||||||
self.report_borrow_conflicts_with_destructor(
|
self.report_borrow_conflicts_with_destructor(
|
||||||
context, borrow, place_span, kind, dropped_ty,
|
location, borrow, place_span, kind, dropped_ty,
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -728,7 +728,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
let place_desc = self.describe_place(&borrow.borrowed_place);
|
let place_desc = self.describe_place(&borrow.borrowed_place);
|
||||||
|
|
||||||
let kind_place = kind.filter(|_| place_desc.is_some()).map(|k| (k, place_span.0));
|
let kind_place = kind.filter(|_| place_desc.is_some()).map(|k| (k, place_span.0));
|
||||||
let explanation = self.explain_why_borrow_contains_point(context, &borrow, kind_place);
|
let explanation = self.explain_why_borrow_contains_point(location, &borrow, kind_place);
|
||||||
|
|
||||||
let err = match (place_desc, explanation) {
|
let err = match (place_desc, explanation) {
|
||||||
(Some(_), _) if self.is_place_thread_local(root_place) => {
|
(Some(_), _) if self.is_place_thread_local(root_place) => {
|
||||||
@ -784,7 +784,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
},
|
},
|
||||||
) => self.report_escaping_data(borrow_span, name, upvar_span, upvar_name, span),
|
) => self.report_escaping_data(borrow_span, name, upvar_span, upvar_name, span),
|
||||||
(Some(name), explanation) => self.report_local_value_does_not_live_long_enough(
|
(Some(name), explanation) => self.report_local_value_does_not_live_long_enough(
|
||||||
context,
|
location,
|
||||||
&name,
|
&name,
|
||||||
&scope_tree,
|
&scope_tree,
|
||||||
&borrow,
|
&borrow,
|
||||||
@ -793,7 +793,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
explanation,
|
explanation,
|
||||||
),
|
),
|
||||||
(None, explanation) => self.report_temporary_value_does_not_live_long_enough(
|
(None, explanation) => self.report_temporary_value_does_not_live_long_enough(
|
||||||
context,
|
location,
|
||||||
&scope_tree,
|
&scope_tree,
|
||||||
&borrow,
|
&borrow,
|
||||||
drop_span,
|
drop_span,
|
||||||
@ -808,7 +808,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
|
|
||||||
fn report_local_value_does_not_live_long_enough(
|
fn report_local_value_does_not_live_long_enough(
|
||||||
&mut self,
|
&mut self,
|
||||||
context: Context,
|
location: Location,
|
||||||
name: &str,
|
name: &str,
|
||||||
scope_tree: &'tcx ScopeTree,
|
scope_tree: &'tcx ScopeTree,
|
||||||
borrow: &BorrowData<'tcx>,
|
borrow: &BorrowData<'tcx>,
|
||||||
@ -820,7 +820,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
"report_local_value_does_not_live_long_enough(\
|
"report_local_value_does_not_live_long_enough(\
|
||||||
{:?}, {:?}, {:?}, {:?}, {:?}, {:?}\
|
{:?}, {:?}, {:?}, {:?}, {:?}, {:?}\
|
||||||
)",
|
)",
|
||||||
context, name, scope_tree, borrow, drop_span, borrow_spans
|
location, name, scope_tree, borrow, drop_span, borrow_spans
|
||||||
);
|
);
|
||||||
|
|
||||||
let borrow_span = borrow_spans.var_or_use();
|
let borrow_span = borrow_spans.var_or_use();
|
||||||
@ -914,7 +914,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
|
|
||||||
fn report_borrow_conflicts_with_destructor(
|
fn report_borrow_conflicts_with_destructor(
|
||||||
&mut self,
|
&mut self,
|
||||||
context: Context,
|
location: Location,
|
||||||
borrow: &BorrowData<'tcx>,
|
borrow: &BorrowData<'tcx>,
|
||||||
(place, drop_span): (&Place<'tcx>, Span),
|
(place, drop_span): (&Place<'tcx>, Span),
|
||||||
kind: Option<WriteKind>,
|
kind: Option<WriteKind>,
|
||||||
@ -924,7 +924,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
"report_borrow_conflicts_with_destructor(\
|
"report_borrow_conflicts_with_destructor(\
|
||||||
{:?}, {:?}, ({:?}, {:?}), {:?}\
|
{:?}, {:?}, ({:?}, {:?}), {:?}\
|
||||||
)",
|
)",
|
||||||
context, borrow, place, drop_span, kind,
|
location, borrow, place, drop_span, kind,
|
||||||
);
|
);
|
||||||
|
|
||||||
let borrow_spans = self.retrieve_borrow_spans(borrow);
|
let borrow_spans = self.retrieve_borrow_spans(borrow);
|
||||||
@ -957,7 +957,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
|
|
||||||
// Only give this note and suggestion if they could be relevant.
|
// Only give this note and suggestion if they could be relevant.
|
||||||
let explanation =
|
let explanation =
|
||||||
self.explain_why_borrow_contains_point(context, borrow, kind.map(|k| (k, place)));
|
self.explain_why_borrow_contains_point(location, borrow, kind.map(|k| (k, place)));
|
||||||
match explanation {
|
match explanation {
|
||||||
BorrowExplanation::UsedLater { .. }
|
BorrowExplanation::UsedLater { .. }
|
||||||
| BorrowExplanation::UsedLaterWhenDropped { .. } => {
|
| BorrowExplanation::UsedLaterWhenDropped { .. } => {
|
||||||
@ -998,7 +998,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
|
|
||||||
fn report_temporary_value_does_not_live_long_enough(
|
fn report_temporary_value_does_not_live_long_enough(
|
||||||
&mut self,
|
&mut self,
|
||||||
context: Context,
|
location: Location,
|
||||||
scope_tree: &'tcx ScopeTree,
|
scope_tree: &'tcx ScopeTree,
|
||||||
borrow: &BorrowData<'tcx>,
|
borrow: &BorrowData<'tcx>,
|
||||||
drop_span: Span,
|
drop_span: Span,
|
||||||
@ -1010,7 +1010,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
"report_temporary_value_does_not_live_long_enough(\
|
"report_temporary_value_does_not_live_long_enough(\
|
||||||
{:?}, {:?}, {:?}, {:?}, {:?}\
|
{:?}, {:?}, {:?}, {:?}, {:?}\
|
||||||
)",
|
)",
|
||||||
context, scope_tree, borrow, drop_span, proper_span
|
location, scope_tree, borrow, drop_span, proper_span
|
||||||
);
|
);
|
||||||
|
|
||||||
if let BorrowExplanation::MustBeValidFor {
|
if let BorrowExplanation::MustBeValidFor {
|
||||||
@ -1246,12 +1246,12 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
err
|
err
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_moved_indexes(&mut self, context: Context, mpi: MovePathIndex) -> Vec<MoveSite> {
|
fn get_moved_indexes(&mut self, location: Location, mpi: MovePathIndex) -> Vec<MoveSite> {
|
||||||
let mir = self.mir;
|
let mir = self.mir;
|
||||||
|
|
||||||
let mut stack = Vec::new();
|
let mut stack = Vec::new();
|
||||||
stack.extend(mir.predecessor_locations(context.loc).map(|predecessor| {
|
stack.extend(mir.predecessor_locations(location).map(|predecessor| {
|
||||||
let is_back_edge = context.loc.dominates(predecessor, &self.dominators);
|
let is_back_edge = location.dominates(predecessor, &self.dominators);
|
||||||
(predecessor, is_back_edge)
|
(predecessor, is_back_edge)
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -1348,7 +1348,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
|
|
||||||
pub(super) fn report_illegal_mutation_of_borrowed(
|
pub(super) fn report_illegal_mutation_of_borrowed(
|
||||||
&mut self,
|
&mut self,
|
||||||
context: Context,
|
location: Location,
|
||||||
(place, span): (&Place<'tcx>, Span),
|
(place, span): (&Place<'tcx>, Span),
|
||||||
loan: &BorrowData<'tcx>,
|
loan: &BorrowData<'tcx>,
|
||||||
) {
|
) {
|
||||||
@ -1386,7 +1386,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
format!("borrow occurs due to use{}", loan_spans.describe()),
|
format!("borrow occurs due to use{}", loan_spans.describe()),
|
||||||
);
|
);
|
||||||
|
|
||||||
self.explain_why_borrow_contains_point(context, loan, None)
|
self.explain_why_borrow_contains_point(location, loan, None)
|
||||||
.add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, "", None);
|
.add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, "", None);
|
||||||
|
|
||||||
err.buffer(&mut self.errors_buffer);
|
err.buffer(&mut self.errors_buffer);
|
||||||
@ -1400,7 +1400,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
/// assignment to `x.f`).
|
/// assignment to `x.f`).
|
||||||
pub(super) fn report_illegal_reassignment(
|
pub(super) fn report_illegal_reassignment(
|
||||||
&mut self,
|
&mut self,
|
||||||
_context: Context,
|
_location: Location,
|
||||||
(place, span): (&Place<'tcx>, Span),
|
(place, span): (&Place<'tcx>, Span),
|
||||||
assigned_span: Span,
|
assigned_span: Span,
|
||||||
err_place: &Place<'tcx>,
|
err_place: &Place<'tcx>,
|
||||||
|
@ -302,11 +302,12 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
|
|||||||
|
|
||||||
// Convert any reservation warnings into lints.
|
// Convert any reservation warnings into lints.
|
||||||
let reservation_warnings = mem::replace(&mut mbcx.reservation_warnings, Default::default());
|
let reservation_warnings = mem::replace(&mut mbcx.reservation_warnings, Default::default());
|
||||||
for (_, (place, span, context, bk, borrow)) in reservation_warnings {
|
for (_, (place, span, location, bk, borrow)) in reservation_warnings {
|
||||||
let mut initial_diag = mbcx.report_conflicting_borrow(context, (&place, span), bk, &borrow);
|
let mut initial_diag =
|
||||||
|
mbcx.report_conflicting_borrow(location, (&place, span), bk, &borrow);
|
||||||
|
|
||||||
let lint_root = if let ClearCrossCrate::Set(ref vsi) = mbcx.mir.source_scope_local_data {
|
let lint_root = if let ClearCrossCrate::Set(ref vsi) = mbcx.mir.source_scope_local_data {
|
||||||
let scope = mbcx.mir.source_info(context.loc).scope;
|
let scope = mbcx.mir.source_info(location).scope;
|
||||||
vsi[scope].lint_root
|
vsi[scope].lint_root
|
||||||
} else {
|
} else {
|
||||||
id
|
id
|
||||||
@ -483,7 +484,7 @@ pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
|
|||||||
/// for the activation of the borrow.
|
/// for the activation of the borrow.
|
||||||
reservation_warnings: FxHashMap<
|
reservation_warnings: FxHashMap<
|
||||||
BorrowIndex,
|
BorrowIndex,
|
||||||
(Place<'tcx>, Span, Context, BorrowKind, BorrowData<'tcx>)
|
(Place<'tcx>, Span, Location, BorrowKind, BorrowData<'tcx>)
|
||||||
>,
|
>,
|
||||||
/// This field keeps track of move errors that are to be reported for given move indicies.
|
/// This field keeps track of move errors that are to be reported for given move indicies.
|
||||||
///
|
///
|
||||||
@ -559,14 +560,13 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
|
|||||||
match stmt.kind {
|
match stmt.kind {
|
||||||
StatementKind::Assign(ref lhs, ref rhs) => {
|
StatementKind::Assign(ref lhs, ref rhs) => {
|
||||||
self.consume_rvalue(
|
self.consume_rvalue(
|
||||||
ContextKind::AssignRhs.new(location),
|
|
||||||
(rhs, span),
|
|
||||||
location,
|
location,
|
||||||
|
(rhs, span),
|
||||||
flow_state,
|
flow_state,
|
||||||
);
|
);
|
||||||
|
|
||||||
self.mutate_place(
|
self.mutate_place(
|
||||||
ContextKind::AssignLhs.new(location),
|
location,
|
||||||
(lhs, span),
|
(lhs, span),
|
||||||
Shallow(None),
|
Shallow(None),
|
||||||
JustWrite,
|
JustWrite,
|
||||||
@ -585,7 +585,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
|
|||||||
// match x {};
|
// match x {};
|
||||||
// from compiling.
|
// from compiling.
|
||||||
self.check_if_path_or_subpath_is_moved(
|
self.check_if_path_or_subpath_is_moved(
|
||||||
ContextKind::FakeRead.new(location),
|
location,
|
||||||
InitializationRequiringAction::Use,
|
InitializationRequiringAction::Use,
|
||||||
(place, span),
|
(place, span),
|
||||||
flow_state,
|
flow_state,
|
||||||
@ -596,7 +596,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
|
|||||||
variant_index: _,
|
variant_index: _,
|
||||||
} => {
|
} => {
|
||||||
self.mutate_place(
|
self.mutate_place(
|
||||||
ContextKind::SetDiscrim.new(location),
|
location,
|
||||||
(place, span),
|
(place, span),
|
||||||
Shallow(None),
|
Shallow(None),
|
||||||
JustWrite,
|
JustWrite,
|
||||||
@ -604,27 +604,26 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
StatementKind::InlineAsm(ref asm) => {
|
StatementKind::InlineAsm(ref asm) => {
|
||||||
let context = ContextKind::InlineAsm.new(location);
|
|
||||||
for (o, output) in asm.asm.outputs.iter().zip(asm.outputs.iter()) {
|
for (o, output) in asm.asm.outputs.iter().zip(asm.outputs.iter()) {
|
||||||
if o.is_indirect {
|
if o.is_indirect {
|
||||||
// FIXME(eddyb) indirect inline asm outputs should
|
// FIXME(eddyb) indirect inline asm outputs should
|
||||||
// be encoded through MIR place derefs instead.
|
// be encoded through MIR place derefs instead.
|
||||||
self.access_place(
|
self.access_place(
|
||||||
context,
|
location,
|
||||||
(output, o.span),
|
(output, o.span),
|
||||||
(Deep, Read(ReadKind::Copy)),
|
(Deep, Read(ReadKind::Copy)),
|
||||||
LocalMutationIsAllowed::No,
|
LocalMutationIsAllowed::No,
|
||||||
flow_state,
|
flow_state,
|
||||||
);
|
);
|
||||||
self.check_if_path_or_subpath_is_moved(
|
self.check_if_path_or_subpath_is_moved(
|
||||||
context,
|
location,
|
||||||
InitializationRequiringAction::Use,
|
InitializationRequiringAction::Use,
|
||||||
(output, o.span),
|
(output, o.span),
|
||||||
flow_state,
|
flow_state,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
self.mutate_place(
|
self.mutate_place(
|
||||||
context,
|
location,
|
||||||
(output, o.span),
|
(output, o.span),
|
||||||
if o.is_rw { Deep } else { Shallow(None) },
|
if o.is_rw { Deep } else { Shallow(None) },
|
||||||
if o.is_rw { WriteAndRead } else { JustWrite },
|
if o.is_rw { WriteAndRead } else { JustWrite },
|
||||||
@ -633,7 +632,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (_, input) in asm.inputs.iter() {
|
for (_, input) in asm.inputs.iter() {
|
||||||
self.consume_operand(context, (input, span), flow_state);
|
self.consume_operand(location, (input, span), flow_state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StatementKind::Nop
|
StatementKind::Nop
|
||||||
@ -645,7 +644,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
|
|||||||
}
|
}
|
||||||
StatementKind::StorageDead(local) => {
|
StatementKind::StorageDead(local) => {
|
||||||
self.access_place(
|
self.access_place(
|
||||||
ContextKind::StorageDead.new(location),
|
location,
|
||||||
(&Place::Base(PlaceBase::Local(local)), span),
|
(&Place::Base(PlaceBase::Local(local)), span),
|
||||||
(Shallow(None), Write(WriteKind::StorageDeadOrDrop)),
|
(Shallow(None), Write(WriteKind::StorageDeadOrDrop)),
|
||||||
LocalMutationIsAllowed::Yes,
|
LocalMutationIsAllowed::Yes,
|
||||||
@ -677,7 +676,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
|
|||||||
values: _,
|
values: _,
|
||||||
targets: _,
|
targets: _,
|
||||||
} => {
|
} => {
|
||||||
self.consume_operand(ContextKind::SwitchInt.new(loc), (discr, span), flow_state);
|
self.consume_operand(loc, (discr, span), flow_state);
|
||||||
}
|
}
|
||||||
TerminatorKind::Drop {
|
TerminatorKind::Drop {
|
||||||
location: ref drop_place,
|
location: ref drop_place,
|
||||||
@ -702,7 +701,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
|
|||||||
loc, term, drop_place, drop_place_ty, span);
|
loc, term, drop_place, drop_place_ty, span);
|
||||||
|
|
||||||
self.access_place(
|
self.access_place(
|
||||||
ContextKind::Drop.new(loc),
|
loc,
|
||||||
(drop_place, span),
|
(drop_place, span),
|
||||||
(AccessDepth::Drop, Write(WriteKind::StorageDeadOrDrop)),
|
(AccessDepth::Drop, Write(WriteKind::StorageDeadOrDrop)),
|
||||||
LocalMutationIsAllowed::Yes,
|
LocalMutationIsAllowed::Yes,
|
||||||
@ -716,14 +715,14 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
|
|||||||
unwind: _,
|
unwind: _,
|
||||||
} => {
|
} => {
|
||||||
self.mutate_place(
|
self.mutate_place(
|
||||||
ContextKind::DropAndReplace.new(loc),
|
loc,
|
||||||
(drop_place, span),
|
(drop_place, span),
|
||||||
Deep,
|
Deep,
|
||||||
JustWrite,
|
JustWrite,
|
||||||
flow_state,
|
flow_state,
|
||||||
);
|
);
|
||||||
self.consume_operand(
|
self.consume_operand(
|
||||||
ContextKind::DropAndReplace.new(loc),
|
loc,
|
||||||
(new_value, span),
|
(new_value, span),
|
||||||
flow_state,
|
flow_state,
|
||||||
);
|
);
|
||||||
@ -735,17 +734,17 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
|
|||||||
cleanup: _,
|
cleanup: _,
|
||||||
from_hir_call: _,
|
from_hir_call: _,
|
||||||
} => {
|
} => {
|
||||||
self.consume_operand(ContextKind::CallOperator.new(loc), (func, span), flow_state);
|
self.consume_operand(loc, (func, span), flow_state);
|
||||||
for arg in args {
|
for arg in args {
|
||||||
self.consume_operand(
|
self.consume_operand(
|
||||||
ContextKind::CallOperand.new(loc),
|
loc,
|
||||||
(arg, span),
|
(arg, span),
|
||||||
flow_state,
|
flow_state,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if let Some((ref dest, _ /*bb*/)) = *destination {
|
if let Some((ref dest, _ /*bb*/)) = *destination {
|
||||||
self.mutate_place(
|
self.mutate_place(
|
||||||
ContextKind::CallDest.new(loc),
|
loc,
|
||||||
(dest, span),
|
(dest, span),
|
||||||
Deep,
|
Deep,
|
||||||
JustWrite,
|
JustWrite,
|
||||||
@ -760,11 +759,11 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
|
|||||||
target: _,
|
target: _,
|
||||||
cleanup: _,
|
cleanup: _,
|
||||||
} => {
|
} => {
|
||||||
self.consume_operand(ContextKind::Assert.new(loc), (cond, span), flow_state);
|
self.consume_operand(loc, (cond, span), flow_state);
|
||||||
use rustc::mir::interpret::InterpError::BoundsCheck;
|
use rustc::mir::interpret::InterpError::BoundsCheck;
|
||||||
if let BoundsCheck { ref len, ref index } = *msg {
|
if let BoundsCheck { ref len, ref index } = *msg {
|
||||||
self.consume_operand(ContextKind::Assert.new(loc), (len, span), flow_state);
|
self.consume_operand(loc, (len, span), flow_state);
|
||||||
self.consume_operand(ContextKind::Assert.new(loc), (index, span), flow_state);
|
self.consume_operand(loc, (index, span), flow_state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -773,7 +772,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
|
|||||||
resume: _,
|
resume: _,
|
||||||
drop: _,
|
drop: _,
|
||||||
} => {
|
} => {
|
||||||
self.consume_operand(ContextKind::Yield.new(loc), (value, span), flow_state);
|
self.consume_operand(loc, (value, span), flow_state);
|
||||||
|
|
||||||
if self.movable_generator {
|
if self.movable_generator {
|
||||||
// Look for any active borrows to locals
|
// Look for any active borrows to locals
|
||||||
@ -796,8 +795,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
|
|||||||
flow_state.with_outgoing_borrows(|borrows| {
|
flow_state.with_outgoing_borrows(|borrows| {
|
||||||
for i in borrows {
|
for i in borrows {
|
||||||
let borrow = &borrow_set[i];
|
let borrow = &borrow_set[i];
|
||||||
let context = ContextKind::StorageDead.new(loc);
|
self.check_for_invalidation_at_exit(loc, borrow, span);
|
||||||
self.check_for_invalidation_at_exit(context, borrow, span);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -955,7 +953,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
/// Returns `true` if an error is reported.
|
/// Returns `true` if an error is reported.
|
||||||
fn access_place(
|
fn access_place(
|
||||||
&mut self,
|
&mut self,
|
||||||
context: Context,
|
location: Location,
|
||||||
place_span: (&Place<'tcx>, Span),
|
place_span: (&Place<'tcx>, Span),
|
||||||
kind: (AccessDepth, ReadOrWrite),
|
kind: (AccessDepth, ReadOrWrite),
|
||||||
is_local_mutation_allowed: LocalMutationIsAllowed,
|
is_local_mutation_allowed: LocalMutationIsAllowed,
|
||||||
@ -994,10 +992,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
rw,
|
rw,
|
||||||
is_local_mutation_allowed,
|
is_local_mutation_allowed,
|
||||||
flow_state,
|
flow_state,
|
||||||
context.loc,
|
location,
|
||||||
);
|
);
|
||||||
let conflict_error =
|
let conflict_error =
|
||||||
self.check_access_for_conflict(context, place_span, sd, rw, flow_state);
|
self.check_access_for_conflict(location, place_span, sd, rw, flow_state);
|
||||||
|
|
||||||
if let (Activation(_, borrow_idx), true) = (kind.1, conflict_error) {
|
if let (Activation(_, borrow_idx), true) = (kind.1, conflict_error) {
|
||||||
// Suppress this warning when there's an error being emited for the
|
// Suppress this warning when there's an error being emited for the
|
||||||
@ -1018,30 +1016,30 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
|
|
||||||
fn check_access_for_conflict(
|
fn check_access_for_conflict(
|
||||||
&mut self,
|
&mut self,
|
||||||
context: Context,
|
location: Location,
|
||||||
place_span: (&Place<'tcx>, Span),
|
place_span: (&Place<'tcx>, Span),
|
||||||
sd: AccessDepth,
|
sd: AccessDepth,
|
||||||
rw: ReadOrWrite,
|
rw: ReadOrWrite,
|
||||||
flow_state: &Flows<'cx, 'gcx, 'tcx>,
|
flow_state: &Flows<'cx, 'gcx, 'tcx>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
debug!(
|
debug!(
|
||||||
"check_access_for_conflict(context={:?}, place_span={:?}, sd={:?}, rw={:?})",
|
"check_access_for_conflict(location={:?}, place_span={:?}, sd={:?}, rw={:?})",
|
||||||
context, place_span, sd, rw,
|
location, place_span, sd, rw,
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut error_reported = false;
|
let mut error_reported = false;
|
||||||
let tcx = self.infcx.tcx;
|
let tcx = self.infcx.tcx;
|
||||||
let mir = self.mir;
|
let mir = self.mir;
|
||||||
let location = self.location_table.start_index(context.loc);
|
let location_table = self.location_table.start_index(location);
|
||||||
let borrow_set = self.borrow_set.clone();
|
let borrow_set = self.borrow_set.clone();
|
||||||
each_borrow_involving_path(
|
each_borrow_involving_path(
|
||||||
self,
|
self,
|
||||||
tcx,
|
tcx,
|
||||||
mir,
|
mir,
|
||||||
context,
|
location,
|
||||||
(sd, place_span.0),
|
(sd, place_span.0),
|
||||||
&borrow_set,
|
&borrow_set,
|
||||||
flow_state.borrows_in_scope(location),
|
flow_state.borrows_in_scope(location_table),
|
||||||
|this, borrow_index, borrow| match (rw, borrow.kind) {
|
|this, borrow_index, borrow| match (rw, borrow.kind) {
|
||||||
// Obviously an activation is compatible with its own
|
// Obviously an activation is compatible with its own
|
||||||
// reservation (or even prior activating uses of same
|
// reservation (or even prior activating uses of same
|
||||||
@ -1075,7 +1073,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
|
|
||||||
(Read(kind), BorrowKind::Unique) | (Read(kind), BorrowKind::Mut { .. }) => {
|
(Read(kind), BorrowKind::Unique) | (Read(kind), BorrowKind::Mut { .. }) => {
|
||||||
// Reading from mere reservations of mutable-borrows is OK.
|
// Reading from mere reservations of mutable-borrows is OK.
|
||||||
if !is_active(&this.dominators, borrow, context.loc) {
|
if !is_active(&this.dominators, borrow, location) {
|
||||||
assert!(allow_two_phase_borrow(borrow.kind));
|
assert!(allow_two_phase_borrow(borrow.kind));
|
||||||
return Control::Continue;
|
return Control::Continue;
|
||||||
}
|
}
|
||||||
@ -1083,11 +1081,11 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
error_reported = true;
|
error_reported = true;
|
||||||
match kind {
|
match kind {
|
||||||
ReadKind::Copy => {
|
ReadKind::Copy => {
|
||||||
this.report_use_while_mutably_borrowed(context, place_span, borrow)
|
this.report_use_while_mutably_borrowed(location, place_span, borrow)
|
||||||
.buffer(&mut this.errors_buffer);
|
.buffer(&mut this.errors_buffer);
|
||||||
}
|
}
|
||||||
ReadKind::Borrow(bk) => {
|
ReadKind::Borrow(bk) => {
|
||||||
this.report_conflicting_borrow(context, place_span, bk, borrow)
|
this.report_conflicting_borrow(location, place_span, bk, borrow)
|
||||||
.buffer(&mut this.errors_buffer);
|
.buffer(&mut this.errors_buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1098,7 +1096,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
| (Reservation(WriteKind::MutableBorrow(bk)), BorrowKind::Shared) if {
|
| (Reservation(WriteKind::MutableBorrow(bk)), BorrowKind::Shared) if {
|
||||||
tcx.migrate_borrowck()
|
tcx.migrate_borrowck()
|
||||||
} => {
|
} => {
|
||||||
let bi = this.borrow_set.location_map[&context.loc];
|
let bi = this.borrow_set.location_map[&location];
|
||||||
debug!(
|
debug!(
|
||||||
"recording invalid reservation of place: {:?} with \
|
"recording invalid reservation of place: {:?} with \
|
||||||
borrow index {:?} as warning",
|
borrow index {:?} as warning",
|
||||||
@ -1111,7 +1109,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
// checking was otherwise successful.
|
// checking was otherwise successful.
|
||||||
this.reservation_warnings.insert(
|
this.reservation_warnings.insert(
|
||||||
bi,
|
bi,
|
||||||
(place_span.0.clone(), place_span.1, context, bk, borrow.clone()),
|
(place_span.0.clone(), place_span.1, location, bk, borrow.clone()),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Don't suppress actual errors.
|
// Don't suppress actual errors.
|
||||||
@ -1143,21 +1141,21 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
error_reported = true;
|
error_reported = true;
|
||||||
match kind {
|
match kind {
|
||||||
WriteKind::MutableBorrow(bk) => {
|
WriteKind::MutableBorrow(bk) => {
|
||||||
this.report_conflicting_borrow(context, place_span, bk, borrow)
|
this.report_conflicting_borrow(location, place_span, bk, borrow)
|
||||||
.buffer(&mut this.errors_buffer);
|
.buffer(&mut this.errors_buffer);
|
||||||
}
|
}
|
||||||
WriteKind::StorageDeadOrDrop => {
|
WriteKind::StorageDeadOrDrop => {
|
||||||
this.report_borrowed_value_does_not_live_long_enough(
|
this.report_borrowed_value_does_not_live_long_enough(
|
||||||
context,
|
location,
|
||||||
borrow,
|
borrow,
|
||||||
place_span,
|
place_span,
|
||||||
Some(kind))
|
Some(kind))
|
||||||
}
|
}
|
||||||
WriteKind::Mutate => {
|
WriteKind::Mutate => {
|
||||||
this.report_illegal_mutation_of_borrowed(context, place_span, borrow)
|
this.report_illegal_mutation_of_borrowed(location, place_span, borrow)
|
||||||
}
|
}
|
||||||
WriteKind::Move => {
|
WriteKind::Move => {
|
||||||
this.report_move_out_while_borrowed(context, place_span, borrow)
|
this.report_move_out_while_borrowed(location, place_span, borrow)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Control::Break
|
Control::Break
|
||||||
@ -1170,7 +1168,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
|
|
||||||
fn mutate_place(
|
fn mutate_place(
|
||||||
&mut self,
|
&mut self,
|
||||||
context: Context,
|
location: Location,
|
||||||
place_span: (&Place<'tcx>, Span),
|
place_span: (&Place<'tcx>, Span),
|
||||||
kind: AccessDepth,
|
kind: AccessDepth,
|
||||||
mode: MutateMode,
|
mode: MutateMode,
|
||||||
@ -1180,14 +1178,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
match mode {
|
match mode {
|
||||||
MutateMode::WriteAndRead => {
|
MutateMode::WriteAndRead => {
|
||||||
self.check_if_path_or_subpath_is_moved(
|
self.check_if_path_or_subpath_is_moved(
|
||||||
context,
|
location,
|
||||||
InitializationRequiringAction::Update,
|
InitializationRequiringAction::Update,
|
||||||
place_span,
|
place_span,
|
||||||
flow_state,
|
flow_state,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
MutateMode::JustWrite => {
|
MutateMode::JustWrite => {
|
||||||
self.check_if_assigned_path_is_moved(context, place_span, flow_state);
|
self.check_if_assigned_path_is_moved(location, place_span, flow_state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1198,7 +1196,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
if let Mutability::Not = self.mir.local_decls[local].mutability {
|
if let Mutability::Not = self.mir.local_decls[local].mutability {
|
||||||
// check for reassignments to immutable local variables
|
// check for reassignments to immutable local variables
|
||||||
self.check_if_reassignment_to_immutable_state(
|
self.check_if_reassignment_to_immutable_state(
|
||||||
context,
|
location,
|
||||||
local,
|
local,
|
||||||
place_span,
|
place_span,
|
||||||
flow_state,
|
flow_state,
|
||||||
@ -1209,7 +1207,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
|
|
||||||
// Otherwise, use the normal access permission rules.
|
// Otherwise, use the normal access permission rules.
|
||||||
self.access_place(
|
self.access_place(
|
||||||
context,
|
location,
|
||||||
place_span,
|
place_span,
|
||||||
(kind, Write(WriteKind::Mutate)),
|
(kind, Write(WriteKind::Mutate)),
|
||||||
LocalMutationIsAllowed::No,
|
LocalMutationIsAllowed::No,
|
||||||
@ -1219,9 +1217,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
|
|
||||||
fn consume_rvalue(
|
fn consume_rvalue(
|
||||||
&mut self,
|
&mut self,
|
||||||
context: Context,
|
location: Location,
|
||||||
(rvalue, span): (&Rvalue<'tcx>, Span),
|
(rvalue, span): (&Rvalue<'tcx>, Span),
|
||||||
_location: Location,
|
|
||||||
flow_state: &Flows<'cx, 'gcx, 'tcx>,
|
flow_state: &Flows<'cx, 'gcx, 'tcx>,
|
||||||
) {
|
) {
|
||||||
match *rvalue {
|
match *rvalue {
|
||||||
@ -1242,7 +1239,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
self.access_place(
|
self.access_place(
|
||||||
context,
|
location,
|
||||||
(place, span),
|
(place, span),
|
||||||
access_kind,
|
access_kind,
|
||||||
LocalMutationIsAllowed::No,
|
LocalMutationIsAllowed::No,
|
||||||
@ -1256,7 +1253,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
self.check_if_path_or_subpath_is_moved(
|
self.check_if_path_or_subpath_is_moved(
|
||||||
context,
|
location,
|
||||||
action,
|
action,
|
||||||
(place, span),
|
(place, span),
|
||||||
flow_state,
|
flow_state,
|
||||||
@ -1267,7 +1264,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
| Rvalue::Repeat(ref operand, _)
|
| Rvalue::Repeat(ref operand, _)
|
||||||
| Rvalue::UnaryOp(_ /*un_op*/, ref operand)
|
| Rvalue::UnaryOp(_ /*un_op*/, ref operand)
|
||||||
| Rvalue::Cast(_ /*cast_kind*/, ref operand, _ /*ty*/) => {
|
| Rvalue::Cast(_ /*cast_kind*/, ref operand, _ /*ty*/) => {
|
||||||
self.consume_operand(context, (operand, span), flow_state)
|
self.consume_operand(location, (operand, span), flow_state)
|
||||||
}
|
}
|
||||||
|
|
||||||
Rvalue::Len(ref place) | Rvalue::Discriminant(ref place) => {
|
Rvalue::Len(ref place) | Rvalue::Discriminant(ref place) => {
|
||||||
@ -1277,14 +1274,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
self.access_place(
|
self.access_place(
|
||||||
context,
|
location,
|
||||||
(place, span),
|
(place, span),
|
||||||
(Shallow(af), Read(ReadKind::Copy)),
|
(Shallow(af), Read(ReadKind::Copy)),
|
||||||
LocalMutationIsAllowed::No,
|
LocalMutationIsAllowed::No,
|
||||||
flow_state,
|
flow_state,
|
||||||
);
|
);
|
||||||
self.check_if_path_or_subpath_is_moved(
|
self.check_if_path_or_subpath_is_moved(
|
||||||
context,
|
location,
|
||||||
InitializationRequiringAction::Use,
|
InitializationRequiringAction::Use,
|
||||||
(place, span),
|
(place, span),
|
||||||
flow_state,
|
flow_state,
|
||||||
@ -1293,8 +1290,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
|
|
||||||
Rvalue::BinaryOp(_bin_op, ref operand1, ref operand2)
|
Rvalue::BinaryOp(_bin_op, ref operand1, ref operand2)
|
||||||
| Rvalue::CheckedBinaryOp(_bin_op, ref operand1, ref operand2) => {
|
| Rvalue::CheckedBinaryOp(_bin_op, ref operand1, ref operand2) => {
|
||||||
self.consume_operand(context, (operand1, span), flow_state);
|
self.consume_operand(location, (operand1, span), flow_state);
|
||||||
self.consume_operand(context, (operand2, span), flow_state);
|
self.consume_operand(location, (operand2, span), flow_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
Rvalue::NullaryOp(_op, _ty) => {
|
Rvalue::NullaryOp(_op, _ty) => {
|
||||||
@ -1326,7 +1323,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for operand in operands {
|
for operand in operands {
|
||||||
self.consume_operand(context, (operand, span), flow_state);
|
self.consume_operand(location, (operand, span), flow_state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1407,7 +1404,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
|
|
||||||
fn consume_operand(
|
fn consume_operand(
|
||||||
&mut self,
|
&mut self,
|
||||||
context: Context,
|
location: Location,
|
||||||
(operand, span): (&Operand<'tcx>, Span),
|
(operand, span): (&Operand<'tcx>, Span),
|
||||||
flow_state: &Flows<'cx, 'gcx, 'tcx>,
|
flow_state: &Flows<'cx, 'gcx, 'tcx>,
|
||||||
) {
|
) {
|
||||||
@ -1416,7 +1413,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
// copy of place: check if this is "copy of frozen path"
|
// copy of place: check if this is "copy of frozen path"
|
||||||
// (FIXME: see check_loans.rs)
|
// (FIXME: see check_loans.rs)
|
||||||
self.access_place(
|
self.access_place(
|
||||||
context,
|
location,
|
||||||
(place, span),
|
(place, span),
|
||||||
(Deep, Read(ReadKind::Copy)),
|
(Deep, Read(ReadKind::Copy)),
|
||||||
LocalMutationIsAllowed::No,
|
LocalMutationIsAllowed::No,
|
||||||
@ -1425,7 +1422,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
|
|
||||||
// Finally, check if path was already moved.
|
// Finally, check if path was already moved.
|
||||||
self.check_if_path_or_subpath_is_moved(
|
self.check_if_path_or_subpath_is_moved(
|
||||||
context,
|
location,
|
||||||
InitializationRequiringAction::Use,
|
InitializationRequiringAction::Use,
|
||||||
(place, span),
|
(place, span),
|
||||||
flow_state,
|
flow_state,
|
||||||
@ -1434,7 +1431,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
Operand::Move(ref place) => {
|
Operand::Move(ref place) => {
|
||||||
// move of place: check if this is move of already borrowed path
|
// move of place: check if this is move of already borrowed path
|
||||||
self.access_place(
|
self.access_place(
|
||||||
context,
|
location,
|
||||||
(place, span),
|
(place, span),
|
||||||
(Deep, Write(WriteKind::Move)),
|
(Deep, Write(WriteKind::Move)),
|
||||||
LocalMutationIsAllowed::Yes,
|
LocalMutationIsAllowed::Yes,
|
||||||
@ -1443,7 +1440,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
|
|
||||||
// Finally, check if path was already moved.
|
// Finally, check if path was already moved.
|
||||||
self.check_if_path_or_subpath_is_moved(
|
self.check_if_path_or_subpath_is_moved(
|
||||||
context,
|
location,
|
||||||
InitializationRequiringAction::Use,
|
InitializationRequiringAction::Use,
|
||||||
(place, span),
|
(place, span),
|
||||||
flow_state,
|
flow_state,
|
||||||
@ -1457,7 +1454,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
/// exits
|
/// exits
|
||||||
fn check_for_invalidation_at_exit(
|
fn check_for_invalidation_at_exit(
|
||||||
&mut self,
|
&mut self,
|
||||||
context: Context,
|
location: Location,
|
||||||
borrow: &BorrowData<'tcx>,
|
borrow: &BorrowData<'tcx>,
|
||||||
span: Span,
|
span: Span,
|
||||||
) {
|
) {
|
||||||
@ -1513,7 +1510,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
// of just a span here.
|
// of just a span here.
|
||||||
let span = self.infcx.tcx.sess.source_map().end_point(span);
|
let span = self.infcx.tcx.sess.source_map().end_point(span);
|
||||||
self.report_borrowed_value_does_not_live_long_enough(
|
self.report_borrowed_value_does_not_live_long_enough(
|
||||||
context,
|
location,
|
||||||
borrow,
|
borrow,
|
||||||
(place, span),
|
(place, span),
|
||||||
None,
|
None,
|
||||||
@ -1558,7 +1555,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
self.access_place(
|
self.access_place(
|
||||||
ContextKind::Activation.new(location),
|
location,
|
||||||
(&borrow.borrowed_place, span),
|
(&borrow.borrowed_place, span),
|
||||||
(
|
(
|
||||||
Deep,
|
Deep,
|
||||||
@ -1577,7 +1574,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||||
fn check_if_reassignment_to_immutable_state(
|
fn check_if_reassignment_to_immutable_state(
|
||||||
&mut self,
|
&mut self,
|
||||||
context: Context,
|
location: Location,
|
||||||
local: Local,
|
local: Local,
|
||||||
place_span: (&Place<'tcx>, Span),
|
place_span: (&Place<'tcx>, Span),
|
||||||
flow_state: &Flows<'cx, 'gcx, 'tcx>,
|
flow_state: &Flows<'cx, 'gcx, 'tcx>,
|
||||||
@ -1590,14 +1587,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
let init = &self.move_data.inits[init_index];
|
let init = &self.move_data.inits[init_index];
|
||||||
let span = init.span(&self.mir);
|
let span = init.span(&self.mir);
|
||||||
self.report_illegal_reassignment(
|
self.report_illegal_reassignment(
|
||||||
context, place_span, span, place_span.0
|
location, place_span, span, place_span.0
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_if_full_path_is_moved(
|
fn check_if_full_path_is_moved(
|
||||||
&mut self,
|
&mut self,
|
||||||
context: Context,
|
location: Location,
|
||||||
desired_action: InitializationRequiringAction,
|
desired_action: InitializationRequiringAction,
|
||||||
place_span: (&Place<'tcx>, Span),
|
place_span: (&Place<'tcx>, Span),
|
||||||
flow_state: &Flows<'cx, 'gcx, 'tcx>,
|
flow_state: &Flows<'cx, 'gcx, 'tcx>,
|
||||||
@ -1644,7 +1641,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
Ok((prefix, mpi)) => {
|
Ok((prefix, mpi)) => {
|
||||||
if maybe_uninits.contains(mpi) {
|
if maybe_uninits.contains(mpi) {
|
||||||
self.report_use_of_moved_or_uninitialized(
|
self.report_use_of_moved_or_uninitialized(
|
||||||
context,
|
location,
|
||||||
desired_action,
|
desired_action,
|
||||||
(prefix, place_span.0, place_span.1),
|
(prefix, place_span.0, place_span.1),
|
||||||
mpi,
|
mpi,
|
||||||
@ -1665,7 +1662,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
|
|
||||||
fn check_if_path_or_subpath_is_moved(
|
fn check_if_path_or_subpath_is_moved(
|
||||||
&mut self,
|
&mut self,
|
||||||
context: Context,
|
location: Location,
|
||||||
desired_action: InitializationRequiringAction,
|
desired_action: InitializationRequiringAction,
|
||||||
place_span: (&Place<'tcx>, Span),
|
place_span: (&Place<'tcx>, Span),
|
||||||
flow_state: &Flows<'cx, 'gcx, 'tcx>,
|
flow_state: &Flows<'cx, 'gcx, 'tcx>,
|
||||||
@ -1687,7 +1684,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
// must have been initialized for the use to be sound.
|
// must have been initialized for the use to be sound.
|
||||||
// 6. Move of `a.b.c` then reinit of `a.b.c.d`, use of `a.b.c.d`
|
// 6. Move of `a.b.c` then reinit of `a.b.c.d`, use of `a.b.c.d`
|
||||||
|
|
||||||
self.check_if_full_path_is_moved(context, desired_action, place_span, flow_state);
|
self.check_if_full_path_is_moved(location, desired_action, place_span, flow_state);
|
||||||
|
|
||||||
// A move of any shallow suffix of `place` also interferes
|
// A move of any shallow suffix of `place` also interferes
|
||||||
// with an attempt to use `place`. This is scenario 3 above.
|
// with an attempt to use `place`. This is scenario 3 above.
|
||||||
@ -1702,7 +1699,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
if let Some(mpi) = self.move_path_for_place(place_span.0) {
|
if let Some(mpi) = self.move_path_for_place(place_span.0) {
|
||||||
if let Some(child_mpi) = maybe_uninits.has_any_child_of(mpi) {
|
if let Some(child_mpi) = maybe_uninits.has_any_child_of(mpi) {
|
||||||
self.report_use_of_moved_or_uninitialized(
|
self.report_use_of_moved_or_uninitialized(
|
||||||
context,
|
location,
|
||||||
desired_action,
|
desired_action,
|
||||||
(place_span.0, place_span.0, place_span.1),
|
(place_span.0, place_span.0, place_span.1),
|
||||||
child_mpi,
|
child_mpi,
|
||||||
@ -1753,7 +1750,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
|
|
||||||
fn check_if_assigned_path_is_moved(
|
fn check_if_assigned_path_is_moved(
|
||||||
&mut self,
|
&mut self,
|
||||||
context: Context,
|
location: Location,
|
||||||
(place, span): (&Place<'tcx>, Span),
|
(place, span): (&Place<'tcx>, Span),
|
||||||
flow_state: &Flows<'cx, 'gcx, 'tcx>,
|
flow_state: &Flows<'cx, 'gcx, 'tcx>,
|
||||||
) {
|
) {
|
||||||
@ -1781,7 +1778,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
// assigning to (*P) requires P to be initialized
|
// assigning to (*P) requires P to be initialized
|
||||||
ProjectionElem::Deref => {
|
ProjectionElem::Deref => {
|
||||||
self.check_if_full_path_is_moved(
|
self.check_if_full_path_is_moved(
|
||||||
context, InitializationRequiringAction::Use,
|
location, InitializationRequiringAction::Use,
|
||||||
(base, span), flow_state);
|
(base, span), flow_state);
|
||||||
// (base initialized; no need to
|
// (base initialized; no need to
|
||||||
// recur further)
|
// recur further)
|
||||||
@ -1789,8 +1786,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ProjectionElem::Subslice { .. } => {
|
ProjectionElem::Subslice { .. } => {
|
||||||
panic!("we don't allow assignments to subslices, context: {:?}",
|
panic!("we don't allow assignments to subslices, location: {:?}",
|
||||||
context);
|
location);
|
||||||
}
|
}
|
||||||
|
|
||||||
ProjectionElem::Field(..) => {
|
ProjectionElem::Field(..) => {
|
||||||
@ -1801,7 +1798,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
match base.ty(self.mir, tcx).ty.sty {
|
match base.ty(self.mir, tcx).ty.sty {
|
||||||
ty::Adt(def, _) if def.has_dtor(tcx) => {
|
ty::Adt(def, _) if def.has_dtor(tcx) => {
|
||||||
self.check_if_path_or_subpath_is_moved(
|
self.check_if_path_or_subpath_is_moved(
|
||||||
context, InitializationRequiringAction::Assignment,
|
location, InitializationRequiringAction::Assignment,
|
||||||
(base, span), flow_state);
|
(base, span), flow_state);
|
||||||
|
|
||||||
// (base initialized; no need to
|
// (base initialized; no need to
|
||||||
@ -1813,7 +1810,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
// Once `let s; s.x = V; read(s.x);`,
|
// Once `let s; s.x = V; read(s.x);`,
|
||||||
// is allowed, remove this match arm.
|
// is allowed, remove this match arm.
|
||||||
ty::Adt(..) | ty::Tuple(..) => {
|
ty::Adt(..) | ty::Tuple(..) => {
|
||||||
check_parent_of_field(self, context, base, span, flow_state);
|
check_parent_of_field(self, location, base, span, flow_state);
|
||||||
|
|
||||||
if let Some(local) = place.base_local() {
|
if let Some(local) = place.base_local() {
|
||||||
// rust-lang/rust#21232,
|
// rust-lang/rust#21232,
|
||||||
@ -1841,7 +1838,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
|
|
||||||
fn check_parent_of_field<'cx, 'gcx, 'tcx>(
|
fn check_parent_of_field<'cx, 'gcx, 'tcx>(
|
||||||
this: &mut MirBorrowckCtxt<'cx, 'gcx, 'tcx>,
|
this: &mut MirBorrowckCtxt<'cx, 'gcx, 'tcx>,
|
||||||
context: Context,
|
location: Location,
|
||||||
base: &Place<'tcx>,
|
base: &Place<'tcx>,
|
||||||
span: Span,
|
span: Span,
|
||||||
flow_state: &Flows<'cx, 'gcx, 'tcx>,
|
flow_state: &Flows<'cx, 'gcx, 'tcx>,
|
||||||
@ -1907,7 +1904,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
if def.is_union() {
|
if def.is_union() {
|
||||||
if this.move_data.path_map[mpi].iter().any(|moi| {
|
if this.move_data.path_map[mpi].iter().any(|moi| {
|
||||||
this.move_data.moves[*moi].source.is_predecessor_of(
|
this.move_data.moves[*moi].source.is_predecessor_of(
|
||||||
context.loc, this.mir,
|
location, this.mir,
|
||||||
)
|
)
|
||||||
}) {
|
}) {
|
||||||
return;
|
return;
|
||||||
@ -1916,7 +1913,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.report_use_of_moved_or_uninitialized(
|
this.report_use_of_moved_or_uninitialized(
|
||||||
context,
|
location,
|
||||||
InitializationRequiringAction::PartialAssignment,
|
InitializationRequiringAction::PartialAssignment,
|
||||||
(prefix, base, span),
|
(prefix, base, span),
|
||||||
mpi,
|
mpi,
|
||||||
@ -2234,7 +2231,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
// Subtle: this is an upvar
|
// Subtle: this is an upvar
|
||||||
// reference, so it looks like
|
// reference, so it looks like
|
||||||
// `self.foo` -- we want to double
|
// `self.foo` -- we want to double
|
||||||
// check that the context `*self`
|
// check that the location `*self`
|
||||||
// is mutable (i.e., this is not a
|
// is mutable (i.e., this is not a
|
||||||
// `Fn` closure). But if that
|
// `Fn` closure). But if that
|
||||||
// check succeeds, we want to
|
// check succeeds, we want to
|
||||||
@ -2331,37 +2328,3 @@ enum Overlap {
|
|||||||
/// will also be disjoint.
|
/// will also be disjoint.
|
||||||
Disjoint,
|
Disjoint,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
|
||||||
struct Context {
|
|
||||||
kind: ContextKind,
|
|
||||||
loc: Location,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
|
||||||
enum ContextKind {
|
|
||||||
Activation,
|
|
||||||
AssignLhs,
|
|
||||||
AssignRhs,
|
|
||||||
SetDiscrim,
|
|
||||||
InlineAsm,
|
|
||||||
SwitchInt,
|
|
||||||
Drop,
|
|
||||||
DropAndReplace,
|
|
||||||
CallOperator,
|
|
||||||
CallOperand,
|
|
||||||
CallDest,
|
|
||||||
Assert,
|
|
||||||
Yield,
|
|
||||||
FakeRead,
|
|
||||||
StorageDead,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ContextKind {
|
|
||||||
fn new(self, loc: Location) -> Context {
|
|
||||||
Context {
|
|
||||||
kind: self,
|
|
||||||
loc,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -4,7 +4,7 @@ use crate::borrow_check::borrow_set::BorrowData;
|
|||||||
use crate::borrow_check::error_reporting::UseSpans;
|
use crate::borrow_check::error_reporting::UseSpans;
|
||||||
use crate::borrow_check::nll::region_infer::{Cause, RegionName};
|
use crate::borrow_check::nll::region_infer::{Cause, RegionName};
|
||||||
use crate::borrow_check::nll::ConstraintDescription;
|
use crate::borrow_check::nll::ConstraintDescription;
|
||||||
use crate::borrow_check::{Context, MirBorrowckCtxt, WriteKind};
|
use crate::borrow_check::{MirBorrowckCtxt, WriteKind};
|
||||||
use rustc::mir::{
|
use rustc::mir::{
|
||||||
CastKind, ConstraintCategory, FakeReadCause, Local, Location, Mir, Operand, Place, PlaceBase,
|
CastKind, ConstraintCategory, FakeReadCause, Local, Location, Mir, Operand, Place, PlaceBase,
|
||||||
Projection, ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind,
|
Projection, ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind,
|
||||||
@ -209,13 +209,13 @@ impl BorrowExplanation {
|
|||||||
|
|
||||||
impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||||
/// Returns structured explanation for *why* the borrow contains the
|
/// Returns structured explanation for *why* the borrow contains the
|
||||||
/// point from `context`. This is key for the "3-point errors"
|
/// point from `location`. This is key for the "3-point errors"
|
||||||
/// [described in the NLL RFC][d].
|
/// [described in the NLL RFC][d].
|
||||||
///
|
///
|
||||||
/// # Parameters
|
/// # Parameters
|
||||||
///
|
///
|
||||||
/// - `borrow`: the borrow in question
|
/// - `borrow`: the borrow in question
|
||||||
/// - `context`: where the borrow occurs
|
/// - `location`: where the borrow occurs
|
||||||
/// - `kind_place`: if Some, this describes the statement that triggered the error.
|
/// - `kind_place`: if Some, this describes the statement that triggered the error.
|
||||||
/// - first half is the kind of write, if any, being performed
|
/// - first half is the kind of write, if any, being performed
|
||||||
/// - second half is the place being accessed
|
/// - second half is the place being accessed
|
||||||
@ -223,13 +223,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
/// [d]: https://rust-lang.github.io/rfcs/2094-nll.html#leveraging-intuition-framing-errors-in-terms-of-points
|
/// [d]: https://rust-lang.github.io/rfcs/2094-nll.html#leveraging-intuition-framing-errors-in-terms-of-points
|
||||||
pub(in crate::borrow_check) fn explain_why_borrow_contains_point(
|
pub(in crate::borrow_check) fn explain_why_borrow_contains_point(
|
||||||
&self,
|
&self,
|
||||||
context: Context,
|
location: Location,
|
||||||
borrow: &BorrowData<'tcx>,
|
borrow: &BorrowData<'tcx>,
|
||||||
kind_place: Option<(WriteKind, &Place<'tcx>)>,
|
kind_place: Option<(WriteKind, &Place<'tcx>)>,
|
||||||
) -> BorrowExplanation {
|
) -> BorrowExplanation {
|
||||||
debug!(
|
debug!(
|
||||||
"explain_why_borrow_contains_point(context={:?}, borrow={:?}, kind_place={:?})",
|
"explain_why_borrow_contains_point(location={:?}, borrow={:?}, kind_place={:?})",
|
||||||
context, borrow, kind_place
|
location, borrow, kind_place
|
||||||
);
|
);
|
||||||
|
|
||||||
let regioncx = &self.nonlexical_regioncx;
|
let regioncx = &self.nonlexical_regioncx;
|
||||||
@ -242,20 +242,20 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||||||
borrow_region_vid
|
borrow_region_vid
|
||||||
);
|
);
|
||||||
|
|
||||||
let region_sub = regioncx.find_sub_region_live_at(borrow_region_vid, context.loc);
|
let region_sub = regioncx.find_sub_region_live_at(borrow_region_vid, location);
|
||||||
debug!(
|
debug!(
|
||||||
"explain_why_borrow_contains_point: region_sub={:?}",
|
"explain_why_borrow_contains_point: region_sub={:?}",
|
||||||
region_sub
|
region_sub
|
||||||
);
|
);
|
||||||
|
|
||||||
match find_use::find(mir, regioncx, tcx, region_sub, context.loc) {
|
match find_use::find(mir, regioncx, tcx, region_sub, location) {
|
||||||
Some(Cause::LiveVar(local, location)) => {
|
Some(Cause::LiveVar(local, location)) => {
|
||||||
let span = mir.source_info(location).span;
|
let span = mir.source_info(location).span;
|
||||||
let spans = self
|
let spans = self
|
||||||
.move_spans(&Place::Base(PlaceBase::Local(local)), location)
|
.move_spans(&Place::Base(PlaceBase::Local(local)), location)
|
||||||
.or_else(|| self.borrow_spans(span, location));
|
.or_else(|| self.borrow_spans(span, location));
|
||||||
|
|
||||||
let borrow_location = context.loc;
|
let borrow_location = location;
|
||||||
if self.is_use_in_later_iteration_of_loop(borrow_location, location) {
|
if self.is_use_in_later_iteration_of_loop(borrow_location, location) {
|
||||||
let later_use = self.later_use_kind(borrow, spans, location);
|
let later_use = self.later_use_kind(borrow, spans, location);
|
||||||
BorrowExplanation::UsedLaterInLoop(later_use.0, later_use.1)
|
BorrowExplanation::UsedLaterInLoop(later_use.0, later_use.1)
|
||||||
|
@ -3,7 +3,6 @@ use crate::borrow_check::location::LocationTable;
|
|||||||
use crate::borrow_check::{JustWrite, WriteAndRead};
|
use crate::borrow_check::{JustWrite, WriteAndRead};
|
||||||
use crate::borrow_check::{AccessDepth, Deep, Shallow};
|
use crate::borrow_check::{AccessDepth, Deep, Shallow};
|
||||||
use crate::borrow_check::{ReadOrWrite, Activation, Read, Reservation, Write};
|
use crate::borrow_check::{ReadOrWrite, Activation, Read, Reservation, Write};
|
||||||
use crate::borrow_check::{Context, ContextKind};
|
|
||||||
use crate::borrow_check::{LocalMutationIsAllowed, MutateMode};
|
use crate::borrow_check::{LocalMutationIsAllowed, MutateMode};
|
||||||
use crate::borrow_check::ArtificialField;
|
use crate::borrow_check::ArtificialField;
|
||||||
use crate::borrow_check::{ReadKind, WriteKind};
|
use crate::borrow_check::{ReadKind, WriteKind};
|
||||||
@ -66,12 +65,12 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> {
|
|||||||
match statement.kind {
|
match statement.kind {
|
||||||
StatementKind::Assign(ref lhs, ref rhs) => {
|
StatementKind::Assign(ref lhs, ref rhs) => {
|
||||||
self.consume_rvalue(
|
self.consume_rvalue(
|
||||||
ContextKind::AssignRhs.new(location),
|
location,
|
||||||
rhs,
|
rhs,
|
||||||
);
|
);
|
||||||
|
|
||||||
self.mutate_place(
|
self.mutate_place(
|
||||||
ContextKind::AssignLhs.new(location),
|
location,
|
||||||
lhs,
|
lhs,
|
||||||
Shallow(None),
|
Shallow(None),
|
||||||
JustWrite
|
JustWrite
|
||||||
@ -85,27 +84,26 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> {
|
|||||||
variant_index: _,
|
variant_index: _,
|
||||||
} => {
|
} => {
|
||||||
self.mutate_place(
|
self.mutate_place(
|
||||||
ContextKind::SetDiscrim.new(location),
|
location,
|
||||||
place,
|
place,
|
||||||
Shallow(None),
|
Shallow(None),
|
||||||
JustWrite,
|
JustWrite,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
StatementKind::InlineAsm(ref asm) => {
|
StatementKind::InlineAsm(ref asm) => {
|
||||||
let context = ContextKind::InlineAsm.new(location);
|
|
||||||
for (o, output) in asm.asm.outputs.iter().zip(asm.outputs.iter()) {
|
for (o, output) in asm.asm.outputs.iter().zip(asm.outputs.iter()) {
|
||||||
if o.is_indirect {
|
if o.is_indirect {
|
||||||
// FIXME(eddyb) indirect inline asm outputs should
|
// FIXME(eddyb) indirect inline asm outputs should
|
||||||
// be encoded through MIR place derefs instead.
|
// be encoded through MIR place derefs instead.
|
||||||
self.access_place(
|
self.access_place(
|
||||||
context,
|
location,
|
||||||
output,
|
output,
|
||||||
(Deep, Read(ReadKind::Copy)),
|
(Deep, Read(ReadKind::Copy)),
|
||||||
LocalMutationIsAllowed::No,
|
LocalMutationIsAllowed::No,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
self.mutate_place(
|
self.mutate_place(
|
||||||
context,
|
location,
|
||||||
output,
|
output,
|
||||||
if o.is_rw { Deep } else { Shallow(None) },
|
if o.is_rw { Deep } else { Shallow(None) },
|
||||||
if o.is_rw { WriteAndRead } else { JustWrite },
|
if o.is_rw { WriteAndRead } else { JustWrite },
|
||||||
@ -113,7 +111,7 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (_, input) in asm.inputs.iter() {
|
for (_, input) in asm.inputs.iter() {
|
||||||
self.consume_operand(context, input);
|
self.consume_operand(location, input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StatementKind::Nop |
|
StatementKind::Nop |
|
||||||
@ -125,7 +123,7 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> {
|
|||||||
}
|
}
|
||||||
StatementKind::StorageDead(local) => {
|
StatementKind::StorageDead(local) => {
|
||||||
self.access_place(
|
self.access_place(
|
||||||
ContextKind::StorageDead.new(location),
|
location,
|
||||||
&Place::Base(PlaceBase::Local(local)),
|
&Place::Base(PlaceBase::Local(local)),
|
||||||
(Shallow(None), Write(WriteKind::StorageDeadOrDrop)),
|
(Shallow(None), Write(WriteKind::StorageDeadOrDrop)),
|
||||||
LocalMutationIsAllowed::Yes,
|
LocalMutationIsAllowed::Yes,
|
||||||
@ -150,7 +148,7 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> {
|
|||||||
values: _,
|
values: _,
|
||||||
targets: _,
|
targets: _,
|
||||||
} => {
|
} => {
|
||||||
self.consume_operand(ContextKind::SwitchInt.new(location), discr);
|
self.consume_operand(location, discr);
|
||||||
}
|
}
|
||||||
TerminatorKind::Drop {
|
TerminatorKind::Drop {
|
||||||
location: ref drop_place,
|
location: ref drop_place,
|
||||||
@ -158,7 +156,7 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> {
|
|||||||
unwind: _,
|
unwind: _,
|
||||||
} => {
|
} => {
|
||||||
self.access_place(
|
self.access_place(
|
||||||
ContextKind::Drop.new(location),
|
location,
|
||||||
drop_place,
|
drop_place,
|
||||||
(AccessDepth::Drop, Write(WriteKind::StorageDeadOrDrop)),
|
(AccessDepth::Drop, Write(WriteKind::StorageDeadOrDrop)),
|
||||||
LocalMutationIsAllowed::Yes,
|
LocalMutationIsAllowed::Yes,
|
||||||
@ -171,13 +169,13 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> {
|
|||||||
unwind: _,
|
unwind: _,
|
||||||
} => {
|
} => {
|
||||||
self.mutate_place(
|
self.mutate_place(
|
||||||
ContextKind::DropAndReplace.new(location),
|
location,
|
||||||
drop_place,
|
drop_place,
|
||||||
Deep,
|
Deep,
|
||||||
JustWrite,
|
JustWrite,
|
||||||
);
|
);
|
||||||
self.consume_operand(
|
self.consume_operand(
|
||||||
ContextKind::DropAndReplace.new(location),
|
location,
|
||||||
new_value,
|
new_value,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -188,13 +186,13 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> {
|
|||||||
cleanup: _,
|
cleanup: _,
|
||||||
from_hir_call: _,
|
from_hir_call: _,
|
||||||
} => {
|
} => {
|
||||||
self.consume_operand(ContextKind::CallOperator.new(location), func);
|
self.consume_operand(location, func);
|
||||||
for arg in args {
|
for arg in args {
|
||||||
self.consume_operand(ContextKind::CallOperand.new(location), arg);
|
self.consume_operand(location, arg);
|
||||||
}
|
}
|
||||||
if let Some((ref dest, _ /*bb*/)) = *destination {
|
if let Some((ref dest, _ /*bb*/)) = *destination {
|
||||||
self.mutate_place(
|
self.mutate_place(
|
||||||
ContextKind::CallDest.new(location),
|
location,
|
||||||
dest,
|
dest,
|
||||||
Deep,
|
Deep,
|
||||||
JustWrite,
|
JustWrite,
|
||||||
@ -208,11 +206,11 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> {
|
|||||||
target: _,
|
target: _,
|
||||||
cleanup: _,
|
cleanup: _,
|
||||||
} => {
|
} => {
|
||||||
self.consume_operand(ContextKind::Assert.new(location), cond);
|
self.consume_operand(location, cond);
|
||||||
use rustc::mir::interpret::InterpError::BoundsCheck;
|
use rustc::mir::interpret::InterpError::BoundsCheck;
|
||||||
if let BoundsCheck { ref len, ref index } = *msg {
|
if let BoundsCheck { ref len, ref index } = *msg {
|
||||||
self.consume_operand(ContextKind::Assert.new(location), len);
|
self.consume_operand(location, len);
|
||||||
self.consume_operand(ContextKind::Assert.new(location), index);
|
self.consume_operand(location, index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TerminatorKind::Yield {
|
TerminatorKind::Yield {
|
||||||
@ -220,7 +218,7 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> {
|
|||||||
resume,
|
resume,
|
||||||
drop: _,
|
drop: _,
|
||||||
} => {
|
} => {
|
||||||
self.consume_operand(ContextKind::Yield.new(location), value);
|
self.consume_operand(location, value);
|
||||||
|
|
||||||
// Invalidate all borrows of local places
|
// Invalidate all borrows of local places
|
||||||
let borrow_set = self.borrow_set.clone();
|
let borrow_set = self.borrow_set.clone();
|
||||||
@ -264,13 +262,13 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> {
|
|||||||
/// Simulates mutation of a place.
|
/// Simulates mutation of a place.
|
||||||
fn mutate_place(
|
fn mutate_place(
|
||||||
&mut self,
|
&mut self,
|
||||||
context: Context,
|
location: Location,
|
||||||
place: &Place<'tcx>,
|
place: &Place<'tcx>,
|
||||||
kind: AccessDepth,
|
kind: AccessDepth,
|
||||||
_mode: MutateMode,
|
_mode: MutateMode,
|
||||||
) {
|
) {
|
||||||
self.access_place(
|
self.access_place(
|
||||||
context,
|
location,
|
||||||
place,
|
place,
|
||||||
(kind, Write(WriteKind::Mutate)),
|
(kind, Write(WriteKind::Mutate)),
|
||||||
LocalMutationIsAllowed::ExceptUpvars,
|
LocalMutationIsAllowed::ExceptUpvars,
|
||||||
@ -280,13 +278,13 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> {
|
|||||||
/// Simulates consumption of an operand.
|
/// Simulates consumption of an operand.
|
||||||
fn consume_operand(
|
fn consume_operand(
|
||||||
&mut self,
|
&mut self,
|
||||||
context: Context,
|
location: Location,
|
||||||
operand: &Operand<'tcx>,
|
operand: &Operand<'tcx>,
|
||||||
) {
|
) {
|
||||||
match *operand {
|
match *operand {
|
||||||
Operand::Copy(ref place) => {
|
Operand::Copy(ref place) => {
|
||||||
self.access_place(
|
self.access_place(
|
||||||
context,
|
location,
|
||||||
place,
|
place,
|
||||||
(Deep, Read(ReadKind::Copy)),
|
(Deep, Read(ReadKind::Copy)),
|
||||||
LocalMutationIsAllowed::No,
|
LocalMutationIsAllowed::No,
|
||||||
@ -294,7 +292,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> {
|
|||||||
}
|
}
|
||||||
Operand::Move(ref place) => {
|
Operand::Move(ref place) => {
|
||||||
self.access_place(
|
self.access_place(
|
||||||
context,
|
location,
|
||||||
place,
|
place,
|
||||||
(Deep, Write(WriteKind::Move)),
|
(Deep, Write(WriteKind::Move)),
|
||||||
LocalMutationIsAllowed::Yes,
|
LocalMutationIsAllowed::Yes,
|
||||||
@ -307,7 +305,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> {
|
|||||||
// Simulates consumption of an rvalue
|
// Simulates consumption of an rvalue
|
||||||
fn consume_rvalue(
|
fn consume_rvalue(
|
||||||
&mut self,
|
&mut self,
|
||||||
context: Context,
|
location: Location,
|
||||||
rvalue: &Rvalue<'tcx>,
|
rvalue: &Rvalue<'tcx>,
|
||||||
) {
|
) {
|
||||||
match *rvalue {
|
match *rvalue {
|
||||||
@ -328,7 +326,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
self.access_place(
|
self.access_place(
|
||||||
context,
|
location,
|
||||||
place,
|
place,
|
||||||
access_kind,
|
access_kind,
|
||||||
LocalMutationIsAllowed::No,
|
LocalMutationIsAllowed::No,
|
||||||
@ -339,7 +337,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> {
|
|||||||
| Rvalue::Repeat(ref operand, _)
|
| Rvalue::Repeat(ref operand, _)
|
||||||
| Rvalue::UnaryOp(_ /*un_op*/, ref operand)
|
| Rvalue::UnaryOp(_ /*un_op*/, ref operand)
|
||||||
| Rvalue::Cast(_ /*cast_kind*/, ref operand, _ /*ty*/) => {
|
| Rvalue::Cast(_ /*cast_kind*/, ref operand, _ /*ty*/) => {
|
||||||
self.consume_operand(context, operand)
|
self.consume_operand(location, operand)
|
||||||
}
|
}
|
||||||
|
|
||||||
Rvalue::Len(ref place) | Rvalue::Discriminant(ref place) => {
|
Rvalue::Len(ref place) | Rvalue::Discriminant(ref place) => {
|
||||||
@ -349,7 +347,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
self.access_place(
|
self.access_place(
|
||||||
context,
|
location,
|
||||||
place,
|
place,
|
||||||
(Shallow(af), Read(ReadKind::Copy)),
|
(Shallow(af), Read(ReadKind::Copy)),
|
||||||
LocalMutationIsAllowed::No,
|
LocalMutationIsAllowed::No,
|
||||||
@ -358,8 +356,8 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> {
|
|||||||
|
|
||||||
Rvalue::BinaryOp(_bin_op, ref operand1, ref operand2)
|
Rvalue::BinaryOp(_bin_op, ref operand1, ref operand2)
|
||||||
| Rvalue::CheckedBinaryOp(_bin_op, ref operand1, ref operand2) => {
|
| Rvalue::CheckedBinaryOp(_bin_op, ref operand1, ref operand2) => {
|
||||||
self.consume_operand(context, operand1);
|
self.consume_operand(location, operand1);
|
||||||
self.consume_operand(context, operand2);
|
self.consume_operand(location, operand2);
|
||||||
}
|
}
|
||||||
|
|
||||||
Rvalue::NullaryOp(_op, _ty) => {
|
Rvalue::NullaryOp(_op, _ty) => {
|
||||||
@ -367,7 +365,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> {
|
|||||||
|
|
||||||
Rvalue::Aggregate(_, ref operands) => {
|
Rvalue::Aggregate(_, ref operands) => {
|
||||||
for operand in operands {
|
for operand in operands {
|
||||||
self.consume_operand(context, operand);
|
self.consume_operand(location, operand);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -376,27 +374,27 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> {
|
|||||||
/// Simulates an access to a place.
|
/// Simulates an access to a place.
|
||||||
fn access_place(
|
fn access_place(
|
||||||
&mut self,
|
&mut self,
|
||||||
context: Context,
|
location: Location,
|
||||||
place: &Place<'tcx>,
|
place: &Place<'tcx>,
|
||||||
kind: (AccessDepth, ReadOrWrite),
|
kind: (AccessDepth, ReadOrWrite),
|
||||||
_is_local_mutation_allowed: LocalMutationIsAllowed,
|
_is_local_mutation_allowed: LocalMutationIsAllowed,
|
||||||
) {
|
) {
|
||||||
let (sd, rw) = kind;
|
let (sd, rw) = kind;
|
||||||
// note: not doing check_access_permissions checks because they don't generate invalidates
|
// note: not doing check_access_permissions checks because they don't generate invalidates
|
||||||
self.check_access_for_conflict(context, place, sd, rw);
|
self.check_access_for_conflict(location, place, sd, rw);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_access_for_conflict(
|
fn check_access_for_conflict(
|
||||||
&mut self,
|
&mut self,
|
||||||
context: Context,
|
location: Location,
|
||||||
place: &Place<'tcx>,
|
place: &Place<'tcx>,
|
||||||
sd: AccessDepth,
|
sd: AccessDepth,
|
||||||
rw: ReadOrWrite,
|
rw: ReadOrWrite,
|
||||||
) {
|
) {
|
||||||
debug!(
|
debug!(
|
||||||
"invalidation::check_access_for_conflict(context={:?}, place={:?}, sd={:?}, \
|
"invalidation::check_access_for_conflict(location={:?}, place={:?}, sd={:?}, \
|
||||||
rw={:?})",
|
rw={:?})",
|
||||||
context,
|
location,
|
||||||
place,
|
place,
|
||||||
sd,
|
sd,
|
||||||
rw,
|
rw,
|
||||||
@ -409,7 +407,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> {
|
|||||||
self,
|
self,
|
||||||
tcx,
|
tcx,
|
||||||
mir,
|
mir,
|
||||||
context,
|
location,
|
||||||
(sd, place),
|
(sd, place),
|
||||||
&borrow_set.clone(),
|
&borrow_set.clone(),
|
||||||
indices,
|
indices,
|
||||||
@ -435,7 +433,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> {
|
|||||||
|
|
||||||
(Read(_), BorrowKind::Unique) | (Read(_), BorrowKind::Mut { .. }) => {
|
(Read(_), BorrowKind::Unique) | (Read(_), BorrowKind::Mut { .. }) => {
|
||||||
// Reading from mere reservations of mutable-borrows is OK.
|
// Reading from mere reservations of mutable-borrows is OK.
|
||||||
if !is_active(&this.dominators, borrow, context.loc) {
|
if !is_active(&this.dominators, borrow, location) {
|
||||||
// If the borrow isn't active yet, reads don't invalidate it
|
// If the borrow isn't active yet, reads don't invalidate it
|
||||||
assert!(allow_two_phase_borrow(borrow.kind));
|
assert!(allow_two_phase_borrow(borrow.kind));
|
||||||
return Control::Continue;
|
return Control::Continue;
|
||||||
@ -443,7 +441,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> {
|
|||||||
|
|
||||||
// Unique and mutable borrows are invalidated by reads from any
|
// Unique and mutable borrows are invalidated by reads from any
|
||||||
// involved path
|
// involved path
|
||||||
this.generate_invalidates(borrow_index, context.loc);
|
this.generate_invalidates(borrow_index, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
(Reservation(_), _)
|
(Reservation(_), _)
|
||||||
@ -453,7 +451,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> {
|
|||||||
// Reservations count as writes since we need to check
|
// Reservations count as writes since we need to check
|
||||||
// that activating the borrow will be OK
|
// that activating the borrow will be OK
|
||||||
// FIXME(bob_twinkles) is this actually the right thing to do?
|
// FIXME(bob_twinkles) is this actually the right thing to do?
|
||||||
this.generate_invalidates(borrow_index, context.loc);
|
this.generate_invalidates(borrow_index, location);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Control::Continue
|
Control::Continue
|
||||||
@ -485,7 +483,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
self.access_place(
|
self.access_place(
|
||||||
ContextKind::Activation.new(location),
|
location,
|
||||||
&borrow.borrowed_place,
|
&borrow.borrowed_place,
|
||||||
(
|
(
|
||||||
Deep,
|
Deep,
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
use crate::borrow_check::borrow_set::{BorrowSet, BorrowData, TwoPhaseActivation};
|
use crate::borrow_check::borrow_set::{BorrowSet, BorrowData, TwoPhaseActivation};
|
||||||
use crate::borrow_check::places_conflict;
|
use crate::borrow_check::places_conflict;
|
||||||
use crate::borrow_check::Context;
|
|
||||||
use crate::borrow_check::AccessDepth;
|
use crate::borrow_check::AccessDepth;
|
||||||
use crate::dataflow::indexes::BorrowIndex;
|
use crate::dataflow::indexes::BorrowIndex;
|
||||||
use rustc::mir::{BasicBlock, Location, Mir, Place, PlaceBase};
|
use rustc::mir::{BasicBlock, Location, Mir, Place, PlaceBase};
|
||||||
@ -27,7 +26,7 @@ pub(super) fn each_borrow_involving_path<'a, 'tcx, 'gcx: 'tcx, F, I, S> (
|
|||||||
s: &mut S,
|
s: &mut S,
|
||||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||||
mir: &Mir<'tcx>,
|
mir: &Mir<'tcx>,
|
||||||
_context: Context,
|
_location: Location,
|
||||||
access_place: (AccessDepth, &Place<'tcx>),
|
access_place: (AccessDepth, &Place<'tcx>),
|
||||||
borrow_set: &BorrowSet<'tcx>,
|
borrow_set: &BorrowSet<'tcx>,
|
||||||
candidates: I,
|
candidates: I,
|
||||||
|
@ -59,7 +59,7 @@ pub(crate) fn eval_promoted<'a, 'mir, 'tcx>(
|
|||||||
) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
|
) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
|
||||||
let span = tcx.def_span(cid.instance.def_id());
|
let span = tcx.def_span(cid.instance.def_id());
|
||||||
let mut ecx = mk_eval_cx(tcx, span, param_env);
|
let mut ecx = mk_eval_cx(tcx, span, param_env);
|
||||||
eval_body_using_ecx(&mut ecx, cid, Some(mir), param_env)
|
eval_body_using_ecx(&mut ecx, cid, mir, param_env)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mplace_to_const<'tcx>(
|
fn mplace_to_const<'tcx>(
|
||||||
@ -107,37 +107,15 @@ fn op_to_const<'tcx>(
|
|||||||
ty::Const { val, ty: op.layout.ty }
|
ty::Const { val, ty: op.layout.ty }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval_body_and_ecx<'a, 'mir, 'tcx>(
|
|
||||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|
||||||
cid: GlobalId<'tcx>,
|
|
||||||
mir: Option<&'mir mir::Mir<'tcx>>,
|
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
|
||||||
) -> (EvalResult<'tcx, MPlaceTy<'tcx>>, CompileTimeEvalContext<'a, 'mir, 'tcx>) {
|
|
||||||
// we start out with the best span we have
|
|
||||||
// and try improving it down the road when more information is available
|
|
||||||
let span = tcx.def_span(cid.instance.def_id());
|
|
||||||
let span = mir.map(|mir| mir.span).unwrap_or(span);
|
|
||||||
let mut ecx = InterpretCx::new(tcx.at(span), param_env, CompileTimeInterpreter::new());
|
|
||||||
let r = eval_body_using_ecx(&mut ecx, cid, mir, param_env);
|
|
||||||
(r, ecx)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns a pointer to where the result lives
|
// Returns a pointer to where the result lives
|
||||||
fn eval_body_using_ecx<'mir, 'tcx>(
|
fn eval_body_using_ecx<'mir, 'tcx>(
|
||||||
ecx: &mut CompileTimeEvalContext<'_, 'mir, 'tcx>,
|
ecx: &mut CompileTimeEvalContext<'_, 'mir, 'tcx>,
|
||||||
cid: GlobalId<'tcx>,
|
cid: GlobalId<'tcx>,
|
||||||
mir: Option<&'mir mir::Mir<'tcx>>,
|
mir: &'mir mir::Mir<'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
|
) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
|
||||||
debug!("eval_body_using_ecx: {:?}, {:?}", cid, param_env);
|
debug!("eval_body_using_ecx: {:?}, {:?}", cid, param_env);
|
||||||
let tcx = ecx.tcx.tcx;
|
let tcx = ecx.tcx.tcx;
|
||||||
let mut mir = match mir {
|
|
||||||
Some(mir) => mir,
|
|
||||||
None => ecx.load_mir(cid.instance.def)?,
|
|
||||||
};
|
|
||||||
if let Some(index) = cid.promoted {
|
|
||||||
mir = &mir.promoted[index];
|
|
||||||
}
|
|
||||||
let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?;
|
let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?;
|
||||||
assert!(!layout.is_unsized());
|
assert!(!layout.is_unsized());
|
||||||
let ret = ecx.allocate(layout, MemoryKind::Stack);
|
let ret = ecx.allocate(layout, MemoryKind::Stack);
|
||||||
@ -618,8 +596,19 @@ pub fn const_eval_raw_provider<'a, 'tcx>(
|
|||||||
return Err(ErrorHandled::Reported);
|
return Err(ErrorHandled::Reported);
|
||||||
}
|
}
|
||||||
|
|
||||||
let (res, ecx) = eval_body_and_ecx(tcx, cid, None, key.param_env);
|
let span = tcx.def_span(cid.instance.def_id());
|
||||||
res.and_then(|place| {
|
let mut ecx = InterpretCx::new(tcx.at(span), key.param_env, CompileTimeInterpreter::new());
|
||||||
|
|
||||||
|
let res = ecx.load_mir(cid.instance.def);
|
||||||
|
res.map(|mir| {
|
||||||
|
if let Some(index) = cid.promoted {
|
||||||
|
&mir.promoted[index]
|
||||||
|
} else {
|
||||||
|
mir
|
||||||
|
}
|
||||||
|
}).and_then(
|
||||||
|
|mir| eval_body_using_ecx(&mut ecx, cid, mir, key.param_env)
|
||||||
|
).and_then(|place| {
|
||||||
Ok(RawConst {
|
Ok(RawConst {
|
||||||
alloc_id: place.to_ptr().expect("we allocated this ptr!").alloc_id,
|
alloc_id: place.to_ptr().expect("we allocated this ptr!").alloc_id,
|
||||||
ty: place.layout.ty
|
ty: place.layout.ty
|
||||||
|
@ -301,7 +301,8 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
|
|||||||
// cannot use `const_eval` here, because that would require having the MIR
|
// cannot use `const_eval` here, because that would require having the MIR
|
||||||
// for the current function available, but we're producing said MIR right now
|
// for the current function available, but we're producing said MIR right now
|
||||||
let res = self.use_ecx(source_info, |this| {
|
let res = self.use_ecx(source_info, |this| {
|
||||||
eval_promoted(this.tcx, cid, this.mir, this.param_env)
|
let mir = &this.mir.promoted[promoted];
|
||||||
|
eval_promoted(this.tcx, cid, mir, this.param_env)
|
||||||
})?;
|
})?;
|
||||||
trace!("evaluated promoted {:?} to {:?}", promoted, res);
|
trace!("evaluated promoted {:?} to {:?}", promoted, res);
|
||||||
Some((res.into(), source_info.span))
|
Some((res.into(), source_info.span))
|
||||||
|
@ -862,7 +862,13 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
|
|||||||
// Walk the generated async arguments if this is an `async fn`, otherwise walk the
|
// Walk the generated async arguments if this is an `async fn`, otherwise walk the
|
||||||
// normal arguments.
|
// normal arguments.
|
||||||
if let IsAsync::Async { ref arguments, .. } = asyncness {
|
if let IsAsync::Async { ref arguments, .. } = asyncness {
|
||||||
for a in arguments { add_argument(&a.arg); }
|
for (i, a) in arguments.iter().enumerate() {
|
||||||
|
if let Some(arg) = &a.arg {
|
||||||
|
add_argument(&arg);
|
||||||
|
} else {
|
||||||
|
add_argument(&declaration.inputs[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
for a in &declaration.inputs { add_argument(a); }
|
for a in &declaration.inputs { add_argument(a); }
|
||||||
}
|
}
|
||||||
@ -882,8 +888,11 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
|
|||||||
let mut body = body.clone();
|
let mut body = body.clone();
|
||||||
// Insert the generated statements into the body before attempting to
|
// Insert the generated statements into the body before attempting to
|
||||||
// resolve names.
|
// resolve names.
|
||||||
for a in arguments {
|
for a in arguments.iter().rev() {
|
||||||
body.stmts.insert(0, a.stmt.clone());
|
if let Some(pat_stmt) = a.pat_stmt.clone() {
|
||||||
|
body.stmts.insert(0, pat_stmt);
|
||||||
|
}
|
||||||
|
body.stmts.insert(0, a.move_stmt.clone());
|
||||||
}
|
}
|
||||||
self.visit_block(&body);
|
self.visit_block(&body);
|
||||||
} else {
|
} else {
|
||||||
@ -4174,7 +4183,7 @@ impl<'a> Resolver<'a> {
|
|||||||
let add_module_candidates = |module: Module<'_>, names: &mut Vec<TypoSuggestion>| {
|
let add_module_candidates = |module: Module<'_>, names: &mut Vec<TypoSuggestion>| {
|
||||||
for (&(ident, _), resolution) in module.resolutions.borrow().iter() {
|
for (&(ident, _), resolution) in module.resolutions.borrow().iter() {
|
||||||
if let Some(binding) = resolution.borrow().binding {
|
if let Some(binding) = resolution.borrow().binding {
|
||||||
if filter_fn(binding.def()) {
|
if !ident.name.is_gensymed() && filter_fn(binding.def()) {
|
||||||
names.push(TypoSuggestion {
|
names.push(TypoSuggestion {
|
||||||
candidate: ident.name,
|
candidate: ident.name,
|
||||||
article: binding.def().article(),
|
article: binding.def().article(),
|
||||||
@ -4192,7 +4201,7 @@ impl<'a> Resolver<'a> {
|
|||||||
for rib in self.ribs[ns].iter().rev() {
|
for rib in self.ribs[ns].iter().rev() {
|
||||||
// Locals and type parameters
|
// Locals and type parameters
|
||||||
for (ident, def) in &rib.bindings {
|
for (ident, def) in &rib.bindings {
|
||||||
if filter_fn(*def) {
|
if !ident.name.is_gensymed() && filter_fn(*def) {
|
||||||
names.push(TypoSuggestion {
|
names.push(TypoSuggestion {
|
||||||
candidate: ident.name,
|
candidate: ident.name,
|
||||||
article: def.article(),
|
article: def.article(),
|
||||||
@ -4219,7 +4228,7 @@ impl<'a> Resolver<'a> {
|
|||||||
index: CRATE_DEF_INDEX,
|
index: CRATE_DEF_INDEX,
|
||||||
});
|
});
|
||||||
|
|
||||||
if filter_fn(crate_mod) {
|
if !ident.name.is_gensymed() && filter_fn(crate_mod) {
|
||||||
Some(TypoSuggestion {
|
Some(TypoSuggestion {
|
||||||
candidate: ident.name,
|
candidate: ident.name,
|
||||||
article: "a",
|
article: "a",
|
||||||
@ -4242,13 +4251,16 @@ impl<'a> Resolver<'a> {
|
|||||||
// Add primitive types to the mix
|
// Add primitive types to the mix
|
||||||
if filter_fn(Def::PrimTy(Bool)) {
|
if filter_fn(Def::PrimTy(Bool)) {
|
||||||
names.extend(
|
names.extend(
|
||||||
self.primitive_type_table.primitive_types.iter().map(|(name, _)| {
|
self.primitive_type_table.primitive_types
|
||||||
TypoSuggestion {
|
.iter()
|
||||||
candidate: *name,
|
.filter(|(name, _)| !name.is_gensymed())
|
||||||
article: "a",
|
.map(|(name, _)| {
|
||||||
kind: "primitive type",
|
TypoSuggestion {
|
||||||
}
|
candidate: *name,
|
||||||
})
|
article: "a",
|
||||||
|
kind: "primitive type",
|
||||||
|
}
|
||||||
|
})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -134,6 +134,18 @@ use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
|
|||||||
/// the parent process wait until the child has actually exited before
|
/// the parent process wait until the child has actually exited before
|
||||||
/// continuing.
|
/// continuing.
|
||||||
///
|
///
|
||||||
|
/// # Warning
|
||||||
|
///
|
||||||
|
/// On some system, calling [`wait`] or similar is necessary for the OS to
|
||||||
|
/// release resources. A process that terminated but has not been waited on is
|
||||||
|
/// still around as a "zombie". Leaving too many zombies around may exhaust
|
||||||
|
/// global resources (for example process IDs).
|
||||||
|
///
|
||||||
|
/// The standard library does *not* automatically wait on child processes (not
|
||||||
|
/// even if the `Child` is dropped), it is up to the application developer to do
|
||||||
|
/// so. As a consequence, dropping `Child` handles without waiting on them first
|
||||||
|
/// is not recommended in long-running applications.
|
||||||
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```should_panic
|
/// ```should_panic
|
||||||
|
@ -1865,10 +1865,14 @@ pub enum Unsafety {
|
|||||||
pub struct AsyncArgument {
|
pub struct AsyncArgument {
|
||||||
/// `__arg0`
|
/// `__arg0`
|
||||||
pub ident: Ident,
|
pub ident: Ident,
|
||||||
/// `__arg0: <ty>` argument to replace existing function argument `<pat>: <ty>`.
|
/// `__arg0: <ty>` argument to replace existing function argument `<pat>: <ty>`. Only if
|
||||||
pub arg: Arg,
|
/// argument is not a simple binding.
|
||||||
/// `let <pat>: <ty> = __arg0;` statement to be inserted at the start of the block.
|
pub arg: Option<Arg>,
|
||||||
pub stmt: Stmt,
|
/// `let __arg0 = __arg0;` statement to be inserted at the start of the block.
|
||||||
|
pub move_stmt: Stmt,
|
||||||
|
/// `let <pat> = __arg0;` statement to be inserted at the start of the block, after matching
|
||||||
|
/// move statement. Only if argument is not a simple binding.
|
||||||
|
pub pat_stmt: Option<Stmt>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
|
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
|
||||||
|
@ -363,6 +363,35 @@ and likely to change in the future.
|
|||||||
|
|
||||||
"##,
|
"##,
|
||||||
|
|
||||||
|
E0704: r##"
|
||||||
|
This error indicates that a incorrect visibility restriction was specified.
|
||||||
|
|
||||||
|
Example of erroneous code:
|
||||||
|
|
||||||
|
```compile_fail,E0704
|
||||||
|
mod foo {
|
||||||
|
pub(foo) struct Bar {
|
||||||
|
x: i32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
To make struct `Bar` only visible in module `foo` the `in` keyword should be
|
||||||
|
used:
|
||||||
|
```
|
||||||
|
mod foo {
|
||||||
|
pub(in crate::foo) struct Bar {
|
||||||
|
x: i32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# fn main() {}
|
||||||
|
```
|
||||||
|
|
||||||
|
For more information see the Rust Reference on [Visibility].
|
||||||
|
|
||||||
|
[Visibility]: https://doc.rust-lang.org/reference/visibility-and-privacy.html
|
||||||
|
"##,
|
||||||
|
|
||||||
E0705: r##"
|
E0705: r##"
|
||||||
A `#![feature]` attribute was declared for a feature that is stable in
|
A `#![feature]` attribute was declared for a feature that is stable in
|
||||||
the current edition, but not in all editions.
|
the current edition, but not in all editions.
|
||||||
@ -417,6 +446,5 @@ register_diagnostics! {
|
|||||||
E0693, // incorrect `repr(align)` attribute format
|
E0693, // incorrect `repr(align)` attribute format
|
||||||
E0694, // an unknown tool name found in scoped attributes
|
E0694, // an unknown tool name found in scoped attributes
|
||||||
E0703, // invalid ABI
|
E0703, // invalid ABI
|
||||||
E0704, // incorrect visibility restriction
|
|
||||||
E0717, // rustc_promotable without stability attribute
|
E0717, // rustc_promotable without stability attribute
|
||||||
}
|
}
|
||||||
|
@ -199,7 +199,10 @@ impl<'a, 'b> MutVisitor for PlaceholderExpander<'a, 'b> {
|
|||||||
|
|
||||||
if let ast::IsAsync::Async { ref mut arguments, .. } = a {
|
if let ast::IsAsync::Async { ref mut arguments, .. } = a {
|
||||||
for argument in arguments.iter_mut() {
|
for argument in arguments.iter_mut() {
|
||||||
self.next_id(&mut argument.stmt.id);
|
self.next_id(&mut argument.move_stmt.id);
|
||||||
|
if let Some(ref mut pat_stmt) = &mut argument.pat_stmt {
|
||||||
|
self.next_id(&mut pat_stmt.id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -694,13 +694,21 @@ pub fn noop_visit_asyncness<T: MutVisitor>(asyncness: &mut IsAsync, vis: &mut T)
|
|||||||
IsAsync::Async { closure_id, return_impl_trait_id, ref mut arguments } => {
|
IsAsync::Async { closure_id, return_impl_trait_id, ref mut arguments } => {
|
||||||
vis.visit_id(closure_id);
|
vis.visit_id(closure_id);
|
||||||
vis.visit_id(return_impl_trait_id);
|
vis.visit_id(return_impl_trait_id);
|
||||||
for AsyncArgument { ident, arg, stmt } in arguments.iter_mut() {
|
for AsyncArgument { ident, arg, pat_stmt, move_stmt } in arguments.iter_mut() {
|
||||||
vis.visit_ident(ident);
|
vis.visit_ident(ident);
|
||||||
vis.visit_arg(arg);
|
if let Some(arg) = arg {
|
||||||
visit_clobber(stmt, |stmt| {
|
vis.visit_arg(arg);
|
||||||
|
}
|
||||||
|
visit_clobber(move_stmt, |stmt| {
|
||||||
vis.flat_map_stmt(stmt)
|
vis.flat_map_stmt(stmt)
|
||||||
.expect_one("expected visitor to produce exactly one item")
|
.expect_one("expected visitor to produce exactly one item")
|
||||||
});
|
});
|
||||||
|
visit_opt(pat_stmt, |stmt| {
|
||||||
|
visit_clobber(stmt, |stmt| {
|
||||||
|
vis.flat_map_stmt(stmt)
|
||||||
|
.expect_one("expected visitor to produce exactly one item")
|
||||||
|
})
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
IsAsync::NotAsync => {}
|
IsAsync::NotAsync => {}
|
||||||
|
226
src/libsyntax/parse/diagnostics.rs
Normal file
226
src/libsyntax/parse/diagnostics.rs
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
use crate::ast;
|
||||||
|
use crate::ast::{Expr, ExprKind, Item, ItemKind, Pat, PatKind, QSelf, Ty, TyKind};
|
||||||
|
use crate::parse::parser::PathStyle;
|
||||||
|
use crate::parse::token;
|
||||||
|
use crate::parse::PResult;
|
||||||
|
use crate::parse::Parser;
|
||||||
|
use crate::print::pprust;
|
||||||
|
use crate::ptr::P;
|
||||||
|
use crate::ThinVec;
|
||||||
|
use errors::Applicability;
|
||||||
|
use syntax_pos::Span;
|
||||||
|
|
||||||
|
pub trait RecoverQPath: Sized + 'static {
|
||||||
|
const PATH_STYLE: PathStyle = PathStyle::Expr;
|
||||||
|
fn to_ty(&self) -> Option<P<Ty>>;
|
||||||
|
fn recovered(qself: Option<QSelf>, path: ast::Path) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RecoverQPath for Ty {
|
||||||
|
const PATH_STYLE: PathStyle = PathStyle::Type;
|
||||||
|
fn to_ty(&self) -> Option<P<Ty>> {
|
||||||
|
Some(P(self.clone()))
|
||||||
|
}
|
||||||
|
fn recovered(qself: Option<QSelf>, path: ast::Path) -> Self {
|
||||||
|
Self {
|
||||||
|
span: path.span,
|
||||||
|
node: TyKind::Path(qself, path),
|
||||||
|
id: ast::DUMMY_NODE_ID,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RecoverQPath for Pat {
|
||||||
|
fn to_ty(&self) -> Option<P<Ty>> {
|
||||||
|
self.to_ty()
|
||||||
|
}
|
||||||
|
fn recovered(qself: Option<QSelf>, path: ast::Path) -> Self {
|
||||||
|
Self {
|
||||||
|
span: path.span,
|
||||||
|
node: PatKind::Path(qself, path),
|
||||||
|
id: ast::DUMMY_NODE_ID,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RecoverQPath for Expr {
|
||||||
|
fn to_ty(&self) -> Option<P<Ty>> {
|
||||||
|
self.to_ty()
|
||||||
|
}
|
||||||
|
fn recovered(qself: Option<QSelf>, path: ast::Path) -> Self {
|
||||||
|
Self {
|
||||||
|
span: path.span,
|
||||||
|
node: ExprKind::Path(qself, path),
|
||||||
|
attrs: ThinVec::new(),
|
||||||
|
id: ast::DUMMY_NODE_ID,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Parser<'a> {
|
||||||
|
crate fn maybe_report_ambiguous_plus(
|
||||||
|
&mut self,
|
||||||
|
allow_plus: bool,
|
||||||
|
impl_dyn_multi: bool,
|
||||||
|
ty: &Ty,
|
||||||
|
) {
|
||||||
|
if !allow_plus && impl_dyn_multi {
|
||||||
|
let sum_with_parens = format!("({})", pprust::ty_to_string(&ty));
|
||||||
|
self.struct_span_err(ty.span, "ambiguous `+` in a type")
|
||||||
|
.span_suggestion(
|
||||||
|
ty.span,
|
||||||
|
"use parentheses to disambiguate",
|
||||||
|
sum_with_parens,
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
crate fn maybe_recover_from_bad_type_plus(
|
||||||
|
&mut self,
|
||||||
|
allow_plus: bool,
|
||||||
|
ty: &Ty,
|
||||||
|
) -> PResult<'a, ()> {
|
||||||
|
// Do not add `+` to expected tokens.
|
||||||
|
if !allow_plus || !self.token.is_like_plus() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
self.bump(); // `+`
|
||||||
|
let bounds = self.parse_generic_bounds(None)?;
|
||||||
|
let sum_span = ty.span.to(self.prev_span);
|
||||||
|
|
||||||
|
let mut err = struct_span_err!(
|
||||||
|
self.sess.span_diagnostic,
|
||||||
|
sum_span,
|
||||||
|
E0178,
|
||||||
|
"expected a path on the left-hand side of `+`, not `{}`",
|
||||||
|
pprust::ty_to_string(ty)
|
||||||
|
);
|
||||||
|
|
||||||
|
match ty.node {
|
||||||
|
TyKind::Rptr(ref lifetime, ref mut_ty) => {
|
||||||
|
let sum_with_parens = pprust::to_string(|s| {
|
||||||
|
use crate::print::pprust::PrintState;
|
||||||
|
|
||||||
|
s.s.word("&")?;
|
||||||
|
s.print_opt_lifetime(lifetime)?;
|
||||||
|
s.print_mutability(mut_ty.mutbl)?;
|
||||||
|
s.popen()?;
|
||||||
|
s.print_type(&mut_ty.ty)?;
|
||||||
|
s.print_type_bounds(" +", &bounds)?;
|
||||||
|
s.pclose()
|
||||||
|
});
|
||||||
|
err.span_suggestion(
|
||||||
|
sum_span,
|
||||||
|
"try adding parentheses",
|
||||||
|
sum_with_parens,
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
TyKind::Ptr(..) | TyKind::BareFn(..) => {
|
||||||
|
err.span_label(sum_span, "perhaps you forgot parentheses?");
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
err.span_label(sum_span, "expected a path");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err.emit();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Try to recover from associated item paths like `[T]::AssocItem`/`(T, U)::AssocItem`.
|
||||||
|
/// Attempt to convert the base expression/pattern/type into a type, parse the `::AssocItem`
|
||||||
|
/// tail, and combine them into a `<Ty>::AssocItem` expression/pattern/type.
|
||||||
|
crate fn maybe_recover_from_bad_qpath<T: RecoverQPath>(
|
||||||
|
&mut self,
|
||||||
|
base: P<T>,
|
||||||
|
allow_recovery: bool,
|
||||||
|
) -> PResult<'a, P<T>> {
|
||||||
|
// Do not add `::` to expected tokens.
|
||||||
|
if allow_recovery && self.token == token::ModSep {
|
||||||
|
if let Some(ty) = base.to_ty() {
|
||||||
|
return self.maybe_recover_from_bad_qpath_stage_2(ty.span, ty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(base)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Given an already parsed `Ty` parse the `::AssocItem` tail and
|
||||||
|
/// combine them into a `<Ty>::AssocItem` expression/pattern/type.
|
||||||
|
crate fn maybe_recover_from_bad_qpath_stage_2<T: RecoverQPath>(
|
||||||
|
&mut self,
|
||||||
|
ty_span: Span,
|
||||||
|
ty: P<Ty>,
|
||||||
|
) -> PResult<'a, P<T>> {
|
||||||
|
self.expect(&token::ModSep)?;
|
||||||
|
|
||||||
|
let mut path = ast::Path {
|
||||||
|
segments: Vec::new(),
|
||||||
|
span: syntax_pos::DUMMY_SP,
|
||||||
|
};
|
||||||
|
self.parse_path_segments(&mut path.segments, T::PATH_STYLE)?;
|
||||||
|
path.span = ty_span.to(self.prev_span);
|
||||||
|
|
||||||
|
let ty_str = self
|
||||||
|
.sess
|
||||||
|
.source_map()
|
||||||
|
.span_to_snippet(ty_span)
|
||||||
|
.unwrap_or_else(|_| pprust::ty_to_string(&ty));
|
||||||
|
self.diagnostic()
|
||||||
|
.struct_span_err(path.span, "missing angle brackets in associated item path")
|
||||||
|
.span_suggestion(
|
||||||
|
// this is a best-effort recovery
|
||||||
|
path.span,
|
||||||
|
"try",
|
||||||
|
format!("<{}>::{}", ty_str, path),
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
|
||||||
|
let path_span = ty_span.shrink_to_hi(); // use an empty path since `position` == 0
|
||||||
|
Ok(P(T::recovered(
|
||||||
|
Some(QSelf {
|
||||||
|
ty,
|
||||||
|
path_span,
|
||||||
|
position: 0,
|
||||||
|
}),
|
||||||
|
path,
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
|
||||||
|
crate fn maybe_consume_incorrect_semicolon(&mut self, items: &[P<Item>]) -> bool {
|
||||||
|
if self.eat(&token::Semi) {
|
||||||
|
let mut err = self.struct_span_err(self.prev_span, "expected item, found `;`");
|
||||||
|
err.span_suggestion_short(
|
||||||
|
self.prev_span,
|
||||||
|
"remove this semicolon",
|
||||||
|
String::new(),
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
if !items.is_empty() {
|
||||||
|
let previous_item = &items[items.len() - 1];
|
||||||
|
let previous_item_kind_name = match previous_item.node {
|
||||||
|
// say "braced struct" because tuple-structs and
|
||||||
|
// braceless-empty-struct declarations do take a semicolon
|
||||||
|
ItemKind::Struct(..) => Some("braced struct"),
|
||||||
|
ItemKind::Enum(..) => Some("enum"),
|
||||||
|
ItemKind::Trait(..) => Some("trait"),
|
||||||
|
ItemKind::Union(..) => Some("union"),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
if let Some(name) = previous_item_kind_name {
|
||||||
|
err.help(&format!(
|
||||||
|
"{} declarations are not followed by a semicolon",
|
||||||
|
name
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err.emit();
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -30,6 +30,7 @@ pub mod parser;
|
|||||||
pub mod lexer;
|
pub mod lexer;
|
||||||
pub mod token;
|
pub mod token;
|
||||||
pub mod attr;
|
pub mod attr;
|
||||||
|
pub mod diagnostics;
|
||||||
|
|
||||||
pub mod classify;
|
pub mod classify;
|
||||||
|
|
||||||
|
@ -189,41 +189,6 @@ enum PrevTokenKind {
|
|||||||
Other,
|
Other,
|
||||||
}
|
}
|
||||||
|
|
||||||
trait RecoverQPath: Sized + 'static {
|
|
||||||
const PATH_STYLE: PathStyle = PathStyle::Expr;
|
|
||||||
fn to_ty(&self) -> Option<P<Ty>>;
|
|
||||||
fn recovered(qself: Option<QSelf>, path: ast::Path) -> Self;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RecoverQPath for Ty {
|
|
||||||
const PATH_STYLE: PathStyle = PathStyle::Type;
|
|
||||||
fn to_ty(&self) -> Option<P<Ty>> {
|
|
||||||
Some(P(self.clone()))
|
|
||||||
}
|
|
||||||
fn recovered(qself: Option<QSelf>, path: ast::Path) -> Self {
|
|
||||||
Self { span: path.span, node: TyKind::Path(qself, path), id: ast::DUMMY_NODE_ID }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RecoverQPath for Pat {
|
|
||||||
fn to_ty(&self) -> Option<P<Ty>> {
|
|
||||||
self.to_ty()
|
|
||||||
}
|
|
||||||
fn recovered(qself: Option<QSelf>, path: ast::Path) -> Self {
|
|
||||||
Self { span: path.span, node: PatKind::Path(qself, path), id: ast::DUMMY_NODE_ID }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RecoverQPath for Expr {
|
|
||||||
fn to_ty(&self) -> Option<P<Ty>> {
|
|
||||||
self.to_ty()
|
|
||||||
}
|
|
||||||
fn recovered(qself: Option<QSelf>, path: ast::Path) -> Self {
|
|
||||||
Self { span: path.span, node: ExprKind::Path(qself, path),
|
|
||||||
attrs: ThinVec::new(), id: ast::DUMMY_NODE_ID }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ident is handled by common.rs */
|
/* ident is handled by common.rs */
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -1479,7 +1444,7 @@ impl<'a> Parser<'a> {
|
|||||||
fn span_err<S: Into<MultiSpan>>(&self, sp: S, m: &str) {
|
fn span_err<S: Into<MultiSpan>>(&self, sp: S, m: &str) {
|
||||||
self.sess.span_diagnostic.span_err(sp, m)
|
self.sess.span_diagnostic.span_err(sp, m)
|
||||||
}
|
}
|
||||||
fn struct_span_err<S: Into<MultiSpan>>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> {
|
crate fn struct_span_err<S: Into<MultiSpan>>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> {
|
||||||
self.sess.span_diagnostic.struct_span_err(sp, m)
|
self.sess.span_diagnostic.struct_span_err(sp, m)
|
||||||
}
|
}
|
||||||
fn struct_span_warn<S: Into<MultiSpan>>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> {
|
fn struct_span_warn<S: Into<MultiSpan>>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> {
|
||||||
@ -1882,99 +1847,6 @@ impl<'a> Parser<'a> {
|
|||||||
Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None))
|
Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn maybe_report_ambiguous_plus(&mut self, allow_plus: bool, impl_dyn_multi: bool, ty: &Ty) {
|
|
||||||
if !allow_plus && impl_dyn_multi {
|
|
||||||
let sum_with_parens = format!("({})", pprust::ty_to_string(&ty));
|
|
||||||
self.struct_span_err(ty.span, "ambiguous `+` in a type")
|
|
||||||
.span_suggestion(
|
|
||||||
ty.span,
|
|
||||||
"use parentheses to disambiguate",
|
|
||||||
sum_with_parens,
|
|
||||||
Applicability::MachineApplicable
|
|
||||||
).emit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn maybe_recover_from_bad_type_plus(&mut self, allow_plus: bool, ty: &Ty) -> PResult<'a, ()> {
|
|
||||||
// Do not add `+` to expected tokens.
|
|
||||||
if !allow_plus || !self.token.is_like_plus() {
|
|
||||||
return Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
self.bump(); // `+`
|
|
||||||
let bounds = self.parse_generic_bounds(None)?;
|
|
||||||
let sum_span = ty.span.to(self.prev_span);
|
|
||||||
|
|
||||||
let mut err = struct_span_err!(self.sess.span_diagnostic, sum_span, E0178,
|
|
||||||
"expected a path on the left-hand side of `+`, not `{}`", pprust::ty_to_string(ty));
|
|
||||||
|
|
||||||
match ty.node {
|
|
||||||
TyKind::Rptr(ref lifetime, ref mut_ty) => {
|
|
||||||
let sum_with_parens = pprust::to_string(|s| {
|
|
||||||
use crate::print::pprust::PrintState;
|
|
||||||
|
|
||||||
s.s.word("&")?;
|
|
||||||
s.print_opt_lifetime(lifetime)?;
|
|
||||||
s.print_mutability(mut_ty.mutbl)?;
|
|
||||||
s.popen()?;
|
|
||||||
s.print_type(&mut_ty.ty)?;
|
|
||||||
s.print_type_bounds(" +", &bounds)?;
|
|
||||||
s.pclose()
|
|
||||||
});
|
|
||||||
err.span_suggestion(
|
|
||||||
sum_span,
|
|
||||||
"try adding parentheses",
|
|
||||||
sum_with_parens,
|
|
||||||
Applicability::MachineApplicable
|
|
||||||
);
|
|
||||||
}
|
|
||||||
TyKind::Ptr(..) | TyKind::BareFn(..) => {
|
|
||||||
err.span_label(sum_span, "perhaps you forgot parentheses?");
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
err.span_label(sum_span, "expected a path");
|
|
||||||
},
|
|
||||||
}
|
|
||||||
err.emit();
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Try to recover from associated item paths like `[T]::AssocItem`/`(T, U)::AssocItem`.
|
|
||||||
/// Attempt to convert the base expression/pattern/type into a type, parse the `::AssocItem`
|
|
||||||
/// tail, and combine them into a `<Ty>::AssocItem` expression/pattern/type.
|
|
||||||
fn maybe_recover_from_bad_qpath<T: RecoverQPath>(&mut self, base: P<T>, allow_recovery: bool)
|
|
||||||
-> PResult<'a, P<T>> {
|
|
||||||
// Do not add `::` to expected tokens.
|
|
||||||
if allow_recovery && self.token == token::ModSep {
|
|
||||||
if let Some(ty) = base.to_ty() {
|
|
||||||
return self.maybe_recover_from_bad_qpath_stage_2(ty.span, ty);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(base)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Given an already parsed `Ty` parse the `::AssocItem` tail and
|
|
||||||
/// combine them into a `<Ty>::AssocItem` expression/pattern/type.
|
|
||||||
fn maybe_recover_from_bad_qpath_stage_2<T: RecoverQPath>(&mut self, ty_span: Span, ty: P<Ty>)
|
|
||||||
-> PResult<'a, P<T>> {
|
|
||||||
self.expect(&token::ModSep)?;
|
|
||||||
|
|
||||||
let mut path = ast::Path { segments: Vec::new(), span: syntax_pos::DUMMY_SP };
|
|
||||||
self.parse_path_segments(&mut path.segments, T::PATH_STYLE)?;
|
|
||||||
path.span = ty_span.to(self.prev_span);
|
|
||||||
|
|
||||||
let ty_str = self.sess.source_map().span_to_snippet(ty_span)
|
|
||||||
.unwrap_or_else(|_| pprust::ty_to_string(&ty));
|
|
||||||
self.diagnostic()
|
|
||||||
.struct_span_err(path.span, "missing angle brackets in associated item path")
|
|
||||||
.span_suggestion( // this is a best-effort recovery
|
|
||||||
path.span, "try", format!("<{}>::{}", ty_str, path), Applicability::MaybeIncorrect
|
|
||||||
).emit();
|
|
||||||
|
|
||||||
let path_span = ty_span.shrink_to_hi(); // use an empty path since `position` == 0
|
|
||||||
Ok(P(T::recovered(Some(QSelf { ty, path_span, position: 0 }), path)))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> {
|
fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> {
|
||||||
let opt_lifetime = if self.check_lifetime() { Some(self.expect_lifetime()) } else { None };
|
let opt_lifetime = if self.check_lifetime() { Some(self.expect_lifetime()) } else { None };
|
||||||
let mutbl = self.parse_mutability();
|
let mutbl = self.parse_mutability();
|
||||||
@ -2410,7 +2282,7 @@ impl<'a> Parser<'a> {
|
|||||||
self.parse_path(style)
|
self.parse_path(style)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_path_segments(&mut self,
|
crate fn parse_path_segments(&mut self,
|
||||||
segments: &mut Vec<PathSegment>,
|
segments: &mut Vec<PathSegment>,
|
||||||
style: PathStyle)
|
style: PathStyle)
|
||||||
-> PResult<'a, ()> {
|
-> PResult<'a, ()> {
|
||||||
@ -5815,7 +5687,8 @@ impl<'a> Parser<'a> {
|
|||||||
return Ok(bounds);
|
return Ok(bounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_generic_bounds(&mut self, colon_span: Option<Span>) -> PResult<'a, GenericBounds> {
|
crate fn parse_generic_bounds(&mut self,
|
||||||
|
colon_span: Option<Span>) -> PResult<'a, GenericBounds> {
|
||||||
self.parse_generic_bounds_common(true, colon_span)
|
self.parse_generic_bounds_common(true, colon_span)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7352,37 +7225,6 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn maybe_consume_incorrect_semicolon(&mut self, items: &[P<Item>]) -> bool {
|
|
||||||
if self.eat(&token::Semi) {
|
|
||||||
let mut err = self.struct_span_err(self.prev_span, "expected item, found `;`");
|
|
||||||
err.span_suggestion_short(
|
|
||||||
self.prev_span,
|
|
||||||
"remove this semicolon",
|
|
||||||
String::new(),
|
|
||||||
Applicability::MachineApplicable,
|
|
||||||
);
|
|
||||||
if !items.is_empty() {
|
|
||||||
let previous_item = &items[items.len()-1];
|
|
||||||
let previous_item_kind_name = match previous_item.node {
|
|
||||||
// say "braced struct" because tuple-structs and
|
|
||||||
// braceless-empty-struct declarations do take a semicolon
|
|
||||||
ItemKind::Struct(..) => Some("braced struct"),
|
|
||||||
ItemKind::Enum(..) => Some("enum"),
|
|
||||||
ItemKind::Trait(..) => Some("trait"),
|
|
||||||
ItemKind::Union(..) => Some("union"),
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
if let Some(name) = previous_item_kind_name {
|
|
||||||
err.help(&format!("{} declarations are not followed by a semicolon", name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
err.emit();
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Given a termination token, parses all of the items in a module.
|
/// Given a termination token, parses all of the items in a module.
|
||||||
fn parse_mod_items(&mut self, term: &token::Token, inner_lo: Span) -> PResult<'a, Mod> {
|
fn parse_mod_items(&mut self, term: &token::Token, inner_lo: Span) -> PResult<'a, Mod> {
|
||||||
let mut items = vec![];
|
let mut items = vec![];
|
||||||
@ -8878,13 +8720,39 @@ impl<'a> Parser<'a> {
|
|||||||
|
|
||||||
// Construct a name for our temporary argument.
|
// Construct a name for our temporary argument.
|
||||||
let name = format!("__arg{}", index);
|
let name = format!("__arg{}", index);
|
||||||
let ident = Ident::from_str(&name);
|
let ident = Ident::from_str(&name).gensym();
|
||||||
|
|
||||||
|
// Check if this is a ident pattern, if so, we can optimize and avoid adding a
|
||||||
|
// `let <pat> = __argN;` statement, instead just adding a `let <pat> = <pat>;`
|
||||||
|
// statement.
|
||||||
|
let (ident, is_simple_pattern) = match input.pat.node {
|
||||||
|
PatKind::Ident(_, ident, _) => (ident, true),
|
||||||
|
_ => (ident, false),
|
||||||
|
};
|
||||||
|
|
||||||
// Construct an argument representing `__argN: <ty>` to replace the argument of the
|
// Construct an argument representing `__argN: <ty>` to replace the argument of the
|
||||||
// async function.
|
// async function if it isn't a simple pattern.
|
||||||
let arg = Arg {
|
let arg = if is_simple_pattern {
|
||||||
ty: input.ty.clone(),
|
None
|
||||||
id,
|
} else {
|
||||||
|
Some(Arg {
|
||||||
|
ty: input.ty.clone(),
|
||||||
|
id,
|
||||||
|
pat: P(Pat {
|
||||||
|
id,
|
||||||
|
node: PatKind::Ident(
|
||||||
|
BindingMode::ByValue(Mutability::Immutable), ident, None,
|
||||||
|
),
|
||||||
|
span,
|
||||||
|
}),
|
||||||
|
source: ArgSource::AsyncFn(input.pat.clone()),
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
// Construct a `let __argN = __argN;` statement to insert at the top of the
|
||||||
|
// async closure. This makes sure that the argument is captured by the closure and
|
||||||
|
// that the drop order is correct.
|
||||||
|
let move_local = Local {
|
||||||
pat: P(Pat {
|
pat: P(Pat {
|
||||||
id,
|
id,
|
||||||
node: PatKind::Ident(
|
node: PatKind::Ident(
|
||||||
@ -8892,13 +8760,6 @@ impl<'a> Parser<'a> {
|
|||||||
),
|
),
|
||||||
span,
|
span,
|
||||||
}),
|
}),
|
||||||
source: ArgSource::AsyncFn(input.pat.clone()),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Construct a `let <pat> = __argN;` statement to insert at the top of the
|
|
||||||
// async closure.
|
|
||||||
let local = P(Local {
|
|
||||||
pat: input.pat.clone(),
|
|
||||||
// We explicitly do not specify the type for this statement. When the user's
|
// We explicitly do not specify the type for this statement. When the user's
|
||||||
// argument type is `impl Trait` then this would require the
|
// argument type is `impl Trait` then this would require the
|
||||||
// `impl_trait_in_bindings` feature to also be present for that same type to
|
// `impl_trait_in_bindings` feature to also be present for that same type to
|
||||||
@ -8918,10 +8779,25 @@ impl<'a> Parser<'a> {
|
|||||||
span,
|
span,
|
||||||
attrs: ThinVec::new(),
|
attrs: ThinVec::new(),
|
||||||
source: LocalSource::AsyncFn,
|
source: LocalSource::AsyncFn,
|
||||||
});
|
};
|
||||||
let stmt = Stmt { id, node: StmtKind::Local(local), span, };
|
|
||||||
|
|
||||||
arguments.push(AsyncArgument { ident, arg, stmt });
|
// Construct a `let <pat> = __argN;` statement to insert at the top of the
|
||||||
|
// async closure if this isn't a simple pattern.
|
||||||
|
let pat_stmt = if is_simple_pattern {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(Stmt {
|
||||||
|
id,
|
||||||
|
node: StmtKind::Local(P(Local {
|
||||||
|
pat: input.pat.clone(),
|
||||||
|
..move_local.clone()
|
||||||
|
})),
|
||||||
|
span,
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
let move_stmt = Stmt { id, node: StmtKind::Local(P(move_local)), span };
|
||||||
|
arguments.push(AsyncArgument { ident, arg, pat_stmt, move_stmt });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ use rustc::session::Session;
|
|||||||
use rustc::session::config::OutputFilenames;
|
use rustc::session::config::OutputFilenames;
|
||||||
use rustc::ty::TyCtxt;
|
use rustc::ty::TyCtxt;
|
||||||
use rustc::ty::query::Providers;
|
use rustc::ty::query::Providers;
|
||||||
use rustc::middle::cstore::MetadataLoader;
|
use rustc::middle::cstore::{EncodedMetadata, MetadataLoader};
|
||||||
use rustc::dep_graph::DepGraph;
|
use rustc::dep_graph::DepGraph;
|
||||||
use rustc::util::common::ErrorReported;
|
use rustc::util::common::ErrorReported;
|
||||||
use rustc_codegen_utils::codegen_backend::CodegenBackend;
|
use rustc_codegen_utils::codegen_backend::CodegenBackend;
|
||||||
@ -61,6 +61,8 @@ impl CodegenBackend for TheBackend {
|
|||||||
fn codegen_crate<'a, 'tcx>(
|
fn codegen_crate<'a, 'tcx>(
|
||||||
&self,
|
&self,
|
||||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
|
_metadata: EncodedMetadata,
|
||||||
|
_need_metadata_module: bool,
|
||||||
_rx: mpsc::Receiver<Box<Any + Send>>
|
_rx: mpsc::Receiver<Box<Any + Send>>
|
||||||
) -> Box<Any> {
|
) -> Box<Any> {
|
||||||
use rustc::hir::def_id::LOCAL_CRATE;
|
use rustc::hir::def_id::LOCAL_CRATE;
|
||||||
|
@ -1,184 +0,0 @@
|
|||||||
// aux-build:arc_wake.rs
|
|
||||||
// edition:2018
|
|
||||||
// run-pass
|
|
||||||
|
|
||||||
#![allow(unused_variables)]
|
|
||||||
#![feature(async_await, await_macro)]
|
|
||||||
|
|
||||||
extern crate arc_wake;
|
|
||||||
|
|
||||||
use arc_wake::ArcWake;
|
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::future::Future;
|
|
||||||
use std::marker::PhantomData;
|
|
||||||
use std::sync::Arc;
|
|
||||||
use std::rc::Rc;
|
|
||||||
use std::task::Context;
|
|
||||||
|
|
||||||
struct EmptyWaker;
|
|
||||||
|
|
||||||
impl ArcWake for EmptyWaker {
|
|
||||||
fn wake(self: Arc<Self>) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq)]
|
|
||||||
enum DropOrder {
|
|
||||||
Function,
|
|
||||||
Val(&'static str),
|
|
||||||
}
|
|
||||||
|
|
||||||
type DropOrderListPtr = Rc<RefCell<Vec<DropOrder>>>;
|
|
||||||
|
|
||||||
struct D(&'static str, DropOrderListPtr);
|
|
||||||
|
|
||||||
impl Drop for D {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
self.1.borrow_mut().push(DropOrder::Val(self.0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check that unused bindings are dropped after the function is polled.
|
|
||||||
async fn foo(x: D, _y: D) {
|
|
||||||
x.1.borrow_mut().push(DropOrder::Function);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check that underscore patterns are dropped after the function is polled.
|
|
||||||
async fn bar(x: D, _: D) {
|
|
||||||
x.1.borrow_mut().push(DropOrder::Function);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check that underscore patterns within more complex patterns are dropped after the function
|
|
||||||
/// is polled.
|
|
||||||
async fn baz((x, _): (D, D)) {
|
|
||||||
x.1.borrow_mut().push(DropOrder::Function);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check that underscore and unused bindings within and outwith more complex patterns are dropped
|
|
||||||
/// after the function is polled.
|
|
||||||
async fn foobar(x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
|
|
||||||
x.1.borrow_mut().push(DropOrder::Function);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Foo;
|
|
||||||
|
|
||||||
impl Foo {
|
|
||||||
/// Check that unused bindings are dropped after the method is polled.
|
|
||||||
async fn foo(x: D, _y: D) {
|
|
||||||
x.1.borrow_mut().push(DropOrder::Function);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check that underscore patterns are dropped after the method is polled.
|
|
||||||
async fn bar(x: D, _: D) {
|
|
||||||
x.1.borrow_mut().push(DropOrder::Function);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check that underscore patterns within more complex patterns are dropped after the method
|
|
||||||
/// is polled.
|
|
||||||
async fn baz((x, _): (D, D)) {
|
|
||||||
x.1.borrow_mut().push(DropOrder::Function);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check that underscore and unused bindings within and outwith more complex patterns are
|
|
||||||
/// dropped after the method is polled.
|
|
||||||
async fn foobar(x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
|
|
||||||
x.1.borrow_mut().push(DropOrder::Function);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Bar<'a>(PhantomData<&'a ()>);
|
|
||||||
|
|
||||||
impl<'a> Bar<'a> {
|
|
||||||
/// Check that unused bindings are dropped after the method with self is polled.
|
|
||||||
async fn foo(&'a self, x: D, _y: D) {
|
|
||||||
x.1.borrow_mut().push(DropOrder::Function);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check that underscore patterns are dropped after the method with self is polled.
|
|
||||||
async fn bar(&'a self, x: D, _: D) {
|
|
||||||
x.1.borrow_mut().push(DropOrder::Function);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check that underscore patterns within more complex patterns are dropped after the method
|
|
||||||
/// with self is polled.
|
|
||||||
async fn baz(&'a self, (x, _): (D, D)) {
|
|
||||||
x.1.borrow_mut().push(DropOrder::Function);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check that underscore and unused bindings within and outwith more complex patterns are
|
|
||||||
/// dropped after the method with self is polled.
|
|
||||||
async fn foobar(&'a self, x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
|
|
||||||
x.1.borrow_mut().push(DropOrder::Function);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_drop_order_after_poll<Fut: Future<Output = ()>>(
|
|
||||||
f: impl FnOnce(DropOrderListPtr) -> Fut,
|
|
||||||
expected_order: &[DropOrder],
|
|
||||||
) {
|
|
||||||
let empty = Arc::new(EmptyWaker);
|
|
||||||
let waker = ArcWake::into_waker(empty);
|
|
||||||
let mut cx = Context::from_waker(&waker);
|
|
||||||
|
|
||||||
let actual_order = Rc::new(RefCell::new(Vec::new()));
|
|
||||||
let mut fut = Box::pin(f(actual_order.clone()));
|
|
||||||
let _ = fut.as_mut().poll(&mut cx);
|
|
||||||
|
|
||||||
assert_eq!(*actual_order.borrow(), expected_order);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
use DropOrder::*;
|
|
||||||
|
|
||||||
// At time of writing (23/04/19), the `bar` and `foobar` tests do not output the same order as
|
|
||||||
// the equivalent non-async functions. This is because the drop order of captured variables
|
|
||||||
// doesn't match the drop order of arguments in a function.
|
|
||||||
|
|
||||||
// Free functions (see doc comment on function for what it tests).
|
|
||||||
assert_drop_order_after_poll(|l| foo(D("x", l.clone()), D("_y", l.clone())),
|
|
||||||
&[Function, Val("_y"), Val("x")]);
|
|
||||||
assert_drop_order_after_poll(|l| bar(D("x", l.clone()), D("_", l.clone())),
|
|
||||||
&[Function, Val("x"), Val("_")]);
|
|
||||||
assert_drop_order_after_poll(|l| baz((D("x", l.clone()), D("_", l.clone()))),
|
|
||||||
&[Function, Val("x"), Val("_")]);
|
|
||||||
assert_drop_order_after_poll(|l| {
|
|
||||||
foobar(
|
|
||||||
D("x", l.clone()),
|
|
||||||
(D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
|
|
||||||
D("_", l.clone()),
|
|
||||||
D("_y", l.clone()),
|
|
||||||
)
|
|
||||||
}, &[Function, Val("_y"), Val("_c"), Val("a"), Val("x"), Val("_"), Val("_")]);
|
|
||||||
|
|
||||||
// Methods w/out self (see doc comment on function for what it tests).
|
|
||||||
assert_drop_order_after_poll(|l| Foo::foo(D("x", l.clone()), D("_y", l.clone())),
|
|
||||||
&[Function, Val("_y"), Val("x")]);
|
|
||||||
assert_drop_order_after_poll(|l| Foo::bar(D("x", l.clone()), D("_", l.clone())),
|
|
||||||
&[Function, Val("x"), Val("_")]);
|
|
||||||
assert_drop_order_after_poll(|l| Foo::baz((D("x", l.clone()), D("_", l.clone()))),
|
|
||||||
&[Function, Val("x"), Val("_")]);
|
|
||||||
assert_drop_order_after_poll(|l| {
|
|
||||||
Foo::foobar(
|
|
||||||
D("x", l.clone()),
|
|
||||||
(D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
|
|
||||||
D("_", l.clone()),
|
|
||||||
D("_y", l.clone()),
|
|
||||||
)
|
|
||||||
}, &[Function, Val("_y"), Val("_c"), Val("a"), Val("x"), Val("_"), Val("_")]);
|
|
||||||
|
|
||||||
// Methods (see doc comment on function for what it tests).
|
|
||||||
let b = Bar(Default::default());
|
|
||||||
assert_drop_order_after_poll(|l| b.foo(D("x", l.clone()), D("_y", l.clone())),
|
|
||||||
&[Function, Val("_y"), Val("x")]);
|
|
||||||
assert_drop_order_after_poll(|l| b.bar(D("x", l.clone()), D("_", l.clone())),
|
|
||||||
&[Function, Val("x"), Val("_")]);
|
|
||||||
assert_drop_order_after_poll(|l| b.baz((D("x", l.clone()), D("_", l.clone()))),
|
|
||||||
&[Function, Val("x"), Val("_")]);
|
|
||||||
assert_drop_order_after_poll(|l| {
|
|
||||||
b.foobar(
|
|
||||||
D("x", l.clone()),
|
|
||||||
(D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
|
|
||||||
D("_", l.clone()),
|
|
||||||
D("_y", l.clone()),
|
|
||||||
)
|
|
||||||
}, &[Function, Val("_y"), Val("_c"), Val("a"), Val("x"), Val("_"), Val("_")]);
|
|
||||||
}
|
|
64
src/test/ui/async-await/auxiliary/arc_wake.rs
Normal file
64
src/test/ui/async-await/auxiliary/arc_wake.rs
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
// edition:2018
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::task::{
|
||||||
|
Waker, RawWaker, RawWakerVTable,
|
||||||
|
};
|
||||||
|
|
||||||
|
macro_rules! waker_vtable {
|
||||||
|
($ty:ident) => {
|
||||||
|
&RawWakerVTable::new(
|
||||||
|
clone_arc_raw::<$ty>,
|
||||||
|
wake_arc_raw::<$ty>,
|
||||||
|
wake_by_ref_arc_raw::<$ty>,
|
||||||
|
drop_arc_raw::<$ty>,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ArcWake {
|
||||||
|
fn wake(self: Arc<Self>);
|
||||||
|
|
||||||
|
fn wake_by_ref(arc_self: &Arc<Self>) {
|
||||||
|
arc_self.clone().wake()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_waker(wake: Arc<Self>) -> Waker where Self: Sized
|
||||||
|
{
|
||||||
|
let ptr = Arc::into_raw(wake) as *const ();
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
Waker::from_raw(RawWaker::new(ptr, waker_vtable!(Self)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn increase_refcount<T: ArcWake>(data: *const ()) {
|
||||||
|
// Retain Arc by creating a copy
|
||||||
|
let arc: Arc<T> = Arc::from_raw(data as *const T);
|
||||||
|
let arc_clone = arc.clone();
|
||||||
|
// Forget the Arcs again, so that the refcount isn't decrased
|
||||||
|
let _ = Arc::into_raw(arc);
|
||||||
|
let _ = Arc::into_raw(arc_clone);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn clone_arc_raw<T: ArcWake>(data: *const ()) -> RawWaker {
|
||||||
|
increase_refcount::<T>(data);
|
||||||
|
RawWaker::new(data, waker_vtable!(T))
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn drop_arc_raw<T: ArcWake>(data: *const ()) {
|
||||||
|
// Drop Arc
|
||||||
|
let _: Arc<T> = Arc::from_raw(data as *const T);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn wake_arc_raw<T: ArcWake>(data: *const ()) {
|
||||||
|
let arc: Arc<T> = Arc::from_raw(data as *const T);
|
||||||
|
ArcWake::wake(arc);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn wake_by_ref_arc_raw<T: ArcWake>(data: *const ()) {
|
||||||
|
let arc: Arc<T> = Arc::from_raw(data as *const T);
|
||||||
|
ArcWake::wake_by_ref(&arc);
|
||||||
|
let _ = Arc::into_raw(arc);
|
||||||
|
}
|
263
src/test/ui/async-await/drop-order-for-async-fn-parameters.rs
Normal file
263
src/test/ui/async-await/drop-order-for-async-fn-parameters.rs
Normal file
@ -0,0 +1,263 @@
|
|||||||
|
// aux-build:arc_wake.rs
|
||||||
|
// edition:2018
|
||||||
|
// run-pass
|
||||||
|
|
||||||
|
#![allow(unused_variables)]
|
||||||
|
#![feature(async_await, await_macro)]
|
||||||
|
|
||||||
|
// Test that the drop order for parameters in a fn and async fn matches up. Also test that
|
||||||
|
// parameters (used or unused) are not dropped until the async fn completes execution.
|
||||||
|
// See also #54716.
|
||||||
|
|
||||||
|
extern crate arc_wake;
|
||||||
|
|
||||||
|
use arc_wake::ArcWake;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::future::Future;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::task::Context;
|
||||||
|
|
||||||
|
struct EmptyWaker;
|
||||||
|
|
||||||
|
impl ArcWake for EmptyWaker {
|
||||||
|
fn wake(self: Arc<Self>) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
|
enum DropOrder {
|
||||||
|
Function,
|
||||||
|
Val(&'static str),
|
||||||
|
}
|
||||||
|
|
||||||
|
type DropOrderListPtr = Rc<RefCell<Vec<DropOrder>>>;
|
||||||
|
|
||||||
|
struct D(&'static str, DropOrderListPtr);
|
||||||
|
|
||||||
|
impl Drop for D {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.1.borrow_mut().push(DropOrder::Val(self.0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check that unused bindings are dropped after the function is polled.
|
||||||
|
async fn foo_async(x: D, _y: D) {
|
||||||
|
x.1.borrow_mut().push(DropOrder::Function);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo_sync(x: D, _y: D) {
|
||||||
|
x.1.borrow_mut().push(DropOrder::Function);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check that underscore patterns are dropped after the function is polled.
|
||||||
|
async fn bar_async(x: D, _: D) {
|
||||||
|
x.1.borrow_mut().push(DropOrder::Function);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bar_sync(x: D, _: D) {
|
||||||
|
x.1.borrow_mut().push(DropOrder::Function);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check that underscore patterns within more complex patterns are dropped after the function
|
||||||
|
/// is polled.
|
||||||
|
async fn baz_async((x, _): (D, D)) {
|
||||||
|
x.1.borrow_mut().push(DropOrder::Function);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn baz_sync((x, _): (D, D)) {
|
||||||
|
x.1.borrow_mut().push(DropOrder::Function);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check that underscore and unused bindings within and outwith more complex patterns are dropped
|
||||||
|
/// after the function is polled.
|
||||||
|
async fn foobar_async(x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
|
||||||
|
x.1.borrow_mut().push(DropOrder::Function);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foobar_sync(x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
|
||||||
|
x.1.borrow_mut().push(DropOrder::Function);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Foo;
|
||||||
|
|
||||||
|
impl Foo {
|
||||||
|
/// Check that unused bindings are dropped after the method is polled.
|
||||||
|
async fn foo_async(x: D, _y: D) {
|
||||||
|
x.1.borrow_mut().push(DropOrder::Function);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo_sync(x: D, _y: D) {
|
||||||
|
x.1.borrow_mut().push(DropOrder::Function);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check that underscore patterns are dropped after the method is polled.
|
||||||
|
async fn bar_async(x: D, _: D) {
|
||||||
|
x.1.borrow_mut().push(DropOrder::Function);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bar_sync(x: D, _: D) {
|
||||||
|
x.1.borrow_mut().push(DropOrder::Function);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check that underscore patterns within more complex patterns are dropped after the method
|
||||||
|
/// is polled.
|
||||||
|
async fn baz_async((x, _): (D, D)) {
|
||||||
|
x.1.borrow_mut().push(DropOrder::Function);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn baz_sync((x, _): (D, D)) {
|
||||||
|
x.1.borrow_mut().push(DropOrder::Function);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check that underscore and unused bindings within and outwith more complex patterns are
|
||||||
|
/// dropped after the method is polled.
|
||||||
|
async fn foobar_async(x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
|
||||||
|
x.1.borrow_mut().push(DropOrder::Function);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foobar_sync(x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
|
||||||
|
x.1.borrow_mut().push(DropOrder::Function);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Bar<'a>(PhantomData<&'a ()>);
|
||||||
|
|
||||||
|
impl<'a> Bar<'a> {
|
||||||
|
/// Check that unused bindings are dropped after the method with self is polled.
|
||||||
|
async fn foo_async(&'a self, x: D, _y: D) {
|
||||||
|
x.1.borrow_mut().push(DropOrder::Function);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo_sync(&'a self, x: D, _y: D) {
|
||||||
|
x.1.borrow_mut().push(DropOrder::Function);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check that underscore patterns are dropped after the method with self is polled.
|
||||||
|
async fn bar_async(&'a self, x: D, _: D) {
|
||||||
|
x.1.borrow_mut().push(DropOrder::Function);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bar_sync(&'a self, x: D, _: D) {
|
||||||
|
x.1.borrow_mut().push(DropOrder::Function);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check that underscore patterns within more complex patterns are dropped after the method
|
||||||
|
/// with self is polled.
|
||||||
|
async fn baz_async(&'a self, (x, _): (D, D)) {
|
||||||
|
x.1.borrow_mut().push(DropOrder::Function);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn baz_sync(&'a self, (x, _): (D, D)) {
|
||||||
|
x.1.borrow_mut().push(DropOrder::Function);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check that underscore and unused bindings within and outwith more complex patterns are
|
||||||
|
/// dropped after the method with self is polled.
|
||||||
|
async fn foobar_async(&'a self, x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
|
||||||
|
x.1.borrow_mut().push(DropOrder::Function);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foobar_sync(&'a self, x: D, (a, _, _c): (D, D, D), _: D, _y: D) {
|
||||||
|
x.1.borrow_mut().push(DropOrder::Function);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn assert_drop_order_after_poll<Fut: Future<Output = ()>>(
|
||||||
|
f: impl FnOnce(DropOrderListPtr) -> Fut,
|
||||||
|
g: impl FnOnce(DropOrderListPtr),
|
||||||
|
) {
|
||||||
|
let empty = Arc::new(EmptyWaker);
|
||||||
|
let waker = ArcWake::into_waker(empty);
|
||||||
|
let mut cx = Context::from_waker(&waker);
|
||||||
|
|
||||||
|
let actual_order = Rc::new(RefCell::new(Vec::new()));
|
||||||
|
let mut fut = Box::pin(f(actual_order.clone()));
|
||||||
|
let _ = fut.as_mut().poll(&mut cx);
|
||||||
|
|
||||||
|
let expected_order = Rc::new(RefCell::new(Vec::new()));
|
||||||
|
g(expected_order.clone());
|
||||||
|
|
||||||
|
assert_eq!(*actual_order.borrow(), *expected_order.borrow());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// Free functions (see doc comment on function for what it tests).
|
||||||
|
assert_drop_order_after_poll(|l| foo_async(D("x", l.clone()), D("_y", l.clone())),
|
||||||
|
|l| foo_sync(D("x", l.clone()), D("_y", l.clone())));
|
||||||
|
assert_drop_order_after_poll(|l| bar_async(D("x", l.clone()), D("_", l.clone())),
|
||||||
|
|l| bar_sync(D("x", l.clone()), D("_", l.clone())));
|
||||||
|
assert_drop_order_after_poll(|l| baz_async((D("x", l.clone()), D("_", l.clone()))),
|
||||||
|
|l| baz_sync((D("x", l.clone()), D("_", l.clone()))));
|
||||||
|
assert_drop_order_after_poll(
|
||||||
|
|l| {
|
||||||
|
foobar_async(
|
||||||
|
D("x", l.clone()),
|
||||||
|
(D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
|
||||||
|
D("_", l.clone()),
|
||||||
|
D("_y", l.clone()),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
|l| {
|
||||||
|
foobar_sync(
|
||||||
|
D("x", l.clone()),
|
||||||
|
(D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
|
||||||
|
D("_", l.clone()),
|
||||||
|
D("_y", l.clone()),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// Methods w/out self (see doc comment on function for what it tests).
|
||||||
|
assert_drop_order_after_poll(|l| Foo::foo_async(D("x", l.clone()), D("_y", l.clone())),
|
||||||
|
|l| Foo::foo_sync(D("x", l.clone()), D("_y", l.clone())));
|
||||||
|
assert_drop_order_after_poll(|l| Foo::bar_async(D("x", l.clone()), D("_", l.clone())),
|
||||||
|
|l| Foo::bar_sync(D("x", l.clone()), D("_", l.clone())));
|
||||||
|
assert_drop_order_after_poll(|l| Foo::baz_async((D("x", l.clone()), D("_", l.clone()))),
|
||||||
|
|l| Foo::baz_sync((D("x", l.clone()), D("_", l.clone()))));
|
||||||
|
assert_drop_order_after_poll(
|
||||||
|
|l| {
|
||||||
|
Foo::foobar_async(
|
||||||
|
D("x", l.clone()),
|
||||||
|
(D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
|
||||||
|
D("_", l.clone()),
|
||||||
|
D("_y", l.clone()),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
|l| {
|
||||||
|
Foo::foobar_sync(
|
||||||
|
D("x", l.clone()),
|
||||||
|
(D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
|
||||||
|
D("_", l.clone()),
|
||||||
|
D("_y", l.clone()),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// Methods (see doc comment on function for what it tests).
|
||||||
|
let b = Bar(Default::default());
|
||||||
|
assert_drop_order_after_poll(|l| b.foo_async(D("x", l.clone()), D("_y", l.clone())),
|
||||||
|
|l| b.foo_sync(D("x", l.clone()), D("_y", l.clone())));
|
||||||
|
assert_drop_order_after_poll(|l| b.bar_async(D("x", l.clone()), D("_", l.clone())),
|
||||||
|
|l| b.bar_sync(D("x", l.clone()), D("_", l.clone())));
|
||||||
|
assert_drop_order_after_poll(|l| b.baz_async((D("x", l.clone()), D("_", l.clone()))),
|
||||||
|
|l| b.baz_sync((D("x", l.clone()), D("_", l.clone()))));
|
||||||
|
assert_drop_order_after_poll(
|
||||||
|
|l| {
|
||||||
|
b.foobar_async(
|
||||||
|
D("x", l.clone()),
|
||||||
|
(D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
|
||||||
|
D("_", l.clone()),
|
||||||
|
D("_y", l.clone()),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
|l| {
|
||||||
|
b.foobar_sync(
|
||||||
|
D("x", l.clone()),
|
||||||
|
(D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())),
|
||||||
|
D("_", l.clone()),
|
||||||
|
D("_y", l.clone()),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
11
src/test/ui/async-await/drop-order-locals-are-hidden.rs
Normal file
11
src/test/ui/async-await/drop-order-locals-are-hidden.rs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// edition:2018
|
||||||
|
|
||||||
|
#![allow(unused_variables)]
|
||||||
|
#![feature(async_await)]
|
||||||
|
|
||||||
|
async fn foobar_async(x: u32, (a, _, _c): (u32, u32, u32), _: u32, _y: u32) {
|
||||||
|
assert_eq!(__arg1, (1, 2, 3)); //~ ERROR cannot find value `__arg1` in this scope [E0425]
|
||||||
|
assert_eq!(__arg2, 4); //~ ERROR cannot find value `__arg2` in this scope [E0425]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
15
src/test/ui/async-await/drop-order-locals-are-hidden.stderr
Normal file
15
src/test/ui/async-await/drop-order-locals-are-hidden.stderr
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
error[E0425]: cannot find value `__arg1` in this scope
|
||||||
|
--> $DIR/drop-order-locals-are-hidden.rs:7:16
|
||||||
|
|
|
||||||
|
LL | assert_eq!(__arg1, (1, 2, 3));
|
||||||
|
| ^^^^^^ not found in this scope
|
||||||
|
|
||||||
|
error[E0425]: cannot find value `__arg2` in this scope
|
||||||
|
--> $DIR/drop-order-locals-are-hidden.rs:8:16
|
||||||
|
|
|
||||||
|
LL | assert_eq!(__arg2, 4);
|
||||||
|
| ^^^^^^ not found in this scope
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0425`.
|
@ -50,3 +50,4 @@ LL | pub (in x) non_parent_invalid: usize,
|
|||||||
|
|
||||||
error: aborting due to 5 previous errors
|
error: aborting due to 5 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0704`.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user