From f72b8a44c51313d384deefcda753df668f2e265e Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sun, 5 Aug 2018 14:33:38 +0100 Subject: [PATCH 01/20] Use span of the closure args in free region errors --- .../error_reporting/region_name.rs | 62 ++++++++++++++++--- ...1-does-not-trigger-for-closures.nll.stderr | 5 +- src/test/ui/issue-40510-1.nll.stderr | 20 +++--- src/test/ui/issue-40510-3.nll.stderr | 25 ++++---- src/test/ui/issue-49824.nll.stderr | 25 ++++---- src/test/ui/nll/issue-48238.stderr | 9 +-- 6 files changed, 91 insertions(+), 55 deletions(-) diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs index 79165276430d3..6a21e00258845 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs @@ -10,6 +10,7 @@ use borrow_check::nll::region_infer::RegionInferenceContext; use borrow_check::nll::ToRegionVid; +use borrow_check::nll::universal_regions::DefiningTy; use rustc::hir; use rustc::hir::def_id::DefId; use rustc::infer::InferCtxt; @@ -72,7 +73,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { }) .or_else(|| { self.give_name_if_anonymous_region_appears_in_output( - infcx.tcx, mir, fr, counter, diag) + infcx.tcx, mir, mir_def_id, fr, counter, diag) }) .unwrap_or_else(|| span_bug!(mir.span, "can't make a name for free region {:?}", fr)) } @@ -107,13 +108,46 @@ impl<'tcx> RegionInferenceContext<'tcx> { }, ty::BoundRegion::BrEnv => { - let closure_span = tcx.hir.span_if_local(mir_def_id).unwrap(); - let region_name = self.synthesize_region_name(counter); - diag.span_label( - closure_span, - format!("lifetime `{}` represents the closure body", region_name), - ); - Some(region_name) + let mir_node_id = tcx.hir.as_local_node_id(mir_def_id).expect("non-local mir"); + let def_ty = self.universal_regions.defining_ty; + + if let DefiningTy::Closure(def_id, substs) = def_ty { + let args_span = if let hir::ExprKind::Closure(_, _, _, span, _) + = tcx.hir.expect_expr(mir_node_id).node + { + span + } else { + bug!("Closure is not defined by a closure expr"); + }; + let region_name = self.synthesize_region_name(counter); + diag.span_label( + args_span, + format!("lifetime `{}` represents this closure's body", region_name), + ); + + let closure_kind_ty = substs.closure_kind_ty(def_id, tcx); + let note = match closure_kind_ty.to_opt_closure_kind() { + Some(ty::ClosureKind::Fn) => { + "closure implements `Fn`, so references to captured variables \ + can't escape the closure" + } + Some(ty::ClosureKind::FnMut) => { + "closure implements `FnMut`, so references to captured variables \ + can't escape the closure" + } + Some(ty::ClosureKind::FnOnce) => { + bug!("BrEnv in a `FnOnce` closure"); + } + None => bug!("Closure kind not inferred in borrow check"), + }; + + diag.note(note); + + Some(region_name) + } else { + // Can't have BrEnv in functions, constants or generators. + bug!("BrEnv outside of closure."); + } } ty::BoundRegion::BrAnon(_) | ty::BoundRegion::BrFresh(_) => None, @@ -545,6 +579,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { &self, tcx: TyCtxt<'_, '_, 'tcx>, mir: &Mir<'tcx>, + mir_def_id: DefId, fr: RegionVid, counter: &mut usize, diag: &mut DiagnosticBuilder<'_>, @@ -558,9 +593,18 @@ impl<'tcx> RegionInferenceContext<'tcx> { return None; } + let mir_node_id = tcx.hir.as_local_node_id(mir_def_id).expect("non-local mir"); + let args_span = if let hir::ExprKind::Closure(_, _, _, span, _) + = tcx.hir.expect_expr(mir_node_id).node + { + span + } else { + mir.span + }; + let region_name = self.synthesize_region_name(counter); diag.span_label( - mir.span, + args_span, format!("lifetime `{}` appears in return type", region_name), ); diff --git a/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.nll.stderr b/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.nll.stderr index 0ac295c54bccb..27a51cb83fb25 100644 --- a/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.nll.stderr +++ b/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.nll.stderr @@ -8,9 +8,8 @@ error: unsatisfied lifetime constraints --> $DIR/E0621-does-not-trigger-for-closures.rs:25:26 | LL | invoke(&x, |a, b| if a > b { a } else { b }); //~ ERROR E0495 - | ----------^^^^^----------------- - | | | | - | | | requires that `'1` must outlive `'2` + | ------ ^^^^^ requires that `'1` must outlive `'2` + | | | | | has type `&'1 i32` | lifetime `'2` appears in return type diff --git a/src/test/ui/issue-40510-1.nll.stderr b/src/test/ui/issue-40510-1.nll.stderr index 312ec6e742e91..7eb6a0e7fb226 100644 --- a/src/test/ui/issue-40510-1.nll.stderr +++ b/src/test/ui/issue-40510-1.nll.stderr @@ -1,17 +1,15 @@ error: unsatisfied lifetime constraints --> $DIR/issue-40510-1.rs:18:9 | -LL | || { - | _____- - | |_____| - | || -LL | || &mut x - | || ^^^^^^ return requires that `'1` must outlive `'2` -LL | || }; - | || - - | ||_____| - | |______lifetime `'1` represents the closure body - | lifetime `'2` appears in return type +LL | || { + | -- + | | + | lifetime `'1` represents this closure's body + | lifetime `'2` appears in return type +LL | &mut x + | ^^^^^^ return requires that `'1` must outlive `'2` + | + = note: closure implements `FnMut`, so references to captured variables can't escape the closure error: aborting due to previous error diff --git a/src/test/ui/issue-40510-3.nll.stderr b/src/test/ui/issue-40510-3.nll.stderr index eb44850e639ab..ae3ae3a27ab20 100644 --- a/src/test/ui/issue-40510-3.nll.stderr +++ b/src/test/ui/issue-40510-3.nll.stderr @@ -1,20 +1,17 @@ error: unsatisfied lifetime constraints --> $DIR/issue-40510-3.rs:18:9 | -LL | || { - | _____- - | |_____| - | || -LL | || || { - | ||_________^ -LL | ||| x.push(()) -LL | ||| } - | |||_________^ requires that `'1` must outlive `'2` -LL | || }; - | || - - | ||_____| - | |______lifetime `'1` represents the closure body - | lifetime `'2` appears in return type +LL | || { + | -- + | | + | lifetime `'1` represents this closure's body + | lifetime `'2` appears in return type +LL | / || { +LL | | x.push(()) +LL | | } + | |_________^ requires that `'1` must outlive `'2` + | + = note: closure implements `FnMut`, so references to captured variables can't escape the closure error: aborting due to previous error diff --git a/src/test/ui/issue-49824.nll.stderr b/src/test/ui/issue-49824.nll.stderr index 59345754e9f59..432036c9d90ce 100644 --- a/src/test/ui/issue-49824.nll.stderr +++ b/src/test/ui/issue-49824.nll.stderr @@ -1,20 +1,17 @@ error: unsatisfied lifetime constraints --> $DIR/issue-49824.rs:22:9 | -LL | || { - | _____- - | |_____| - | || -LL | || || { - | ||_________^ -LL | ||| let _y = &mut x; -LL | ||| } - | |||_________^ requires that `'1` must outlive `'2` -LL | || }; - | || - - | ||_____| - | |______lifetime `'1` represents the closure body - | lifetime `'2` appears in return type +LL | || { + | -- + | | + | lifetime `'1` represents this closure's body + | lifetime `'2` appears in return type +LL | / || { +LL | | let _y = &mut x; +LL | | } + | |_________^ requires that `'1` must outlive `'2` + | + = note: closure implements `FnMut`, so references to captured variables can't escape the closure error: aborting due to previous error diff --git a/src/test/ui/nll/issue-48238.stderr b/src/test/ui/nll/issue-48238.stderr index 7bdac345e9047..4baa904442464 100644 --- a/src/test/ui/nll/issue-48238.stderr +++ b/src/test/ui/nll/issue-48238.stderr @@ -2,11 +2,12 @@ error: unsatisfied lifetime constraints --> $DIR/issue-48238.rs:21:13 | LL | move || use_val(&orig); //~ ERROR - | --------^^^^^^^^^^^^^^ - | | | - | | argument requires that `'1` must outlive `'2` - | lifetime `'1` represents the closure body + | ------- ^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2` + | | + | lifetime `'1` represents this closure's body | lifetime `'2` appears in return type + | + = note: closure implements `Fn`, so references to captured variables can't escape the closure error: aborting due to previous error From 70cafecaba233037bd5df5259140c3167941e70c Mon Sep 17 00:00:00 2001 From: Vadim Pashkov Date: Mon, 6 Aug 2018 04:18:19 +0300 Subject: [PATCH 02/20] improper_ctypes lint for individual foreign items --- src/librustc_lint/types.rs | 23 ++++++++++------------- src/test/ui/lint-ctypes.rs | 7 +++++++ 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 4dc66fb812144..f1636c4dcb08a 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -790,21 +790,18 @@ impl LintPass for ImproperCTypes { } impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImproperCTypes { - fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { + fn check_foreign_item(&mut self, cx: &LateContext, it: &hir::ForeignItem) { let mut vis = ImproperCTypesVisitor { cx: cx }; - if let hir::ItemKind::ForeignMod(ref nmod) = it.node { - if nmod.abi != Abi::RustIntrinsic && nmod.abi != Abi::PlatformIntrinsic { - for ni in &nmod.items { - match ni.node { - hir::ForeignItemKind::Fn(ref decl, _, _) => { - vis.check_foreign_fn(ni.id, decl); - } - hir::ForeignItemKind::Static(ref ty, _) => { - vis.check_foreign_static(ni.id, ty.span); - } - hir::ForeignItemKind::Type => () - } + let abi = cx.tcx.hir.get_foreign_abi(it.id); + if abi != Abi::RustIntrinsic && abi != Abi::PlatformIntrinsic { + match it.node { + hir::ForeignItemKind::Fn(ref decl, _, _) => { + vis.check_foreign_fn(it.id, decl); + } + hir::ForeignItemKind::Static(ref ty, _) => { + vis.check_foreign_static(it.id, ty.span); } + hir::ForeignItemKind::Type => () } } } diff --git a/src/test/ui/lint-ctypes.rs b/src/test/ui/lint-ctypes.rs index 7f22dc8739e76..b8b1a675c5f6d 100644 --- a/src/test/ui/lint-ctypes.rs +++ b/src/test/ui/lint-ctypes.rs @@ -88,6 +88,13 @@ extern { pub fn good15(p: TransparentLifetime); pub fn good16(p: TransparentUnit); pub fn good17(p: TransparentCustomZst); + #[allow(improper_ctypes)] + pub fn good18(_: &String); +} + +#[allow(improper_ctypes)] +extern { + pub fn good19(_: &String); } #[cfg(not(target_arch = "wasm32"))] From e8bb7bf35a0d5066a081cfa9a581849e34a91e02 Mon Sep 17 00:00:00 2001 From: Igor Matuszewski Date: Mon, 6 Aug 2018 14:07:08 +0200 Subject: [PATCH 03/20] Account for --remap-path-prefix in save-analysis --- src/librustc_save_analysis/lib.rs | 2 +- src/librustc_save_analysis/span_utils.rs | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 6e49951ff298a..431147e0829af 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -125,7 +125,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { result.push(ExternalCrateData { // FIXME: change file_name field to PathBuf in rls-data // https://github.com/nrc/rls-data/issues/7 - file_name: SpanUtils::make_path_string(&lo_loc.file.name), + file_name: self.span_utils.make_path_string(&lo_loc.file.name), num: n.as_u32(), id: GlobalCrateId { name: self.tcx.crate_name(n).to_string(), diff --git a/src/librustc_save_analysis/span_utils.rs b/src/librustc_save_analysis/span_utils.rs index 4d93e81a78fa1..85dd2a3a20683 100644 --- a/src/librustc_save_analysis/span_utils.rs +++ b/src/librustc_save_analysis/span_utils.rs @@ -13,7 +13,6 @@ use rustc::session::Session; use generated_code; use std::cell::Cell; -use std::env; use syntax::parse::lexer::{self, StringReader}; use syntax::parse::token::{self, Token}; @@ -36,11 +35,10 @@ impl<'a> SpanUtils<'a> { } } - pub fn make_path_string(path: &FileName) -> String { + pub fn make_path_string(&self, path: &FileName) -> String { match *path { FileName::Real(ref path) if !path.is_absolute() => - env::current_dir() - .unwrap() + self.sess.working_dir.0 .join(&path) .display() .to_string(), From b011b091cb68bb36e9aea2fab4fcd1b74d26a1e8 Mon Sep 17 00:00:00 2001 From: "Jonathan A. Kollasch" Date: Sun, 5 Aug 2018 11:53:58 -0500 Subject: [PATCH 04/20] NetBSD: fix signedess of char --- src/libstd/os/raw/mod.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libstd/os/raw/mod.rs b/src/libstd/os/raw/mod.rs index d5eeb5252f0f1..4b8dda493b097 100644 --- a/src/libstd/os/raw/mod.rs +++ b/src/libstd/os/raw/mod.rs @@ -29,6 +29,8 @@ use fmt; all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")), all(target_os = "l4re", target_arch = "x86_64"), + all(target_os = "netbsd", any(target_arch = "arm", + target_arch = "powerpc")), all(target_os = "openbsd", target_arch = "aarch64"), all(target_os = "fuchsia", target_arch = "aarch64")))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = u8; @@ -41,6 +43,8 @@ use fmt; all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")), all(target_os = "l4re", target_arch = "x86_64"), + all(target_os = "netbsd", any(target_arch = "arm", + target_arch = "powerpc")), all(target_os = "openbsd", target_arch = "aarch64"), all(target_os = "fuchsia", target_arch = "aarch64"))))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = i8; From 7235e7df78b0d4c763504fe496a44db3220ee1e6 Mon Sep 17 00:00:00 2001 From: ljedrz Date: Sun, 5 Aug 2018 12:04:56 +0200 Subject: [PATCH 05/20] Move SmallVec and ThinVec out of libsyntax --- src/Cargo.lock | 1 + src/librustc/hir/lowering.rs | 25 +++--- src/librustc/hir/mod.rs | 2 +- src/librustc_allocator/Cargo.toml | 1 + src/librustc_allocator/expand.rs | 14 ++-- src/librustc_allocator/lib.rs | 1 + src/librustc_data_structures/lib.rs | 1 + src/librustc_data_structures/small_vec.rs | 65 +++++++++++++++ .../thin_vec.rs | 0 src/librustc_driver/pretty.rs | 10 +-- src/libsyntax/ast.rs | 2 +- src/libsyntax/attr/mod.rs | 2 +- src/libsyntax/config.rs | 12 +-- src/libsyntax/diagnostics/plugin.rs | 6 +- src/libsyntax/ext/base.rs | 57 ++++++------- src/libsyntax/ext/build.rs | 11 +-- src/libsyntax/ext/expand.rs | 44 +++++----- src/libsyntax/ext/placeholders.rs | 29 +++---- src/libsyntax/ext/quote.rs | 7 +- src/libsyntax/ext/source_util.rs | 6 +- src/libsyntax/ext/tt/macro_parser.rs | 14 ++-- src/libsyntax/ext/tt/transcribe.rs | 4 +- src/libsyntax/fold.rs | 37 ++++----- src/libsyntax/lib.rs | 6 +- src/libsyntax/parse/parser.rs | 2 +- src/libsyntax/test.rs | 15 ++-- src/libsyntax/util/move_map.rs | 5 +- src/libsyntax/util/small_vector.rs | 81 ------------------- src/libsyntax_ext/asm.rs | 4 +- src/libsyntax_ext/concat_idents.rs | 4 +- src/libsyntax_ext/deriving/debug.rs | 4 +- src/libsyntax_ext/deriving/generic/mod.rs | 3 +- src/libsyntax_ext/global_asm.rs | 6 +- .../auxiliary/issue-16723.rs | 6 +- .../pprust-expr-roundtrip.rs | 3 +- 35 files changed, 245 insertions(+), 245 deletions(-) rename src/{libsyntax/util => librustc_data_structures}/thin_vec.rs (100%) delete mode 100644 src/libsyntax/util/small_vector.rs diff --git a/src/Cargo.lock b/src/Cargo.lock index 7c57cf32d1b14..ace8f6195b720 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -2140,6 +2140,7 @@ version = "0.0.0" dependencies = [ "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", + "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", "rustc_target 0.0.0", "syntax 0.0.0", diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 4b69e3b6bc70d..cb0e10a039337 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -51,6 +51,8 @@ use lint::builtin::{self, PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES, ELIDED_LIFETIMES_IN_PATHS}; use middle::cstore::CrateStore; use rustc_data_structures::indexed_vec::IndexVec; +use rustc_data_structures::small_vec::OneVector; +use rustc_data_structures::thin_vec::ThinVec; use session::Session; use util::common::FN_OUTPUT_NAME; use util::nodemap::{DefIdMap, NodeMap}; @@ -71,7 +73,6 @@ use syntax::std_inject; use syntax::symbol::{keywords, Symbol}; use syntax::tokenstream::{Delimited, TokenStream, TokenTree}; use syntax::parse::token::Token; -use syntax::util::small_vector::SmallVector; use syntax::visit::{self, Visitor}; use syntax_pos::{Span, MultiSpan}; @@ -3122,12 +3123,12 @@ impl<'a> LoweringContext<'a> { &mut self, decl: &FnDecl, header: &FnHeader, - ids: &mut SmallVector, + ids: &mut OneVector, ) { if let Some(id) = header.asyncness.opt_return_id() { ids.push(hir::ItemId { id }); } - struct IdVisitor<'a> { ids: &'a mut SmallVector } + struct IdVisitor<'a> { ids: &'a mut OneVector } impl<'a, 'b> Visitor<'a> for IdVisitor<'b> { fn visit_ty(&mut self, ty: &'a Ty) { match ty.node { @@ -3160,21 +3161,21 @@ impl<'a> LoweringContext<'a> { } } - fn lower_item_id(&mut self, i: &Item) -> SmallVector { + fn lower_item_id(&mut self, i: &Item) -> OneVector { match i.node { ItemKind::Use(ref use_tree) => { - let mut vec = SmallVector::one(hir::ItemId { id: i.id }); + let mut vec = OneVector::one(hir::ItemId { id: i.id }); self.lower_item_id_use_tree(use_tree, i.id, &mut vec); vec } - ItemKind::MacroDef(..) => SmallVector::new(), + ItemKind::MacroDef(..) => OneVector::new(), ItemKind::Fn(ref decl, ref header, ..) => { - let mut ids = SmallVector::one(hir::ItemId { id: i.id }); + let mut ids = OneVector::one(hir::ItemId { id: i.id }); self.lower_impl_trait_ids(decl, header, &mut ids); ids }, ItemKind::Impl(.., None, _, ref items) => { - let mut ids = SmallVector::one(hir::ItemId { id: i.id }); + let mut ids = OneVector::one(hir::ItemId { id: i.id }); for item in items { if let ImplItemKind::Method(ref sig, _) = item.node { self.lower_impl_trait_ids(&sig.decl, &sig.header, &mut ids); @@ -3182,14 +3183,14 @@ impl<'a> LoweringContext<'a> { } ids }, - _ => SmallVector::one(hir::ItemId { id: i.id }), + _ => OneVector::one(hir::ItemId { id: i.id }), } } fn lower_item_id_use_tree(&mut self, tree: &UseTree, base_id: NodeId, - vec: &mut SmallVector) + vec: &mut OneVector) { match tree.kind { UseTreeKind::Nested(ref nested_vec) => for &(ref nested, id) in nested_vec { @@ -4281,8 +4282,8 @@ impl<'a> LoweringContext<'a> { } } - fn lower_stmt(&mut self, s: &Stmt) -> SmallVector { - SmallVector::one(match s.node { + fn lower_stmt(&mut self, s: &Stmt) -> OneVector { + OneVector::one(match s.node { StmtKind::Local(ref l) => Spanned { node: hir::StmtKind::Decl( P(Spanned { diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 610add90b8577..107b5502bb361 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -33,13 +33,13 @@ use syntax::ext::hygiene::SyntaxContext; use syntax::ptr::P; use syntax::symbol::{Symbol, keywords}; use syntax::tokenstream::TokenStream; -use syntax::util::ThinVec; use syntax::util::parser::ExprPrecedence; use ty::AdtKind; use ty::query::Providers; use rustc_data_structures::indexed_vec; use rustc_data_structures::sync::{ParallelIterator, par_iter, Send, Sync, scope}; +use rustc_data_structures::thin_vec::ThinVec; use serialize::{self, Encoder, Encodable, Decoder, Decodable}; use std::collections::BTreeMap; diff --git a/src/librustc_allocator/Cargo.toml b/src/librustc_allocator/Cargo.toml index 1cbde181cafae..83a918f2af837 100644 --- a/src/librustc_allocator/Cargo.toml +++ b/src/librustc_allocator/Cargo.toml @@ -10,6 +10,7 @@ test = false [dependencies] rustc = { path = "../librustc" } +rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } rustc_target = { path = "../librustc_target" } syntax = { path = "../libsyntax" } diff --git a/src/librustc_allocator/expand.rs b/src/librustc_allocator/expand.rs index ffbbd8a33a1d0..84ef0b0778e59 100644 --- a/src/librustc_allocator/expand.rs +++ b/src/librustc_allocator/expand.rs @@ -9,6 +9,7 @@ // except according to those terms. use rustc::middle::allocator::AllocatorKind; +use rustc_data_structures::small_vec::OneVector; use rustc_errors; use syntax::{ ast::{ @@ -28,8 +29,7 @@ use syntax::{ fold::{self, Folder}, parse::ParseSess, ptr::P, - symbol::Symbol, - util::small_vector::SmallVector, + symbol::Symbol }; use syntax_pos::Span; @@ -65,7 +65,7 @@ struct ExpandAllocatorDirectives<'a> { } impl<'a> Folder for ExpandAllocatorDirectives<'a> { - fn fold_item(&mut self, item: P) -> SmallVector> { + fn fold_item(&mut self, item: P) -> OneVector> { debug!("in submodule {}", self.in_submod); let name = if attr::contains_name(&item.attrs, "global_allocator") { @@ -78,20 +78,20 @@ impl<'a> Folder for ExpandAllocatorDirectives<'a> { _ => { self.handler .span_err(item.span, "allocators must be statics"); - return SmallVector::one(item); + return OneVector::one(item); } } if self.in_submod > 0 { self.handler .span_err(item.span, "`global_allocator` cannot be used in submodules"); - return SmallVector::one(item); + return OneVector::one(item); } if self.found { self.handler .span_err(item.span, "cannot define more than one #[global_allocator]"); - return SmallVector::one(item); + return OneVector::one(item); } self.found = true; @@ -152,7 +152,7 @@ impl<'a> Folder for ExpandAllocatorDirectives<'a> { let module = f.cx.monotonic_expander().fold_item(module).pop().unwrap(); // Return the item and new submodule - let mut ret = SmallVector::with_capacity(2); + let mut ret = OneVector::with_capacity(2); ret.push(item); ret.push(module); diff --git a/src/librustc_allocator/lib.rs b/src/librustc_allocator/lib.rs index b217d3665a245..c7dc336b1ca51 100644 --- a/src/librustc_allocator/lib.rs +++ b/src/librustc_allocator/lib.rs @@ -12,6 +12,7 @@ #[macro_use] extern crate log; extern crate rustc; +extern crate rustc_data_structures; extern crate rustc_errors; extern crate rustc_target; extern crate syntax; diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index a9e582e510e78..337f6278accc7 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -75,6 +75,7 @@ pub mod sorted_map; pub mod stable_hasher; pub mod sync; pub mod tiny_list; +pub mod thin_vec; pub mod transitive_relation; pub mod tuple_slice; pub use ena::unify; diff --git a/src/librustc_data_structures/small_vec.rs b/src/librustc_data_structures/small_vec.rs index 76b01beb4bad3..c12039cfdd009 100644 --- a/src/librustc_data_structures/small_vec.rs +++ b/src/librustc_data_structures/small_vec.rs @@ -29,6 +29,8 @@ use array_vec::Array; pub struct SmallVec(AccumulateVec); +pub type OneVector = SmallVec<[T; 1]>; + impl Clone for SmallVec where A: Array, A::Element: Clone { @@ -222,6 +224,69 @@ mod tests { use super::*; + #[test] + fn test_len() { + let v: OneVector = OneVector::new(); + assert_eq!(0, v.len()); + + assert_eq!(1, OneVector::one(1).len()); + assert_eq!(5, OneVector::many(vec![1, 2, 3, 4, 5]).len()); + } + + #[test] + fn test_push_get() { + let mut v = OneVector::new(); + v.push(1); + assert_eq!(1, v.len()); + assert_eq!(1, v[0]); + v.push(2); + assert_eq!(2, v.len()); + assert_eq!(2, v[1]); + v.push(3); + assert_eq!(3, v.len()); + assert_eq!(3, v[2]); + } + + #[test] + fn test_from_iter() { + let v: OneVector = (vec![1, 2, 3]).into_iter().collect(); + assert_eq!(3, v.len()); + assert_eq!(1, v[0]); + assert_eq!(2, v[1]); + assert_eq!(3, v[2]); + } + + #[test] + fn test_move_iter() { + let v = OneVector::new(); + let v: Vec = v.into_iter().collect(); + assert_eq!(v, Vec::new()); + + let v = OneVector::one(1); + assert_eq!(v.into_iter().collect::>(), [1]); + + let v = OneVector::many(vec![1, 2, 3]); + assert_eq!(v.into_iter().collect::>(), [1, 2, 3]); + } + + #[test] + #[should_panic] + fn test_expect_one_zero() { + let _: isize = OneVector::new().expect_one(""); + } + + #[test] + #[should_panic] + fn test_expect_one_many() { + OneVector::many(vec![1, 2]).expect_one(""); + } + + #[test] + fn test_expect_one_one() { + assert_eq!(1, OneVector::one(1).expect_one("")); + assert_eq!(1, OneVector::many(vec![1]).expect_one("")); + } + #[bench] fn fill_small_vec_1_10_with_cap(b: &mut Bencher) { b.iter(|| { diff --git a/src/libsyntax/util/thin_vec.rs b/src/librustc_data_structures/thin_vec.rs similarity index 100% rename from src/libsyntax/util/thin_vec.rs rename to src/librustc_data_structures/thin_vec.rs diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 3e74aef9e7345..a66392833f695 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -24,6 +24,8 @@ use rustc::session::Session; use rustc::session::config::{Input, OutputFilenames}; use rustc_borrowck as borrowck; use rustc_borrowck::graphviz as borrowck_dot; +use rustc_data_structures::small_vec::OneVector; +use rustc_data_structures::thin_vec::ThinVec; use rustc_metadata::cstore::CStore; use rustc_mir::util::{write_mir_pretty, write_mir_graphviz}; @@ -33,8 +35,6 @@ use syntax::fold::{self, Folder}; use syntax::print::{pprust}; use syntax::print::pprust::PrintState; use syntax::ptr::P; -use syntax::util::ThinVec; -use syntax::util::small_vector::SmallVector; use syntax_pos::{self, FileName}; use graphviz as dot; @@ -727,7 +727,7 @@ impl<'a> fold::Folder for ReplaceBodyWithLoop<'a> { self.run(is_const, |s| fold::noop_fold_item_kind(i, s)) } - fn fold_trait_item(&mut self, i: ast::TraitItem) -> SmallVector { + fn fold_trait_item(&mut self, i: ast::TraitItem) -> OneVector { let is_const = match i.node { ast::TraitItemKind::Const(..) => true, ast::TraitItemKind::Method(ast::MethodSig { ref decl, ref header, .. }, _) => @@ -737,7 +737,7 @@ impl<'a> fold::Folder for ReplaceBodyWithLoop<'a> { self.run(is_const, |s| fold::noop_fold_trait_item(i, s)) } - fn fold_impl_item(&mut self, i: ast::ImplItem) -> SmallVector { + fn fold_impl_item(&mut self, i: ast::ImplItem) -> OneVector { let is_const = match i.node { ast::ImplItemKind::Const(..) => true, ast::ImplItemKind::Method(ast::MethodSig { ref decl, ref header, .. }, _) => @@ -785,7 +785,7 @@ impl<'a> fold::Folder for ReplaceBodyWithLoop<'a> { node: ast::ExprKind::Loop(P(empty_block), None), id: self.sess.next_node_id(), span: syntax_pos::DUMMY_SP, - attrs: ast::ThinVec::new(), + attrs: ThinVec::new(), }); let loop_stmt = ast::Stmt { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 28c1e4324de7a..17e3d88a9099d 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -13,7 +13,6 @@ pub use self::UnsafeSource::*; pub use self::GenericArgs::*; pub use symbol::{Ident, Symbol as Name}; -pub use util::ThinVec; pub use util::parser::ExprPrecedence; use syntax_pos::{Span, DUMMY_SP}; @@ -25,6 +24,7 @@ use ptr::P; use rustc_data_structures::indexed_vec; use rustc_data_structures::indexed_vec::Idx; use symbol::{Symbol, keywords}; +use ThinVec; use tokenstream::{ThinTokenStream, TokenStream}; use serialize::{self, Encoder, Decoder}; diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index b3b173db70b89..879f555ba03ee 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -33,8 +33,8 @@ use parse::{self, ParseSess, PResult}; use parse::token::{self, Token}; use ptr::P; use symbol::Symbol; +use ThinVec; use tokenstream::{TokenStream, TokenTree, Delimited}; -use util::ThinVec; use GLOBALS; use std::iter; diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 3364378913952..4fe78bf829a1c 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -15,9 +15,9 @@ use ast; use codemap::Spanned; use edition::Edition; use parse::{token, ParseSess}; +use OneVector; use ptr::P; -use util::small_vector::SmallVector; /// A folder that strips out items that do not belong in the current configuration. pub struct StripUnconfigured<'a> { @@ -319,22 +319,22 @@ impl<'a> fold::Folder for StripUnconfigured<'a> { Some(P(fold::noop_fold_expr(expr, self))) } - fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector { + fn fold_stmt(&mut self, stmt: ast::Stmt) -> OneVector { match self.configure_stmt(stmt) { Some(stmt) => fold::noop_fold_stmt(stmt, self), - None => return SmallVector::new(), + None => return OneVector::new(), } } - fn fold_item(&mut self, item: P) -> SmallVector> { + fn fold_item(&mut self, item: P) -> OneVector> { fold::noop_fold_item(configure!(self, item), self) } - fn fold_impl_item(&mut self, item: ast::ImplItem) -> SmallVector { + fn fold_impl_item(&mut self, item: ast::ImplItem) -> OneVector { fold::noop_fold_impl_item(configure!(self, item), self) } - fn fold_trait_item(&mut self, item: ast::TraitItem) -> SmallVector { + fn fold_trait_item(&mut self, item: ast::TraitItem) -> OneVector { fold::noop_fold_trait_item(configure!(self, item), self) } diff --git a/src/libsyntax/diagnostics/plugin.rs b/src/libsyntax/diagnostics/plugin.rs index 72ce2740190d4..6a5a2a5e500ff 100644 --- a/src/libsyntax/diagnostics/plugin.rs +++ b/src/libsyntax/diagnostics/plugin.rs @@ -19,9 +19,9 @@ use ext::base::{ExtCtxt, MacEager, MacResult}; use ext::build::AstBuilder; use parse::token; use ptr::P; +use OneVector; use symbol::{keywords, Symbol}; use tokenstream::{TokenTree}; -use util::small_vector::SmallVector; use diagnostics::metadata::output_metadata; @@ -131,7 +131,7 @@ pub fn expand_register_diagnostic<'cx>(ecx: &'cx mut ExtCtxt, let sym = Ident::with_empty_ctxt(Symbol::gensym(&format!( "__register_diagnostic_{}", code ))); - MacEager::items(SmallVector::many(vec![ + MacEager::items(OneVector::many(vec![ ecx.item_mod( span, span, @@ -214,7 +214,7 @@ pub fn expand_build_diagnostic_array<'cx>(ecx: &'cx mut ExtCtxt, ), ); - MacEager::items(SmallVector::many(vec![ + MacEager::items(OneVector::many(vec![ P(ast::Item { ident: *name, attrs: Vec::new(), diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 8450daa3f7c94..e3cf635c939d5 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -22,8 +22,9 @@ use fold::{self, Folder}; use parse::{self, parser, DirectoryOwnership}; use parse::token; use ptr::P; +use OneVector; use symbol::{keywords, Ident, Symbol}; -use util::small_vector::SmallVector; +use ThinVec; use std::collections::HashMap; use std::iter; @@ -315,7 +316,7 @@ impl IdentMacroExpander for F // Use a macro because forwarding to a simple function has type system issues macro_rules! make_stmts_default { ($me:expr) => { - $me.make_expr().map(|e| SmallVector::one(ast::Stmt { + $me.make_expr().map(|e| OneVector::one(ast::Stmt { id: ast::DUMMY_NODE_ID, span: e.span, node: ast::StmtKind::Expr(e), @@ -331,22 +332,22 @@ pub trait MacResult { None } /// Create zero or more items. - fn make_items(self: Box) -> Option>> { + fn make_items(self: Box) -> Option>> { None } /// Create zero or more impl items. - fn make_impl_items(self: Box) -> Option> { + fn make_impl_items(self: Box) -> Option> { None } /// Create zero or more trait items. - fn make_trait_items(self: Box) -> Option> { + fn make_trait_items(self: Box) -> Option> { None } /// Create zero or more items in an `extern {}` block - fn make_foreign_items(self: Box) -> Option> { None } + fn make_foreign_items(self: Box) -> Option> { None } /// Create a pattern. fn make_pat(self: Box) -> Option> { @@ -357,7 +358,7 @@ pub trait MacResult { /// /// By default this attempts to create an expression statement, /// returning None if that fails. - fn make_stmts(self: Box) -> Option> { + fn make_stmts(self: Box) -> Option> { make_stmts_default!(self) } @@ -393,11 +394,11 @@ macro_rules! make_MacEager { make_MacEager! { expr: P, pat: P, - items: SmallVector>, - impl_items: SmallVector, - trait_items: SmallVector, - foreign_items: SmallVector, - stmts: SmallVector, + items: OneVector>, + impl_items: OneVector, + trait_items: OneVector, + foreign_items: OneVector, + stmts: OneVector, ty: P, } @@ -406,23 +407,23 @@ impl MacResult for MacEager { self.expr } - fn make_items(self: Box) -> Option>> { + fn make_items(self: Box) -> Option>> { self.items } - fn make_impl_items(self: Box) -> Option> { + fn make_impl_items(self: Box) -> Option> { self.impl_items } - fn make_trait_items(self: Box) -> Option> { + fn make_trait_items(self: Box) -> Option> { self.trait_items } - fn make_foreign_items(self: Box) -> Option> { + fn make_foreign_items(self: Box) -> Option> { self.foreign_items } - fn make_stmts(self: Box) -> Option> { + fn make_stmts(self: Box) -> Option> { match self.stmts.as_ref().map_or(0, |s| s.len()) { 0 => make_stmts_default!(self), _ => self.stmts, @@ -482,7 +483,7 @@ impl DummyResult { id: ast::DUMMY_NODE_ID, node: ast::ExprKind::Lit(P(codemap::respan(sp, ast::LitKind::Bool(false)))), span: sp, - attrs: ast::ThinVec::new(), + attrs: ThinVec::new(), }) } @@ -513,41 +514,41 @@ impl MacResult for DummyResult { Some(P(DummyResult::raw_pat(self.span))) } - fn make_items(self: Box) -> Option>> { + fn make_items(self: Box) -> Option>> { // this code needs a comment... why not always just return the Some() ? if self.expr_only { None } else { - Some(SmallVector::new()) + Some(OneVector::new()) } } - fn make_impl_items(self: Box) -> Option> { + fn make_impl_items(self: Box) -> Option> { if self.expr_only { None } else { - Some(SmallVector::new()) + Some(OneVector::new()) } } - fn make_trait_items(self: Box) -> Option> { + fn make_trait_items(self: Box) -> Option> { if self.expr_only { None } else { - Some(SmallVector::new()) + Some(OneVector::new()) } } - fn make_foreign_items(self: Box) -> Option> { + fn make_foreign_items(self: Box) -> Option> { if self.expr_only { None } else { - Some(SmallVector::new()) + Some(OneVector::new()) } } - fn make_stmts(self: Box) -> Option> { - Some(SmallVector::one(ast::Stmt { + fn make_stmts(self: Box) -> Option> { + Some(OneVector::one(ast::Stmt { id: ast::DUMMY_NODE_ID, node: ast::StmtKind::Expr(DummyResult::raw_expr(self.span)), span: self.span, diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 6135650766569..1a17aa3e8fb64 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -16,6 +16,7 @@ use codemap::{dummy_spanned, respan, Spanned}; use ext::base::ExtCtxt; use ptr::P; use symbol::{Symbol, keywords}; +use ThinVec; // Transitional re-exports so qquote can find the paths it is looking for mod syntax { @@ -519,7 +520,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { init: Some(ex), id: ast::DUMMY_NODE_ID, span: sp, - attrs: ast::ThinVec::new(), + attrs: ThinVec::new(), }); ast::Stmt { id: ast::DUMMY_NODE_ID, @@ -547,7 +548,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { init: Some(ex), id: ast::DUMMY_NODE_ID, span: sp, - attrs: ast::ThinVec::new(), + attrs: ThinVec::new(), }); ast::Stmt { id: ast::DUMMY_NODE_ID, @@ -564,7 +565,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { init: None, id: ast::DUMMY_NODE_ID, span, - attrs: ast::ThinVec::new(), + attrs: ThinVec::new(), }); ast::Stmt { id: ast::DUMMY_NODE_ID, @@ -603,7 +604,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { id: ast::DUMMY_NODE_ID, node, span, - attrs: ast::ThinVec::new(), + attrs: ThinVec::new(), }) } @@ -678,7 +679,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { expr: e, span, is_shorthand: false, - attrs: ast::ThinVec::new(), + attrs: ThinVec::new(), } } fn expr_struct(&self, span: Span, path: ast::Path, fields: Vec) -> P { diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 8bd30e434767b..102545db68f62 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -26,12 +26,12 @@ use parse::{DirectoryOwnership, PResult, ParseSess}; use parse::token::{self, Token}; use parse::parser::Parser; use ptr::P; +use OneVector; use symbol::Symbol; use symbol::keywords; use syntax_pos::{Span, DUMMY_SP, FileName}; use syntax_pos::hygiene::ExpnFormat; use tokenstream::{TokenStream, TokenTree}; -use util::small_vector::SmallVector; use visit::{self, Visitor}; use std::collections::HashMap; @@ -131,7 +131,7 @@ macro_rules! ast_fragments { self.expand_fragment(AstFragment::$Kind(ast)).$make_ast() })*)* $($(fn $fold_ast_elt(&mut self, ast_elt: <$AstTy as IntoIterator>::Item) -> $AstTy { - self.expand_fragment(AstFragment::$Kind(SmallVector::one(ast_elt))).$make_ast() + self.expand_fragment(AstFragment::$Kind(OneVector::one(ast_elt))).$make_ast() })*)* } @@ -148,15 +148,15 @@ ast_fragments! { Expr(P) { "expression"; one fn fold_expr; fn visit_expr; fn make_expr; } Pat(P) { "pattern"; one fn fold_pat; fn visit_pat; fn make_pat; } Ty(P) { "type"; one fn fold_ty; fn visit_ty; fn make_ty; } - Stmts(SmallVector) { "statement"; many fn fold_stmt; fn visit_stmt; fn make_stmts; } - Items(SmallVector>) { "item"; many fn fold_item; fn visit_item; fn make_items; } - TraitItems(SmallVector) { + Stmts(OneVector) { "statement"; many fn fold_stmt; fn visit_stmt; fn make_stmts; } + Items(OneVector>) { "item"; many fn fold_item; fn visit_item; fn make_items; } + TraitItems(OneVector) { "trait item"; many fn fold_trait_item; fn visit_trait_item; fn make_trait_items; } - ImplItems(SmallVector) { + ImplItems(OneVector) { "impl item"; many fn fold_impl_item; fn visit_impl_item; fn make_impl_items; } - ForeignItems(SmallVector) { + ForeignItems(OneVector) { "foreign item"; many fn fold_foreign_item; fn visit_foreign_item; fn make_foreign_items; } } @@ -286,7 +286,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let orig_mod_span = krate.module.inner; - let krate_item = AstFragment::Items(SmallVector::one(P(ast::Item { + let krate_item = AstFragment::Items(OneVector::one(P(ast::Item { attrs: krate.attrs, span: krate.span, node: ast::ItemKind::Mod(krate.module), @@ -993,28 +993,28 @@ impl<'a> Parser<'a> { -> PResult<'a, AstFragment> { Ok(match kind { AstFragmentKind::Items => { - let mut items = SmallVector::new(); + let mut items = OneVector::new(); while let Some(item) = self.parse_item()? { items.push(item); } AstFragment::Items(items) } AstFragmentKind::TraitItems => { - let mut items = SmallVector::new(); + let mut items = OneVector::new(); while self.token != token::Eof { items.push(self.parse_trait_item(&mut false)?); } AstFragment::TraitItems(items) } AstFragmentKind::ImplItems => { - let mut items = SmallVector::new(); + let mut items = OneVector::new(); while self.token != token::Eof { items.push(self.parse_impl_item(&mut false)?); } AstFragment::ImplItems(items) } AstFragmentKind::ForeignItems => { - let mut items = SmallVector::new(); + let mut items = OneVector::new(); while self.token != token::Eof { if let Some(item) = self.parse_foreign_item()? { items.push(item); @@ -1023,7 +1023,7 @@ impl<'a> Parser<'a> { AstFragment::ForeignItems(items) } AstFragmentKind::Stmts => { - let mut stmts = SmallVector::new(); + let mut stmts = OneVector::new(); while self.token != token::Eof && // won't make progress on a `}` self.token != token::CloseDelim(token::Brace) { @@ -1090,12 +1090,12 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { /// Folds the item allowing tests to be expanded because they are still nameable. /// This should probably only be called with module items - fn fold_nameable(&mut self, item: P) -> SmallVector> { + fn fold_nameable(&mut self, item: P) -> OneVector> { fold::noop_fold_item(item, self) } /// Folds the item but doesn't allow tests to occur within it - fn fold_unnameable(&mut self, item: P) -> SmallVector> { + fn fold_unnameable(&mut self, item: P) -> OneVector> { let was_nameable = mem::replace(&mut self.tests_nameable, false); let items = fold::noop_fold_item(item, self); self.tests_nameable = was_nameable; @@ -1258,10 +1258,10 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { }) } - fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector { + fn fold_stmt(&mut self, stmt: ast::Stmt) -> OneVector { let mut stmt = match self.cfg.configure_stmt(stmt) { Some(stmt) => stmt, - None => return SmallVector::new(), + None => return OneVector::new(), }; // we'll expand attributes on expressions separately @@ -1317,7 +1317,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { result } - fn fold_item(&mut self, item: P) -> SmallVector> { + fn fold_item(&mut self, item: P) -> OneVector> { let item = configure!(self, item); let (attr, traits, mut item) = self.classify_item(item); @@ -1426,7 +1426,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { ui }); - SmallVector::many( + OneVector::many( self.fold_unnameable(item).into_iter() .chain(self.fold_unnameable(use_item))) } else { @@ -1437,7 +1437,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { } } - fn fold_trait_item(&mut self, item: ast::TraitItem) -> SmallVector { + fn fold_trait_item(&mut self, item: ast::TraitItem) -> OneVector { let item = configure!(self, item); let (attr, traits, item) = self.classify_item(item); @@ -1457,7 +1457,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { } } - fn fold_impl_item(&mut self, item: ast::ImplItem) -> SmallVector { + fn fold_impl_item(&mut self, item: ast::ImplItem) -> OneVector { let item = configure!(self, item); let (attr, traits, item) = self.classify_item(item); @@ -1494,7 +1494,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { } fn fold_foreign_item(&mut self, - foreign_item: ast::ForeignItem) -> SmallVector { + foreign_item: ast::ForeignItem) -> OneVector { let (attr, traits, foreign_item) = self.classify_item(foreign_item); let explain = if self.cx.ecfg.use_extern_macros_enabled() { diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs index 968cf508edaaa..1dc9bae8848f3 100644 --- a/src/libsyntax/ext/placeholders.rs +++ b/src/libsyntax/ext/placeholders.rs @@ -16,9 +16,10 @@ use ext::hygiene::Mark; use tokenstream::TokenStream; use fold::*; use ptr::P; +use OneVector; use symbol::keywords; +use ThinVec; use util::move_map::MoveMap; -use util::small_vector::SmallVector; use std::collections::HashMap; @@ -38,31 +39,31 @@ pub fn placeholder(kind: AstFragmentKind, id: ast::NodeId) -> AstFragment { let span = DUMMY_SP; let expr_placeholder = || P(ast::Expr { id, span, - attrs: ast::ThinVec::new(), + attrs: ThinVec::new(), node: ast::ExprKind::Mac(mac_placeholder()), }); match kind { AstFragmentKind::Expr => AstFragment::Expr(expr_placeholder()), AstFragmentKind::OptExpr => AstFragment::OptExpr(Some(expr_placeholder())), - AstFragmentKind::Items => AstFragment::Items(SmallVector::one(P(ast::Item { + AstFragmentKind::Items => AstFragment::Items(OneVector::one(P(ast::Item { id, span, ident, vis, attrs, node: ast::ItemKind::Mac(mac_placeholder()), tokens: None, }))), - AstFragmentKind::TraitItems => AstFragment::TraitItems(SmallVector::one(ast::TraitItem { + AstFragmentKind::TraitItems => AstFragment::TraitItems(OneVector::one(ast::TraitItem { id, span, ident, attrs, generics, node: ast::TraitItemKind::Macro(mac_placeholder()), tokens: None, })), - AstFragmentKind::ImplItems => AstFragment::ImplItems(SmallVector::one(ast::ImplItem { + AstFragmentKind::ImplItems => AstFragment::ImplItems(OneVector::one(ast::ImplItem { id, span, ident, vis, attrs, generics, node: ast::ImplItemKind::Macro(mac_placeholder()), defaultness: ast::Defaultness::Final, tokens: None, })), AstFragmentKind::ForeignItems => - AstFragment::ForeignItems(SmallVector::one(ast::ForeignItem { + AstFragment::ForeignItems(OneVector::one(ast::ForeignItem { id, span, ident, vis, attrs, node: ast::ForeignItemKind::Macro(mac_placeholder()), })), @@ -72,8 +73,8 @@ pub fn placeholder(kind: AstFragmentKind, id: ast::NodeId) -> AstFragment { AstFragmentKind::Ty => AstFragment::Ty(P(ast::Ty { id, span, node: ast::TyKind::Mac(mac_placeholder()), })), - AstFragmentKind::Stmts => AstFragment::Stmts(SmallVector::one({ - let mac = P((mac_placeholder(), ast::MacStmtStyle::Braces, ast::ThinVec::new())); + AstFragmentKind::Stmts => AstFragment::Stmts(OneVector::one({ + let mac = P((mac_placeholder(), ast::MacStmtStyle::Braces, ThinVec::new())); ast::Stmt { id, span, node: ast::StmtKind::Mac(mac) } })), } @@ -114,31 +115,31 @@ impl<'a, 'b> PlaceholderExpander<'a, 'b> { } impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> { - fn fold_item(&mut self, item: P) -> SmallVector> { + fn fold_item(&mut self, item: P) -> OneVector> { match item.node { ast::ItemKind::Mac(_) => return self.remove(item.id).make_items(), - ast::ItemKind::MacroDef(_) => return SmallVector::one(item), + ast::ItemKind::MacroDef(_) => return OneVector::one(item), _ => {} } noop_fold_item(item, self) } - fn fold_trait_item(&mut self, item: ast::TraitItem) -> SmallVector { + fn fold_trait_item(&mut self, item: ast::TraitItem) -> OneVector { match item.node { ast::TraitItemKind::Macro(_) => self.remove(item.id).make_trait_items(), _ => noop_fold_trait_item(item, self), } } - fn fold_impl_item(&mut self, item: ast::ImplItem) -> SmallVector { + fn fold_impl_item(&mut self, item: ast::ImplItem) -> OneVector { match item.node { ast::ImplItemKind::Macro(_) => self.remove(item.id).make_impl_items(), _ => noop_fold_impl_item(item, self), } } - fn fold_foreign_item(&mut self, item: ast::ForeignItem) -> SmallVector { + fn fold_foreign_item(&mut self, item: ast::ForeignItem) -> OneVector { match item.node { ast::ForeignItemKind::Macro(_) => self.remove(item.id).make_foreign_items(), _ => noop_fold_foreign_item(item, self), @@ -159,7 +160,7 @@ impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> { } } - fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector { + fn fold_stmt(&mut self, stmt: ast::Stmt) -> OneVector { let (style, mut stmts) = match stmt.node { ast::StmtKind::Mac(mac) => (mac.1, self.remove(stmt.id).make_stmts()), _ => return noop_fold_stmt(stmt, self), diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index 1ace4d4a880e2..bc891700fc1b6 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -34,6 +34,7 @@ pub mod rt { use parse::token::{self, Token}; use ptr::P; use symbol::Symbol; + use ThinVec; use tokenstream::{self, TokenTree, TokenStream}; @@ -274,7 +275,7 @@ pub mod rt { id: ast::DUMMY_NODE_ID, node: ast::ExprKind::Lit(P(self.clone())), span: DUMMY_SP, - attrs: ast::ThinVec::new(), + attrs: ThinVec::new(), }).to_tokens(cx) } } @@ -305,7 +306,7 @@ pub mod rt { id: ast::DUMMY_NODE_ID, node: ast::ExprKind::Lit(P(dummy_spanned(lit))), span: DUMMY_SP, - attrs: ast::ThinVec::new(), + attrs: ThinVec::new(), }); if *self >= 0 { return lit.to_tokens(cx); @@ -314,7 +315,7 @@ pub mod rt { id: ast::DUMMY_NODE_ID, node: ast::ExprKind::Unary(ast::UnOp::Neg, lit), span: DUMMY_SP, - attrs: ast::ThinVec::new(), + attrs: ThinVec::new(), }).to_tokens(cx) } } diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index 0c36c072a0302..9b7e0fe1ae55c 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -17,9 +17,9 @@ use parse::{token, DirectoryOwnership}; use parse; use print::pprust; use ptr::P; +use OneVector; use symbol::Symbol; use tokenstream; -use util::small_vector::SmallVector; use std::fs::File; use std::io::prelude::*; @@ -111,8 +111,8 @@ pub fn expand_include<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[tokenstream::T Some(panictry!(self.p.parse_expr())) } fn make_items(mut self: Box>) - -> Option>> { - let mut ret = SmallVector::new(); + -> Option>> { + let mut ret = OneVector::new(); while self.p.token != token::Eof { match panictry!(self.p.parse_item()) { Some(item) => ret.push(item), diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index 3046525b7144c..82f88d1d8643e 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -92,9 +92,9 @@ use parse::{Directory, ParseSess}; use parse::parser::{Parser, PathStyle}; use parse::token::{self, DocComment, Nonterminal, Token}; use print::pprust; +use OneVector; use symbol::keywords; use tokenstream::TokenStream; -use util::small_vector::SmallVector; use std::mem; use std::ops::{Deref, DerefMut}; @@ -440,10 +440,10 @@ fn token_name_eq(t1: &Token, t2: &Token) -> bool { /// A `ParseResult`. Note that matches are kept track of through the items generated. fn inner_parse_loop<'a>( sess: &ParseSess, - cur_items: &mut SmallVector>, + cur_items: &mut OneVector>, next_items: &mut Vec>, - eof_items: &mut SmallVector>, - bb_items: &mut SmallVector>, + eof_items: &mut OneVector>, + bb_items: &mut OneVector>, token: &Token, span: syntax_pos::Span, ) -> ParseResult<()> { @@ -644,15 +644,15 @@ pub fn parse( // This MatcherPos instance is allocated on the stack. All others -- and // there are frequently *no* others! -- are allocated on the heap. let mut initial = initial_matcher_pos(ms, parser.span.lo()); - let mut cur_items = SmallVector::one(MatcherPosHandle::Ref(&mut initial)); + let mut cur_items = OneVector::one(MatcherPosHandle::Ref(&mut initial)); let mut next_items = Vec::new(); loop { // Matcher positions black-box parsed by parser.rs (`parser`) - let mut bb_items = SmallVector::new(); + let mut bb_items = OneVector::new(); // Matcher positions that would be valid if the macro invocation was over now - let mut eof_items = SmallVector::new(); + let mut eof_items = OneVector::new(); assert!(next_items.is_empty()); // Process `cur_items` until either we have finished the input or we need to get some diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs index 1cdb6b0e5c902..d451227e77cf3 100644 --- a/src/libsyntax/ext/tt/transcribe.rs +++ b/src/libsyntax/ext/tt/transcribe.rs @@ -15,9 +15,9 @@ use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal}; use ext::tt::quoted; use fold::noop_fold_tt; use parse::token::{self, Token, NtTT}; +use OneVector; use syntax_pos::{Span, DUMMY_SP}; use tokenstream::{TokenStream, TokenTree, Delimited}; -use util::small_vector::SmallVector; use std::rc::Rc; use rustc_data_structures::sync::Lrc; @@ -70,7 +70,7 @@ pub fn transcribe(cx: &ExtCtxt, interp: Option>>, src: Vec) -> TokenStream { - let mut stack = SmallVector::one(Frame::new(src)); + let mut stack = OneVector::one(Frame::new(src)); let interpolations = interp.unwrap_or_else(HashMap::new); /* just a convenience */ let mut repeats = Vec::new(); let mut result: Vec = Vec::new(); diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 9d5982c1e2861..3209939d9b14d 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -24,9 +24,10 @@ use syntax_pos::Span; use codemap::{Spanned, respan}; use parse::token::{self, Token}; use ptr::P; +use OneVector; use symbol::keywords; +use ThinVec; use tokenstream::*; -use util::small_vector::SmallVector; use util::move_map::MoveMap; use rustc_data_structures::sync::Lrc; @@ -60,7 +61,7 @@ pub trait Folder : Sized { noop_fold_use_tree(use_tree, self) } - fn fold_foreign_item(&mut self, ni: ForeignItem) -> SmallVector { + fn fold_foreign_item(&mut self, ni: ForeignItem) -> OneVector { noop_fold_foreign_item(ni, self) } @@ -68,7 +69,7 @@ pub trait Folder : Sized { noop_fold_foreign_item_simple(ni, self) } - fn fold_item(&mut self, i: P) -> SmallVector> { + fn fold_item(&mut self, i: P) -> OneVector> { noop_fold_item(i, self) } @@ -88,11 +89,11 @@ pub trait Folder : Sized { noop_fold_item_kind(i, self) } - fn fold_trait_item(&mut self, i: TraitItem) -> SmallVector { + fn fold_trait_item(&mut self, i: TraitItem) -> OneVector { noop_fold_trait_item(i, self) } - fn fold_impl_item(&mut self, i: ImplItem) -> SmallVector { + fn fold_impl_item(&mut self, i: ImplItem) -> OneVector { noop_fold_impl_item(i, self) } @@ -108,7 +109,7 @@ pub trait Folder : Sized { noop_fold_block(b, self) } - fn fold_stmt(&mut self, s: Stmt) -> SmallVector { + fn fold_stmt(&mut self, s: Stmt) -> OneVector { noop_fold_stmt(s, self) } @@ -960,8 +961,8 @@ pub fn noop_fold_item_kind(i: ItemKind, folder: &mut T) -> ItemKind { } pub fn noop_fold_trait_item(i: TraitItem, folder: &mut T) - -> SmallVector { - SmallVector::one(TraitItem { + -> OneVector { + OneVector::one(TraitItem { id: folder.new_id(i.id), ident: folder.fold_ident(i.ident), attrs: fold_attrs(i.attrs, folder), @@ -989,8 +990,8 @@ pub fn noop_fold_trait_item(i: TraitItem, folder: &mut T) } pub fn noop_fold_impl_item(i: ImplItem, folder: &mut T) - -> SmallVector { - SmallVector::one(ImplItem { + -> OneVector { + OneVector::one(ImplItem { id: folder.new_id(i.id), vis: folder.fold_vis(i.vis), ident: folder.fold_ident(i.ident), @@ -1065,8 +1066,8 @@ pub fn noop_fold_crate(Crate {module, attrs, span}: Crate, } // fold one item into possibly many items -pub fn noop_fold_item(i: P, folder: &mut T) -> SmallVector> { - SmallVector::one(i.map(|i| folder.fold_item_simple(i))) +pub fn noop_fold_item(i: P, folder: &mut T) -> OneVector> { + OneVector::one(i.map(|i| folder.fold_item_simple(i))) } // fold one item into exactly one item @@ -1087,8 +1088,8 @@ pub fn noop_fold_item_simple(Item {id, ident, attrs, node, vis, span, } pub fn noop_fold_foreign_item(ni: ForeignItem, folder: &mut T) --> SmallVector { - SmallVector::one(folder.fold_foreign_item_simple(ni)) +-> OneVector { + OneVector::one(folder.fold_foreign_item_simple(ni)) } pub fn noop_fold_foreign_item_simple(ni: ForeignItem, folder: &mut T) -> ForeignItem { @@ -1366,7 +1367,7 @@ pub fn noop_fold_exprs(es: Vec>, folder: &mut T) -> Vec(Stmt {node, span, id}: Stmt, folder: &mut T) -> SmallVector { +pub fn noop_fold_stmt(Stmt {node, span, id}: Stmt, folder: &mut T) -> OneVector { let id = folder.new_id(id); let span = folder.new_span(span); noop_fold_stmt_kind(node, folder).into_iter().map(|node| { @@ -1374,9 +1375,9 @@ pub fn noop_fold_stmt(Stmt {node, span, id}: Stmt, folder: &mut T) -> }).collect() } -pub fn noop_fold_stmt_kind(node: StmtKind, folder: &mut T) -> SmallVector { +pub fn noop_fold_stmt_kind(node: StmtKind, folder: &mut T) -> OneVector { match node { - StmtKind::Local(local) => SmallVector::one(StmtKind::Local(folder.fold_local(local))), + StmtKind::Local(local) => OneVector::one(StmtKind::Local(folder.fold_local(local))), StmtKind::Item(item) => folder.fold_item(item).into_iter().map(StmtKind::Item).collect(), StmtKind::Expr(expr) => { folder.fold_opt_expr(expr).into_iter().map(StmtKind::Expr).collect() @@ -1384,7 +1385,7 @@ pub fn noop_fold_stmt_kind(node: StmtKind, folder: &mut T) -> SmallVe StmtKind::Semi(expr) => { folder.fold_opt_expr(expr).into_iter().map(StmtKind::Semi).collect() } - StmtKind::Mac(mac) => SmallVector::one(StmtKind::Mac(mac.map(|(mac, semi, attrs)| { + StmtKind::Mac(mac) => OneVector::one(StmtKind::Mac(mac.map(|(mac, semi, attrs)| { (folder.fold_mac(mac), semi, fold_attrs(attrs.into(), folder).into()) }))), } diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 0c105865e0c2e..e842d8038b240 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -44,6 +44,8 @@ extern crate serialize as rustc_serialize; // used by deriving use rustc_data_structures::sync::Lock; use rustc_data_structures::bitvec::BitVector; +pub use rustc_data_structures::small_vec::OneVector; +pub use rustc_data_structures::thin_vec::ThinVec; use ast::AttrId; // A variant of 'try!' that panics on an Err. This is used as a crutch on the @@ -123,12 +125,8 @@ pub mod util { pub mod parser; #[cfg(test)] pub mod parser_testing; - pub mod small_vector; pub mod move_map; - mod thin_vec; - pub use self::thin_vec::ThinVec; - mod rc_slice; pub use self::rc_slice::RcSlice; } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 9011b6e48b974..27b0f23315180 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -53,9 +53,9 @@ use util::parser::{AssocOp, Fixity}; use print::pprust; use ptr::P; use parse::PResult; +use ThinVec; use tokenstream::{self, Delimited, ThinTokenStream, TokenTree, TokenStream}; use symbol::{Symbol, keywords}; -use util::ThinVec; use std::borrow::Cow; use std::cmp; diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index d8b8d13a38c2e..41701f4b9c94d 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -38,8 +38,9 @@ use parse::{token, ParseSess}; use print::pprust; use ast::{self, Ident}; use ptr::P; +use OneVector; use symbol::{self, Symbol, keywords}; -use util::small_vector::SmallVector; +use ThinVec; enum ShouldPanic { No, @@ -115,7 +116,7 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> { folded } - fn fold_item(&mut self, i: P) -> SmallVector> { + fn fold_item(&mut self, i: P) -> OneVector> { let ident = i.ident; if ident.name != keywords::Invalid.name() { self.cx.path.push(ident); @@ -182,7 +183,7 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> { if ident.name != keywords::Invalid.name() { self.cx.path.pop(); } - SmallVector::one(P(item)) + OneVector::one(P(item)) } fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { mac } @@ -194,7 +195,7 @@ struct EntryPointCleaner { } impl fold::Folder for EntryPointCleaner { - fn fold_item(&mut self, i: P) -> SmallVector> { + fn fold_item(&mut self, i: P) -> OneVector> { self.depth += 1; let folded = fold::noop_fold_item(i, self).expect_one("noop did something"); self.depth -= 1; @@ -234,7 +235,7 @@ impl fold::Folder for EntryPointCleaner { EntryPointType::OtherMain => folded, }; - SmallVector::one(folded) + OneVector::one(folded) } fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { mac } @@ -675,10 +676,10 @@ fn mk_test_descs(cx: &TestCtxt) -> P { mk_test_desc_and_fn_rec(cx, test) }).collect()), span: DUMMY_SP, - attrs: ast::ThinVec::new(), + attrs: ThinVec::new(), })), span: DUMMY_SP, - attrs: ast::ThinVec::new(), + attrs: ThinVec::new(), }) } diff --git a/src/libsyntax/util/move_map.rs b/src/libsyntax/util/move_map.rs index 8cc37afa354ff..eb2c5a2458c15 100644 --- a/src/libsyntax/util/move_map.rs +++ b/src/libsyntax/util/move_map.rs @@ -9,8 +9,7 @@ // except according to those terms. use std::ptr; - -use util::small_vector::SmallVector; +use OneVector; pub trait MoveMap: Sized { fn move_map(self, mut f: F) -> Self where F: FnMut(T) -> T { @@ -78,7 +77,7 @@ impl MoveMap for ::ptr::P<[T]> { } } -impl MoveMap for SmallVector { +impl MoveMap for OneVector { fn move_flat_map(mut self, mut f: F) -> Self where F: FnMut(T) -> I, I: IntoIterator diff --git a/src/libsyntax/util/small_vector.rs b/src/libsyntax/util/small_vector.rs deleted file mode 100644 index 31e675836fc72..0000000000000 --- a/src/libsyntax/util/small_vector.rs +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use rustc_data_structures::small_vec::SmallVec; - -pub type SmallVector = SmallVec<[T; 1]>; - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_len() { - let v: SmallVector = SmallVector::new(); - assert_eq!(0, v.len()); - - assert_eq!(1, SmallVector::one(1).len()); - assert_eq!(5, SmallVector::many(vec![1, 2, 3, 4, 5]).len()); - } - - #[test] - fn test_push_get() { - let mut v = SmallVector::new(); - v.push(1); - assert_eq!(1, v.len()); - assert_eq!(1, v[0]); - v.push(2); - assert_eq!(2, v.len()); - assert_eq!(2, v[1]); - v.push(3); - assert_eq!(3, v.len()); - assert_eq!(3, v[2]); - } - - #[test] - fn test_from_iter() { - let v: SmallVector = (vec![1, 2, 3]).into_iter().collect(); - assert_eq!(3, v.len()); - assert_eq!(1, v[0]); - assert_eq!(2, v[1]); - assert_eq!(3, v[2]); - } - - #[test] - fn test_move_iter() { - let v = SmallVector::new(); - let v: Vec = v.into_iter().collect(); - assert_eq!(v, Vec::new()); - - let v = SmallVector::one(1); - assert_eq!(v.into_iter().collect::>(), [1]); - - let v = SmallVector::many(vec![1, 2, 3]); - assert_eq!(v.into_iter().collect::>(), [1, 2, 3]); - } - - #[test] - #[should_panic] - fn test_expect_one_zero() { - let _: isize = SmallVector::new().expect_one(""); - } - - #[test] - #[should_panic] - fn test_expect_one_many() { - SmallVector::many(vec![1, 2]).expect_one(""); - } - - #[test] - fn test_expect_one_one() { - assert_eq!(1, SmallVector::one(1).expect_one("")); - assert_eq!(1, SmallVector::many(vec![1]).expect_one("")); - } -} diff --git a/src/libsyntax_ext/asm.rs b/src/libsyntax_ext/asm.rs index 4ebb1fcb65393..026ddccd7be97 100644 --- a/src/libsyntax_ext/asm.rs +++ b/src/libsyntax_ext/asm.rs @@ -12,6 +12,8 @@ // use self::State::*; +use rustc_data_structures::thin_vec::ThinVec; + use syntax::ast; use syntax::ext::base; use syntax::ext::base::*; @@ -263,6 +265,6 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, ctxt: cx.backtrace(), })), span: sp, - attrs: ast::ThinVec::new(), + attrs: ThinVec::new(), })) } diff --git a/src/libsyntax_ext/concat_idents.rs b/src/libsyntax_ext/concat_idents.rs index a3c5c3df66e4c..c8cc11e43545a 100644 --- a/src/libsyntax_ext/concat_idents.rs +++ b/src/libsyntax_ext/concat_idents.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use rustc_data_structures::thin_vec::ThinVec; + use syntax::ast; use syntax::ext::base::*; use syntax::ext::base; @@ -68,7 +70,7 @@ pub fn expand_syntax_ext<'cx>(cx: &'cx mut ExtCtxt, id: ast::DUMMY_NODE_ID, node: ast::ExprKind::Path(None, ast::Path::from_ident(self.ident)), span: self.ident.span, - attrs: ast::ThinVec::new(), + attrs: ThinVec::new(), })) } diff --git a/src/libsyntax_ext/deriving/debug.rs b/src/libsyntax_ext/deriving/debug.rs index c2a7dea331673..df9c351ef1c95 100644 --- a/src/libsyntax_ext/deriving/debug.rs +++ b/src/libsyntax_ext/deriving/debug.rs @@ -12,6 +12,8 @@ use deriving::path_std; use deriving::generic::*; use deriving::generic::ty::*; +use rustc_data_structures::thin_vec::ThinVec; + use syntax::ast::{self, Ident}; use syntax::ast::{Expr, MetaItem}; use syntax::ext::base::{Annotatable, ExtCtxt}; @@ -139,7 +141,7 @@ fn stmt_let_undescore(cx: &mut ExtCtxt, sp: Span, expr: P) -> ast::St init: Some(expr), id: ast::DUMMY_NODE_ID, span: sp, - attrs: ast::ThinVec::new(), + attrs: ThinVec::new(), }); ast::Stmt { id: ast::DUMMY_NODE_ID, diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index e0f985c26c7a1..41759c375b8ee 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -191,6 +191,7 @@ use std::cell::RefCell; use std::iter; use std::vec; +use rustc_data_structures::thin_vec::ThinVec; use rustc_target::spec::abi::Abi; use syntax::ast::{self, BinOpKind, EnumDef, Expr, Generics, Ident, PatKind}; use syntax::ast::{VariantData, GenericParamKind, GenericArg}; @@ -1624,7 +1625,7 @@ impl<'a> TraitDef<'a> { ident: ident.unwrap(), pat, is_shorthand: false, - attrs: ast::ThinVec::new(), + attrs: ThinVec::new(), }, } }) diff --git a/src/libsyntax_ext/global_asm.rs b/src/libsyntax_ext/global_asm.rs index 40ecd6e1519c3..7290b701e4dec 100644 --- a/src/libsyntax_ext/global_asm.rs +++ b/src/libsyntax_ext/global_asm.rs @@ -18,6 +18,8 @@ /// LLVM's `module asm "some assembly here"`. All of LLVM's caveats /// therefore apply. +use rustc_data_structures::small_vec::OneVector; + use syntax::ast; use syntax::codemap::respan; use syntax::ext::base; @@ -28,8 +30,6 @@ use syntax::symbol::Symbol; use syntax_pos::Span; use syntax::tokenstream; -use syntax::util::small_vector::SmallVector; - pub const MACRO: &'static str = "global_asm"; pub fn expand_global_asm<'cx>(cx: &'cx mut ExtCtxt, @@ -52,7 +52,7 @@ pub fn expand_global_asm<'cx>(cx: &'cx mut ExtCtxt, None => return DummyResult::any(sp), }; - MacEager::items(SmallVector::one(P(ast::Item { + MacEager::items(OneVector::one(P(ast::Item { ident: ast::Ident::with_empty_ctxt(Symbol::intern("")), attrs: Vec::new(), id: ast::DUMMY_NODE_ID, diff --git a/src/test/run-pass-fulldeps/auxiliary/issue-16723.rs b/src/test/run-pass-fulldeps/auxiliary/issue-16723.rs index 7f8a741465b30..ff5d9a59bfa00 100644 --- a/src/test/run-pass-fulldeps/auxiliary/issue-16723.rs +++ b/src/test/run-pass-fulldeps/auxiliary/issue-16723.rs @@ -15,12 +15,12 @@ extern crate syntax; extern crate rustc; +extern crate rustc_data_structures; extern crate rustc_plugin; extern crate syntax_pos; -use syntax::ast; +use rustc_data_structures::small_vec::OneVector; use syntax::ext::base::{ExtCtxt, MacResult, MacEager}; -use syntax::util::small_vector::SmallVector; use syntax::tokenstream; use rustc_plugin::Registry; @@ -31,7 +31,7 @@ pub fn plugin_registrar(reg: &mut Registry) { fn expand(cx: &mut ExtCtxt, _: syntax_pos::Span, _: &[tokenstream::TokenTree]) -> Box { - MacEager::items(SmallVector::many(vec![ + MacEager::items(OneVector::many(vec![ quote_item!(cx, struct Struct1;).unwrap(), quote_item!(cx, struct Struct2;).unwrap() ])) diff --git a/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs b/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs index bbd81e790b838..3da50f1696545 100644 --- a/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs +++ b/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs @@ -30,8 +30,10 @@ #![feature(rustc_private)] +extern crate rustc_data_structures; extern crate syntax; +use rustc_data_structures::thin_vec::ThinVec; use syntax::ast::*; use syntax::codemap::{Spanned, DUMMY_SP, FileName}; use syntax::codemap::FilePathMapping; @@ -39,7 +41,6 @@ use syntax::fold::{self, Folder}; use syntax::parse::{self, ParseSess}; use syntax::print::pprust; use syntax::ptr::P; -use syntax::util::ThinVec; fn parse_expr(ps: &ParseSess, src: &str) -> P { From 5187ad143975ca082d7e4780967783cfc33de565 Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 6 Aug 2018 21:15:15 +0200 Subject: [PATCH 06/20] Correctly identify named early bound regions. --- .../nice_region_error/named_anon_conflict.rs | 2 +- src/librustc/ty/mod.rs | 8 ++++- .../error_reporting/region_name.rs | 8 +++-- src/test/ui/nll/issue-52742.rs | 30 +++++++++++++++++++ src/test/ui/nll/issue-52742.stderr | 12 ++++++++ 5 files changed, 56 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/nll/issue-52742.rs create mode 100644 src/test/ui/nll/issue-52742.stderr diff --git a/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs index 51abfa2505ab5..457e20eddf7c5 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs @@ -127,7 +127,7 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> { ty::BrNamed(..) => true, _ => false, }, - ty::ReEarlyBound(_) => true, + ty::ReEarlyBound(ebr) => ebr.has_name(), _ => false, } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 4fda3bdca3dfc..d7e30b0ca7143 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -51,7 +51,7 @@ use std::{mem, ptr}; use syntax::ast::{self, DUMMY_NODE_ID, Name, Ident, NodeId}; use syntax::attr; use syntax::ext::hygiene::Mark; -use syntax::symbol::{Symbol, LocalInternedString, InternedString}; +use syntax::symbol::{keywords, Symbol, LocalInternedString, InternedString}; use syntax_pos::{DUMMY_SP, Span}; use rustc_data_structures::accumulate_vec::IntoIter as AccIntoIter; @@ -824,6 +824,12 @@ impl ty::EarlyBoundRegion { pub fn to_bound_region(&self) -> ty::BoundRegion { ty::BoundRegion::BrNamed(self.def_id, self.name) } + + /// Does this early bound region have a name? Early bound regions normally + /// always have names except when using anonymous lifetimes (`'_`). + pub fn has_name(&self) -> bool { + self.name != keywords::UnderscoreLifetime.name().as_interned_str() + } } #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs index 79165276430d3..e2937e3048ccc 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs @@ -94,8 +94,12 @@ impl<'tcx> RegionInferenceContext<'tcx> { debug!("give_region_a_name: error_region = {:?}", error_region); match error_region { ty::ReEarlyBound(ebr) => { - self.highlight_named_span(tcx, error_region, &ebr.name, diag); - Some(ebr.name) + if ebr.has_name() { + self.highlight_named_span(tcx, error_region, &ebr.name, diag); + Some(ebr.name) + } else { + None + } }, ty::ReStatic => Some(keywords::StaticLifetime.name().as_interned_str()), diff --git a/src/test/ui/nll/issue-52742.rs b/src/test/ui/nll/issue-52742.rs new file mode 100644 index 0000000000000..84d06a1d20aac --- /dev/null +++ b/src/test/ui/nll/issue-52742.rs @@ -0,0 +1,30 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(nll)] +#![feature(in_band_lifetimes)] + +struct Foo<'a, 'b> { + x: &'a u32, + y: &'b u32, +} + +struct Bar<'b> { + z: &'b u32 +} + +impl Foo<'_, '_> { + fn take_bar(&mut self, b: Bar<'_>) { + self.y = b.z + //~^ ERROR unsatisfied lifetime constraints + } +} + +fn main() { } diff --git a/src/test/ui/nll/issue-52742.stderr b/src/test/ui/nll/issue-52742.stderr new file mode 100644 index 0000000000000..89c235c4e8f9e --- /dev/null +++ b/src/test/ui/nll/issue-52742.stderr @@ -0,0 +1,12 @@ +error: unsatisfied lifetime constraints + --> $DIR/issue-52742.rs:25:9 + | +LL | fn take_bar(&mut self, b: Bar<'_>) { + | --------- -- let's call this `'1` + | | + | lifetime `'2` appears in this type +LL | self.y = b.z + | ^^^^^^^^^^^^ requires that `'1` must outlive `'2` + +error: aborting due to previous error + From 2403d911e41057dd42878de1e6b78c8775f2840b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 6 Aug 2018 16:41:35 -0400 Subject: [PATCH 07/20] remove `let x = baz` which was obscuring the real error --- ...-push-one-existing-name-early-bound.nll.stderr | 15 ++++++++------- .../ex2a-push-one-existing-name-early-bound.rs | 1 - 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/test/ui/lifetime-errors/ex2a-push-one-existing-name-early-bound.nll.stderr b/src/test/ui/lifetime-errors/ex2a-push-one-existing-name-early-bound.nll.stderr index c5f3510fa0ed2..ad8b4edbf2db4 100644 --- a/src/test/ui/lifetime-errors/ex2a-push-one-existing-name-early-bound.nll.stderr +++ b/src/test/ui/lifetime-errors/ex2a-push-one-existing-name-early-bound.nll.stderr @@ -4,14 +4,15 @@ warning: not reporting region error due to nll LL | x.push(y); //~ ERROR explicit lifetime required | ^ -error[E0282]: type annotations needed - --> $DIR/ex2a-push-one-existing-name-early-bound.rs:20:9 +error[E0621]: explicit lifetime required in the type of `y` + --> $DIR/ex2a-push-one-existing-name-early-bound.rs:17:5 | -LL | let x = baz; - | - ^^^ cannot infer type for `T` - | | - | consider giving `x` a type +LL | fn baz<'a, 'b, T>(x: &mut Vec<&'a T>, y: &T) + | - consider changing the type of `y` to `&'a T` +... +LL | x.push(y); //~ ERROR explicit lifetime required + | ^^^^^^^^^ lifetime `'a` required error: aborting due to previous error -For more information about this error, try `rustc --explain E0282`. +For more information about this error, try `rustc --explain E0621`. diff --git a/src/test/ui/lifetime-errors/ex2a-push-one-existing-name-early-bound.rs b/src/test/ui/lifetime-errors/ex2a-push-one-existing-name-early-bound.rs index 18a720f345d7f..cad0a3c6ac13d 100644 --- a/src/test/ui/lifetime-errors/ex2a-push-one-existing-name-early-bound.rs +++ b/src/test/ui/lifetime-errors/ex2a-push-one-existing-name-early-bound.rs @@ -17,5 +17,4 @@ fn baz<'a, 'b, T>(x: &mut Vec<&'a T>, y: &T) x.push(y); //~ ERROR explicit lifetime required } fn main() { -let x = baz; } From b13e3f87709031be5c599ff23d73f981d04416fd Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Mon, 6 Aug 2018 21:42:26 +0100 Subject: [PATCH 08/20] Name return type in free region messages --- .../error_reporting/region_name.rs | 35 +++++++++++++------ ...1-does-not-trigger-for-closures.nll.stderr | 8 ++--- src/test/ui/issue-40510-1.nll.stderr | 4 +-- src/test/ui/issue-40510-3.nll.stderr | 4 +-- src/test/ui/issue-49824.nll.stderr | 4 +-- src/test/ui/nll/issue-48238.stderr | 4 +-- 6 files changed, 36 insertions(+), 23 deletions(-) diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs index 6a21e00258845..8c2a5f19038bb 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs @@ -73,7 +73,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { }) .or_else(|| { self.give_name_if_anonymous_region_appears_in_output( - infcx.tcx, mir, mir_def_id, fr, counter, diag) + infcx, mir, mir_def_id, fr, counter, diag) }) .unwrap_or_else(|| span_bug!(mir.span, "can't make a name for free region {:?}", fr)) } @@ -577,38 +577,51 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// or be early bound (named, not in argument). fn give_name_if_anonymous_region_appears_in_output( &self, - tcx: TyCtxt<'_, '_, 'tcx>, + infcx: &InferCtxt<'_, '_, 'tcx>, mir: &Mir<'tcx>, mir_def_id: DefId, fr: RegionVid, counter: &mut usize, diag: &mut DiagnosticBuilder<'_>, ) -> Option { + let tcx = infcx.tcx; + let return_ty = self.universal_regions.unnormalized_output_ty; debug!( "give_name_if_anonymous_region_appears_in_output: return_ty = {:?}", return_ty ); - if !tcx.any_free_region_meets(&return_ty, |r| r.to_region_vid() == fr) { + if !infcx.tcx.any_free_region_meets(&return_ty, |r| r.to_region_vid() == fr) { return None; } - let mir_node_id = tcx.hir.as_local_node_id(mir_def_id).expect("non-local mir"); - let args_span = if let hir::ExprKind::Closure(_, _, _, span, _) + let type_name = with_highlight_region(fr, *counter, || { + infcx.extract_type_name(&return_ty) + }); + + let mir_node_id = tcx.hir.as_local_node_id(mir_def_id).expect("non-local mir"); + + let (return_span, mir_description) = if let hir::ExprKind::Closure(_, _, _, span, gen_move) = tcx.hir.expect_expr(mir_node_id).node { - span + ( + tcx.sess.codemap().end_point(span), + if gen_move.is_some() { " of generator" } else { " of closure" } + ) } else { - mir.span + // unreachable? + (mir.span, "") }; - let region_name = self.synthesize_region_name(counter); diag.span_label( - args_span, - format!("lifetime `{}` appears in return type", region_name), + return_span, + format!("return type{} is {}", mir_description, type_name), ); - Some(region_name) + // This counter value will already have been used, so this function will increment it + // so the next value will be used next and return the region name that would have been + // used. + Some(self.synthesize_region_name(counter)) } /// Create a synthetic region named `'1`, incrementing the diff --git a/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.nll.stderr b/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.nll.stderr index 27a51cb83fb25..3f9104373d6ef 100644 --- a/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.nll.stderr +++ b/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.nll.stderr @@ -8,10 +8,10 @@ error: unsatisfied lifetime constraints --> $DIR/E0621-does-not-trigger-for-closures.rs:25:26 | LL | invoke(&x, |a, b| if a > b { a } else { b }); //~ ERROR E0495 - | ------ ^^^^^ requires that `'1` must outlive `'2` - | | | - | | has type `&'1 i32` - | lifetime `'2` appears in return type + | -- ^^^^^ requires that `'1` must outlive `'2` + | || + | |return type of closure is &'2 i32 + | has type `&'1 i32` error: aborting due to previous error diff --git a/src/test/ui/issue-40510-1.nll.stderr b/src/test/ui/issue-40510-1.nll.stderr index 7eb6a0e7fb226..6c77bcb275724 100644 --- a/src/test/ui/issue-40510-1.nll.stderr +++ b/src/test/ui/issue-40510-1.nll.stderr @@ -3,9 +3,9 @@ error: unsatisfied lifetime constraints | LL | || { | -- - | | + | || + | |return type of closure is &'2 mut std::boxed::Box<()> | lifetime `'1` represents this closure's body - | lifetime `'2` appears in return type LL | &mut x | ^^^^^^ return requires that `'1` must outlive `'2` | diff --git a/src/test/ui/issue-40510-3.nll.stderr b/src/test/ui/issue-40510-3.nll.stderr index ae3ae3a27ab20..8aeef86c2e86b 100644 --- a/src/test/ui/issue-40510-3.nll.stderr +++ b/src/test/ui/issue-40510-3.nll.stderr @@ -3,9 +3,9 @@ error: unsatisfied lifetime constraints | LL | || { | -- - | | + | || + | |return type of closure is [closure@$DIR/issue-40510-3.rs:18:9: 20:10 x:&'2 mut std::vec::Vec<()>] | lifetime `'1` represents this closure's body - | lifetime `'2` appears in return type LL | / || { LL | | x.push(()) LL | | } diff --git a/src/test/ui/issue-49824.nll.stderr b/src/test/ui/issue-49824.nll.stderr index 432036c9d90ce..fb4bed76a717f 100644 --- a/src/test/ui/issue-49824.nll.stderr +++ b/src/test/ui/issue-49824.nll.stderr @@ -3,9 +3,9 @@ error: unsatisfied lifetime constraints | LL | || { | -- - | | + | || + | |return type of closure is [closure@$DIR/issue-49824.rs:22:9: 24:10 x:&'2 mut i32] | lifetime `'1` represents this closure's body - | lifetime `'2` appears in return type LL | / || { LL | | let _y = &mut x; LL | | } diff --git a/src/test/ui/nll/issue-48238.stderr b/src/test/ui/nll/issue-48238.stderr index 4baa904442464..84d0730025a5c 100644 --- a/src/test/ui/nll/issue-48238.stderr +++ b/src/test/ui/nll/issue-48238.stderr @@ -3,9 +3,9 @@ error: unsatisfied lifetime constraints | LL | move || use_val(&orig); //~ ERROR | ------- ^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2` - | | + | | | + | | return type of closure is &'2 u8 | lifetime `'1` represents this closure's body - | lifetime `'2` appears in return type | = note: closure implements `Fn`, so references to captured variables can't escape the closure From 12037ff14869ae3631f9fa7777c081fda8edbf0c Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 6 Aug 2018 23:09:36 +0200 Subject: [PATCH 09/20] Fallback to 'has type' error messages rather than 'lifetime appears in type'. --- .../error_reporting/region_name.rs | 34 +++++-------------- src/test/ui/nll/issue-52742.stderr | 2 +- 2 files changed, 10 insertions(+), 26 deletions(-) diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs index e2937e3048ccc..7ccea451c501b 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs @@ -208,17 +208,14 @@ impl<'tcx> RegionInferenceContext<'tcx> { return Some(region_name); } - let (_argument_name, argument_span) = self.get_argument_name_and_span_for_region( - mir, argument_index); - - let region_name = self.synthesize_region_name(counter); - - diag.span_label( - argument_span, - format!("lifetime `{}` appears in this argument", region_name,), - ); - - Some(region_name) + self.give_name_if_we_cannot_match_hir_ty( + infcx, + mir, + fr, + arg_ty, + counter, + diag, + ) } fn give_name_if_we_can_match_hir_ty_from_argument( @@ -336,14 +333,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { search_stack.push((argument_ty, argument_hir_ty)); - let mut closest_match: &hir::Ty = argument_hir_ty; - while let Some((ty, hir_ty)) = search_stack.pop() { - // While we search, also track the closet match. - if tcx.any_free_region_meets(&ty, |r| r.to_region_vid() == needle_fr) { - closest_match = hir_ty; - } - match (&ty.sty, &hir_ty.node) { // Check if the `argument_ty` is `&'X ..` where `'X` // is the region we are looking for -- if so, and we have a `&T` @@ -418,13 +408,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } - let region_name = self.synthesize_region_name(counter); - diag.span_label( - closest_match.span, - format!("lifetime `{}` appears in this type", region_name), - ); - - return Some(region_name); + return None; } /// We've found an enum/struct/union type with the substitutions diff --git a/src/test/ui/nll/issue-52742.stderr b/src/test/ui/nll/issue-52742.stderr index 89c235c4e8f9e..d1b830b9dfc29 100644 --- a/src/test/ui/nll/issue-52742.stderr +++ b/src/test/ui/nll/issue-52742.stderr @@ -4,7 +4,7 @@ error: unsatisfied lifetime constraints LL | fn take_bar(&mut self, b: Bar<'_>) { | --------- -- let's call this `'1` | | - | lifetime `'2` appears in this type + | has type `&mut Foo<'_, '2>` LL | self.y = b.z | ^^^^^^^^^^^^ requires that `'1` must outlive `'2` From 44d32d441342aac1eb802c4379aa4eb324c90679 Mon Sep 17 00:00:00 2001 From: ljedrz Date: Fri, 27 Jul 2018 13:20:13 +0200 Subject: [PATCH 10/20] Avoid unnecessary pattern matching against Option and Result --- src/librustc/traits/auto_trait.rs | 5 +---- src/librustc/traits/error_reporting.rs | 2 +- src/librustc/traits/query/outlives_bounds.rs | 2 +- src/librustc/traits/select.rs | 4 ++-- src/librustc/ty/instance.rs | 2 +- src/librustc_errors/emitter.rs | 2 +- src/librustc_mir/borrow_check/error_reporting.rs | 4 ++-- src/librustc_resolve/lib.rs | 4 ++-- src/librustc_save_analysis/json_dumper.rs | 2 +- src/librustc_typeck/check/method/probe.rs | 5 +++-- src/librustc_typeck/check/mod.rs | 2 +- src/librustdoc/core.rs | 2 +- src/librustdoc/html/highlight.rs | 2 +- src/librustdoc/html/markdown.rs | 2 +- src/libsyntax/test.rs | 2 +- src/libsyntax_ext/env.rs | 2 +- 16 files changed, 21 insertions(+), 23 deletions(-) diff --git a/src/librustc/traits/auto_trait.rs b/src/librustc/traits/auto_trait.rs index cfe3583a9806f..1ffe8157a0fb4 100644 --- a/src/librustc/traits/auto_trait.rs +++ b/src/librustc/traits/auto_trait.rs @@ -681,10 +681,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { } } &ty::Predicate::RegionOutlives(ref binder) => { - if let Err(_) = select - .infcx() - .region_outlives_predicate(&dummy_cause, binder) - { + if select.infcx().region_outlives_predicate(&dummy_cause, binder).is_err() { return false; } } diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index c04785aac2095..a02b63755dc12 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -143,7 +143,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // Eventually I'll need to implement param-env-aware // `Γ₁ ⊦ φ₁ => Γ₂ ⊦ φ₂` logic. let param_env = ty::ParamEnv::empty(); - if let Ok(_) = self.can_sub(param_env, error, implication) { + if self.can_sub(param_env, error, implication).is_ok() { debug!("error_implies: {:?} -> {:?} -> {:?}", cond, error, implication); return true } diff --git a/src/librustc/traits/query/outlives_bounds.rs b/src/librustc/traits/query/outlives_bounds.rs index f79ce73ad928a..0127ae423da54 100644 --- a/src/librustc/traits/query/outlives_bounds.rs +++ b/src/librustc/traits/query/outlives_bounds.rs @@ -137,7 +137,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { // variables. Process these constraints. let mut fulfill_cx = FulfillmentContext::new(); fulfill_cx.register_predicate_obligations(self, result.obligations); - if let Err(_) = fulfill_cx.select_all_or_error(self) { + if fulfill_cx.select_all_or_error(self).is_err() { self.tcx.sess.delay_span_bug( span, "implied_outlives_bounds failed to solve obligations from instantiation" diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 35184ca6a2559..1e3fe70535bcc 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1587,8 +1587,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { -> bool { assert!(!skol_trait_ref.has_escaping_regions()); - if let Err(_) = self.infcx.at(&obligation.cause, obligation.param_env) - .sup(ty::Binder::dummy(skol_trait_ref), trait_bound) { + if self.infcx.at(&obligation.cause, obligation.param_env) + .sup(ty::Binder::dummy(skol_trait_ref), trait_bound).is_err() { return false; } diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 66edbeff749f7..7329f4832f2e2 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -294,7 +294,7 @@ fn resolve_associated_item<'a, 'tcx>( }) } traits::VtableBuiltin(..) => { - if let Some(_) = tcx.lang_items().clone_trait() { + if tcx.lang_items().clone_trait().is_some() { Some(Instance { def: ty::InstanceDef::CloneShim(def_id, trait_ref.self_ty()), substs: rcvr_substs diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 09295e2c7ff00..6b1298750fba0 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -1295,7 +1295,7 @@ impl EmitterWriter { } // if we elided some lines, add an ellipsis - if let Some(_) = lines.next() { + if lines.next().is_some() { buffer.puts(row_num, max_line_num_len - 1, "...", Style::LineNumber); } else if !show_underline { draw_col_separator_no_space(&mut buffer, row_num, max_line_num_len + 1); diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index aabed6686858f..67b92d92a343d 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -138,7 +138,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { let tables = self.tcx.typeck_tables_of(id); let node_id = self.tcx.hir.as_local_node_id(id).unwrap(); let hir_id = self.tcx.hir.node_to_hir_id(node_id); - if let Some(_) = tables.closure_kind_origins().get(hir_id) { + if tables.closure_kind_origins().get(hir_id).is_some() { false } else { true @@ -735,7 +735,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { &including_downcast, )?; buf.push_str("["); - if let Err(_) = self.append_local_to_string(index, buf) { + if self.append_local_to_string(index, buf).is_err() { buf.push_str(".."); } buf.push_str("]"); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index a7fcc89f6b974..5d57390dd05af 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2698,7 +2698,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { self.label_ribs.pop(); } self.ribs[ValueNS].pop(); - if let Some(_) = anonymous_module { + if anonymous_module.is_some() { self.ribs[TypeNS].pop(); } debug!("(resolving block) leaving block"); @@ -4254,7 +4254,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { while let Some((in_module, path_segments)) = worklist.pop() { // abort if the module is already found - if let Some(_) = result { break; } + if result.is_some() { break; } self.populate_module_if_necessary(in_module); diff --git a/src/librustc_save_analysis/json_dumper.rs b/src/librustc_save_analysis/json_dumper.rs index 2fe7d73de8aa0..d2e52f98238dd 100644 --- a/src/librustc_save_analysis/json_dumper.rs +++ b/src/librustc_save_analysis/json_dumper.rs @@ -39,7 +39,7 @@ pub struct WriteOutput<'b, W: Write + 'b> { impl<'b, W: Write> DumpOutput for WriteOutput<'b, W> { fn dump(&mut self, result: &Analysis) { - if let Err(_) = write!(self.output, "{}", as_json(&result)) { + if write!(self.output, "{}", as_json(&result)).is_err() { error!("Error writing output"); } } diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 8d8482208b97d..68e851446dc96 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -758,8 +758,9 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { self.span, infer::FnCall, &fty); if let Some(self_ty) = self_ty { - if let Err(_) = self.at(&ObligationCause::dummy(), self.param_env) - .sup(fty.inputs()[0], self_ty) + if self.at(&ObligationCause::dummy(), self.param_env) + .sup(fty.inputs()[0], self_ty) + .is_err() { return false } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 8c47df8b04221..9b6772e2dbb21 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3915,7 +3915,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } hir::ExprKind::Continue(destination) => { - if let Ok(_) = destination.target_id { + if destination.target_id.is_ok() { tcx.types.never } else { // There was an error, make typecheck fail diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 86e5bbeab706a..68e4618328077 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -486,7 +486,7 @@ pub fn run_core(search_paths: SearchPaths, &name, &output_filenames, |tcx, analysis, _, result| { - if let Err(_) = result { + if result.is_err() { sess.fatal("Compilation failed, aborting rustdoc"); } diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 73d7a9ab8599d..ff2cc35fce807 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -44,7 +44,7 @@ pub fn render_with_highlighting(src: &str, class: Option<&str>, write_header(class, &mut out).unwrap(); let mut classifier = Classifier::new(lexer::StringReader::new(&sess, fm, None), sess.codemap()); - if let Err(_) = classifier.write_source(&mut out) { + if classifier.write_source(&mut out).is_err() { return format!("
{}
", src); } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index b22e239e20a0e..c104b88334061 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -625,7 +625,7 @@ impl LangString { data.no_run = true; } x if allow_error_code_check && x.starts_with("E") && x.len() == 5 => { - if let Ok(_) = x[1..].parse::() { + if x[1..].parse::().is_ok() { data.error_codes.push(x.to_owned()); seen_rust_tags = !seen_other_tags || seen_rust_tags; } else { diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index d8b8d13a38c2e..62dd00387d3ab 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -631,7 +631,7 @@ fn path_name_i(idents: &[Ident]) -> String { let mut idents_iter = idents.iter().peekable(); while let Some(ident) = idents_iter.next() { path_name.push_str(&ident.as_str()); - if let Some(_) = idents_iter.peek() { + if idents_iter.peek().is_some() { path_name.push_str("::") } } diff --git a/src/libsyntax_ext/env.rs b/src/libsyntax_ext/env.rs index 3c34bf496da59..8f26b2402aadf 100644 --- a/src/libsyntax_ext/env.rs +++ b/src/libsyntax_ext/env.rs @@ -81,7 +81,7 @@ pub fn expand_env<'cx>(cx: &'cx mut ExtCtxt, } }; - if let Some(_) = exprs.next() { + if exprs.next().is_some() { cx.span_err(sp, "env! takes 1 or 2 arguments"); return DummyResult::expr(sp); } From 43850e0bee0a23147b706206295c0e160ac3544f Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 6 Aug 2018 21:06:00 +0200 Subject: [PATCH 11/20] Special case error message for thread-local statics. --- .../borrow_check/error_reporting.rs | 48 +++++++++++++++++-- src/librustc_mir/borrow_check/mod.rs | 9 +--- src/librustc_mir/diagnostics.rs | 23 +++++++++ src/librustc_mir/util/borrowck_errors.rs | 16 +++++++ ...-thread-local-static-borrow-outlives-fn.rs | 2 +- src/test/ui/issue-17954.ast.nll.stderr | 14 ------ src/test/ui/issue-17954.mir.stderr | 14 ------ src/test/ui/issue-17954.nll.stderr | 12 +++++ src/test/ui/issue-17954.rs | 15 ++---- ...ue-17954.ast.stderr => issue-17954.stderr} | 2 +- 10 files changed, 104 insertions(+), 51 deletions(-) delete mode 100644 src/test/ui/issue-17954.ast.nll.stderr delete mode 100644 src/test/ui/issue-17954.mir.stderr create mode 100644 src/test/ui/issue-17954.nll.stderr rename src/test/ui/{issue-17954.ast.stderr => issue-17954.stderr} (92%) diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index aabed6686858f..b55a7ff068c47 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -412,6 +412,12 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { .insert((root_place.clone(), borrow_span)); let mut err = match &self.describe_place(&borrow.borrowed_place) { + Some(_) if self.is_place_thread_local(root_place) => { + self.report_thread_local_value_does_not_live_long_enough( + drop_span, + borrow_span, + ) + } Some(name) => self.report_local_value_does_not_live_long_enough( context, name, @@ -455,9 +461,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { context, name, scope_tree, borrow, drop_span, borrow_span ); - let tcx = self.tcx; - let mut err = - tcx.path_does_not_live_long_enough(borrow_span, &format!("`{}`", name), Origin::Mir); + let mut err = self.tcx.path_does_not_live_long_enough( + borrow_span, &format!("`{}`", name), Origin::Mir); + err.span_label(borrow_span, "borrowed value does not live long enough"); err.span_label( drop_span, @@ -468,6 +474,27 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { err } + fn report_thread_local_value_does_not_live_long_enough( + &mut self, + drop_span: Span, + borrow_span: Span, + ) -> DiagnosticBuilder<'cx> { + debug!( + "report_thread_local_value_does_not_live_long_enough(\ + {:?}, {:?}\ + )", + drop_span, borrow_span + ); + + let mut err = self.tcx.thread_local_value_does_not_live_long_enough( + borrow_span, Origin::Mir); + + err.span_label(borrow_span, + "thread-local variables cannot be borrowed beyond the end of the function"); + err.span_label(drop_span, "end of enclosing function is here"); + err + } + fn report_temporary_value_does_not_live_long_enough( &mut self, context: Context, @@ -856,6 +883,21 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { }, } } + + /// Check if a place is a thread-local static. + pub fn is_place_thread_local(&self, place: &Place<'tcx>) -> bool { + if let Place::Static(statik) = place { + let attrs = self.tcx.get_attrs(statik.def_id); + let is_thread_local = attrs.iter().any(|attr| attr.check_name("thread_local")); + + debug!("is_place_thread_local: attrs={:?} is_thread_local={:?}", + attrs, is_thread_local); + is_thread_local + } else { + debug!("is_place_thread_local: no"); + false + } + } } // The span(s) associated to a use of a place. diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 320d3a4720321..967a8d9033096 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -1487,15 +1487,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // FIXME: allow thread-locals to borrow other thread locals? let (might_be_alive, will_be_dropped) = match root_place { Place::Promoted(_) => (true, false), - Place::Static(statik) => { + Place::Static(_) => { // Thread-locals might be dropped after the function exits, but // "true" statics will never be. - let is_thread_local = self - .tcx - .get_attrs(statik.def_id) - .iter() - .any(|attr| attr.check_name("thread_local")); - + let is_thread_local = self.is_place_thread_local(&root_place); (true, is_thread_local) } Place::Local(_) => { diff --git a/src/librustc_mir/diagnostics.rs b/src/librustc_mir/diagnostics.rs index 3c751d52b0664..e72ef798612ae 100644 --- a/src/librustc_mir/diagnostics.rs +++ b/src/librustc_mir/diagnostics.rs @@ -2251,6 +2251,29 @@ unsafe { b.resume() }; ``` "##, +E0712: r##" +This error occurs because a borrow of a thread-local variable was made inside a +function which outlived the lifetime of the function. + +Example of erroneous code: + +```compile_fail,E0712 +#![feature(nll)] +#![feature(thread_local)] + +#[thread_local] +static FOO: u8 = 3; + +fn main() { + let a = &FOO; // error: thread-local variable borrowed past end of function + + std::thread::spawn(move || { + println!("{}", a); + }); +} +``` +"##, + } register_diagnostics! { diff --git a/src/librustc_mir/util/borrowck_errors.rs b/src/librustc_mir/util/borrowck_errors.rs index 0a53361df6e95..7be6241b3f91e 100644 --- a/src/librustc_mir/util/borrowck_errors.rs +++ b/src/librustc_mir/util/borrowck_errors.rs @@ -675,6 +675,22 @@ pub trait BorrowckErrors<'cx>: Sized + Copy { self.cancel_if_wrong_origin(err, o) } + + fn thread_local_value_does_not_live_long_enough( + self, + span: Span, + o: Origin, + ) -> DiagnosticBuilder<'cx> { + let err = struct_span_err!( + self, + span, + E0712, + "thread-local variable borrowed past end of function{OGN}", + OGN = o + ); + + self.cancel_if_wrong_origin(err, o) + } } impl<'cx, 'gcx, 'tcx> BorrowckErrors<'cx> for TyCtxt<'cx, 'gcx, 'tcx> { diff --git a/src/test/compile-fail/borrowck/borrowck-thread-local-static-borrow-outlives-fn.rs b/src/test/compile-fail/borrowck/borrowck-thread-local-static-borrow-outlives-fn.rs index f2e6d51d064d1..7aa02558446e3 100644 --- a/src/test/compile-fail/borrowck/borrowck-thread-local-static-borrow-outlives-fn.rs +++ b/src/test/compile-fail/borrowck/borrowck-thread-local-static-borrow-outlives-fn.rs @@ -19,5 +19,5 @@ static FOO: u8 = 3; fn assert_static(_t: &'static u8) {} fn main() { assert_static(&FOO); //[ast]~ ERROR [E0597] - //[mir]~^ ERROR [E0597] + //[mir]~^ ERROR [E0712] } diff --git a/src/test/ui/issue-17954.ast.nll.stderr b/src/test/ui/issue-17954.ast.nll.stderr deleted file mode 100644 index 5cab7ca9e7a3f..0000000000000 --- a/src/test/ui/issue-17954.ast.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0597]: `FOO` does not live long enough - --> $DIR/issue-17954.rs:20:13 - | -LL | let a = &FOO; - | ^^^^ borrowed value does not live long enough -... -LL | } - | - `FOO` dropped here while still borrowed - | - = note: borrowed value must be valid for the static lifetime... - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/issue-17954.mir.stderr b/src/test/ui/issue-17954.mir.stderr deleted file mode 100644 index 5cab7ca9e7a3f..0000000000000 --- a/src/test/ui/issue-17954.mir.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0597]: `FOO` does not live long enough - --> $DIR/issue-17954.rs:20:13 - | -LL | let a = &FOO; - | ^^^^ borrowed value does not live long enough -... -LL | } - | - `FOO` dropped here while still borrowed - | - = note: borrowed value must be valid for the static lifetime... - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/issue-17954.nll.stderr b/src/test/ui/issue-17954.nll.stderr new file mode 100644 index 0000000000000..67a5e3eaec787 --- /dev/null +++ b/src/test/ui/issue-17954.nll.stderr @@ -0,0 +1,12 @@ +error[E0712]: thread-local variable borrowed past end of function + --> $DIR/issue-17954.rs:17:13 + | +LL | let a = &FOO; + | ^^^^ thread-local variables cannot be borrowed beyond the end of the function +... +LL | } + | - end of enclosing function is here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0712`. diff --git a/src/test/ui/issue-17954.rs b/src/test/ui/issue-17954.rs index b5e550e5be1c9..ce554a7254812 100644 --- a/src/test/ui/issue-17954.rs +++ b/src/test/ui/issue-17954.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// revisions: ast mir -//[mir]compile-flags: -Z borrowck=mir - #![feature(thread_local)] #[thread_local] @@ -18,16 +15,12 @@ static FOO: u8 = 3; fn main() { let a = &FOO; - //[mir]~^ ERROR `FOO` does not live long enough [E0597] - //[mir]~| does not live long enough - //[mir]~| NOTE borrowed value must be valid for the static lifetime - //[ast]~^^^^ ERROR borrowed value does not live long enough - //[ast]~| does not live long enough - //[ast]~| NOTE borrowed value must be valid for the static lifetime + //~^ ERROR borrowed value does not live long enough + //~| does not live long enough + //~| NOTE borrowed value must be valid for the static lifetime std::thread::spawn(move || { println!("{}", a); }); } -//[mir]~^ `FOO` dropped here while still borrowed -//[ast]~^^ temporary value only lives until here +//~^ NOTE temporary value only lives until here diff --git a/src/test/ui/issue-17954.ast.stderr b/src/test/ui/issue-17954.stderr similarity index 92% rename from src/test/ui/issue-17954.ast.stderr rename to src/test/ui/issue-17954.stderr index 677d2cbfffc47..76858a9b097b2 100644 --- a/src/test/ui/issue-17954.ast.stderr +++ b/src/test/ui/issue-17954.stderr @@ -1,5 +1,5 @@ error[E0597]: borrowed value does not live long enough - --> $DIR/issue-17954.rs:20:14 + --> $DIR/issue-17954.rs:17:14 | LL | let a = &FOO; | ^^^ temporary value does not live long enough From 66085525252035d20b146b318d4d00dd3c05be7e Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 7 Aug 2018 12:17:29 +0200 Subject: [PATCH 12/20] Re-enable drop-locations debuginfo tests. --- src/test/debuginfo/drop-locations.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/test/debuginfo/drop-locations.rs b/src/test/debuginfo/drop-locations.rs index 76c2826ee8c61..845af6a60bc30 100644 --- a/src/test/debuginfo/drop-locations.rs +++ b/src/test/debuginfo/drop-locations.rs @@ -10,13 +10,11 @@ // ignore-windows // ignore-android -// ignore-test // Test temporarily ignored due to debuginfo tests being disabled, see PR 47155 // min-lldb-version: 310 #![allow(unused)] -// compile-flags:-g -O -C no-prepopulate-passes -// -O -C no-prepopulate-passes added to work around https://bugs.llvm.org/show_bug.cgi?id=32123 +// compile-flags:-g // This test checks that drop glue code gets attributed to scope's closing brace, // and function epilogues - to function's closing brace. @@ -90,4 +88,5 @@ fn foo() { } // #loc4 +#[inline(never)] fn zzz() {()} From 4eb52ff15e56bad5e84cc1cd47ccd1805a8ae567 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 7 Aug 2018 12:34:52 +0200 Subject: [PATCH 13/20] Re-enable a bunch of debuginfo tests. --- .../debuginfo/by-value-non-immediate-argument.rs | 1 - .../debuginfo/function-arg-initialization.rs | 1 - .../function-prologue-stepping-regular.rs | 1 - src/test/debuginfo/pretty-std.rs | 16 ++++++++-------- 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/test/debuginfo/by-value-non-immediate-argument.rs b/src/test/debuginfo/by-value-non-immediate-argument.rs index 9007b44296bcc..0fe08c3a22731 100644 --- a/src/test/debuginfo/by-value-non-immediate-argument.rs +++ b/src/test/debuginfo/by-value-non-immediate-argument.rs @@ -9,7 +9,6 @@ // except according to those terms. // ignore-tidy-linelength -// ignore-test // Test temporarily ignored due to debuginfo tests being disabled, see PR 47155 // min-lldb-version: 310 // compile-flags:-g diff --git a/src/test/debuginfo/function-arg-initialization.rs b/src/test/debuginfo/function-arg-initialization.rs index 90088a0297aa8..06acfec88aaec 100644 --- a/src/test/debuginfo/function-arg-initialization.rs +++ b/src/test/debuginfo/function-arg-initialization.rs @@ -9,7 +9,6 @@ // except according to those terms. // ignore-tidy-linelength -// ignore-test // Test temporarily ignored due to debuginfo tests being disabled, see PR 47155 // min-lldb-version: 310 // This test case checks if function arguments already have the correct value diff --git a/src/test/debuginfo/function-prologue-stepping-regular.rs b/src/test/debuginfo/function-prologue-stepping-regular.rs index d50d105e009ff..529a8cd635a92 100644 --- a/src/test/debuginfo/function-prologue-stepping-regular.rs +++ b/src/test/debuginfo/function-prologue-stepping-regular.rs @@ -13,7 +13,6 @@ // min-lldb-version: 310 // ignore-gdb -// ignore-test // Test temporarily ignored due to debuginfo tests being disabled, see PR 47155 // compile-flags:-g // lldb-command:breakpoint set --name immediate_args diff --git a/src/test/debuginfo/pretty-std.rs b/src/test/debuginfo/pretty-std.rs index 7bc566480e763..d26e7b8a4c81b 100644 --- a/src/test/debuginfo/pretty-std.rs +++ b/src/test/debuginfo/pretty-std.rs @@ -10,7 +10,6 @@ // ignore-windows failing on win32 bot // ignore-freebsd: gdb package too new -// ignore-test // Test temporarily ignored due to debuginfo tests being disabled, see PR 47155 // ignore-android: FIXME(#10381) // compile-flags:-g // min-gdb-version 7.7 @@ -40,14 +39,15 @@ // gdbr-check:$6 = core::option::Option::None // gdb-command: print os_string -// gdb-check:$7 = "IAMA OS string 😃" +// gdb-check:$7 = "IAMA OS string" -// gdb-command: print some_string -// gdb-check:$8 = Some = {"IAMA optional string!"} +// Disabled due to https://github.com/rust-lang/rust/issues/53153 +// g d b-command: print some_string +// g d b-check:$8 = Some = {"IAMA optional string!"} -// gdb-command: set print length 5 -// gdb-command: print some_string -// gdb-check:$8 = Some = {"IAMA "...} +// g d b-command: set print length 5 +// g d b-command: print some_string +// g d b-check:$8 = Some = {"IAMA "...} // === LLDB TESTS ================================================================================== @@ -92,7 +92,7 @@ fn main() { let string = "IAMA string!".to_string(); // OsString - let os_string = OsString::from("IAMA OS string \u{1F603}"); + let os_string = OsString::from("IAMA OS string"); // Option let some = Some(8i16); From efda9f80f047a2b657a9cc2100fcd208bc056557 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 7 Aug 2018 15:37:32 +0200 Subject: [PATCH 14/20] Added some debug logging. --- src/librustc_mir/borrow_check/move_errors.rs | 5 +++++ src/librustc_mir/borrow_check/mutability_errors.rs | 12 ++++++++++++ 2 files changed, 17 insertions(+) diff --git a/src/librustc_mir/borrow_check/move_errors.rs b/src/librustc_mir/borrow_check/move_errors.rs index 4d988fef450b8..86bbec795b0f4 100644 --- a/src/librustc_mir/borrow_check/move_errors.rs +++ b/src/librustc_mir/borrow_check/move_errors.rs @@ -221,6 +221,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { | GroupedMoveError::OtherIllegalMove { span, ref kind } => (span, kind), }; let origin = Origin::Mir; + debug!("report: span={:?}, kind={:?}", span, kind); ( match kind { IllegalMoveOriginKind::Static => { @@ -262,6 +263,10 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { } None => bug!("closure kind not inferred by borrowck"), }; + debug!("report: closure_kind_ty={:?} closure_kind={:?} \ + place_description={:?}", closure_kind_ty, closure_kind, + place_description); + self.tcx.cannot_move_out_of(span, place_description, origin) } _ => self diff --git a/src/librustc_mir/borrow_check/mutability_errors.rs b/src/librustc_mir/borrow_check/mutability_errors.rs index e8862320ddf3f..25428d2c4241f 100644 --- a/src/librustc_mir/borrow_check/mutability_errors.rs +++ b/src/librustc_mir/borrow_check/mutability_errors.rs @@ -36,10 +36,18 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { error_access: AccessKind, location: Location, ) { + debug!( + "report_mutability_error(\ + access_place={:?}, span={:?}, the_place_err={:?}, error_access={:?}, location={:?},\ + )", + access_place, span, the_place_err, error_access, location, + ); + let mut err; let item_msg; let reason; let access_place_desc = self.describe_place(access_place); + debug!("report_mutability_error: access_place_desc={:?}", access_place_desc); match the_place_err { Place::Local(local) => { @@ -155,6 +163,8 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { }) => bug!("Unexpected immutable place."), } + debug!("report_mutability_error: item_msg={:?}, reason={:?}", item_msg, reason); + // `act` and `acted_on` are strings that let us abstract over // the verbs used in some diagnostic messages. let act; @@ -199,6 +209,8 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { } }; + debug!("report_mutability_error: act={:?}, acted_on={:?}", act, acted_on); + match the_place_err { // We want to suggest users use `let mut` for local (user // variable) mutations... From 0e5bda19e954ae9017b8bb0aeeafe0d2372c511b Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 7 Aug 2018 17:06:21 +0200 Subject: [PATCH 15/20] Label definition of captured variables in errors. --- src/librustc/mir/tcx.rs | 27 +++++-- src/librustc_mir/borrow_check/mod.rs | 2 +- src/librustc_mir/borrow_check/move_errors.rs | 74 +++++++++++++------ .../borrow_check/mutability_errors.rs | 30 +------- .../dataflow/move_paths/builder.rs | 15 ++-- src/librustc_mir/dataflow/move_paths/mod.rs | 2 +- .../ui/borrowck/borrowck-in-static.nll.stderr | 2 + ...upvar-from-non-once-ref-closure.nll.stderr | 3 + ...owck-call-is-borrow-issue-12224.nll.stderr | 3 + 9 files changed, 95 insertions(+), 63 deletions(-) diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index b55843ac527df..e972b02b581f7 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -127,14 +127,14 @@ impl<'tcx> Place<'tcx> { /// of a closure type. pub fn is_upvar_field_projection<'cx, 'gcx>(&self, mir: &'cx Mir<'tcx>, tcx: &TyCtxt<'cx, 'gcx, 'tcx>) -> Option { - let place = if let Place::Projection(ref proj) = self { + let (place, by_ref) = if let Place::Projection(ref proj) = self { if let ProjectionElem::Deref = proj.elem { - &proj.base + (&proj.base, true) } else { - self + (self, false) } } else { - self + (self, false) }; match place { @@ -142,7 +142,9 @@ impl<'tcx> Place<'tcx> { ProjectionElem::Field(field, _ty) => { let base_ty = proj.base.ty(mir, *tcx).to_ty(*tcx); - if base_ty.is_closure() || base_ty.is_generator() { + if (base_ty.is_closure() || base_ty.is_generator()) && + (!by_ref || mir.upvar_decls[field.index()].by_ref) + { Some(field) } else { None @@ -153,6 +155,21 @@ impl<'tcx> Place<'tcx> { _ => None, } } + + /// Strip the deref projections from a `Place`. For example, given `(*(*((*_1).0: &&T)))`, this + /// will return `((*_1).0)`. Once stripped of any deref projections, places can then be + /// checked as upvar field projections using `is_upvar_field_projection`. + pub fn strip_deref_projections(&self) -> &Place<'tcx> { + let mut current = self; + while let Place::Projection(ref proj) = current { + if let ProjectionElem::Deref = proj.elem { + current = &proj.base; + } else { + break; + } + } + current + } } pub enum RvalueInitializationState { diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 320d3a4720321..ceef8fd209434 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -151,7 +151,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( let location_table = &LocationTable::new(mir); let mut errors_buffer = Vec::new(); - let (move_data, move_errors): (MoveData<'tcx>, Option>>) = + let (move_data, move_errors): (MoveData<'tcx>, Option, MoveError<'tcx>)>>) = match MoveData::gather_moves(mir, tcx) { Ok(move_data) => (move_data, None), Err((move_data, move_errors)) => (move_data, Some(move_errors)), diff --git a/src/librustc_mir/borrow_check/move_errors.rs b/src/librustc_mir/borrow_check/move_errors.rs index 86bbec795b0f4..2c3bf83fc2a40 100644 --- a/src/librustc_mir/borrow_check/move_errors.rs +++ b/src/librustc_mir/borrow_check/move_errors.rs @@ -11,8 +11,8 @@ use rustc::hir; use rustc::mir::*; use rustc::ty; -use rustc_data_structures::indexed_vec::Idx; use rustc_errors::DiagnosticBuilder; +use rustc_data_structures::indexed_vec::Idx; use syntax_pos::Span; use borrow_check::MirBorrowckCtxt; @@ -38,6 +38,7 @@ enum GroupedMoveError<'tcx> { // Match place can't be moved from // e.g. match x[0] { s => (), } where x: &[String] MovesFromMatchPlace { + original_path: Place<'tcx>, span: Span, move_from: Place<'tcx>, kind: IllegalMoveOriginKind<'tcx>, @@ -46,6 +47,7 @@ enum GroupedMoveError<'tcx> { // Part of a pattern can't be moved from, // e.g. match &String::new() { &x => (), } MovesFromPattern { + original_path: Place<'tcx>, span: Span, move_from: MovePathIndex, kind: IllegalMoveOriginKind<'tcx>, @@ -53,23 +55,27 @@ enum GroupedMoveError<'tcx> { }, // Everything that isn't from pattern matching. OtherIllegalMove { + original_path: Place<'tcx>, span: Span, kind: IllegalMoveOriginKind<'tcx>, }, } impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { - pub(crate) fn report_move_errors(&mut self, move_errors: Vec>) { + pub(crate) fn report_move_errors(&mut self, move_errors: Vec<(Place<'tcx>, MoveError<'tcx>)>) { let grouped_errors = self.group_move_errors(move_errors); for error in grouped_errors { self.report(error); } } - fn group_move_errors(&self, errors: Vec>) -> Vec> { + fn group_move_errors( + &self, + errors: Vec<(Place<'tcx>, MoveError<'tcx>)> + ) -> Vec> { let mut grouped_errors = Vec::new(); - for error in errors { - self.append_to_grouped_errors(&mut grouped_errors, error); + for (original_path, error) in errors { + self.append_to_grouped_errors(&mut grouped_errors, original_path, error); } grouped_errors } @@ -77,6 +83,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { fn append_to_grouped_errors( &self, grouped_errors: &mut Vec>, + original_path: Place<'tcx>, error: MoveError<'tcx>, ) { match error { @@ -116,6 +123,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { self.append_binding_error( grouped_errors, kind, + original_path, move_from, *local, opt_match_place, @@ -127,6 +135,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { } grouped_errors.push(GroupedMoveError::OtherIllegalMove { span: stmt_source_info.span, + original_path, kind, }); } @@ -137,6 +146,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { &self, grouped_errors: &mut Vec>, kind: IllegalMoveOriginKind<'tcx>, + original_path: Place<'tcx>, move_from: &Place<'tcx>, bind_to: Local, match_place: &Option>, @@ -176,6 +186,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { grouped_errors.push(GroupedMoveError::MovesFromMatchPlace { span, move_from: match_place.clone(), + original_path, kind, binds_to, }); @@ -206,6 +217,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { grouped_errors.push(GroupedMoveError::MovesFromPattern { span: match_span, move_from: mpi, + original_path, kind, binds_to: vec![bind_to], }); @@ -215,13 +227,23 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { fn report(&mut self, error: GroupedMoveError<'tcx>) { let (mut err, err_span) = { - let (span, kind): (Span, &IllegalMoveOriginKind) = match error { - GroupedMoveError::MovesFromMatchPlace { span, ref kind, .. } - | GroupedMoveError::MovesFromPattern { span, ref kind, .. } - | GroupedMoveError::OtherIllegalMove { span, ref kind } => (span, kind), - }; + let (span, original_path, kind): (Span, &Place<'tcx>, &IllegalMoveOriginKind) = + match error { + GroupedMoveError::MovesFromMatchPlace { + span, + ref original_path, + ref kind, + .. + } | + GroupedMoveError::MovesFromPattern { span, ref original_path, ref kind, .. } | + GroupedMoveError::OtherIllegalMove { span, ref original_path, ref kind } => { + (span, original_path, kind) + }, + }; let origin = Origin::Mir; - debug!("report: span={:?}, kind={:?}", span, kind); + debug!("report: original_path={:?} span={:?}, kind={:?} \ + original_path.is_upvar_field_projection={:?}", original_path, span, kind, + original_path.is_upvar_field_projection(self.mir, &self.tcx)); ( match kind { IllegalMoveOriginKind::Static => { @@ -237,17 +259,11 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { .tcx .cannot_move_out_of_interior_noncopy(span, ty, None, origin), ty::TyClosure(def_id, closure_substs) - if !self.mir.upvar_decls.is_empty() - && { - match place { - Place::Projection(ref proj) => { - proj.base == Place::Local(Local::new(1)) - } - Place::Promoted(_) | - Place::Local(_) | Place::Static(_) => unreachable!(), - } - } => - { + if !self.mir.upvar_decls.is_empty() && + original_path.strip_deref_projections() + .is_upvar_field_projection(self.mir, &self.tcx) + .is_some() + => { let closure_kind_ty = closure_substs.closure_kind_ty(def_id, self.tcx); let closure_kind = closure_kind_ty.to_opt_closure_kind(); @@ -267,7 +283,19 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { place_description={:?}", closure_kind_ty, closure_kind, place_description); - self.tcx.cannot_move_out_of(span, place_description, origin) + let mut diag = self.tcx.cannot_move_out_of( + span, place_description, origin); + + if let Some(field) = original_path.is_upvar_field_projection( + self.mir, &self.tcx) { + let upvar_decl = &self.mir.upvar_decls[field.index()]; + let upvar_hir_id = upvar_decl.var_hir_id.assert_crate_local(); + let upvar_node_id = self.tcx.hir.hir_to_node_id(upvar_hir_id); + let upvar_span = self.tcx.hir.span(upvar_node_id); + diag.span_label(upvar_span, "captured outer variable"); + } + + diag } _ => self .tcx diff --git a/src/librustc_mir/borrow_check/mutability_errors.rs b/src/librustc_mir/borrow_check/mutability_errors.rs index 25428d2c4241f..283cccd51174a 100644 --- a/src/librustc_mir/borrow_check/mutability_errors.rs +++ b/src/librustc_mir/borrow_check/mutability_errors.rs @@ -71,7 +71,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { )); item_msg = format!("`{}`", access_place_desc.unwrap()); - if self.is_upvar(access_place) { + if access_place.is_upvar_field_projection(self.mir, &self.tcx).is_some() { reason = ", as it is not declared as mutable".to_string(); } else { let name = self.mir.upvar_decls[upvar_index.index()].debug_name; @@ -90,7 +90,8 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { the_place_err.ty(self.mir, self.tcx).to_ty(self.tcx) )); - reason = if self.is_upvar(access_place) { + reason = if access_place.is_upvar_field_projection(self.mir, + &self.tcx).is_some() { ", as it is a captured variable in a `Fn` closure".to_string() } else { ", as `Fn` closures cannot mutate their captured variables".to_string() @@ -394,31 +395,6 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { err.buffer(&mut self.errors_buffer); } - - // Does this place refer to what the user sees as an upvar - fn is_upvar(&self, place: &Place<'tcx>) -> bool { - match *place { - Place::Projection(box Projection { - ref base, - elem: ProjectionElem::Field(_, _), - }) => { - let base_ty = base.ty(self.mir, self.tcx).to_ty(self.tcx); - is_closure_or_generator(base_ty) - } - Place::Projection(box Projection { - base: - Place::Projection(box Projection { - ref base, - elem: ProjectionElem::Field(upvar_index, _), - }), - elem: ProjectionElem::Deref, - }) => { - let base_ty = base.ty(self.mir, self.tcx).to_ty(self.tcx); - is_closure_or_generator(base_ty) && self.mir.upvar_decls[upvar_index.index()].by_ref - } - _ => false, - } - } } fn suggest_ampmut_self<'cx, 'gcx, 'tcx>( diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs index 44e46e90549a7..60030f2702055 100644 --- a/src/librustc_mir/dataflow/move_paths/builder.rs +++ b/src/librustc_mir/dataflow/move_paths/builder.rs @@ -27,7 +27,7 @@ struct MoveDataBuilder<'a, 'gcx: 'tcx, 'tcx: 'a> { mir: &'a Mir<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>, data: MoveData<'tcx>, - errors: Vec>, + errors: Vec<(Place<'tcx>, MoveError<'tcx>)>, } impl<'a, 'gcx, 'tcx> MoveDataBuilder<'a, 'gcx, 'tcx> { @@ -186,7 +186,9 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> { } impl<'a, 'gcx, 'tcx> MoveDataBuilder<'a, 'gcx, 'tcx> { - fn finalize(self) -> Result, (MoveData<'tcx>, Vec>)> { + fn finalize( + self + ) -> Result, (MoveData<'tcx>, Vec<(Place<'tcx>, MoveError<'tcx>)>)> { debug!("{}", { debug!("moves for {:?}:", self.mir.span); for (j, mo) in self.data.moves.iter_enumerated() { @@ -207,9 +209,10 @@ impl<'a, 'gcx, 'tcx> MoveDataBuilder<'a, 'gcx, 'tcx> { } } -pub(super) fn gather_moves<'a, 'gcx, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>) - -> Result, - (MoveData<'tcx>, Vec>)> { +pub(super) fn gather_moves<'a, 'gcx, 'tcx>( + mir: &Mir<'tcx>, + tcx: TyCtxt<'a, 'gcx, 'tcx> +) -> Result, (MoveData<'tcx>, Vec<(Place<'tcx>, MoveError<'tcx>)>)> { let mut builder = MoveDataBuilder::new(mir, tcx); builder.gather_args(); @@ -407,7 +410,7 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> { let path = match self.move_path_for(place) { Ok(path) | Err(MoveError::UnionMove { path }) => path, Err(error @ MoveError::IllegalMove { .. }) => { - self.builder.errors.push(error); + self.builder.errors.push((place.clone(), error)); return; } }; diff --git a/src/librustc_mir/dataflow/move_paths/mod.rs b/src/librustc_mir/dataflow/move_paths/mod.rs index 64bfd36b7eeb6..7b4cbdf7131b0 100644 --- a/src/librustc_mir/dataflow/move_paths/mod.rs +++ b/src/librustc_mir/dataflow/move_paths/mod.rs @@ -313,7 +313,7 @@ impl<'tcx> MoveError<'tcx> { impl<'a, 'gcx, 'tcx> MoveData<'tcx> { pub fn gather_moves(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>) - -> Result>)> { + -> Result, MoveError<'tcx>)>)> { builder::gather_moves(mir, tcx) } } diff --git a/src/test/ui/borrowck/borrowck-in-static.nll.stderr b/src/test/ui/borrowck/borrowck-in-static.nll.stderr index 05a022a726cd9..45fa1764f7027 100644 --- a/src/test/ui/borrowck/borrowck-in-static.nll.stderr +++ b/src/test/ui/borrowck/borrowck-in-static.nll.stderr @@ -1,6 +1,8 @@ error[E0507]: cannot move out of captured variable in an `Fn` closure --> $DIR/borrowck-in-static.rs:15:17 | +LL | let x = Box::new(0); + | - captured outer variable LL | Box::new(|| x) //~ ERROR cannot move out of captured outer variable | ^ cannot move out of captured variable in an `Fn` closure diff --git a/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.nll.stderr b/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.nll.stderr index 07a9f374b2c39..0eb5fc8c32435 100644 --- a/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.nll.stderr +++ b/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.nll.stderr @@ -1,6 +1,9 @@ error[E0507]: cannot move out of captured variable in an `Fn` closure --> $DIR/unboxed-closures-move-upvar-from-non-once-ref-closure.rs:21:9 | +LL | let y = vec![format!("World")]; + | - captured outer variable +LL | call(|| { LL | y.into_iter(); | ^ cannot move out of captured variable in an `Fn` closure diff --git a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.nll.stderr b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.nll.stderr index c7dbc043cdaee..a05a3911aa771 100644 --- a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.nll.stderr +++ b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.nll.stderr @@ -31,6 +31,9 @@ LL | f.f.call_mut(()) error[E0507]: cannot move out of captured variable in an `FnMut` closure --> $DIR/borrowck-call-is-borrow-issue-12224.rs:66:13 | +LL | let mut f = move |g: Box, b: isize| { + | ----- captured outer variable +... LL | foo(f); | ^ cannot move out of captured variable in an `FnMut` closure From 56232c67ff20a3e5f7ef5314b9c66122e359f33f Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 7 Aug 2018 19:50:19 +0200 Subject: [PATCH 16/20] Improved how upvars are detected when presenting errors using prefixes. --- src/librustc/mir/tcx.rs | 17 +---------- src/librustc_mir/borrow_check/move_errors.rs | 29 ++++++++++++------- src/test/ui/issue-4335.nll.stderr | 2 ++ ...issue-52663-span-decl-captured-variable.rs | 23 +++++++++++++++ ...e-52663-span-decl-captured-variable.stderr | 11 +++++++ 5 files changed, 55 insertions(+), 27 deletions(-) create mode 100644 src/test/ui/nll/issue-52663-span-decl-captured-variable.rs create mode 100644 src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index e972b02b581f7..5991845d265b2 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -151,25 +151,10 @@ impl<'tcx> Place<'tcx> { } }, _ => None, - }, + } _ => None, } } - - /// Strip the deref projections from a `Place`. For example, given `(*(*((*_1).0: &&T)))`, this - /// will return `((*_1).0)`. Once stripped of any deref projections, places can then be - /// checked as upvar field projections using `is_upvar_field_projection`. - pub fn strip_deref_projections(&self) -> &Place<'tcx> { - let mut current = self; - while let Place::Projection(ref proj) = current { - if let ProjectionElem::Deref = proj.elem { - current = &proj.base; - } else { - break; - } - } - current - } } pub enum RvalueInitializationState { diff --git a/src/librustc_mir/borrow_check/move_errors.rs b/src/librustc_mir/borrow_check/move_errors.rs index 2c3bf83fc2a40..d3524e841b223 100644 --- a/src/librustc_mir/borrow_check/move_errors.rs +++ b/src/librustc_mir/borrow_check/move_errors.rs @@ -16,6 +16,7 @@ use rustc_data_structures::indexed_vec::Idx; use syntax_pos::Span; use borrow_check::MirBorrowckCtxt; +use borrow_check::prefixes::PrefixSet; use dataflow::move_paths::{IllegalMoveOrigin, IllegalMoveOriginKind}; use dataflow::move_paths::{LookupResult, MoveError, MovePathIndex}; use util::borrowck_errors::{BorrowckErrors, Origin}; @@ -254,15 +255,16 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { // borrow to provide feedback about why this // was a move rather than a copy. let ty = place.ty(self.mir, self.tcx).to_ty(self.tcx); + let is_upvar_field_projection = + self.prefixes(&original_path, PrefixSet::All) + .any(|p| p.is_upvar_field_projection(self.mir, &self.tcx) + .is_some()); match ty.sty { ty::TyArray(..) | ty::TySlice(..) => self .tcx .cannot_move_out_of_interior_noncopy(span, ty, None, origin), ty::TyClosure(def_id, closure_substs) - if !self.mir.upvar_decls.is_empty() && - original_path.strip_deref_projections() - .is_upvar_field_projection(self.mir, &self.tcx) - .is_some() + if !self.mir.upvar_decls.is_empty() && is_upvar_field_projection => { let closure_kind_ty = closure_substs.closure_kind_ty(def_id, self.tcx); @@ -286,13 +288,18 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { let mut diag = self.tcx.cannot_move_out_of( span, place_description, origin); - if let Some(field) = original_path.is_upvar_field_projection( - self.mir, &self.tcx) { - let upvar_decl = &self.mir.upvar_decls[field.index()]; - let upvar_hir_id = upvar_decl.var_hir_id.assert_crate_local(); - let upvar_node_id = self.tcx.hir.hir_to_node_id(upvar_hir_id); - let upvar_span = self.tcx.hir.span(upvar_node_id); - diag.span_label(upvar_span, "captured outer variable"); + for prefix in self.prefixes(&original_path, PrefixSet::All) { + if let Some(field) = prefix.is_upvar_field_projection( + self.mir, &self.tcx) { + let upvar_decl = &self.mir.upvar_decls[field.index()]; + let upvar_hir_id = + upvar_decl.var_hir_id.assert_crate_local(); + let upvar_node_id = + self.tcx.hir.hir_to_node_id(upvar_hir_id); + let upvar_span = self.tcx.hir.span(upvar_node_id); + diag.span_label(upvar_span, "captured outer variable"); + break; + } } diag diff --git a/src/test/ui/issue-4335.nll.stderr b/src/test/ui/issue-4335.nll.stderr index 4ccd24fa45921..a9345e86f7248 100644 --- a/src/test/ui/issue-4335.nll.stderr +++ b/src/test/ui/issue-4335.nll.stderr @@ -1,6 +1,8 @@ error[E0507]: cannot move out of captured variable in an `FnMut` closure --> $DIR/issue-4335.rs:16:20 | +LL | fn f<'r, T>(v: &'r T) -> Box T + 'r> { + | - captured outer variable LL | id(Box::new(|| *v)) | ^^ cannot move out of captured variable in an `FnMut` closure diff --git a/src/test/ui/nll/issue-52663-span-decl-captured-variable.rs b/src/test/ui/nll/issue-52663-span-decl-captured-variable.rs new file mode 100644 index 0000000000000..dc40b0c44fd02 --- /dev/null +++ b/src/test/ui/nll/issue-52663-span-decl-captured-variable.rs @@ -0,0 +1,23 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(nll)] + +fn expect_fn(f: F) where F : Fn() { + f(); +} + +fn main() { + { + let x = (vec![22], vec![44]); + expect_fn(|| drop(x.0)); + //~^ ERROR cannot move out of captured variable in an `Fn` closure [E0507] + } +} diff --git a/src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr b/src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr new file mode 100644 index 0000000000000..51f19565855a7 --- /dev/null +++ b/src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr @@ -0,0 +1,11 @@ +error[E0507]: cannot move out of captured variable in an `Fn` closure + --> $DIR/issue-52663-span-decl-captured-variable.rs:20:26 + | +LL | let x = (vec![22], vec![44]); + | - captured outer variable +LL | expect_fn(|| drop(x.0)); + | ^^^ cannot move out of captured variable in an `Fn` closure + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0507`. From 5ce865e1c46ae0de15320076b49f53db8de3aab0 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Wed, 8 Aug 2018 01:39:52 +0200 Subject: [PATCH 17/20] Add wasm32 simd128 target feature --- src/librustc_codegen_llvm/llvm_util.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/librustc_codegen_llvm/llvm_util.rs b/src/librustc_codegen_llvm/llvm_util.rs index 441fff5f08c8f..ff26e0f35f00f 100644 --- a/src/librustc_codegen_llvm/llvm_util.rs +++ b/src/librustc_codegen_llvm/llvm_util.rs @@ -169,6 +169,10 @@ const MIPS_WHITELIST: &[(&str, Option<&str>)] = &[ ("msa", Some("mips_target_feature")), ]; +const WASM_WHITELIST: &[(&str, Option<&str>)] = &[ + ("simd128", Some("wasm_target_feature")), +]; + /// When rustdoc is running, provide a list of all known features so that all their respective /// primtives may be documented. /// @@ -181,6 +185,7 @@ pub fn all_known_features() -> impl Iterator(sess: &Session, s: &'a str) -> &'a str { @@ -228,6 +233,7 @@ pub fn target_feature_whitelist(sess: &Session) "hexagon" => HEXAGON_WHITELIST, "mips" | "mips64" => MIPS_WHITELIST, "powerpc" | "powerpc64" => POWERPC_WHITELIST, + "wasm32" => WASM_WHITELIST, _ => &[], } } From 020b0731fb79e0e888df178547fbaa8f7dc318aa Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Wed, 8 Aug 2018 01:43:00 +0200 Subject: [PATCH 18/20] add wasm_target_feature feature gate --- src/libsyntax/feature_gate.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 6d71d276390c4..f29bcd8ee58c3 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -446,6 +446,7 @@ declare_features! ( (active, mmx_target_feature, "1.27.0", Some(44839), None), (active, sse4a_target_feature, "1.27.0", Some(44839), None), (active, tbm_target_feature, "1.27.0", Some(44839), None), + (active, wasm_target_feature, "1.30.0", Some(44839), None), // Allows macro invocations of the form `#[foo::bar]` (active, proc_macro_path_invoc, "1.27.0", Some(38356), None), From 877c469395b77058425e6b1d44a251f10543ccee Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Tue, 7 Aug 2018 16:50:36 -0700 Subject: [PATCH 19/20] Avoid increased alignment of TLS segments on Fuchsia This is a temporary workaround for Fuchsia's libc not supporting TLS segments with alignments greater than 32 bytes. It should be reverted ASAP following the fix to libc. --- src/librustc_codegen_llvm/consts.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/librustc_codegen_llvm/consts.rs b/src/librustc_codegen_llvm/consts.rs index 72ff65361cada..364131722152f 100644 --- a/src/librustc_codegen_llvm/consts.rs +++ b/src/librustc_codegen_llvm/consts.rs @@ -345,7 +345,7 @@ pub fn codegen_static<'a, 'tcx>( if attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) { llvm::set_thread_local_mode(g, cx.tls_model); - // Do not allow LLVM to change the alignment of a TLS on macOS. + // Do not allow LLVM to change the alignment of a TLS on macOS and Fuchsia. // // By default a global's alignment can be freely increased. // This allows LLVM to generate more performant instructions @@ -355,6 +355,10 @@ pub fn codegen_static<'a, 'tcx>( // respect any alignment given on the TLS (radar 24221680). // This will violate the alignment assumption, and causing segfault at runtime. // + // Fuchsia's libc currently does not support greater than 16-byte alignment + // of TLS segments, so this hack is also enabled temporarily for Fuchsia targets + // until libc is fixed. + // // This bug is very easy to trigger. In `println!` and `panic!`, // the `LOCAL_STDOUT`/`LOCAL_STDERR` handles are stored in a TLS, // which the values would be `mem::replace`d on initialization. @@ -374,7 +378,9 @@ pub fn codegen_static<'a, 'tcx>( // will use load-unaligned instructions instead, and thus avoiding the crash. // // We could remove this hack whenever we decide to drop macOS 10.10 support. - if cx.tcx.sess.target.target.options.is_like_osx { + if cx.tcx.sess.target.target.options.is_like_osx || + (cx.tcx.sess.target.target.target_os == "fuchsia") + { let sect_name = if alloc.bytes.iter().all(|b| *b == 0) { CStr::from_bytes_with_nul_unchecked(b"__DATA,__thread_bss\0") } else { From 2cdaf3bae5c23958d3a4fc08fb12ff68343b7772 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Wed, 8 Aug 2018 02:10:06 +0200 Subject: [PATCH 20/20] add feature-gate test --- src/test/ui/target-feature-gate.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/ui/target-feature-gate.rs b/src/test/ui/target-feature-gate.rs index c2dc927c4b524..8a045884cae31 100644 --- a/src/test/ui/target-feature-gate.rs +++ b/src/test/ui/target-feature-gate.rs @@ -23,6 +23,7 @@ // gate-test-hexagon_target_feature // gate-test-mips_target_feature // gate-test-mmx_target_feature +// gate-test-wasm_target_feature // min-llvm-version 6.0 #[target_feature(enable = "avx512bw")]