From c70eb4b6eaeb0256422d32bed949b15ecc37bac9 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 5 Aug 2018 18:22:44 +0200 Subject: [PATCH 01/23] Automatically expand section if url id point to one of its component --- src/librustdoc/html/static/main.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 62ef5626ee5bb..07507047dc2c9 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -2208,6 +2208,25 @@ }; autoCollapse(getPageId(), getCurrentValue("rustdoc-collapse") === "true"); + + if (window.location.hash && window.location.hash.length > 0) { + var hash = getPageId(); + if (hash !== null) { + var elem = document.getElementById(hash); + if (elem && elem.offsetParent === null) { + console.log(elem, elem.parentNode); + if (elem.parentNode && elem.parentNode.previousSibling) { + var collapses = elem.parentNode + .previousSibling + .getElementsByClassName("collapse-toggle"); + if (collapses.length > 0) { + // The element is not visible, we need to make it appear! + collapseDocs(collapses[0], "show"); + } + } + } + } + } }()); // Sets the focus on the search bar at the top of the page From 70cafecaba233037bd5df5259140c3167941e70c Mon Sep 17 00:00:00 2001 From: Vadim Pashkov Date: Mon, 6 Aug 2018 04:18:19 +0300 Subject: [PATCH 02/23] 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/23] 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/23] 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 44d32d441342aac1eb802c4379aa4eb324c90679 Mon Sep 17 00:00:00 2001 From: ljedrz Date: Fri, 27 Jul 2018 13:20:13 +0200 Subject: [PATCH 05/23] 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 06/23] 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 07/23] 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 08/23] 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 d5f8edfa103442e755e1ab3ba76dfd6b0418c043 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 2 Aug 2018 14:16:43 +0200 Subject: [PATCH 09/23] Fix outdated description of -Zcross-lang-lto. --- src/librustc/session/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 3111777f4ad5a..219607a456b49 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -831,7 +831,7 @@ macro_rules! options { pub const parse_lto: Option<&'static str> = Some("one of `thin`, `fat`, or omitted"); pub const parse_cross_lang_lto: Option<&'static str> = - Some("either a boolean (`yes`, `no`, `on`, `off`, etc), `no-link`, \ + Some("either a boolean (`yes`, `no`, `on`, `off`, etc), \ or the path to the linker plugin"); } From 3a3b3317d99f0b72884002d1e4809bbe87356f8f Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 2 Aug 2018 14:26:27 +0200 Subject: [PATCH 10/23] Fix issue around dllimport and ThinLTO as LLD runs it. --- src/librustc/session/config.rs | 7 ------- src/librustc/session/mod.rs | 20 +++++++++++++++++++- src/librustc_codegen_llvm/back/lto.rs | 4 ++++ src/librustc_codegen_llvm/back/write.rs | 24 ++++++++++++++++++------ src/librustc_codegen_llvm/consts.rs | 15 ++++++++++++++- 5 files changed, 55 insertions(+), 15 deletions(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 219607a456b49..dddf921aec68c 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -2006,13 +2006,6 @@ pub fn build_session_options_and_crate_config( (&None, &None) => None, }.map(|m| PathBuf::from(m)); - if cg.lto != Lto::No && incremental.is_some() { - early_error( - error_format, - "can't perform LTO when compiling incrementally", - ); - } - if debugging_opts.profile && incremental.is_some() { early_error( error_format, diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 0173c4933f821..505511a4a0c1c 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -20,7 +20,7 @@ use lint::builtin::BuiltinLintDiagnostics; use middle::allocator::AllocatorKind; use middle::dependency_format; use session::search_paths::PathKind; -use session::config::{OutputType}; +use session::config::{OutputType, Lto}; use ty::tls; use util::nodemap::{FxHashMap, FxHashSet}; use util::common::{duration_to_secs_str, ErrorReported}; @@ -1189,9 +1189,27 @@ pub fn build_session_( driver_lint_caps: FxHashMap(), }; + validate_commandline_args_with_session_available(&sess); + sess } +// If it is useful to have a Session available already for validating a +// commandline argument, you can do so here. +fn validate_commandline_args_with_session_available(sess: &Session) { + + if sess.lto() != Lto::No && sess.opts.incremental.is_some() { + sess.err("can't perform LTO when compiling incrementally"); + } + + if sess.opts.debugging_opts.cross_lang_lto.enabled() && + sess.opts.cg.prefer_dynamic && + sess.target.target.options.is_like_msvc { + sess.err("Linker plugin based LTO is not supported together with \ + `-C prefer-dynamic` when targeting MSVC"); + } +} + /// Hash value constructed out of all the `-C metadata` arguments passed to the /// compiler. Together with the crate-name forms a unique global identifier for /// the crate. diff --git a/src/librustc_codegen_llvm/back/lto.rs b/src/librustc_codegen_llvm/back/lto.rs index 098676c95a289..d7741230327bb 100644 --- a/src/librustc_codegen_llvm/back/lto.rs +++ b/src/librustc_codegen_llvm/back/lto.rs @@ -195,6 +195,10 @@ pub(crate) fn run(cgcx: &CodegenContext, } Lto::Thin | Lto::ThinLocal => { + if cgcx.opts.debugging_opts.cross_lang_lto.enabled() { + unreachable!("We should never reach this case if the LTO step \ + is deferred to the linker"); + } thin_lto(&diag_handler, modules, upstream_modules, &arr, timeline) } Lto::No => unreachable!(), diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs index 5e23c6e868f47..9d235eced2eab 100644 --- a/src/librustc_codegen_llvm/back/write.rs +++ b/src/librustc_codegen_llvm/back/write.rs @@ -1351,6 +1351,8 @@ fn execute_work_item(cgcx: &CodegenContext, unsafe { optimize(cgcx, &diag_handler, &module, config, timeline)?; + let linker_does_lto = cgcx.opts.debugging_opts.cross_lang_lto.enabled(); + // After we've done the initial round of optimizations we need to // decide whether to synchronously codegen this module or ship it // back to the coordinator thread for further LTO processing (which @@ -1361,6 +1363,11 @@ fn execute_work_item(cgcx: &CodegenContext, let needs_lto = match cgcx.lto { Lto::No => false, + // If the linker does LTO, we don't have to do it. Note that we + // keep doing full LTO, if it is requested, as not to break the + // assumption that the output will be a single module. + Lto::Thin | Lto::ThinLocal if linker_does_lto => false, + // Here we've got a full crate graph LTO requested. We ignore // this, however, if the crate type is only an rlib as there's // no full crate graph to process, that'll happen later. @@ -1391,11 +1398,6 @@ fn execute_work_item(cgcx: &CodegenContext, // settings. let needs_lto = needs_lto && module.kind != ModuleKind::Metadata; - // Don't run LTO passes when cross-lang LTO is enabled. The linker - // will do that for us in this case. - let needs_lto = needs_lto && - !cgcx.opts.debugging_opts.cross_lang_lto.enabled(); - if needs_lto { Ok(WorkItemResult::NeedsLTO(module)) } else { @@ -2375,8 +2377,18 @@ pub(crate) fn submit_codegened_module_to_llvm(tcx: TyCtxt, } fn msvc_imps_needed(tcx: TyCtxt) -> bool { + // This should never be true (because it's not supported). If it is true, + // something is wrong with commandline arg validation. + assert!(!(tcx.sess.opts.debugging_opts.cross_lang_lto.enabled() && + tcx.sess.target.target.options.is_like_msvc && + tcx.sess.opts.cg.prefer_dynamic)); + tcx.sess.target.target.options.is_like_msvc && - tcx.sess.crate_types.borrow().iter().any(|ct| *ct == config::CrateType::Rlib) + tcx.sess.crate_types.borrow().iter().any(|ct| *ct == config::CrateTypeRlib) && + // ThinLTO can't handle this workaround in all cases, so we don't + // emit the `__imp_` symbols. Instead we make them unnecessary by disallowing + // dynamic linking when cross-language LTO is enabled. + !tcx.sess.opts.debugging_opts.cross_lang_lto.enabled() } // Create a `__imp_ = &symbol` global for every public static `symbol`. diff --git a/src/librustc_codegen_llvm/consts.rs b/src/librustc_codegen_llvm/consts.rs index 21bf490beb0fb..fafc0e723225d 100644 --- a/src/librustc_codegen_llvm/consts.rs +++ b/src/librustc_codegen_llvm/consts.rs @@ -189,7 +189,20 @@ pub fn get_static(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'ll Value { llvm::set_thread_local_mode(g, cx.tls_model); } - if cx.use_dll_storage_attrs && !cx.tcx.is_foreign_item(def_id) { + let needs_dll_storage_attr = + cx.use_dll_storage_attrs && !cx.tcx.is_foreign_item(def_id) && + // ThinLTO can't handle this workaround in all cases, so we don't + // emit the attrs. Instead we make them unnecessary by disallowing + // dynamic linking when cross-language LTO is enabled. + !cx.tcx.sess.opts.debugging_opts.cross_lang_lto.enabled(); + + // If this assertion triggers, there's something wrong with commandline + // argument validation. + debug_assert!(!(cx.tcx.sess.opts.debugging_opts.cross_lang_lto.enabled() && + cx.tcx.sess.target.target.options.is_like_msvc && + cx.tcx.sess.opts.cg.prefer_dynamic)); + + if needs_dll_storage_attr { // This item is external but not foreign, i.e. it originates from an external Rust // crate. Since we don't know whether this crate will be linked dynamically or // statically in the final application, we always mark such symbols as 'dllimport'. From aa9eeff26370b17e8ba140b6cb285a4613047132 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 2 Aug 2018 14:26:55 +0200 Subject: [PATCH 11/23] Make sure upstream object files are added to staticlibs when compiling with ThinLTO and cross-lang-lto. Normally, when compiling with whole-crate-graph ThinLTO, we expect rustc's LTO step to "uplift" upstream object files/LLVM modules to the current set of compilation artifacts. Therefore the staticlib creation code skips this uplifting. However, when compiling with "cross-language LTO" (i.e. defer LTO to the actual linker), the LTO step in rustc is not performed, so we have to take care of copying upstream object files during archive creation (like we already do when compiling without any LTO). --- src/librustc_codegen_llvm/back/link.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/librustc_codegen_llvm/back/link.rs b/src/librustc_codegen_llvm/back/link.rs index 108734b67d3b8..72084c170aa71 100644 --- a/src/librustc_codegen_llvm/back/link.rs +++ b/src/librustc_codegen_llvm/back/link.rs @@ -1626,8 +1626,12 @@ fn relevant_lib(sess: &Session, lib: &NativeLibrary) -> bool { fn is_full_lto_enabled(sess: &Session) -> bool { match sess.lto() { Lto::Yes | - Lto::Thin | Lto::Fat => true, + Lto::Thin => { + // If we defer LTO to the linker, we haven't run LTO ourselves, so + // any upstream object files have not been copied yet. + !sess.opts.debugging_opts.cross_lang_lto.enabled() + } Lto::No | Lto::ThinLocal => false, } From 54fba3ac1aa308ecec1bf6b25049c669bbf003c3 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 3 Aug 2018 17:06:01 +0200 Subject: [PATCH 12/23] Run cross-lang-lto tests also for MSVC (since there's no reason not to) --- src/test/run-make-fulldeps/cross-lang-lto/Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/run-make-fulldeps/cross-lang-lto/Makefile b/src/test/run-make-fulldeps/cross-lang-lto/Makefile index efe1b7072ffb8..6d06fade35296 100644 --- a/src/test/run-make-fulldeps/cross-lang-lto/Makefile +++ b/src/test/run-make-fulldeps/cross-lang-lto/Makefile @@ -1,4 +1,3 @@ -# ignore-msvc -include ../tools.mk From 386e000c5f28dfac697ae145524bcc1c17759993 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 3 Aug 2018 17:07:38 +0200 Subject: [PATCH 13/23] Add test case for omitting dllimport during cross-lang LTO. --- .../codegen/no-dllimport-w-cross-lang-lto.rs | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/test/codegen/no-dllimport-w-cross-lang-lto.rs diff --git a/src/test/codegen/no-dllimport-w-cross-lang-lto.rs b/src/test/codegen/no-dllimport-w-cross-lang-lto.rs new file mode 100644 index 0000000000000..025e7cbf179a7 --- /dev/null +++ b/src/test/codegen/no-dllimport-w-cross-lang-lto.rs @@ -0,0 +1,23 @@ +// Copyright 2018 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. + +// This test makes sure that functions get annotated with the proper +// "target-cpu" attribute in LLVM. + +// no-prefer-dynamic +// only-msvc +// compile-flags: -C no-prepopulate-passes -Z cross-lang-lto + +#![crate_type = "rlib"] + +// CHECK-NOT: @{{.*}}__imp_{{.*}}GLOBAL{{.*}} = global i8* + +pub static GLOBAL: u32 = 0; +pub static mut GLOBAL2: u32 = 0; From 3742f4d9f6eaf7b4b7a8aa246ee3dc2fdb2b80c3 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 3 Aug 2018 17:09:50 +0200 Subject: [PATCH 14/23] Add test case for including upstream object files in staticlibs when doing cross-lang LTO. --- .../cross-lang-lto-upstream-rlibs/Makefile | 23 +++++++++++++++++++ .../staticlib.rs | 18 +++++++++++++++ .../cross-lang-lto-upstream-rlibs/upstream.rs | 13 +++++++++++ 3 files changed, 54 insertions(+) create mode 100644 src/test/run-make-fulldeps/cross-lang-lto-upstream-rlibs/Makefile create mode 100644 src/test/run-make-fulldeps/cross-lang-lto-upstream-rlibs/staticlib.rs create mode 100644 src/test/run-make-fulldeps/cross-lang-lto-upstream-rlibs/upstream.rs diff --git a/src/test/run-make-fulldeps/cross-lang-lto-upstream-rlibs/Makefile b/src/test/run-make-fulldeps/cross-lang-lto-upstream-rlibs/Makefile new file mode 100644 index 0000000000000..de42c6e0eb54e --- /dev/null +++ b/src/test/run-make-fulldeps/cross-lang-lto-upstream-rlibs/Makefile @@ -0,0 +1,23 @@ + +-include ../tools.mk + +# This test makes sure that we don't loose upstream object files when compiling +# staticlibs with -Zcross-lang-lto + +all: staticlib.rs upstream.rs + $(RUSTC) upstream.rs -Z cross-lang-lto -Ccodegen-units=1 + + # Check No LTO + $(RUSTC) staticlib.rs -Z cross-lang-lto -Ccodegen-units=1 -L. -o $(TMPDIR)/staticlib.a + (cd $(TMPDIR); llvm-ar x ./staticlib.a) + # Make sure the upstream object file was included + ls upstream.*.rcgu.o + + # Cleanup + rm $(TMPDIR)/* + + # Check ThinLTO + $(RUSTC) upstream.rs -Z cross-lang-lto -Ccodegen-units=1 -Clto=thin + $(RUSTC) staticlib.rs -Z cross-lang-lto -Ccodegen-units=1 -Clto=thin -L. -o $(TMPDIR)/staticlib.a + (cd $(TMPDIR); llvm-ar x ./staticlib.a) + ls upstream.*.rcgu.o diff --git a/src/test/run-make-fulldeps/cross-lang-lto-upstream-rlibs/staticlib.rs b/src/test/run-make-fulldeps/cross-lang-lto-upstream-rlibs/staticlib.rs new file mode 100644 index 0000000000000..b370b7b859d87 --- /dev/null +++ b/src/test/run-make-fulldeps/cross-lang-lto-upstream-rlibs/staticlib.rs @@ -0,0 +1,18 @@ +// Copyright 2018 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. + +#![crate_type="staticlib"] + +extern crate upstream; + +#[no_mangle] +pub extern fn bar() { + upstream::foo(); +} diff --git a/src/test/run-make-fulldeps/cross-lang-lto-upstream-rlibs/upstream.rs b/src/test/run-make-fulldeps/cross-lang-lto-upstream-rlibs/upstream.rs new file mode 100644 index 0000000000000..a79b9bf08fc65 --- /dev/null +++ b/src/test/run-make-fulldeps/cross-lang-lto-upstream-rlibs/upstream.rs @@ -0,0 +1,13 @@ +// Copyright 2018 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. + +#![crate_type = "rlib"] + +pub fn foo() {} From f2969ed6c3c067659b5a160de08e9a57450b1047 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 3 Aug 2018 17:04:53 +0200 Subject: [PATCH 15/23] Set 'PrepareForThinLTO' whenever doing cross-language LTO. --- src/librustc_codegen_llvm/back/write.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs index 9d235eced2eab..47440d864d5e7 100644 --- a/src/librustc_codegen_llvm/back/write.rs +++ b/src/librustc_codegen_llvm/back/write.rs @@ -552,7 +552,8 @@ unsafe fn optimize(cgcx: &CodegenContext, llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod); llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod); let opt_level = config.opt_level.unwrap_or(llvm::CodeGenOptLevel::None); - let prepare_for_thin_lto = cgcx.lto == Lto::Thin || cgcx.lto == Lto::ThinLocal; + let prepare_for_thin_lto = cgcx.lto == Lto::Thin || cgcx.lto == Lto::ThinLocal || + (cgcx.lto != Lto::Fat && cgcx.opts.debugging_opts.cross_lang_lto.enabled()); have_name_anon_globals_pass = have_name_anon_globals_pass || prepare_for_thin_lto; if using_thin_buffers && !prepare_for_thin_lto { assert!(addpass("name-anon-globals")); From b27a161939620626ca5fdcb9f4dd486a6ed1e827 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 2 Aug 2018 18:10:26 +0200 Subject: [PATCH 16/23] Annotate functions in LLVM with target-cpu, same as Clang does. --- src/librustc_codegen_llvm/attributes.rs | 18 +++++++++++++ src/librustc_codegen_llvm/base.rs | 1 + src/librustc_codegen_llvm/context.rs | 3 +++ src/test/codegen/target-cpu-on-functions.rs | 28 +++++++++++++++++++++ 4 files changed, 50 insertions(+) create mode 100644 src/test/codegen/target-cpu-on-functions.rs diff --git a/src/librustc_codegen_llvm/attributes.rs b/src/librustc_codegen_llvm/attributes.rs index c52f894410899..714e8914e48c5 100644 --- a/src/librustc_codegen_llvm/attributes.rs +++ b/src/librustc_codegen_llvm/attributes.rs @@ -123,6 +123,15 @@ pub fn llvm_target_features(sess: &Session) -> impl Iterator { .filter(|l| !l.is_empty()) } +pub fn apply_target_cpu_attr(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) { + let target_cpu = CString::new(cx.tcx.sess.target_cpu().to_string()).unwrap(); + llvm::AddFunctionAttrStringValue( + llfn, + llvm::AttributePlace::Function, + cstr("target-cpu\0"), + target_cpu.as_c_str()); +} + /// Composite function which sets LLVM attributes for function depending on its AST (#[attribute]) /// attributes. pub fn from_fn_attrs(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value, id: DefId) { @@ -167,6 +176,15 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value, id: DefId) { Some(true) | None => {} } + // Always annotate functions with the target-cpu they are compiled for. + // Without this, ThinLTO won't inline Rust functions into Clang generated + // functions (because Clang annotates functions this way too). + // NOTE: For now we just apply this if -Zcross-lang-lto is specified, since + // it introduce a little overhead and isn't really necessary otherwise. + if cx.tcx.sess.opts.debugging_opts.cross_lang_lto.enabled() { + apply_target_cpu_attr(cx, llfn); + } + let features = llvm_target_features(cx.tcx.sess) .map(|s| s.to_string()) .chain( diff --git a/src/librustc_codegen_llvm/base.rs b/src/librustc_codegen_llvm/base.rs index 41336165684f6..13e8426155a95 100644 --- a/src/librustc_codegen_llvm/base.rs +++ b/src/librustc_codegen_llvm/base.rs @@ -596,6 +596,7 @@ fn maybe_create_entry_wrapper(cx: &CodegenCx) { // `main` should respect same config for frame pointer elimination as rest of code attributes::set_frame_pointer_elimination(cx, llfn); + attributes::apply_target_cpu_attr(cx, llfn); let bx = Builder::new_block(cx, llfn, "top"); diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs index 2f557d0b09998..7a308bb6e8823 100644 --- a/src/librustc_codegen_llvm/context.rs +++ b/src/librustc_codegen_llvm/context.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use attributes; use common; use llvm; use rustc::dep_graph::DepGraphSafe; @@ -381,6 +382,7 @@ impl<'b, 'tcx> CodegenCx<'b, 'tcx> { declare::declare_cfn(self, name, fty) } }; + attributes::apply_target_cpu_attr(self, llfn); self.eh_personality.set(Some(llfn)); llfn } @@ -412,6 +414,7 @@ impl<'b, 'tcx> CodegenCx<'b, 'tcx> { let llfn = declare::declare_fn(self, "rust_eh_unwind_resume", ty); attributes::unwind(llfn, true); + attributes::apply_target_cpu_attr(self, llfn); unwresume.set(Some(llfn)); llfn } diff --git a/src/test/codegen/target-cpu-on-functions.rs b/src/test/codegen/target-cpu-on-functions.rs new file mode 100644 index 0000000000000..c2765a46caae0 --- /dev/null +++ b/src/test/codegen/target-cpu-on-functions.rs @@ -0,0 +1,28 @@ +// Copyright 2018 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. + +// This test makes sure that functions get annotated with the proper +// "target-cpu" attribute in LLVM. + +// only-x86_64 +// compile-flags: -C no-prepopulate-passes -C panic=abort + +#![crate_type = "staticlib"] + +// CHECK-LABEL: define {{.*}} @exported() {{.*}} #0 +#[no_mangle] +pub extern fn exported() { + not_exported(); +} + +// CHECK-LABEL: define {{.*}} @_ZN23target_cpu_on_functions12not_exported{{.*}}() {{.*}} #0 +fn not_exported() {} + +// CHECK: attributes #0 = {{.*}} "target-cpu"="x86-64" From 5ce865e1c46ae0de15320076b49f53db8de3aab0 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Wed, 8 Aug 2018 01:39:52 +0200 Subject: [PATCH 17/23] 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/23] 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/23] 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/23] 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")] From f4039affa338fc5640c102ac5786a491bc94201f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 7 Aug 2018 22:28:09 -0700 Subject: [PATCH 21/23] Suggest comma when missing in macro call When missing a comma in a macro call, suggest it, regardless of position. When a macro call doesn't match any of the patterns, check if the call's token stream could be missing a comma between two idents, and if so, create a new token stream containing the comma and try to match against the macro patterns. If successful, emit the suggestion. --- src/libsyntax/ext/tt/macro_rules.rs | 4 +-- src/libsyntax/tokenstream.rs | 48 ++++++++++++++++++------- src/test/ui/macros/missing-comma.rs | 12 ++++++- src/test/ui/macros/missing-comma.stderr | 28 +++++++++++++-- 4 files changed, 73 insertions(+), 19 deletions(-) diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index e7e94614ac865..f51d079a6c058 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -181,7 +181,7 @@ fn generic_extension<'cx>(cx: &'cx mut ExtCtxt, for lhs in lhses { // try each arm's matchers let lhs_tt = match *lhs { quoted::TokenTree::Delimited(_, ref delim) => &delim.tts[..], - _ => cx.span_bug(sp, "malformed macro lhs") + _ => continue, }; match TokenTree::parse(cx, lhs_tt, arg.clone()) { Success(_) => { @@ -191,7 +191,7 @@ fn generic_extension<'cx>(cx: &'cx mut ExtCtxt, err.span_suggestion_short( comma_span, "missing comma here", - ",".to_string(), + ", ".to_string(), ); } } diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index f84b5307a1137..fda975e6c456b 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -186,21 +186,43 @@ impl TokenStream { /// Given a `TokenStream` with a `Stream` of only two arguments, return a new `TokenStream` /// separating the two arguments with a comma for diagnostic suggestions. pub(crate) fn add_comma(&self) -> Option<(TokenStream, Span)> { - // Used to suggest if a user writes `println!("{}" a);` + // Used to suggest if a user writes `foo!(a b);` if let TokenStreamKind::Stream(ref slice) = self.kind { - if slice.len() == 2 { - let comma_span = match slice[0] { - TokenStream { kind: TokenStreamKind::Tree(TokenTree::Token(sp, _)) } | - TokenStream { kind: TokenStreamKind::Tree(TokenTree::Delimited(sp, _)) } => { - sp.shrink_to_hi() + let mut suggestion = None; + let mut iter = slice.iter().enumerate().peekable(); + while let Some((pos, ts)) = iter.next() { + if let Some((_, next)) = iter.peek() { + match (ts, next) { + (TokenStream { + kind: TokenStreamKind::Tree(TokenTree::Token(_, token::Token::Comma)) + }, _) | + (_, TokenStream { + kind: TokenStreamKind::Tree(TokenTree::Token(_, token::Token::Comma)) + }) => {} + (TokenStream { + kind: TokenStreamKind::Tree(TokenTree::Token(sp, _)) + }, _) | + (TokenStream { + kind: TokenStreamKind::Tree(TokenTree::Delimited(sp, _)) + }, _) => { + let sp = sp.shrink_to_hi(); + let comma = TokenStream { + kind: TokenStreamKind::Tree(TokenTree::Token(sp, token::Comma)), + }; + suggestion = Some((pos, comma, sp)); + } + _ => {} } - _ => DUMMY_SP, - }; - let comma = TokenStream { - kind: TokenStreamKind::Tree(TokenTree::Token(comma_span, token::Comma)), - }; - let slice = RcSlice::new(vec![slice[0].clone(), comma, slice[1].clone()]); - return Some((TokenStream { kind: TokenStreamKind::Stream(slice) }, comma_span)); + } + } + if let Some((pos, comma, sp)) = suggestion { + let mut new_slice = vec![]; + let parts = slice.split_at(pos + 1); + new_slice.extend_from_slice(parts.0); + new_slice.push(comma); + new_slice.extend_from_slice(parts.1); + let slice = RcSlice::new(new_slice); + return Some((TokenStream { kind: TokenStreamKind::Stream(slice) }, sp)); } } None diff --git a/src/test/ui/macros/missing-comma.rs b/src/test/ui/macros/missing-comma.rs index ac82171a4e8cc..07e69b9619d1f 100644 --- a/src/test/ui/macros/missing-comma.rs +++ b/src/test/ui/macros/missing-comma.rs @@ -9,7 +9,11 @@ // except according to those terms. macro_rules! foo { - ($a:ident, $b:ident) => () + ($a:ident) => (); + ($a:ident, $b:ident) => (); + ($a:ident, $b:ident, $c:ident) => (); + ($a:ident, $b:ident, $c:ident, $d:ident) => (); + ($a:ident, $b:ident, $c:ident, $d:ident, $e:ident) => (); } fn main() { @@ -17,4 +21,10 @@ fn main() { //~^ ERROR expected token: `,` foo!(a b); //~^ ERROR no rules expected the token `b` + foo!(a, b, c, d e); + //~^ ERROR no rules expected the token `e` + foo!(a, b, c d, e); + //~^ ERROR no rules expected the token `d` + foo!(a, b, c d e); + //~^ ERROR no rules expected the token `d` } diff --git a/src/test/ui/macros/missing-comma.stderr b/src/test/ui/macros/missing-comma.stderr index 3467032d9b5f3..9d8de87e5bb7f 100644 --- a/src/test/ui/macros/missing-comma.stderr +++ b/src/test/ui/macros/missing-comma.stderr @@ -1,16 +1,38 @@ error: expected token: `,` - --> $DIR/missing-comma.rs:16:19 + --> $DIR/missing-comma.rs:20:19 | LL | println!("{}" a); | ^ error: no rules expected the token `b` - --> $DIR/missing-comma.rs:18:12 + --> $DIR/missing-comma.rs:22:12 | LL | foo!(a b); | -^ | | | help: missing comma here -error: aborting due to 2 previous errors +error: no rules expected the token `e` + --> $DIR/missing-comma.rs:24:21 + | +LL | foo!(a, b, c, d e); + | -^ + | | + | help: missing comma here + +error: no rules expected the token `d` + --> $DIR/missing-comma.rs:26:18 + | +LL | foo!(a, b, c d, e); + | -^ + | | + | help: missing comma here + +error: no rules expected the token `d` + --> $DIR/missing-comma.rs:28:18 + | +LL | foo!(a, b, c d e); + | ^ + +error: aborting due to 5 previous errors From 3a7005037726263c0beffd0efc3d5d147b2a86b4 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 6 Aug 2018 11:16:28 +0200 Subject: [PATCH 22/23] Address review comments for #53031 and fix some merge fallout. --- src/librustc/session/mod.rs | 7 +++++++ src/librustc_codegen_llvm/back/link.rs | 10 +++++----- src/librustc_codegen_llvm/back/write.rs | 2 +- src/test/codegen/no-dllimport-w-cross-lang-lto.rs | 2 +- src/test/codegen/target-cpu-on-functions.rs | 4 +++- .../cross-lang-lto-upstream-rlibs/Makefile | 4 ++-- 6 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 505511a4a0c1c..9a3ce50fcbdce 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -1202,6 +1202,13 @@ fn validate_commandline_args_with_session_available(sess: &Session) { sess.err("can't perform LTO when compiling incrementally"); } + // Since we don't know if code in an rlib will be linked to statically or + // dynamically downstream, rustc generates `__imp_` symbols that help the + // MSVC linker deal with this lack of knowledge (#27438). Unfortunately, + // these manually generated symbols confuse LLD when it tries to merge + // bitcode during ThinLTO. Therefore we disallow dynamic linking on MSVC + // when compiling for LLD ThinLTO. This way we can validly just not generate + // the `dllimport` attributes and `__imp_` symbols in that case. if sess.opts.debugging_opts.cross_lang_lto.enabled() && sess.opts.cg.prefer_dynamic && sess.target.target.options.is_like_msvc { diff --git a/src/librustc_codegen_llvm/back/link.rs b/src/librustc_codegen_llvm/back/link.rs index 72084c170aa71..50d41d76986fb 100644 --- a/src/librustc_codegen_llvm/back/link.rs +++ b/src/librustc_codegen_llvm/back/link.rs @@ -563,7 +563,7 @@ fn link_staticlib(sess: &Session, }); ab.add_rlib(path, &name.as_str(), - is_full_lto_enabled(sess) && + are_upstream_rust_objects_already_included(sess) && !ignored_for_lto(sess, &codegen_results.crate_info, cnum), skip_object_files).unwrap(); @@ -1446,7 +1446,7 @@ fn add_upstream_rust_crates(cmd: &mut dyn Linker, lib.kind == NativeLibraryKind::NativeStatic && !relevant_lib(sess, lib) }); - if (!is_full_lto_enabled(sess) || + if (!are_upstream_rust_objects_already_included(sess) || ignored_for_lto(sess, &codegen_results.crate_info, cnum)) && crate_type != config::CrateType::Dylib && !skip_native { @@ -1500,7 +1500,7 @@ fn add_upstream_rust_crates(cmd: &mut dyn Linker, // file, then we don't need the object file as it's part of the // LTO module. Note that `#![no_builtins]` is excluded from LTO, // though, so we let that object file slide. - let skip_because_lto = is_full_lto_enabled(sess) && + let skip_because_lto = are_upstream_rust_objects_already_included(sess) && is_rust_object && (sess.target.target.options.no_builtins || !codegen_results.crate_info.is_no_builtins.contains(&cnum)); @@ -1537,7 +1537,7 @@ fn add_upstream_rust_crates(cmd: &mut dyn Linker, fn add_dynamic_crate(cmd: &mut dyn Linker, sess: &Session, cratepath: &Path) { // If we're performing LTO, then it should have been previously required // that all upstream rust dependencies were available in an rlib format. - assert!(!is_full_lto_enabled(sess)); + assert!(!are_upstream_rust_objects_already_included(sess)); // Just need to tell the linker about where the library lives and // what its name is @@ -1623,7 +1623,7 @@ fn relevant_lib(sess: &Session, lib: &NativeLibrary) -> bool { } } -fn is_full_lto_enabled(sess: &Session) -> bool { +fn are_upstream_rust_objects_already_included(sess: &Session) -> bool { match sess.lto() { Lto::Yes | Lto::Fat => true, diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs index 47440d864d5e7..640e1c1f3d4f1 100644 --- a/src/librustc_codegen_llvm/back/write.rs +++ b/src/librustc_codegen_llvm/back/write.rs @@ -2385,7 +2385,7 @@ fn msvc_imps_needed(tcx: TyCtxt) -> bool { tcx.sess.opts.cg.prefer_dynamic)); tcx.sess.target.target.options.is_like_msvc && - tcx.sess.crate_types.borrow().iter().any(|ct| *ct == config::CrateTypeRlib) && + tcx.sess.crate_types.borrow().iter().any(|ct| *ct == config::CrateType::Rlib) && // ThinLTO can't handle this workaround in all cases, so we don't // emit the `__imp_` symbols. Instead we make them unnecessary by disallowing // dynamic linking when cross-language LTO is enabled. diff --git a/src/test/codegen/no-dllimport-w-cross-lang-lto.rs b/src/test/codegen/no-dllimport-w-cross-lang-lto.rs index 025e7cbf179a7..0d5d02206a632 100644 --- a/src/test/codegen/no-dllimport-w-cross-lang-lto.rs +++ b/src/test/codegen/no-dllimport-w-cross-lang-lto.rs @@ -13,7 +13,7 @@ // no-prefer-dynamic // only-msvc -// compile-flags: -C no-prepopulate-passes -Z cross-lang-lto +// compile-flags: -Z cross-lang-lto #![crate_type = "rlib"] diff --git a/src/test/codegen/target-cpu-on-functions.rs b/src/test/codegen/target-cpu-on-functions.rs index c2765a46caae0..1a6ab22e5685d 100644 --- a/src/test/codegen/target-cpu-on-functions.rs +++ b/src/test/codegen/target-cpu-on-functions.rs @@ -11,8 +11,10 @@ // This test makes sure that functions get annotated with the proper // "target-cpu" attribute in LLVM. +// no-prefer-dynamic +// ignore-tidy-linelength // only-x86_64 -// compile-flags: -C no-prepopulate-passes -C panic=abort +// compile-flags: -C no-prepopulate-passes -C panic=abort -Z cross-lang-lto -Cpasses=name-anon-globals #![crate_type = "staticlib"] diff --git a/src/test/run-make-fulldeps/cross-lang-lto-upstream-rlibs/Makefile b/src/test/run-make-fulldeps/cross-lang-lto-upstream-rlibs/Makefile index de42c6e0eb54e..0a6f226a027f3 100644 --- a/src/test/run-make-fulldeps/cross-lang-lto-upstream-rlibs/Makefile +++ b/src/test/run-make-fulldeps/cross-lang-lto-upstream-rlibs/Makefile @@ -11,7 +11,7 @@ all: staticlib.rs upstream.rs $(RUSTC) staticlib.rs -Z cross-lang-lto -Ccodegen-units=1 -L. -o $(TMPDIR)/staticlib.a (cd $(TMPDIR); llvm-ar x ./staticlib.a) # Make sure the upstream object file was included - ls upstream.*.rcgu.o + ls $(TMPDIR)/upstream.*.rcgu.o # Cleanup rm $(TMPDIR)/* @@ -20,4 +20,4 @@ all: staticlib.rs upstream.rs $(RUSTC) upstream.rs -Z cross-lang-lto -Ccodegen-units=1 -Clto=thin $(RUSTC) staticlib.rs -Z cross-lang-lto -Ccodegen-units=1 -Clto=thin -L. -o $(TMPDIR)/staticlib.a (cd $(TMPDIR); llvm-ar x ./staticlib.a) - ls upstream.*.rcgu.o + ls $(TMPDIR)/upstream.*.rcgu.o From 9876e38f5cce74bf06a0af699eef7ee6510727d9 Mon Sep 17 00:00:00 2001 From: ljedrz Date: Sun, 5 Aug 2018 12:04:56 +0200 Subject: [PATCH 23/23] 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 71d064a13f36a..be414f094dc56 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -2048,6 +2048,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 6b66fd8a2b2ff..9ae5ab7f8be2e 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}; @@ -3136,12 +3137,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 { @@ -3174,21 +3175,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); @@ -3196,14 +3197,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 { @@ -4295,8 +4296,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 0003790e6d552..899d91990e2b2 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 05843852ee0de..676dbeeeeb00b 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 dd90cf7ae19e4..8c8cc8ce7a19a 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -74,6 +74,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 de391ee4219a4..482d8c2cf9866 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 12941a8566987..f7ea781e02115 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; } } @@ -279,7 +279,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), @@ -989,28 +989,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); @@ -1019,7 +1019,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) { @@ -1086,12 +1086,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; @@ -1254,10 +1254,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 @@ -1313,7 +1313,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); @@ -1422,7 +1422,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 { @@ -1433,7 +1433,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); @@ -1453,7 +1453,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); @@ -1490,7 +1490,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); if attr.is_some() || !traits.is_empty() { 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 c8e60620248b3..7937799272c66 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -43,6 +43,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 @@ -122,12 +124,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 {