From ef6fddd16f49f7e18c737850657b951c9299a926 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 31 Jul 2018 01:59:41 +0300 Subject: [PATCH 01/23] cleanup: Remove `Def::GlobalAsm` --- src/librustc/hir/def.rs | 6 +----- src/librustc/hir/map/mod.rs | 2 +- src/librustc/ich/impls_hir.rs | 1 - src/librustc_metadata/decoder.rs | 2 +- src/librustc_resolve/lib.rs | 9 ++------- src/librustc_save_analysis/lib.rs | 1 - 6 files changed, 5 insertions(+), 16 deletions(-) diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs index 1c355e35fd6ea..7866ae8a72061 100644 --- a/src/librustc/hir/def.rs +++ b/src/librustc/hir/def.rs @@ -68,8 +68,6 @@ pub enum Def { // Macro namespace Macro(DefId, MacroKind), - GlobalAsm(DefId), - // Both namespaces Err, } @@ -249,8 +247,7 @@ impl Def { Def::AssociatedTy(id) | Def::TyParam(id) | Def::Struct(id) | Def::StructCtor(id, ..) | Def::Union(id) | Def::Trait(id) | Def::Method(id) | Def::Const(id) | Def::AssociatedConst(id) | Def::Macro(id, ..) | - Def::Existential(id) | Def::AssociatedExistential(id) | - Def::GlobalAsm(id) | Def::TyForeign(id) => { + Def::Existential(id) | Def::AssociatedExistential(id) | Def::TyForeign(id) => { id } @@ -298,7 +295,6 @@ impl Def { Def::Label(..) => "label", Def::SelfTy(..) => "self type", Def::Macro(.., macro_kind) => macro_kind.descr(), - Def::GlobalAsm(..) => "global asm", Def::Err => "unresolved item", } } diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 49231e58cf0fc..b05bcadf82649 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -432,7 +432,6 @@ impl<'hir> Map<'hir> { ItemKind::Const(..) => Some(Def::Const(def_id())), ItemKind::Fn(..) => Some(Def::Fn(def_id())), ItemKind::Mod(..) => Some(Def::Mod(def_id())), - ItemKind::GlobalAsm(..) => Some(Def::GlobalAsm(def_id())), ItemKind::Existential(..) => Some(Def::Existential(def_id())), ItemKind::Ty(..) => Some(Def::TyAlias(def_id())), ItemKind::Enum(..) => Some(Def::Enum(def_id())), @@ -445,6 +444,7 @@ impl<'hir> Map<'hir> { ItemKind::ExternCrate(_) | ItemKind::Use(..) | ItemKind::ForeignMod(..) | + ItemKind::GlobalAsm(..) | ItemKind::Impl(..) => None, } } diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index 410d578d4044c..4d53e9eeea4cd 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -1015,7 +1015,6 @@ impl_stable_hash_for!(enum hir::def::Def { Upvar(def_id, index, expr_id), Label(node_id), Macro(def_id, macro_kind), - GlobalAsm(def_id), Err }); diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index ab566654c389c..cf034d9425759 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -427,10 +427,10 @@ impl<'tcx> EntryKind<'tcx> { EntryKind::Trait(_) => Def::Trait(did), EntryKind::Enum(..) => Def::Enum(did), EntryKind::MacroDef(_) => Def::Macro(did, MacroKind::Bang), - EntryKind::GlobalAsm => Def::GlobalAsm(did), EntryKind::ForeignType => Def::TyForeign(did), EntryKind::ForeignMod | + EntryKind::GlobalAsm | EntryKind::Impl(_) | EntryKind::Field | EntryKind::Generator(_) | diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 9714679949ff4..7c21eab78bf88 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -200,15 +200,10 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver, err.span_label(typaram_span, "type variable from outer function"); } }, - Def::Mod(..) | Def::Struct(..) | Def::Union(..) | Def::Enum(..) | Def::Variant(..) | - Def::Trait(..) | Def::TyAlias(..) | Def::TyForeign(..) | Def::TraitAlias(..) | - Def::AssociatedTy(..) | Def::PrimTy(..) | Def::Fn(..) | Def::Const(..) | - Def::Static(..) | Def::StructCtor(..) | Def::VariantCtor(..) | Def::Method(..) | - Def::AssociatedConst(..) | Def::Local(..) | Def::Upvar(..) | Def::Label(..) | - Def::Existential(..) | Def::AssociatedExistential(..) | - Def::Macro(..) | Def::GlobalAsm(..) | Def::Err => + _ => { bug!("TypeParametersFromOuterFunction should only be used with Def::SelfTy or \ Def::TyParam") + } } // Try to retrieve the span of the function signature and generate a new message with diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 761521c8807ca..5260076f464d0 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -810,7 +810,6 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { HirDef::SelfTy(..) | HirDef::Label(..) | HirDef::Macro(..) | - HirDef::GlobalAsm(..) | HirDef::Err => None, } } From e9509d78bd1c790b49000bc469e8ad812ea88457 Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Mon, 30 Jul 2018 19:55:08 -0500 Subject: [PATCH 02/23] Disable debug sections when optimization flags is set for LLD. --- src/librustc_codegen_llvm/back/linker.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/librustc_codegen_llvm/back/linker.rs b/src/librustc_codegen_llvm/back/linker.rs index 5f2f3733ec7f0..7253b5346b9ab 100644 --- a/src/librustc_codegen_llvm/back/linker.rs +++ b/src/librustc_codegen_llvm/back/linker.rs @@ -1006,6 +1006,18 @@ impl<'a> Linker for WasmLd<'a> { OptLevel::Size => "-O2", OptLevel::SizeMin => "-O2" }); + match self.sess.opts.optimize { + OptLevel::No => (), + OptLevel::Less | + OptLevel::Default | + OptLevel::Aggressive | + OptLevel::Size | + OptLevel::SizeMin => { + // LLD generates incorrect debugging information when + // optimization is applied: strip debug sections. + self.cmd.arg("--strip-debug"); + } + } } fn pgo_gen(&mut self) { From 5e70e5e439fb30cd459df275df87242932c2b7a6 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Tue, 31 Jul 2018 12:07:37 -0600 Subject: [PATCH 03/23] Move validate_crate_name to rustc_metadata --- src/Cargo.lock | 1 + src/librustc/middle/cstore.rs | 27 ------------------------- src/librustc_codegen_utils/Cargo.toml | 1 + src/librustc_codegen_utils/lib.rs | 1 + src/librustc_codegen_utils/link.rs | 5 +++-- src/librustc_metadata/creader.rs | 29 ++++++++++++++++++++++++++- 6 files changed, 34 insertions(+), 30 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index be32872dad80a..e4f8b28a815e3 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -2115,6 +2115,7 @@ dependencies = [ "rustc 0.0.0", "rustc_data_structures 0.0.0", "rustc_incremental 0.0.0", + "rustc_metadata 0.0.0", "rustc_mir 0.0.0", "rustc_target 0.0.0", "syntax 0.0.0", diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 54169acac46ac..6132d8f2bf6a1 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -260,33 +260,6 @@ pub trait CrateStore { pub type CrateStoreDyn = dyn CrateStore + sync::Sync; -// FIXME: find a better place for this? -pub fn validate_crate_name(sess: Option<&Session>, s: &str, sp: Option) { - let mut err_count = 0; - { - let mut say = |s: &str| { - match (sp, sess) { - (_, None) => bug!("{}", s), - (Some(sp), Some(sess)) => sess.span_err(sp, s), - (None, Some(sess)) => sess.err(s), - } - err_count += 1; - }; - if s.is_empty() { - say("crate name must not be empty"); - } - for c in s.chars() { - if c.is_alphanumeric() { continue } - if c == '_' { continue } - say(&format!("invalid character `{}` in crate name: `{}`", c, s)); - } - } - - if err_count > 0 { - sess.unwrap().abort_if_errors(); - } -} - /// A dummy crate store that does not support any non-local crates, /// for test purposes. pub struct DummyCrateStore; diff --git a/src/librustc_codegen_utils/Cargo.toml b/src/librustc_codegen_utils/Cargo.toml index 30f533285ddfd..9701b06fbe835 100644 --- a/src/librustc_codegen_utils/Cargo.toml +++ b/src/librustc_codegen_utils/Cargo.toml @@ -20,3 +20,4 @@ rustc_target = { path = "../librustc_target" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_mir = { path = "../librustc_mir" } rustc_incremental = { path = "../librustc_incremental" } +rustc_metadata = { path = "../librustc_metadata" } diff --git a/src/librustc_codegen_utils/lib.rs b/src/librustc_codegen_utils/lib.rs index f59cf5832fcb4..e0d99b90d4797 100644 --- a/src/librustc_codegen_utils/lib.rs +++ b/src/librustc_codegen_utils/lib.rs @@ -37,6 +37,7 @@ extern crate rustc_incremental; extern crate syntax; extern crate syntax_pos; #[macro_use] extern crate rustc_data_structures; +extern crate rustc_metadata; use rustc::ty::TyCtxt; diff --git a/src/librustc_codegen_utils/link.rs b/src/librustc_codegen_utils/link.rs index aabe931d79c57..8c01bb454b314 100644 --- a/src/librustc_codegen_utils/link.rs +++ b/src/librustc_codegen_utils/link.rs @@ -10,11 +10,12 @@ use rustc::session::config::{self, OutputFilenames, Input, OutputType}; use rustc::session::Session; -use rustc::middle::cstore::{self, LinkMeta}; +use rustc::middle::cstore::LinkMeta; use rustc::hir::svh::Svh; use std::path::{Path, PathBuf}; use syntax::{ast, attr}; use syntax_pos::Span; +use rustc_metadata::creader; pub fn out_filename(sess: &Session, crate_type: config::CrateType, @@ -61,7 +62,7 @@ pub fn find_crate_name(sess: Option<&Session>, attrs: &[ast::Attribute], input: &Input) -> String { let validate = |s: String, span: Option| { - cstore::validate_crate_name(sess, &s, span); + creader::validate_crate_name(sess, &s, span); s }; diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 4f808dee61f21..7ddca344b03e4 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -25,7 +25,7 @@ use rustc::session::config::{Sanitizer, self}; use rustc_target::spec::{PanicStrategy, TargetTriple}; use rustc::session::search_paths::PathKind; use rustc::middle; -use rustc::middle::cstore::{validate_crate_name, ExternCrate, ExternCrateSource}; +use rustc::middle::cstore::{ExternCrate, ExternCrateSource}; use rustc::util::common::record_time; use rustc::util::nodemap::FxHashSet; use rustc::hir::map::Definitions; @@ -1165,3 +1165,30 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> { cnum } } + +pub fn validate_crate_name(sess: Option<&Session>, s: &str, sp: Option) { + let mut err_count = 0; + { + let mut say = |s: &str| { + match (sp, sess) { + (_, None) => bug!("{}", s), + (Some(sp), Some(sess)) => sess.span_err(sp, s), + (None, Some(sess)) => sess.err(s), + } + err_count += 1; + }; + if s.is_empty() { + say("crate name must not be empty"); + } + for c in s.chars() { + if c.is_alphanumeric() { continue } + if c == '_' { continue } + say(&format!("invalid character `{}` in crate name: `{}`", c, s)); + } + } + + if err_count > 0 { + sess.unwrap().abort_if_errors(); + } +} + From 8752e61080776dfe1a234780f49d9d935c61cdb8 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Tue, 31 Jul 2018 14:24:31 -0600 Subject: [PATCH 04/23] Delete dummy crate store --- src/librustc/middle/cstore.rs | 63 ----------------------------------- 1 file changed, 63 deletions(-) diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 6132d8f2bf6a1..793a3f2abc140 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -260,69 +260,6 @@ pub trait CrateStore { pub type CrateStoreDyn = dyn CrateStore + sync::Sync; -/// A dummy crate store that does not support any non-local crates, -/// for test purposes. -pub struct DummyCrateStore; - -#[allow(unused_variables)] -impl CrateStore for DummyCrateStore { - fn crate_data_as_rc_any(&self, krate: CrateNum) -> Lrc - { bug!("crate_data_as_rc_any") } - // item info - fn visibility_untracked(&self, def: DefId) -> ty::Visibility { bug!("visibility") } - fn item_generics_cloned_untracked(&self, def: DefId, sess: &Session) -> ty::Generics - { bug!("item_generics_cloned") } - - // trait/impl-item info - fn associated_item_cloned_untracked(&self, def: DefId) -> ty::AssociatedItem - { bug!("associated_item_cloned") } - - // crate metadata - fn dep_kind_untracked(&self, cnum: CrateNum) -> DepKind { bug!("is_explicitly_linked") } - fn export_macros_untracked(&self, cnum: CrateNum) { bug!("export_macros") } - fn crate_name_untracked(&self, cnum: CrateNum) -> Symbol { bug!("crate_name") } - fn crate_disambiguator_untracked(&self, cnum: CrateNum) -> CrateDisambiguator { - bug!("crate_disambiguator") - } - fn crate_hash_untracked(&self, cnum: CrateNum) -> Svh { bug!("crate_hash") } - fn crate_edition_untracked(&self, cnum: CrateNum) -> Edition { bug!("crate_edition_untracked") } - - // resolve - fn def_key(&self, def: DefId) -> DefKey { bug!("def_key") } - fn def_path(&self, def: DefId) -> hir_map::DefPath { - bug!("relative_def_path") - } - fn def_path_hash(&self, def: DefId) -> hir_map::DefPathHash { - bug!("def_path_hash") - } - fn def_path_table(&self, cnum: CrateNum) -> Lrc { - bug!("def_path_table") - } - fn struct_field_names_untracked(&self, def: DefId) -> Vec { - bug!("struct_field_names") - } - fn item_children_untracked(&self, did: DefId, sess: &Session) -> Vec { - bug!("item_children") - } - fn load_macro_untracked(&self, did: DefId, sess: &Session) -> LoadedMacro { bug!("load_macro") } - - fn crates_untracked(&self) -> Vec { vec![] } - - // utility functions - fn extern_mod_stmt_cnum_untracked(&self, emod_id: ast::NodeId) -> Option { None } - fn encode_metadata<'a, 'tcx>(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - link_meta: &LinkMeta) - -> EncodedMetadata { - bug!("encode_metadata") - } - fn metadata_encoding_version(&self) -> &[u8] { bug!("metadata_encoding_version") } - fn postorder_cnums_untracked(&self) -> Vec { bug!("postorder_cnums_untracked") } - - // access to the metadata loader - fn metadata_loader(&self) -> &dyn MetadataLoader { bug!("metadata_loader") } -} - pub trait CrateLoader { fn process_extern_crate(&mut self, item: &ast::Item, defs: &Definitions) -> CrateNum; From 5ce5f310cc1d08fd27d16f0335ff74f56ef321c2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 1 Aug 2018 00:25:46 +0200 Subject: [PATCH 05/23] check_const: use the same ParamEnv as codegen for statics --- src/librustc_lint/builtin.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 7cb4f7d386098..223edd16c635a 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1630,7 +1630,12 @@ fn validate_const<'a, 'tcx>( fn check_const(cx: &LateContext, body_id: hir::BodyId, what: &str) { let def_id = cx.tcx.hir.body_owner_def_id(body_id); - let param_env = cx.tcx.param_env(def_id); + let is_static = cx.tcx.is_static(def_id).is_some(); + let param_env = if is_static { + ty::ParamEnv::reveal_all() + } else { + cx.tcx.param_env(def_id) + }; let cid = ::rustc::mir::interpret::GlobalId { instance: ty::Instance::mono(cx.tcx, def_id), promoted: None @@ -1638,8 +1643,8 @@ fn check_const(cx: &LateContext, body_id: hir::BodyId, what: &str) { match cx.tcx.const_eval(param_env.and(cid)) { Ok(val) => validate_const(cx.tcx, val, param_env, cid, what), Err(err) => { - // errors for statics are already reported directly in the query - if cx.tcx.is_static(def_id).is_none() { + // errors for statics are already reported directly in the query, avoid duplicates + if !is_static { let span = cx.tcx.def_span(def_id); err.report_as_lint( cx.tcx.at(span), From d148b4112e2a49b7949296682403e7021f8ed10e Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Tue, 31 Jul 2018 15:35:35 -0600 Subject: [PATCH 06/23] Visibility is now a query --- src/librustc/middle/cstore.rs | 1 - src/librustc_metadata/cstore_impl.rs | 4 ---- 2 files changed, 5 deletions(-) diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 793a3f2abc140..caa8ad7da995a 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -231,7 +231,6 @@ pub trait CrateStore { fn def_path_table(&self, cnum: CrateNum) -> Lrc; // "queries" used in resolve that aren't tracked for incremental compilation - fn visibility_untracked(&self, def: DefId) -> ty::Visibility; fn export_macros_untracked(&self, cnum: CrateNum); fn dep_kind_untracked(&self, cnum: CrateNum) -> DepKind; fn crate_name_untracked(&self, cnum: CrateNum) -> Symbol; diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index e3a7918f8c589..fc23494585a76 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -420,10 +420,6 @@ impl CrateStore for cstore::CStore { &*self.metadata_loader } - fn visibility_untracked(&self, def: DefId) -> ty::Visibility { - self.get_crate_data(def.krate).get_visibility(def.index) - } - fn item_generics_cloned_untracked(&self, def: DefId, sess: &Session) -> ty::Generics { self.get_crate_data(def.krate).get_generics(def.index, sess) } From 222dd1794452308724bfdf2842d50718a710b22c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 1 Aug 2018 08:39:30 +0200 Subject: [PATCH 07/23] add comment --- src/librustc_lint/builtin.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 223edd16c635a..cf3a5449b0395 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1632,6 +1632,7 @@ fn check_const(cx: &LateContext, body_id: hir::BodyId, what: &str) { let def_id = cx.tcx.hir.body_owner_def_id(body_id); let is_static = cx.tcx.is_static(def_id).is_some(); let param_env = if is_static { + // Use the same param_env as `codegen_static_initializer`, to reuse the cache. ty::ParamEnv::reveal_all() } else { cx.tcx.param_env(def_id) From 0da7da8391cfb27a809b3fea7e0f50dd64d018c8 Mon Sep 17 00:00:00 2001 From: kennytm Date: Wed, 1 Aug 2018 18:03:19 +0800 Subject: [PATCH 08/23] Align 6-week cycle check with beta promotion instead of stable release. The regression check is to make beta promotion easier, so it makes more sense to use the Tuesday of the release week (T-2) as the end point of the regression prevention, instead of Thursday (T-0). But since the beta promotion PR is sent at Tuesday evening at UTC, the protection should include the whole Tuesday as well, meaning the 6-week cycle will start from Wednesdays. This will also move the start of the regression protection week one day earlier. --- src/ci/docker/x86_64-gnu-tools/checktools.sh | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/ci/docker/x86_64-gnu-tools/checktools.sh b/src/ci/docker/x86_64-gnu-tools/checktools.sh index 16055078ad5eb..d876cb7f37a41 100755 --- a/src/ci/docker/x86_64-gnu-tools/checktools.sh +++ b/src/ci/docker/x86_64-gnu-tools/checktools.sh @@ -17,9 +17,11 @@ TOOLSTATE_FILE="$(realpath $2)" OS="$3" COMMIT="$(git rev-parse HEAD)" CHANGED_FILES="$(git diff --name-status HEAD HEAD^)" -SIX_WEEK_CYCLE="$(( ($(date +%s) / 604800 - 3) % 6 ))" -# ^ 1970 Jan 1st is a Thursday, and our release dates are also on Thursdays, -# thus we could divide by 604800 (7 days in seconds) directly. +SIX_WEEK_CYCLE="$(( ($(date +%s) / 86400 - 20) % 42 ))" +# ^ Number of days after the last promotion of beta. +# Its value is 41 on the Tuesday where "Promote master to beta (T-2)" happens. +# The Wednesday after this has value 0. +# We track this value to prevent regressing tools in the last week of the 6-week cycle. touch "$TOOLSTATE_FILE" @@ -98,7 +100,7 @@ change_toolstate() { if python2.7 "$CHECK_NOT" "$OS" "$TOOLSTATE_FILE" "_data/latest.json" changed; then echo 'Toolstate is not changed. Not updating.' else - if [ $SIX_WEEK_CYCLE -eq 5 ]; then + if [ $SIX_WEEK_CYCLE -ge 35 ]; then python2.7 "$CHECK_NOT" "$OS" "$TOOLSTATE_FILE" "_data/latest.json" regressed fi sed -i "1 a\\ From 424f6bdf9b793b0afd76ace2ac7696f1385a6ef3 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Tue, 31 Jul 2018 15:23:31 -0600 Subject: [PATCH 09/23] Store concrete crate stores where possible --- src/Cargo.lock | 1 + src/librustc/middle/cstore.rs | 22 +------------- src/librustc_driver/driver.rs | 15 +++++----- src/librustc_driver/lib.rs | 6 ++-- src/librustc_driver/pretty.rs | 8 +++--- src/librustc_metadata/creader.rs | 13 +++++---- src/librustc_resolve/Cargo.toml | 1 + src/librustc_resolve/build_reduced_graph.rs | 11 +++---- src/librustc_resolve/check_unused.rs | 18 ++++++------ src/librustc_resolve/lib.rs | 30 +++++++++++--------- src/librustc_resolve/macros.rs | 11 ++++--- src/librustc_resolve/resolve_imports.rs | 23 ++++++++------- src/librustdoc/clean/auto_trait.rs | 9 +++--- src/librustdoc/clean/inline.rs | 2 +- src/librustdoc/clean/mod.rs | 2 +- src/librustdoc/core.rs | 9 +++--- src/librustdoc/visit_ast.rs | 10 ++++--- src/librustdoc/visit_lib.rs | 10 ++++--- src/test/run-pass-fulldeps/compiler-calls.rs | 5 ++-- 19 files changed, 101 insertions(+), 105 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index e4f8b28a815e3..07fd9765fa0c5 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -2338,6 +2338,7 @@ dependencies = [ "rustc 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", + "rustc_metadata 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", ] diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index caa8ad7da995a..492be23fa1714 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -25,7 +25,7 @@ use hir::def; use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use hir::map as hir_map; -use hir::map::definitions::{Definitions, DefKey, DefPathTable}; +use hir::map::definitions::{DefKey, DefPathTable}; use hir::svh::Svh; use ty::{self, TyCtxt}; use session::{Session, CrateDisambiguator}; @@ -259,26 +259,6 @@ pub trait CrateStore { pub type CrateStoreDyn = dyn CrateStore + sync::Sync; -pub trait CrateLoader { - fn process_extern_crate(&mut self, item: &ast::Item, defs: &Definitions) -> CrateNum; - - fn process_path_extern( - &mut self, - name: Symbol, - span: Span, - ) -> CrateNum; - - fn process_use_extern( - &mut self, - name: Symbol, - span: Span, - id: ast::NodeId, - defs: &Definitions, - ) -> CrateNum; - - fn postprocess(&mut self, krate: &ast::Crate); -} - // This method is used when generating the command line to pass through to // system linker. The linker expects undefined symbols on the left of the // command line to be defined in libraries on the right, not the other way diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 24a2354775cb5..93469dcf96df1 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -20,7 +20,6 @@ use rustc::session::config::{self, Input, OutputFilenames, OutputType}; use rustc::session::search_paths::PathKind; use rustc::lint; use rustc::middle::{self, reachable, resolve_lifetime, stability}; -use rustc::middle::cstore::CrateStoreDyn; use rustc::middle::privacy::AccessLevels; use rustc::ty::{self, AllArenas, Resolutions, TyCtxt}; use rustc::traits; @@ -475,7 +474,7 @@ impl<'a> ::CompilerCalls<'a> for CompileController<'a> { codegen_backend: &dyn (::CodegenBackend), matches: &::getopts::Matches, sess: &Session, - cstore: &dyn (::CrateStore), + cstore: &CStore, input: &Input, odir: &Option, ofile: &Option, @@ -717,9 +716,9 @@ pub struct ExpansionResult { pub hir_forest: hir_map::Forest, } -pub struct InnerExpansionResult<'a> { +pub struct InnerExpansionResult<'a, 'b: 'a> { pub expanded_crate: ast::Crate, - pub resolver: Resolver<'a>, + pub resolver: Resolver<'a, 'b>, pub hir_forest: hir_map::Forest, } @@ -795,7 +794,7 @@ where /// Same as phase_2_configure_and_expand, but doesn't let you keep the resolver /// around -pub fn phase_2_configure_and_expand_inner<'a, F>( +pub fn phase_2_configure_and_expand_inner<'a, 'b: 'a, F>( sess: &'a Session, cstore: &'a CStore, mut krate: ast::Crate, @@ -804,9 +803,9 @@ pub fn phase_2_configure_and_expand_inner<'a, F>( addl_plugins: Option>, make_glob_map: MakeGlobMap, resolver_arenas: &'a ResolverArenas<'a>, - crate_loader: &'a mut CrateLoader, + crate_loader: &'a mut CrateLoader<'b>, after_expand: F, -) -> Result, CompileIncomplete> +) -> Result, CompileIncomplete> where F: FnOnce(&ast::Crate) -> CompileResult, { @@ -1196,7 +1195,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>( codegen_backend: &dyn CodegenBackend, control: &CompileController, sess: &'tcx Session, - cstore: &'tcx CrateStoreDyn, + cstore: &'tcx CStore, hir_map: hir_map::Map<'tcx>, mut analysis: ty::CrateAnalysis, resolutions: Resolutions, diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index df641b8fbc0fe..ed3fda8e72300 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -676,7 +676,7 @@ pub trait CompilerCalls<'a> { _: &dyn CodegenBackend, _: &getopts::Matches, _: &Session, - _: &dyn CrateStore, + _: &CStore, _: &Input, _: &Option, _: &Option) @@ -884,7 +884,7 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { codegen_backend: &dyn CodegenBackend, matches: &getopts::Matches, sess: &Session, - cstore: &dyn CrateStore, + cstore: &CStore, input: &Input, odir: &Option, ofile: &Option) @@ -990,7 +990,7 @@ pub fn enable_save_analysis(control: &mut CompileController) { impl RustcDefaultCalls { pub fn list_metadata(sess: &Session, - cstore: &dyn CrateStore, + cstore: &CStore, matches: &getopts::Matches, input: &Input) -> Compilation { diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 6433a93a317a6..5c1f3bfbe670b 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -20,11 +20,11 @@ use {abort_on_err, driver}; use rustc::ty::{self, TyCtxt, Resolutions, AllArenas}; use rustc::cfg; use rustc::cfg::graphviz::LabelledCFG; -use rustc::middle::cstore::CrateStoreDyn; use rustc::session::Session; use rustc::session::config::{Input, OutputFilenames}; use rustc_borrowck as borrowck; use rustc_borrowck::graphviz as borrowck_dot; +use rustc_metadata::cstore::CStore; use rustc_mir::util::{write_mir_pretty, write_mir_graphviz}; @@ -199,7 +199,7 @@ impl PpSourceMode { } fn call_with_pp_support_hir<'tcx, A, F>(&self, sess: &'tcx Session, - cstore: &'tcx CrateStoreDyn, + cstore: &'tcx CStore, hir_map: &hir_map::Map<'tcx>, analysis: &ty::CrateAnalysis, resolutions: &Resolutions, @@ -918,7 +918,7 @@ pub fn print_after_parsing(sess: &Session, } pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session, - cstore: &'tcx CrateStoreDyn, + cstore: &'tcx CStore, hir_map: &hir_map::Map<'tcx>, analysis: &ty::CrateAnalysis, resolutions: &Resolutions, @@ -1074,7 +1074,7 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session, // with a different callback than the standard driver, so that isn't easy. // Instead, we call that function ourselves. fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session, - cstore: &'a CrateStoreDyn, + cstore: &'a CStore, hir_map: &hir_map::Map<'tcx>, analysis: &ty::CrateAnalysis, resolutions: &Resolutions, diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 7ddca344b03e4..2971fbb5b4266 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -24,7 +24,6 @@ use rustc::session::{Session, CrateDisambiguator}; use rustc::session::config::{Sanitizer, self}; use rustc_target::spec::{PanicStrategy, TargetTriple}; use rustc::session::search_paths::PathKind; -use rustc::middle; use rustc::middle::cstore::{ExternCrate, ExternCrateSource}; use rustc::util::common::record_time; use rustc::util::nodemap::FxHashSet; @@ -1056,8 +1055,8 @@ impl<'a> CrateLoader<'a> { } } -impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> { - fn postprocess(&mut self, krate: &ast::Crate) { +impl<'a> CrateLoader<'a> { + pub fn postprocess(&mut self, krate: &ast::Crate) { // inject the sanitizer runtime before the allocator runtime because all // sanitizers force the use of the `alloc_system` allocator self.inject_sanitizer_runtime(); @@ -1070,7 +1069,9 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> { } } - fn process_extern_crate(&mut self, item: &ast::Item, definitions: &Definitions) -> CrateNum { + pub fn process_extern_crate( + &mut self, item: &ast::Item, definitions: &Definitions, + ) -> CrateNum { match item.node { ast::ItemKind::ExternCrate(orig_name) => { debug!("resolving extern crate stmt. ident: {} orig_name: {:?}", @@ -1113,7 +1114,7 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> { } } - fn process_path_extern( + pub fn process_path_extern( &mut self, name: Symbol, span: Span, @@ -1137,7 +1138,7 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> { cnum } - fn process_use_extern( + pub fn process_use_extern( &mut self, name: Symbol, span: Span, diff --git a/src/librustc_resolve/Cargo.toml b/src/librustc_resolve/Cargo.toml index 4c8d42cf02f98..837340f70fce7 100644 --- a/src/librustc_resolve/Cargo.toml +++ b/src/librustc_resolve/Cargo.toml @@ -17,3 +17,4 @@ arena = { path = "../libarena" } rustc_errors = { path = "../librustc_errors" } syntax_pos = { path = "../libsyntax_pos" } rustc_data_structures = { path = "../librustc_data_structures" } +rustc_metadata = { path = "../librustc_metadata" } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index da2847dc55793..71fd08f2f15be 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -25,6 +25,7 @@ use rustc::middle::cstore::LoadedMacro; use rustc::hir::def::*; use rustc::hir::def_id::{BUILTIN_MACROS_CRATE, CRATE_DEF_INDEX, LOCAL_CRATE, DefId}; use rustc::ty; +use rustc::middle::cstore::CrateStore; use std::cell::Cell; use rustc_data_structures::sync::Lrc; @@ -73,7 +74,7 @@ struct LegacyMacroImports { imports: Vec<(Name, Span)>, } -impl<'a> Resolver<'a> { +impl<'a, 'cl> Resolver<'a, 'cl> { /// Defines `name` in namespace `ns` of module `parent` to be `def` if it is not yet defined; /// otherwise, reports an error. pub fn define(&mut self, parent: Module<'a>, ident: Ident, ns: Namespace, def: T) @@ -762,13 +763,13 @@ impl<'a> Resolver<'a> { } } -pub struct BuildReducedGraphVisitor<'a, 'b: 'a> { - pub resolver: &'a mut Resolver<'b>, +pub struct BuildReducedGraphVisitor<'a, 'b: 'a, 'c: 'b> { + pub resolver: &'a mut Resolver<'b, 'c>, pub legacy_scope: LegacyScope<'b>, pub expansion: Mark, } -impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { +impl<'a, 'b, 'cl> BuildReducedGraphVisitor<'a, 'b, 'cl> { fn visit_invoc(&mut self, id: ast::NodeId) -> &'b InvocationData<'b> { let mark = id.placeholder_to_mark(); self.resolver.current_module.unresolved_invocations.borrow_mut().insert(mark); @@ -791,7 +792,7 @@ macro_rules! method { } } -impl<'a, 'b> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b> { +impl<'a, 'b, 'cl> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b, 'cl> { method!(visit_impl_item: ast::ImplItem, ast::ImplItemKind::Macro, walk_impl_item); method!(visit_expr: ast::Expr, ast::ExprKind::Mac, walk_expr); method!(visit_pat: ast::Pat, ast::PatKind::Mac, walk_pat); diff --git a/src/librustc_resolve/check_unused.rs b/src/librustc_resolve/check_unused.rs index ec067a6477b6d..cbbb921981ce9 100644 --- a/src/librustc_resolve/check_unused.rs +++ b/src/librustc_resolve/check_unused.rs @@ -31,8 +31,8 @@ use syntax::visit::{self, Visitor}; use syntax_pos::{Span, MultiSpan, DUMMY_SP}; -struct UnusedImportCheckVisitor<'a, 'b: 'a> { - resolver: &'a mut Resolver<'b>, +struct UnusedImportCheckVisitor<'a, 'b: 'a, 'd: 'b> { + resolver: &'a mut Resolver<'b, 'd>, /// All the (so far) unused imports, grouped path list unused_imports: NodeMap>, base_id: ast::NodeId, @@ -40,21 +40,21 @@ struct UnusedImportCheckVisitor<'a, 'b: 'a> { } // Deref and DerefMut impls allow treating UnusedImportCheckVisitor as Resolver. -impl<'a, 'b> Deref for UnusedImportCheckVisitor<'a, 'b> { - type Target = Resolver<'b>; +impl<'a, 'b, 'd> Deref for UnusedImportCheckVisitor<'a, 'b, 'd> { + type Target = Resolver<'b, 'd>; - fn deref<'c>(&'c self) -> &'c Resolver<'b> { + fn deref<'c>(&'c self) -> &'c Resolver<'b, 'd> { &*self.resolver } } -impl<'a, 'b> DerefMut for UnusedImportCheckVisitor<'a, 'b> { - fn deref_mut<'c>(&'c mut self) -> &'c mut Resolver<'b> { +impl<'a, 'b, 'd> DerefMut for UnusedImportCheckVisitor<'a, 'b, 'd> { + fn deref_mut<'c>(&'c mut self) -> &'c mut Resolver<'b, 'd> { &mut *self.resolver } } -impl<'a, 'b> UnusedImportCheckVisitor<'a, 'b> { +impl<'a, 'b, 'd> UnusedImportCheckVisitor<'a, 'b, 'd> { // We have information about whether `use` (import) directives are actually // used now. If an import is not used at all, we signal a lint error. fn check_import(&mut self, item_id: ast::NodeId, id: ast::NodeId, span: Span) { @@ -77,7 +77,7 @@ impl<'a, 'b> UnusedImportCheckVisitor<'a, 'b> { } } -impl<'a, 'b> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b> { +impl<'a, 'b, 'cl> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b, 'cl> { fn visit_item(&mut self, item: &'a ast::Item) { self.item_span = item.span; diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 9714679949ff4..5564346d5c13c 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -26,6 +26,7 @@ extern crate arena; #[macro_use] extern crate rustc; extern crate rustc_data_structures; +extern crate rustc_metadata; pub use rustc::hir::def::{Namespace, PerNS}; @@ -34,7 +35,7 @@ use self::RibKind::*; use rustc::hir::map::{Definitions, DefCollector}; use rustc::hir::{self, PrimTy, TyBool, TyChar, TyFloat, TyInt, TyUint, TyStr}; -use rustc::middle::cstore::{CrateStore, CrateLoader}; +use rustc::middle::cstore::CrateStore; use rustc::session::Session; use rustc::lint; use rustc::hir::def::*; @@ -44,6 +45,9 @@ use rustc::ty; use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap}; use rustc::util::nodemap::{NodeMap, NodeSet, FxHashMap, FxHashSet, DefIdMap}; +use rustc_metadata::creader::CrateLoader; +use rustc_metadata::cstore::CStore; + use syntax::codemap::CodeMap; use syntax::ext::hygiene::{Mark, Transparency, SyntaxContext}; use syntax::ast::{self, Name, NodeId, Ident, FloatTy, IntTy, UintTy}; @@ -688,7 +692,7 @@ impl<'tcx> Visitor<'tcx> for UsePlacementFinder { } /// This thing walks the whole crate in DFS manner, visiting each item, resolving names as it goes. -impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> { +impl<'a, 'tcx, 'cl> Visitor<'tcx> for Resolver<'a, 'cl> { fn visit_item(&mut self, item: &'tcx Item) { self.resolve_item(item); } @@ -1177,7 +1181,7 @@ impl<'a> NameBinding<'a> { } } - fn get_macro(&self, resolver: &mut Resolver<'a>) -> Lrc { + fn get_macro<'b: 'a>(&self, resolver: &mut Resolver<'a, 'b>) -> Lrc { resolver.get_macro(self.def_ignoring_ambiguity()) } @@ -1292,9 +1296,9 @@ impl PrimitiveTypeTable { /// The main resolver class. /// /// This is the visitor that walks the whole crate. -pub struct Resolver<'a> { +pub struct Resolver<'a, 'b: 'a> { session: &'a Session, - cstore: &'a dyn CrateStore, + cstore: &'a CStore, pub definitions: Definitions, @@ -1390,7 +1394,7 @@ pub struct Resolver<'a> { /// true if `#![feature(use_extern_macros)]` use_extern_macros: bool, - crate_loader: &'a mut dyn CrateLoader, + crate_loader: &'a mut CrateLoader<'b>, macro_names: FxHashSet, macro_prelude: FxHashMap>, pub all_macros: FxHashMap, @@ -1471,7 +1475,7 @@ impl<'a> ResolverArenas<'a> { } } -impl<'a, 'b: 'a> ty::DefIdTree for &'a Resolver<'b> { +impl<'a, 'b: 'a, 'cl: 'b> ty::DefIdTree for &'a Resolver<'b, 'cl> { fn parent(self, id: DefId) -> Option { match id.krate { LOCAL_CRATE => self.definitions.def_key(id.index).parent, @@ -1482,7 +1486,7 @@ impl<'a, 'b: 'a> ty::DefIdTree for &'a Resolver<'b> { /// This interface is used through the AST→HIR step, to embed full paths into the HIR. After that /// the resolver is no longer needed as all the relevant information is inline. -impl<'a> hir::lowering::Resolver for Resolver<'a> { +impl<'a, 'cl> hir::lowering::Resolver for Resolver<'a, 'cl> { fn resolve_hir_path(&mut self, path: &mut hir::Path, is_value: bool) { self.resolve_hir_path_cb(path, is_value, |resolver, span, error| resolve_error(resolver, span, error)) @@ -1535,7 +1539,7 @@ impl<'a> hir::lowering::Resolver for Resolver<'a> { } } -impl<'a> Resolver<'a> { +impl<'a, 'crateloader> Resolver<'a, 'crateloader> { /// Rustdoc uses this to resolve things in a recoverable way. ResolutionError<'a> /// isn't something that can be returned because it can't be made to live that long, /// and also it's a private type. Fortunately rustdoc doesn't need to know the error, @@ -1601,15 +1605,15 @@ impl<'a> Resolver<'a> { } } -impl<'a> Resolver<'a> { +impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { pub fn new(session: &'a Session, - cstore: &'a dyn CrateStore, + cstore: &'a CStore, krate: &Crate, crate_name: &str, make_glob_map: MakeGlobMap, - crate_loader: &'a mut dyn CrateLoader, + crate_loader: &'a mut CrateLoader<'crateloader>, arenas: &'a ResolverArenas<'a>) - -> Resolver<'a> { + -> Resolver<'a, 'crateloader> { let root_def_id = DefId::local(CRATE_DEF_INDEX); let root_module_kind = ModuleKind::Def(Def::Mod(root_def_id), keywords::Invalid.name()); let graph_root = arenas.alloc_module(ModuleData { diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 29b6f958cc119..ae345c1eaadd1 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -18,6 +18,7 @@ use rustc::hir::def_id::{DefId, BUILTIN_MACROS_CRATE, CRATE_DEF_INDEX, DefIndex, use rustc::hir::def::{Def, Export}; use rustc::hir::map::{self, DefCollector}; use rustc::{ty, lint}; +use rustc::middle::cstore::CrateStore; use syntax::ast::{self, Name, Ident}; use syntax::attr::{self, HasAttrs}; use syntax::errors::DiagnosticBuilder; @@ -117,7 +118,7 @@ impl<'a> MacroBinding<'a> { } } -impl<'a> base::Resolver for Resolver<'a> { +impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> { fn next_node_id(&mut self) -> ast::NodeId { self.session.next_node_id() } @@ -135,9 +136,11 @@ impl<'a> base::Resolver for Resolver<'a> { } fn eliminate_crate_var(&mut self, item: P) -> P { - struct EliminateCrateVar<'b, 'a: 'b>(&'b mut Resolver<'a>, Span); + struct EliminateCrateVar<'b, 'a: 'b, 'crateloader: 'a>( + &'b mut Resolver<'a, 'crateloader>, Span + ); - impl<'a, 'b> Folder for EliminateCrateVar<'a, 'b> { + impl<'a, 'b, 'crateloader> Folder for EliminateCrateVar<'a, 'b, 'crateloader> { fn fold_path(&mut self, path: ast::Path) -> ast::Path { match self.fold_qpath(None, path) { (None, path) => path, @@ -370,7 +373,7 @@ impl<'a> base::Resolver for Resolver<'a> { } } -impl<'a> Resolver<'a> { +impl<'a, 'cl> Resolver<'a, 'cl> { fn report_proc_macro_stub(&self, span: Span) { self.session.span_err(span, "can't use a procedural macro from the same crate that defines it"); diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index acdb7c4d4edfc..a136139d6f402 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -25,6 +25,7 @@ use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; use rustc::hir::def::*; use rustc::session::DiagnosticMessageId; use rustc::util::nodemap::{FxHashMap, FxHashSet}; +use rustc::middle::cstore::CrateStore; use syntax::ast::{Ident, Name, NodeId, CRATE_NODE_ID}; use syntax::ext::base::Determinacy::{self, Determined, Undetermined}; @@ -123,7 +124,7 @@ impl<'a> NameResolution<'a> { } } -impl<'a> Resolver<'a> { +impl<'a, 'crateloader> Resolver<'a, 'crateloader> { fn resolution(&self, module: Module<'a>, ident: Ident, ns: Namespace) -> &'a RefCell> { *module.resolutions.borrow_mut().entry((ident.modern(), ns)) @@ -388,7 +389,7 @@ impl<'a> Resolver<'a> { // If the resolution becomes a success, define it in the module's glob importers. fn update_resolution(&mut self, module: Module<'a>, ident: Ident, ns: Namespace, f: F) -> T - where F: FnOnce(&mut Resolver<'a>, &mut NameResolution<'a>) -> T + where F: FnOnce(&mut Resolver<'a, 'crateloader>, &mut NameResolution<'a>) -> T { // Ensure that `resolution` isn't borrowed when defining in the module's glob importers, // during which the resolution might end up getting re-defined via a glob cycle. @@ -439,30 +440,30 @@ impl<'a> Resolver<'a> { } } -pub struct ImportResolver<'a, 'b: 'a> { - pub resolver: &'a mut Resolver<'b>, +pub struct ImportResolver<'a, 'b: 'a, 'c: 'a + 'b> { + pub resolver: &'a mut Resolver<'b, 'c>, } -impl<'a, 'b: 'a> ::std::ops::Deref for ImportResolver<'a, 'b> { - type Target = Resolver<'b>; - fn deref(&self) -> &Resolver<'b> { +impl<'a, 'b: 'a, 'c: 'a + 'b> ::std::ops::Deref for ImportResolver<'a, 'b, 'c> { + type Target = Resolver<'b, 'c>; + fn deref(&self) -> &Resolver<'b, 'c> { self.resolver } } -impl<'a, 'b: 'a> ::std::ops::DerefMut for ImportResolver<'a, 'b> { - fn deref_mut(&mut self) -> &mut Resolver<'b> { +impl<'a, 'b: 'a, 'c: 'a + 'b> ::std::ops::DerefMut for ImportResolver<'a, 'b, 'c> { + fn deref_mut(&mut self) -> &mut Resolver<'b, 'c> { self.resolver } } -impl<'a, 'b: 'a> ty::DefIdTree for &'a ImportResolver<'a, 'b> { +impl<'a, 'b: 'a, 'c: 'a + 'b> ty::DefIdTree for &'a ImportResolver<'a, 'b, 'c> { fn parent(self, id: DefId) -> Option { self.resolver.parent(id) } } -impl<'a, 'b:'a> ImportResolver<'a, 'b> { +impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { // Import resolution // // This is a fixed-point algorithm. We resolve imports until our efforts diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index c30d6817b4664..23056218269b6 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -13,6 +13,7 @@ use rustc::traits::{self, auto_trait as auto}; use rustc::ty::{self, ToPredicate, TypeFoldable}; use rustc::ty::subst::Subst; use rustc::infer::InferOk; +use rustc::middle::cstore::CrateStore; use std::fmt::Debug; use syntax_pos::DUMMY_SP; @@ -20,13 +21,13 @@ use core::DocAccessLevels; use super::*; -pub struct AutoTraitFinder<'a, 'tcx: 'a, 'rcx: 'a> { - pub cx: &'a core::DocContext<'a, 'tcx, 'rcx>, +pub struct AutoTraitFinder<'a, 'tcx: 'a, 'rcx: 'a, 'cstore: 'rcx> { + pub cx: &'a core::DocContext<'a, 'tcx, 'rcx, 'cstore>, pub f: auto::AutoTraitFinder<'a, 'tcx>, } -impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> { - pub fn new(cx: &'a core::DocContext<'a, 'tcx, 'rcx>) -> Self { +impl<'a, 'tcx, 'rcx, 'cstore> AutoTraitFinder<'a, 'tcx, 'rcx, 'cstore> { + pub fn new(cx: &'a core::DocContext<'a, 'tcx, 'rcx, 'cstore>) -> Self { let f = auto::AutoTraitFinder::new(&cx.tcx); AutoTraitFinder { cx, f } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 9245ef3cf507b..6ce6144147ea1 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -19,7 +19,7 @@ use syntax_pos::Span; use rustc::hir; use rustc::hir::def::{Def, CtorKind}; use rustc::hir::def_id::DefId; -use rustc::middle::cstore::LoadedMacro; +use rustc::middle::cstore::{CrateStore, LoadedMacro}; use rustc::ty; use rustc::util::nodemap::FxHashSet; diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 7454f79ed6bbb..2c81199ba65d1 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -145,7 +145,7 @@ pub struct Crate { pub masked_crates: FxHashSet, } -impl<'a, 'tcx, 'rcx> Clean for visit_ast::RustdocVisitor<'a, 'tcx, 'rcx> { +impl<'a, 'tcx, 'rcx, 'cstore> Clean for visit_ast::RustdocVisitor<'a, 'tcx, 'rcx, 'cstore> { fn clean(&self, cx: &DocContext) -> Crate { use ::visit_lib::LibEmbargoVisitor; diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 769c9804a355a..84741f12ad183 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -13,7 +13,6 @@ use rustc_driver::{self, driver, target_features, abort_on_err}; use rustc::session::{self, config}; use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE}; use rustc::hir::def::Def; -use rustc::middle::cstore::CrateStore; use rustc::middle::privacy::AccessLevels; use rustc::ty::{self, TyCtxt, AllArenas}; use rustc::hir::map as hir_map; @@ -49,13 +48,13 @@ pub use rustc::session::search_paths::SearchPaths; pub type ExternalPaths = FxHashMap, clean::TypeKind)>; -pub struct DocContext<'a, 'tcx: 'a, 'rcx: 'a> { +pub struct DocContext<'a, 'tcx: 'a, 'rcx: 'a, 'cstore: 'rcx> { pub tcx: TyCtxt<'a, 'tcx, 'tcx>, - pub resolver: &'a RefCell>, + pub resolver: &'a RefCell>, /// The stack of module NodeIds up till this point pub mod_ids: RefCell>, pub crate_name: Option, - pub cstore: Rc, + pub cstore: Rc, pub populated_all_crate_impls: Cell, // Note that external items for which `doc(hidden)` applies to are shown as // non-reachable while local items aren't. This is because we're reusing @@ -87,7 +86,7 @@ pub struct DocContext<'a, 'tcx: 'a, 'rcx: 'a> { pub all_traits: Vec, } -impl<'a, 'tcx, 'rcx> DocContext<'a, 'tcx, 'rcx> { +impl<'a, 'tcx, 'rcx, 'cstore> DocContext<'a, 'tcx, 'rcx, 'cstore> { pub fn sess(&self) -> &session::Session { &self.tcx.sess } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 09d304b71a2c1..d03990af3c4c7 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -38,10 +38,10 @@ use doctree::*; // also, is there some reason that this doesn't use the 'visit' // framework from syntax? -pub struct RustdocVisitor<'a, 'tcx: 'a, 'rcx: 'a> { +pub struct RustdocVisitor<'a, 'tcx: 'a, 'rcx: 'a, 'cstore: 'rcx> { pub module: Module, pub attrs: hir::HirVec, - pub cx: &'a core::DocContext<'a, 'tcx, 'rcx>, + pub cx: &'a core::DocContext<'a, 'tcx, 'rcx, 'cstore>, view_item_stack: FxHashSet, inlining: bool, /// Is the current module and all of its parents public? @@ -49,8 +49,10 @@ pub struct RustdocVisitor<'a, 'tcx: 'a, 'rcx: 'a> { exact_paths: Option>>, } -impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { - pub fn new(cx: &'a core::DocContext<'a, 'tcx, 'rcx>) -> RustdocVisitor<'a, 'tcx, 'rcx> { +impl<'a, 'tcx, 'rcx, 'cstore> RustdocVisitor<'a, 'tcx, 'rcx, 'cstore> { + pub fn new( + cx: &'a core::DocContext<'a, 'tcx, 'rcx, 'cstore> + ) -> RustdocVisitor<'a, 'tcx, 'rcx, 'cstore> { // If the root is re-exported, terminate all recursion. let mut stack = FxHashSet(); stack.insert(ast::CRATE_NODE_ID); diff --git a/src/librustdoc/visit_lib.rs b/src/librustdoc/visit_lib.rs index 4c773fc1dd78b..10a4e69dcc6cd 100644 --- a/src/librustdoc/visit_lib.rs +++ b/src/librustdoc/visit_lib.rs @@ -22,8 +22,8 @@ use clean::{AttributesExt, NestedAttributesExt}; /// Similar to `librustc_privacy::EmbargoVisitor`, but also takes /// specific rustdoc annotations into account (i.e. `doc(hidden)`) -pub struct LibEmbargoVisitor<'a, 'tcx: 'a, 'rcx: 'a> { - cx: &'a ::core::DocContext<'a, 'tcx, 'rcx>, +pub struct LibEmbargoVisitor<'a, 'tcx: 'a, 'rcx: 'a, 'cstore: 'rcx> { + cx: &'a ::core::DocContext<'a, 'tcx, 'rcx, 'cstore>, // Accessibility levels for reachable nodes access_levels: RefMut<'a, AccessLevels>, // Previous accessibility level, None means unreachable @@ -32,8 +32,10 @@ pub struct LibEmbargoVisitor<'a, 'tcx: 'a, 'rcx: 'a> { visited_mods: FxHashSet, } -impl<'a, 'tcx, 'rcx> LibEmbargoVisitor<'a, 'tcx, 'rcx> { - pub fn new(cx: &'a ::core::DocContext<'a, 'tcx, 'rcx>) -> LibEmbargoVisitor<'a, 'tcx, 'rcx> { +impl<'a, 'tcx, 'rcx, 'cstore> LibEmbargoVisitor<'a, 'tcx, 'rcx, 'cstore> { + pub fn new( + cx: &'a ::core::DocContext<'a, 'tcx, 'rcx, 'cstore> + ) -> LibEmbargoVisitor<'a, 'tcx, 'rcx, 'cstore> { LibEmbargoVisitor { cx, access_levels: cx.access_levels.borrow_mut(), diff --git a/src/test/run-pass-fulldeps/compiler-calls.rs b/src/test/run-pass-fulldeps/compiler-calls.rs index b3a6fb4d590ae..cc2b6c641e90c 100644 --- a/src/test/run-pass-fulldeps/compiler-calls.rs +++ b/src/test/run-pass-fulldeps/compiler-calls.rs @@ -21,12 +21,13 @@ extern crate rustc_driver; extern crate rustc_codegen_utils; extern crate syntax; extern crate rustc_errors as errors; +extern crate rustc_metadata; -use rustc::middle::cstore::CrateStore; use rustc::session::Session; use rustc::session::config::{self, Input}; use rustc_driver::{driver, CompilerCalls, Compilation}; use rustc_codegen_utils::codegen_backend::CodegenBackend; +use rustc_metadata::cstore::CStore; use syntax::ast; use std::path::PathBuf; @@ -51,7 +52,7 @@ impl<'a> CompilerCalls<'a> for TestCalls<'a> { _: &CodegenBackend, _: &getopts::Matches, _: &Session, - _: &CrateStore, + _: &CStore, _: &Input, _: &Option, _: &Option) From dd753cdd28f6c5292e577de6a2a37b59b30052ae Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Tue, 31 Jul 2018 17:23:29 -0600 Subject: [PATCH 10/23] Move unused trait functions to inherent functions --- src/librustc/middle/cstore.rs | 18 --- src/librustc_driver/lib.rs | 3 +- src/librustc_metadata/cstore.rs | 5 + src/librustc_metadata/cstore_impl.rs | 149 ++++++++++---------- src/librustc_resolve/build_reduced_graph.rs | 2 +- src/librustc_resolve/resolve_imports.rs | 1 - src/librustdoc/clean/inline.rs | 2 +- 7 files changed, 79 insertions(+), 101 deletions(-) diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 492be23fa1714..0e84104245dcb 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -22,7 +22,6 @@ //! are *mostly* used as a part of that interface, but these should //! probably get a better home if someone can find one. -use hir::def; use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use hir::map as hir_map; use hir::map::definitions::{DefKey, DefPathTable}; @@ -34,8 +33,6 @@ use session::search_paths::PathKind; use std::any::Any; use std::path::{Path, PathBuf}; use syntax::ast; -use syntax::edition::Edition; -use syntax::ext::base::SyntaxExtension; use syntax::symbol::Symbol; use syntax_pos::Span; use rustc_target::spec::Target; @@ -140,11 +137,6 @@ pub struct ForeignModule { pub def_id: DefId, } -pub enum LoadedMacro { - MacroDef(ast::Item), - ProcMacro(Lrc), -} - #[derive(Copy, Clone, Debug)] pub struct ExternCrate { pub src: ExternCrateSource, @@ -221,9 +213,6 @@ pub trait MetadataLoader { pub trait CrateStore { fn crate_data_as_rc_any(&self, krate: CrateNum) -> Lrc; - // access to the metadata loader - fn metadata_loader(&self) -> &dyn MetadataLoader; - // resolve fn def_key(&self, def: DefId) -> DefKey; fn def_path(&self, def: DefId) -> hir_map::DefPath; @@ -231,18 +220,11 @@ pub trait CrateStore { fn def_path_table(&self, cnum: CrateNum) -> Lrc; // "queries" used in resolve that aren't tracked for incremental compilation - fn export_macros_untracked(&self, cnum: CrateNum); - fn dep_kind_untracked(&self, cnum: CrateNum) -> DepKind; fn crate_name_untracked(&self, cnum: CrateNum) -> Symbol; fn crate_disambiguator_untracked(&self, cnum: CrateNum) -> CrateDisambiguator; fn crate_hash_untracked(&self, cnum: CrateNum) -> Svh; - fn crate_edition_untracked(&self, cnum: CrateNum) -> Edition; - fn struct_field_names_untracked(&self, def: DefId) -> Vec; - fn item_children_untracked(&self, did: DefId, sess: &Session) -> Vec; - fn load_macro_untracked(&self, did: DefId, sess: &Session) -> LoadedMacro; fn extern_mod_stmt_cnum_untracked(&self, emod_id: ast::NodeId) -> Option; fn item_generics_cloned_untracked(&self, def: DefId, sess: &Session) -> ty::Generics; - fn associated_item_cloned_untracked(&self, def: DefId) -> ty::AssociatedItem; fn postorder_cnums_untracked(&self) -> Vec; // This is basically a 1-based range of ints, which is a little diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index ed3fda8e72300..74e7d328891e0 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -78,7 +78,6 @@ use rustc::session::filesearch; use rustc::session::{early_error, early_warn}; use rustc::lint::Lint; use rustc::lint; -use rustc::middle::cstore::CrateStore; use rustc_metadata::locator; use rustc_metadata::cstore::CStore; use rustc_metadata::dynamic_lib::DynamicLibrary; @@ -1002,7 +1001,7 @@ impl RustcDefaultCalls { let mut v = Vec::new(); locator::list_file_metadata(&sess.target.target, path, - cstore.metadata_loader(), + &*cstore.metadata_loader, &mut v) .unwrap(); println!("{}", String::from_utf8(v).unwrap()); diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index d93a7f9526e1a..2d3e3080c89e3 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -93,6 +93,11 @@ pub struct CStore { pub metadata_loader: Box, } +pub enum LoadedMacro { + MacroDef(ast::Item), + ProcMacro(Lrc), +} + impl CStore { pub fn new(metadata_loader: Box) -> CStore { CStore { diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index fc23494585a76..916c0920e0b4b 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use cstore; +use cstore::{self, LoadedMacro}; use encoder; use link_args; use native_libs; @@ -17,8 +17,8 @@ use schema; use rustc::ty::query::QueryConfig; use rustc::middle::cstore::{CrateStore, DepKind, - MetadataLoader, LinkMeta, - LoadedMacro, EncodedMetadata, NativeLibraryKind}; + LinkMeta, + EncodedMetadata, NativeLibraryKind}; use rustc::middle::exported_symbols::ExportedSymbol; use rustc::middle::stability::DeprecationEntry; use rustc::hir::def; @@ -411,32 +411,8 @@ pub fn provide<'tcx>(providers: &mut Providers<'tcx>) { }; } -impl CrateStore for cstore::CStore { - fn crate_data_as_rc_any(&self, krate: CrateNum) -> Lrc { - self.get_crate_data(krate) - } - - fn metadata_loader(&self) -> &dyn MetadataLoader { - &*self.metadata_loader - } - - fn item_generics_cloned_untracked(&self, def: DefId, sess: &Session) -> ty::Generics { - self.get_crate_data(def.krate).get_generics(def.index, sess) - } - - fn associated_item_cloned_untracked(&self, def: DefId) -> ty::AssociatedItem - { - self.get_crate_data(def.krate).get_associated_item(def.index) - } - - fn dep_kind_untracked(&self, cnum: CrateNum) -> DepKind - { - let data = self.get_crate_data(cnum); - let r = *data.dep_kind.lock(); - r - } - - fn export_macros_untracked(&self, cnum: CrateNum) { +impl cstore::CStore { + pub fn export_macros_untracked(&self, cnum: CrateNum) { let data = self.get_crate_data(cnum); let mut dep_kind = data.dep_kind.lock(); if *dep_kind == DepKind::UnexportedMacrosOnly { @@ -444,69 +420,28 @@ impl CrateStore for cstore::CStore { } } - fn crate_name_untracked(&self, cnum: CrateNum) -> Symbol - { - self.get_crate_data(cnum).name - } - - fn crate_disambiguator_untracked(&self, cnum: CrateNum) -> CrateDisambiguator - { - self.get_crate_data(cnum).root.disambiguator - } - - fn crate_hash_untracked(&self, cnum: CrateNum) -> hir::svh::Svh - { - self.get_crate_data(cnum).root.hash + pub fn dep_kind_untracked(&self, cnum: CrateNum) -> DepKind { + let data = self.get_crate_data(cnum); + let r = *data.dep_kind.lock(); + r } - fn crate_edition_untracked(&self, cnum: CrateNum) -> Edition - { + pub fn crate_edition_untracked(&self, cnum: CrateNum) -> Edition { self.get_crate_data(cnum).root.edition } - /// Returns the `DefKey` for a given `DefId`. This indicates the - /// parent `DefId` as well as some idea of what kind of data the - /// `DefId` refers to. - fn def_key(&self, def: DefId) -> DefKey { - // Note: loading the def-key (or def-path) for a def-id is not - // a *read* of its metadata. This is because the def-id is - // really just an interned shorthand for a def-path, which is the - // canonical name for an item. - // - // self.dep_graph.read(DepNode::MetaData(def)); - self.get_crate_data(def.krate).def_key(def.index) - } - - fn def_path(&self, def: DefId) -> DefPath { - // See `Note` above in `def_key()` for why this read is - // commented out: - // - // self.dep_graph.read(DepNode::MetaData(def)); - self.get_crate_data(def.krate).def_path(def.index) - } - - fn def_path_hash(&self, def: DefId) -> DefPathHash { - self.get_crate_data(def.krate).def_path_hash(def.index) - } - - fn def_path_table(&self, cnum: CrateNum) -> Lrc { - self.get_crate_data(cnum).def_path_table.clone() - } - - fn struct_field_names_untracked(&self, def: DefId) -> Vec - { + pub fn struct_field_names_untracked(&self, def: DefId) -> Vec { self.get_crate_data(def.krate).get_struct_field_names(def.index) } - fn item_children_untracked(&self, def_id: DefId, sess: &Session) -> Vec - { + pub fn item_children_untracked(&self, def_id: DefId, sess: &Session) -> Vec { let mut result = vec![]; self.get_crate_data(def_id.krate) .each_child_of_item(def_id.index, |child| result.push(child), sess); result } - fn load_macro_untracked(&self, id: DefId, sess: &Session) -> LoadedMacro { + pub fn load_macro_untracked(&self, id: DefId, sess: &Session) -> LoadedMacro { let data = self.get_crate_data(id.krate); if let Some(ref proc_macros) = data.proc_macros { return LoadedMacro::ProcMacro(proc_macros[id.index.to_proc_macro_index()].1.clone()); @@ -555,6 +490,64 @@ impl CrateStore for cstore::CStore { }) } + pub fn associated_item_cloned_untracked(&self, def: DefId) -> ty::AssociatedItem { + self.get_crate_data(def.krate).get_associated_item(def.index) + } +} + +impl CrateStore for cstore::CStore { + fn crate_data_as_rc_any(&self, krate: CrateNum) -> Lrc { + self.get_crate_data(krate) + } + + fn item_generics_cloned_untracked(&self, def: DefId, sess: &Session) -> ty::Generics { + self.get_crate_data(def.krate).get_generics(def.index, sess) + } + + fn crate_name_untracked(&self, cnum: CrateNum) -> Symbol + { + self.get_crate_data(cnum).name + } + + fn crate_disambiguator_untracked(&self, cnum: CrateNum) -> CrateDisambiguator + { + self.get_crate_data(cnum).root.disambiguator + } + + fn crate_hash_untracked(&self, cnum: CrateNum) -> hir::svh::Svh + { + self.get_crate_data(cnum).root.hash + } + + /// Returns the `DefKey` for a given `DefId`. This indicates the + /// parent `DefId` as well as some idea of what kind of data the + /// `DefId` refers to. + fn def_key(&self, def: DefId) -> DefKey { + // Note: loading the def-key (or def-path) for a def-id is not + // a *read* of its metadata. This is because the def-id is + // really just an interned shorthand for a def-path, which is the + // canonical name for an item. + // + // self.dep_graph.read(DepNode::MetaData(def)); + self.get_crate_data(def.krate).def_key(def.index) + } + + fn def_path(&self, def: DefId) -> DefPath { + // See `Note` above in `def_key()` for why this read is + // commented out: + // + // self.dep_graph.read(DepNode::MetaData(def)); + self.get_crate_data(def.krate).def_path(def.index) + } + + fn def_path_hash(&self, def: DefId) -> DefPathHash { + self.get_crate_data(def.krate).def_path_hash(def.index) + } + + fn def_path_table(&self, cnum: CrateNum) -> Lrc { + self.get_crate_data(cnum).def_path_table.clone() + } + fn crates_untracked(&self) -> Vec { let mut result = vec![]; diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 71fd08f2f15be..27ac1edd0463a 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -21,11 +21,11 @@ use {PerNS, Resolver, ResolverArenas}; use Namespace::{self, TypeNS, ValueNS, MacroNS}; use {resolve_error, resolve_struct_error, ResolutionError}; -use rustc::middle::cstore::LoadedMacro; use rustc::hir::def::*; use rustc::hir::def_id::{BUILTIN_MACROS_CRATE, CRATE_DEF_INDEX, LOCAL_CRATE, DefId}; use rustc::ty; use rustc::middle::cstore::CrateStore; +use rustc_metadata::cstore::LoadedMacro; use std::cell::Cell; use rustc_data_structures::sync::Lrc; diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index a136139d6f402..55e6c2435bbc7 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -25,7 +25,6 @@ use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; use rustc::hir::def::*; use rustc::session::DiagnosticMessageId; use rustc::util::nodemap::{FxHashMap, FxHashSet}; -use rustc::middle::cstore::CrateStore; use syntax::ast::{Ident, Name, NodeId, CRATE_NODE_ID}; use syntax::ext::base::Determinacy::{self, Determined, Undetermined}; diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 6ce6144147ea1..8b4df1b7b7d21 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -19,7 +19,7 @@ use syntax_pos::Span; use rustc::hir; use rustc::hir::def::{Def, CtorKind}; use rustc::hir::def_id::DefId; -use rustc::middle::cstore::{CrateStore, LoadedMacro}; +use rustc_metadata::cstore::LoadedMacro; use rustc::ty; use rustc::util::nodemap::FxHashSet; From c3618c8b2e87d58fc5e8f18f5a2f8801e29c01e7 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 26 Jul 2018 22:29:50 +0200 Subject: [PATCH 11/23] Special-case `Box` in `rustc_mir::borrow_check`. This should address issue 45696. Since we know dropping a box will not access any `&mut` or `&` references, it is safe to model its destructor as only touching the contents *owned* by the box. Note: At some point we may want to generalize this machinery to other reference and collection types that are "pure" in the same sense as box. If we add a `&move` reference type, it would probably also fall into this branch of code. But for the short term, we will be conservative and restrict this change to `Box` alone. The code works by recursively descending a deref of the `Box`. We prevent `visit_terminator_drop` infinite-loop (which can arise in a very obscure scenario) via a linked-list of seen types. Note: A similar style stack-only linked-list definition can be found in `rustc_mir::borrow_check::places_conflict`. It might be good at some point in the future to unify the two types and put the resulting definition into `librustc_data_structures/`. ---- One final note: Review feedback led to significant simplification of logic here. During review, eddyb RalfJung and I uncovered the heart of why I needed a so-called "step 2" aka the Shallow Write to the Deref of the box. It was because the `visit_terminator_drop`, in its base case, will not emit any write at all (shallow or deep) to a place unless that place has a need_drop. So I was encoding a Shallow Write by hand for a `Box`, as a separate step from recursively descending through `*a_box` (which was at the time known as "step 1"; it is now the *only* step, apart from the change to the base case for `visit_terminator_drop` that this commit now has encoded). eddyb aruged that *something* should be emitting some sort of write in the base case here (even a shallow one), of the dropped place, since by analogy we also emit a write when you *move* a place. That led to the revision here in this commit. * (Its possible that this desired write should be attached in some manner to StorageDead instead of Drop. But in this PR, I tried to leave the StorageDead logic alone and focus my attention solely on how Drop(x) is modelled in MIR-borrowck.) --- src/librustc_mir/borrow_check/mod.rs | 151 ++++++++++++++++++++++++++- 1 file changed, 146 insertions(+), 5 deletions(-) diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 27221296ff31f..4596c7be1c557 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -22,7 +22,7 @@ use rustc::mir::{ClearCrossCrate, Local, Location, Mir, Mutability, Operand, Pla use rustc::mir::{Field, Projection, ProjectionElem, Rvalue, Statement, StatementKind}; use rustc::mir::{Terminator, TerminatorKind}; use rustc::ty::query::Providers; -use rustc::ty::{self, ParamEnv, TyCtxt}; +use rustc::ty::{self, ParamEnv, TyCtxt, Ty}; use rustc_errors::{Diagnostic, DiagnosticBuilder, Level}; use rustc_data_structures::graph::dominators::Dominators; @@ -598,7 +598,12 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx // that is useful later. let drop_place_ty = gcx.lift(&drop_place_ty).unwrap(); - self.visit_terminator_drop(loc, term, flow_state, drop_place, drop_place_ty, span); + debug!("visit_terminator_drop \ + loc: {:?} term: {:?} drop_place: {:?} drop_place_ty: {:?} span: {:?}", + loc, term, drop_place, drop_place_ty, span); + + self.visit_terminator_drop( + loc, term, flow_state, drop_place, drop_place_ty, span, SeenTy(None)); } TerminatorKind::DropAndReplace { location: ref drop_place, @@ -832,6 +837,35 @@ impl InitializationRequiringAction { } } +/// A simple linked-list threaded up the stack of recursive calls in `visit_terminator_drop`. +#[derive(Copy, Clone, Debug)] +struct SeenTy<'a, 'gcx: 'a>(Option<(Ty<'gcx>, &'a SeenTy<'a, 'gcx>)>); + +impl<'a, 'gcx> SeenTy<'a, 'gcx> { + /// Return a new list with `ty` prepended to the front of `self`. + fn cons(&'a self, ty: Ty<'gcx>) -> Self { + SeenTy(Some((ty, self))) + } + + /// True if and only if `ty` occurs on the linked list `self`. + fn have_seen(self, ty: Ty) -> bool { + let mut this = self.0; + loop { + match this { + None => return false, + Some((seen_ty, recur)) => { + if seen_ty == ty { + return true; + } else { + this = recur.0; + continue; + } + } + } + } + } +} + impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { /// Invokes `access_place` as appropriate for dropping the value /// at `drop_place`. Note that the *actual* `Drop` in the MIR is @@ -847,14 +881,57 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { drop_place: &Place<'tcx>, erased_drop_place_ty: ty::Ty<'gcx>, span: Span, + prev_seen: SeenTy<'_, 'gcx>, ) { + if prev_seen.have_seen(erased_drop_place_ty) { + // if we have directly seen the input ty `T`, then we must + // have had some *direct* ownership loop between `T` and + // some directly-owned (as in, actually traversed by + // recursive calls below) part that is also of type `T`. + // + // Note: in *all* such cases, the data in question cannot + // be constructed (nor destructed) in finite time/space. + // + // Proper examples, some of which are statically rejected: + // + // * `struct A { field: A, ... }`: + // statically rejected as infinite size + // + // * `type B = (B, ...);`: + // statically rejected as cyclic + // + // * `struct C { field: Box, ... }` + // * `struct D { field: Box<(D, D)>, ... }`: + // *accepted*, though impossible to construct + // + // Here is *NOT* an example: + // * `struct Z { field: Option>, ... }`: + // Here, the type is both representable in finite space (due to the boxed indirection) + // and constructable in finite time (since the recursion can bottom out with `None`). + // This is an obvious instance of something the compiler must accept. + // + // Since some of the above impossible cases like `C` and + // `D` are accepted by the compiler, we must take care not + // to infinite-loop while processing them. But since such + // cases cannot actually arise, it is sound for us to just + // skip them during drop. If the developer uses unsafe + // code to construct them, they should not be surprised by + // weird drop behavior in their resulting code. + debug!("visit_terminator_drop previously seen \ + erased_drop_place_ty: {:?} on prev_seen: {:?}; returning early.", + erased_drop_place_ty, prev_seen); + return; + } + let gcx = self.tcx.global_tcx(); let drop_field = |mir: &mut MirBorrowckCtxt<'cx, 'gcx, 'tcx>, (index, field): (usize, ty::Ty<'gcx>)| { let field_ty = gcx.normalize_erasing_regions(mir.param_env, field); let place = drop_place.clone().field(Field::new(index), field_ty); - mir.visit_terminator_drop(loc, term, flow_state, &place, field_ty, span); + debug!("visit_terminator_drop drop_field place: {:?} field_ty: {:?}", place, field_ty); + let seen = prev_seen.cons(erased_drop_place_ty); + mir.visit_terminator_drop(loc, term, flow_state, &place, field_ty, span, seen); }; match erased_drop_place_ty.sty { @@ -899,13 +976,42 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { .enumerate() .for_each(|field| drop_field(self, field)); } + + // #45696: special-case Box by treating its dtor as + // only deep *across owned content*. Namely, we know + // dropping a box does not touch data behind any + // references it holds; if we were to instead fall into + // the base case below, we would have a Deep Write due to + // the box being `needs_drop`, and that Deep Write would + // touch `&mut` data in the box. + ty::TyAdt(def, _) if def.is_box() => { + // When/if we add a `&own T` type, this action would + // be like running the destructor of the `&own T`. + // (And the owner of backing storage referenced by the + // `&own T` would be responsible for deallocating that + // backing storage.) + + // we model dropping any content owned by the box by + // recurring on box contents. This catches cases like + // `Box>>`, while + // still restricting Write to *owned* content. + let ty = erased_drop_place_ty.boxed_ty(); + let deref_place = drop_place.clone().deref(); + debug!("visit_terminator_drop drop-box-content deref_place: {:?} ty: {:?}", + deref_place, ty); + let seen = prev_seen.cons(erased_drop_place_ty); + self.visit_terminator_drop( + loc, term, flow_state, &deref_place, ty, span, seen); + } + _ => { // We have now refined the type of the value being // dropped (potentially) to just the type of a // subfield; so check whether that field's type still - // "needs drop". If so, we assume that the destructor - // may access any data it likes (i.e., a Deep Write). + // "needs drop". if erased_drop_place_ty.needs_drop(gcx, self.param_env) { + // If so, we assume that the destructor may access + // any data it likes (i.e., a Deep Write). self.access_place( ContextKind::Drop.new(loc), (drop_place, span), @@ -913,6 +1019,41 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { LocalMutationIsAllowed::Yes, flow_state, ); + } else { + // If there is no destructor, we still include a + // *shallow* write. This essentially ensures that + // borrows of the memory directly at `drop_place` + // cannot continue to be borrowed across the drop. + // + // If we were to use a Deep Write here, then any + // `&mut T` that is reachable from `drop_place` + // would get invalidated; fixing that is the + // essence of resolving issue #45696. + // + // * Note: In the compiler today, doing a Deep + // Write here would not actually break + // anything beyond #45696; for example it does not + // break this example: + // + // ```rust + // fn reborrow(x: &mut i32) -> &mut i32 { &mut *x } + // ``` + // + // Why? Because we do not schedule/emit + // `Drop(x)` in the MIR unless `x` needs drop in + // the first place. + // + // FIXME: Its possible this logic actually should + // be attached to the `StorageDead` statement + // rather than the `Drop`. See discussion on PR + // #52782. + self.access_place( + ContextKind::Drop.new(loc), + (drop_place, span), + (Shallow(None), Write(WriteKind::StorageDeadOrDrop)), + LocalMutationIsAllowed::Yes, + flow_state, + ); } } } From 1863cb73720c4c2059757ee27ad1addbb50ab59e Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 1 Aug 2018 17:02:43 +0200 Subject: [PATCH 12/23] Errors are more specific in cases where borrows are used in future iterations of loops. --- .../borrow_check/nll/explain_borrow/mod.rs | 89 +++++++++++++++++-- .../mut-borrow-outside-loop.nll.stderr | 2 +- ...ssue-52126-assign-op-invariance.nll.stderr | 2 +- .../borrowck-issue-49631.nll.stderr | 2 +- ...egions-escape-loop-via-variable.nll.stderr | 2 +- .../regions-escape-loop-via-vec.nll.stderr | 8 +- 6 files changed, 92 insertions(+), 13 deletions(-) diff --git a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs index cdb0351d9a8f0..d98bba72f7a33 100644 --- a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs +++ b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs @@ -11,7 +11,7 @@ use borrow_check::borrow_set::BorrowData; use borrow_check::nll::region_infer::Cause; use borrow_check::{Context, MirBorrowckCtxt, WriteKind}; -use rustc::mir::Place; +use rustc::mir::{Location, Place, TerminatorKind}; use rustc_errors::DiagnosticBuilder; mod find_use; @@ -63,10 +63,17 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { match find_use::find(mir, regioncx, tcx, region_sub, context.loc) { Some(Cause::LiveVar(_local, location)) => { - err.span_label( - mir.source_info(location).span, - "borrow later used here".to_string(), - ); + if self.is_borrow_location_in_loop(context.loc) { + err.span_label( + mir.source_info(location).span, + "borrow used here in later iteration of loop".to_string(), + ); + } else { + err.span_label( + mir.source_info(location).span, + "borrow later used here".to_string(), + ); + } } Some(Cause::DropVar(local, location)) => match &mir.local_decls[local].name { @@ -107,4 +114,76 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } } } + + /// Check if a borrow location is within a loop. + fn is_borrow_location_in_loop( + &self, + borrow_location: Location, + ) -> bool { + let mut visited_locations = Vec::new(); + let mut pending_locations = vec![ borrow_location ]; + debug!("is_in_loop: borrow_location={:?}", borrow_location); + + while let Some(location) = pending_locations.pop() { + debug!("is_in_loop: location={:?} pending_locations={:?} visited_locations={:?}", + location, pending_locations, visited_locations); + if location == borrow_location && visited_locations.contains(&borrow_location) { + // We've managed to return to where we started (and this isn't the start of the + // search). + debug!("is_in_loop: found!"); + return true; + } + + // Skip locations we've been. + if visited_locations.contains(&location) { continue; } + + let block = &self.mir.basic_blocks()[location.block]; + if location.statement_index == block.statements.len() { + // Add start location of the next blocks to pending locations. + match block.terminator().kind { + TerminatorKind::Goto { target } => { + pending_locations.push(target.start_location()); + }, + TerminatorKind::SwitchInt { ref targets, .. } => { + for target in targets { + pending_locations.push(target.start_location()); + } + }, + TerminatorKind::Drop { target, unwind, .. } | + TerminatorKind::DropAndReplace { target, unwind, .. } | + TerminatorKind::Assert { target, cleanup: unwind, .. } | + TerminatorKind::Yield { resume: target, drop: unwind, .. } | + TerminatorKind::FalseUnwind { real_target: target, unwind, .. } => { + pending_locations.push(target.start_location()); + if let Some(unwind) = unwind { + pending_locations.push(unwind.start_location()); + } + }, + TerminatorKind::Call { ref destination, cleanup, .. } => { + if let Some((_, destination)) = destination { + pending_locations.push(destination.start_location()); + } + if let Some(cleanup) = cleanup { + pending_locations.push(cleanup.start_location()); + } + }, + TerminatorKind::FalseEdges { real_target, ref imaginary_targets, .. } => { + pending_locations.push(real_target.start_location()); + for target in imaginary_targets { + pending_locations.push(target.start_location()); + } + }, + _ => {}, + } + } else { + // Add the next statement to pending locations. + pending_locations.push(location.successor_within_block()); + } + + // Keep track of where we have visited. + visited_locations.push(location); + } + + false + } } diff --git a/src/test/ui/borrowck/mut-borrow-outside-loop.nll.stderr b/src/test/ui/borrowck/mut-borrow-outside-loop.nll.stderr index 55f57e97ba4fa..02e5b44c17c4a 100644 --- a/src/test/ui/borrowck/mut-borrow-outside-loop.nll.stderr +++ b/src/test/ui/borrowck/mut-borrow-outside-loop.nll.stderr @@ -17,7 +17,7 @@ LL | let inner_second = &mut inner_void; //~ ERROR cannot borrow | ^^^^^^^^^^^^^^^ second mutable borrow occurs here LL | inner_second.use_mut(); LL | inner_first.use_mut(); - | ----------- borrow later used here + | ----------- borrow used here in later iteration of loop error: aborting due to 2 previous errors diff --git a/src/test/ui/issue-52126-assign-op-invariance.nll.stderr b/src/test/ui/issue-52126-assign-op-invariance.nll.stderr index ccbb852b14574..e3e389d11970a 100644 --- a/src/test/ui/issue-52126-assign-op-invariance.nll.stderr +++ b/src/test/ui/issue-52126-assign-op-invariance.nll.stderr @@ -5,7 +5,7 @@ LL | let v: Vec<&str> = line.split_whitespace().collect(); | ^^^^ borrowed value does not live long enough LL | //~^ ERROR `line` does not live long enough LL | println!("accumulator before add_assign {:?}", acc.map); - | ------- borrow later used here + | ------- borrow used here in later iteration of loop ... LL | } | - `line` dropped here while still borrowed diff --git a/src/test/ui/rfc-2005-default-binding-mode/borrowck-issue-49631.nll.stderr b/src/test/ui/rfc-2005-default-binding-mode/borrowck-issue-49631.nll.stderr index 10384e3b7ca29..606d678542269 100644 --- a/src/test/ui/rfc-2005-default-binding-mode/borrowck-issue-49631.nll.stderr +++ b/src/test/ui/rfc-2005-default-binding-mode/borrowck-issue-49631.nll.stderr @@ -7,7 +7,7 @@ LL | foo.mutate(); | ^^^^^^^^^^^^ mutable borrow occurs here LL | //~^ ERROR cannot borrow `foo` as mutable LL | println!("foo={:?}", *string); - | ------- borrow later used here + | ------- borrow used here in later iteration of loop error: aborting due to previous error diff --git a/src/test/ui/span/regions-escape-loop-via-variable.nll.stderr b/src/test/ui/span/regions-escape-loop-via-variable.nll.stderr index 08ca100c247dc..7aaec700d8985 100644 --- a/src/test/ui/span/regions-escape-loop-via-variable.nll.stderr +++ b/src/test/ui/span/regions-escape-loop-via-variable.nll.stderr @@ -2,7 +2,7 @@ error[E0597]: `x` does not live long enough --> $DIR/regions-escape-loop-via-variable.rs:21:13 | LL | let x = 1 + *p; - | -- borrow later used here + | -- borrow used here in later iteration of loop LL | p = &x; | ^^ borrowed value does not live long enough LL | } diff --git a/src/test/ui/span/regions-escape-loop-via-vec.nll.stderr b/src/test/ui/span/regions-escape-loop-via-vec.nll.stderr index 4d81211673e6e..2dc758428ef3a 100644 --- a/src/test/ui/span/regions-escape-loop-via-vec.nll.stderr +++ b/src/test/ui/span/regions-escape-loop-via-vec.nll.stderr @@ -7,7 +7,7 @@ LL | while x < 10 { //~ ERROR cannot use `x` because it was mutably borrowed | ^ use of borrowed `x` LL | let mut z = x; //~ ERROR cannot use `x` because it was mutably borrowed LL | _y.push(&mut z); - | -- borrow later used here + | -- borrow used here in later iteration of loop error[E0503]: cannot use `x` because it was mutably borrowed --> $DIR/regions-escape-loop-via-vec.rs:16:21 @@ -18,7 +18,7 @@ LL | while x < 10 { //~ ERROR cannot use `x` because it was mutably borrowed LL | let mut z = x; //~ ERROR cannot use `x` because it was mutably borrowed | ^ use of borrowed `x` LL | _y.push(&mut z); - | -- borrow later used here + | -- borrow used here in later iteration of loop error[E0597]: `z` does not live long enough --> $DIR/regions-escape-loop-via-vec.rs:17:17 @@ -26,7 +26,7 @@ error[E0597]: `z` does not live long enough LL | _y.push(&mut z); | -- ^^^^^^ borrowed value does not live long enough | | - | borrow later used here + | borrow used here in later iteration of loop ... LL | } | - `z` dropped here while still borrowed @@ -38,7 +38,7 @@ LL | let mut _y = vec![&mut x]; | ------ borrow of `x` occurs here ... LL | _y.push(&mut z); - | -- borrow later used here + | -- borrow used here in later iteration of loop LL | //~^ ERROR `z` does not live long enough LL | x += 1; //~ ERROR cannot assign | ^^^^^^ use of borrowed `x` From 88284baa0e3a8e8f9274b4c5a76803d84c9533a9 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 27 Jul 2018 17:58:17 +0200 Subject: [PATCH 13/23] minor fallout from the change. (Presumably the place that borrow_check ends up reporting for the error about is no longer the root `Local` itself, and thus the note diagnostic here stops firing.) --- src/test/ui/generator/dropck.nll.stderr | 2 -- src/test/ui/span/dropck-object-cycle.nll.stderr | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/test/ui/generator/dropck.nll.stderr b/src/test/ui/generator/dropck.nll.stderr index ef7e64ffd97ae..b49bf81715079 100644 --- a/src/test/ui/generator/dropck.nll.stderr +++ b/src/test/ui/generator/dropck.nll.stderr @@ -9,8 +9,6 @@ LL | } | | | `*cell` dropped here while still borrowed | borrow later used here, when `gen` is dropped - | - = note: values in a scope are dropped in the opposite order they are defined error[E0597]: `ref_` does not live long enough --> $DIR/dropck.rs:22:11 diff --git a/src/test/ui/span/dropck-object-cycle.nll.stderr b/src/test/ui/span/dropck-object-cycle.nll.stderr index 225ed0f9cc832..08e4b9ec9faa2 100644 --- a/src/test/ui/span/dropck-object-cycle.nll.stderr +++ b/src/test/ui/span/dropck-object-cycle.nll.stderr @@ -9,8 +9,6 @@ LL | } | | | `*m` dropped here while still borrowed | borrow later used here, when `m` is dropped - | - = note: values in a scope are dropped in the opposite order they are defined error: aborting due to previous error From 08b3a8e4294484adcb8b7ed36e76f49e76c3a5f8 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 27 Jul 2018 15:52:17 +0200 Subject: [PATCH 14/23] Regression tests. --- .../issue-45696-long-live-borrows-in-boxes.rs | 103 ++++++++++++++++ ...-45696-scribble-on-boxed-borrow.ast.stderr | 14 +++ ...96-scribble-on-boxed-borrow.migrate.stderr | 69 +++++++++++ ...-45696-scribble-on-boxed-borrow.nll.stderr | 48 ++++++++ .../issue-45696-scribble-on-boxed-borrow.rs | 110 ++++++++++++++++++ 5 files changed, 344 insertions(+) create mode 100644 src/test/ui/issue-45696-long-live-borrows-in-boxes.rs create mode 100644 src/test/ui/issue-45696-scribble-on-boxed-borrow.ast.stderr create mode 100644 src/test/ui/issue-45696-scribble-on-boxed-borrow.migrate.stderr create mode 100644 src/test/ui/issue-45696-scribble-on-boxed-borrow.nll.stderr create mode 100644 src/test/ui/issue-45696-scribble-on-boxed-borrow.rs diff --git a/src/test/ui/issue-45696-long-live-borrows-in-boxes.rs b/src/test/ui/issue-45696-long-live-borrows-in-boxes.rs new file mode 100644 index 0000000000000..e5326bb315ea3 --- /dev/null +++ b/src/test/ui/issue-45696-long-live-borrows-in-boxes.rs @@ -0,0 +1,103 @@ +// 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. + +// rust-lang/rust#45696: This test is checking that we can return +// mutable borrows owned by boxes even when the boxes are dropped. +// +// We will explicitly test AST-borrowck, NLL, and migration modes; +// thus we will also skip the automated compare-mode=nll. + +// revisions: ast nll migrate +// ignore-compare-mode-nll + +#![cfg_attr(nll, feature(nll))] +//[migrate]compile-flags: -Z borrowck=migrate -Z two-phase-borrows + +// run-pass + +type Boxed<'a, 'b> = Box<(&'a mut u32, &'b mut u32)>; + +fn return_borrow_from_dropped_box<'a>(x: Boxed<'a, '_>) -> &'a mut u32 { + &mut *x.0 +} + +fn return_borrow_from_dropped_tupled_box<'a>(x: (Boxed<'a, '_>, &mut u32)) -> &'a mut u32 { + &mut *(x.0).0 +} + +fn basic_tests() { + let mut x = 2; + let mut y = 3; + let mut z = 4; + *return_borrow_from_dropped_box(Box::new((&mut x, &mut y))) += 10; + assert_eq!((x, y, z), (12, 3, 4)); + *return_borrow_from_dropped_tupled_box((Box::new((&mut x, &mut y)), &mut z)) += 10; + assert_eq!((x, y, z), (22, 3, 4)); +} + +// These scribbling tests have been transcribed from +// issue-45696-scribble-on-boxed-borrow.rs +// +// In the context of that file, these tests are meant to show cases +// that should be *accepted* by the compiler, so here we are actually +// checking that the code we get when they are compiled matches our +// expectations. + +struct Scribble<'a>(&'a mut u32); + +impl<'a> Drop for Scribble<'a> { fn drop(&mut self) { *self.0 = 42; } } + +// this is okay, in both AST-borrowck and NLL: The `Scribble` here *has* +// to strictly outlive `'a` +fn borrowed_scribble<'a>(s: &'a mut Scribble) -> &'a mut u32 { + &mut *s.0 +} + +// this, by analogy to previous case, is also okay. +fn boxed_borrowed_scribble<'a>(s: Box<&'a mut Scribble>) -> &'a mut u32 { + &mut *(*s).0 +} + +// this, by analogy to previous case, is also okay. +fn boxed_boxed_borrowed_scribble<'a>(s: Box>) -> &'a mut u32 { + &mut *(**s).0 +} + +fn scribbling_tests() { + let mut x = 1; + { + let mut long_lived = Scribble(&mut x); + *borrowed_scribble(&mut long_lived) += 10; + assert_eq!(*long_lived.0, 11); + // (Scribble dtor runs here, after `&mut`-borrow above ends) + } + assert_eq!(x, 42); + x = 1; + { + let mut long_lived = Scribble(&mut x); + *boxed_borrowed_scribble(Box::new(&mut long_lived)) += 10; + assert_eq!(*long_lived.0, 11); + // (Scribble dtor runs here, after `&mut`-borrow above ends) + } + assert_eq!(x, 42); + x = 1; + { + let mut long_lived = Scribble(&mut x); + *boxed_boxed_borrowed_scribble(Box::new(Box::new(&mut long_lived))) += 10; + assert_eq!(*long_lived.0, 11); + // (Scribble dtor runs here, after `&mut`-borrow above ends) + } + assert_eq!(x, 42); +} + +fn main() { + basic_tests(); + scribbling_tests(); +} diff --git a/src/test/ui/issue-45696-scribble-on-boxed-borrow.ast.stderr b/src/test/ui/issue-45696-scribble-on-boxed-borrow.ast.stderr new file mode 100644 index 0000000000000..6172a5e35a8d9 --- /dev/null +++ b/src/test/ui/issue-45696-scribble-on-boxed-borrow.ast.stderr @@ -0,0 +1,14 @@ +error: compilation successful + --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:89:1 + | +LL | / fn main() { //[ast]~ ERROR compilation successful +LL | | //[migrate]~^ ERROR compilation successful +LL | | let mut x = 1; +LL | | { +... | +LL | | *boxed_boxed_scribbled(Box::new(Box::new(Scribble(&mut x)))) += 10; +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/issue-45696-scribble-on-boxed-borrow.migrate.stderr b/src/test/ui/issue-45696-scribble-on-boxed-borrow.migrate.stderr new file mode 100644 index 0000000000000..da0dfac2d18b1 --- /dev/null +++ b/src/test/ui/issue-45696-scribble-on-boxed-borrow.migrate.stderr @@ -0,0 +1,69 @@ +warning[E0597]: `*s.0` does not live long enough + --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:63:5 + | +LL | &mut *s.0 //[nll]~ ERROR `*s.0` does not live long enough [E0597] + | ^^^^^^^^^ borrowed value does not live long enough +... +LL | } + | - `*s.0` dropped here while still borrowed + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 62:14... + --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:62:14 + | +LL | fn scribbled<'a>(s: Scribble<'a>) -> &'a mut u32 { + | ^^ + = warning: This error has been downgraded to a warning for backwards compatibility with previous releases. + It represents potential unsoundness in your code. + This warning will become a hard error in the future. + +warning[E0597]: `*s.0` does not live long enough + --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:73:5 + | +LL | &mut *(*s).0 //[nll]~ ERROR `*s.0` does not live long enough [E0597] + | ^^^^^^^^^^^^ borrowed value does not live long enough +... +LL | } + | - `*s.0` dropped here while still borrowed + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 72:20... + --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:72:20 + | +LL | fn boxed_scribbled<'a>(s: Box>) -> &'a mut u32 { + | ^^ + = warning: This error has been downgraded to a warning for backwards compatibility with previous releases. + It represents potential unsoundness in your code. + This warning will become a hard error in the future. + +warning[E0597]: `*s.0` does not live long enough + --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:83:5 + | +LL | &mut *(**s).0 //[nll]~ ERROR `*s.0` does not live long enough [E0597] + | ^^^^^^^^^^^^^ borrowed value does not live long enough +... +LL | } + | - `*s.0` dropped here while still borrowed + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 82:26... + --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:82:26 + | +LL | fn boxed_boxed_scribbled<'a>(s: Box>>) -> &'a mut u32 { + | ^^ + = warning: This error has been downgraded to a warning for backwards compatibility with previous releases. + It represents potential unsoundness in your code. + This warning will become a hard error in the future. + +error: compilation successful + --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:89:1 + | +LL | / fn main() { //[ast]~ ERROR compilation successful +LL | | //[migrate]~^ ERROR compilation successful +LL | | let mut x = 1; +LL | | { +... | +LL | | *boxed_boxed_scribbled(Box::new(Box::new(Scribble(&mut x)))) += 10; +LL | | } + | |_^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/issue-45696-scribble-on-boxed-borrow.nll.stderr b/src/test/ui/issue-45696-scribble-on-boxed-borrow.nll.stderr new file mode 100644 index 0000000000000..09cbc2f945129 --- /dev/null +++ b/src/test/ui/issue-45696-scribble-on-boxed-borrow.nll.stderr @@ -0,0 +1,48 @@ +error[E0597]: `*s.0` does not live long enough + --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:63:5 + | +LL | &mut *s.0 //[nll]~ ERROR `*s.0` does not live long enough [E0597] + | ^^^^^^^^^ borrowed value does not live long enough +... +LL | } + | - `*s.0` dropped here while still borrowed + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 62:14... + --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:62:14 + | +LL | fn scribbled<'a>(s: Scribble<'a>) -> &'a mut u32 { + | ^^ + +error[E0597]: `*s.0` does not live long enough + --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:73:5 + | +LL | &mut *(*s).0 //[nll]~ ERROR `*s.0` does not live long enough [E0597] + | ^^^^^^^^^^^^ borrowed value does not live long enough +... +LL | } + | - `*s.0` dropped here while still borrowed + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 72:20... + --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:72:20 + | +LL | fn boxed_scribbled<'a>(s: Box>) -> &'a mut u32 { + | ^^ + +error[E0597]: `*s.0` does not live long enough + --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:83:5 + | +LL | &mut *(**s).0 //[nll]~ ERROR `*s.0` does not live long enough [E0597] + | ^^^^^^^^^^^^^ borrowed value does not live long enough +... +LL | } + | - `*s.0` dropped here while still borrowed + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 82:26... + --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:82:26 + | +LL | fn boxed_boxed_scribbled<'a>(s: Box>>) -> &'a mut u32 { + | ^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/issue-45696-scribble-on-boxed-borrow.rs b/src/test/ui/issue-45696-scribble-on-boxed-borrow.rs new file mode 100644 index 0000000000000..5a4874249e2f4 --- /dev/null +++ b/src/test/ui/issue-45696-scribble-on-boxed-borrow.rs @@ -0,0 +1,110 @@ +// 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. + +// rust-lang/rust#45696: This test is checking that we *cannot* return +// mutable borrows that would be scribbled over by destructors before +// the return occurs. +// +// We will explicitly test AST-borrowck, NLL, and migration modes; +// thus we will also skip the automated compare-mode=nll. + +// revisions: ast nll migrate +// ignore-compare-mode-nll + +// This test is going to pass in the ast and migrate revisions, +// because the AST-borrowck accepted this code in the past (see notes +// below). So we use `#[rustc_error]` to keep the outcome as an error +// in all scenarios, and rely on the stderr files to show what the +// actual behavior is. (See rust-lang/rust#49855.) +#![feature(rustc_attrs)] + +#![cfg_attr(nll, feature(nll))] +//[migrate]compile-flags: -Z borrowck=migrate -Z two-phase-borrows + +struct Scribble<'a>(&'a mut u32); + +impl<'a> Drop for Scribble<'a> { fn drop(&mut self) { *self.0 = 42; } } + +// this is okay, in both AST-borrowck and NLL: The `Scribble` here *has* +// to strictly outlive `'a` +fn borrowed_scribble<'a>(s: &'a mut Scribble) -> &'a mut u32 { + &mut *s.0 +} + +// this, by analogy to previous case, is also okay. +fn boxed_borrowed_scribble<'a>(s: Box<&'a mut Scribble>) -> &'a mut u32 { + &mut *(*s).0 +} + +// this, by analogy to previous case, is also okay. +fn boxed_boxed_borrowed_scribble<'a>(s: Box>) -> &'a mut u32 { + &mut *(**s).0 +} + +// this is not okay: in between the time that we take the mutable +// borrow and the caller receives it as a return value, the drop of +// `s` will scribble on it, violating our aliasing guarantees. +// +// * (Maybe in the future the two-phase borrows system will be +// extended to support this case. But for now, it is an error in +// NLL, even with two-phase borrows.) +// +// In any case, the AST-borrowck was not smart enough to know that +// this should be an error. (Which is perhaps the essence of why +// rust-lang/rust#45696 arose in the first place.) +fn scribbled<'a>(s: Scribble<'a>) -> &'a mut u32 { + &mut *s.0 //[nll]~ ERROR `*s.0` does not live long enough [E0597] + //[migrate]~^ WARNING `*s.0` does not live long enough [E0597] + //[migrate]~| WARNING This error has been downgraded to a warning for backwards compatibility +} + +// This, by analogy to previous case, is *also* not okay. +// +// (But again, AST-borrowck was not smart enogh to know that this +// should be an error.) +fn boxed_scribbled<'a>(s: Box>) -> &'a mut u32 { + &mut *(*s).0 //[nll]~ ERROR `*s.0` does not live long enough [E0597] + //[migrate]~^ WARNING `*s.0` does not live long enough [E0597] + //[migrate]~| WARNING This error has been downgraded to a warning for backwards compatibility +} + +// This, by analogy to previous case, is *also* not okay. +// +// (But again, AST-borrowck was not smart enogh to know that this +// should be an error.) +fn boxed_boxed_scribbled<'a>(s: Box>>) -> &'a mut u32 { + &mut *(**s).0 //[nll]~ ERROR `*s.0` does not live long enough [E0597] + //[migrate]~^ WARNING `*s.0` does not live long enough [E0597] + //[migrate]~| WARNING This error has been downgraded to a warning for backwards compatibility +} + +#[rustc_error] +fn main() { //[ast]~ ERROR compilation successful + //[migrate]~^ ERROR compilation successful + let mut x = 1; + { + let mut long_lived = Scribble(&mut x); + *borrowed_scribble(&mut long_lived) += 10; + // (Scribble dtor runs here, after `&mut`-borrow above ends) + } + { + let mut long_lived = Scribble(&mut x); + *boxed_borrowed_scribble(Box::new(&mut long_lived)) += 10; + // (Scribble dtor runs here, after `&mut`-borrow above ends) + } + { + let mut long_lived = Scribble(&mut x); + *boxed_boxed_borrowed_scribble(Box::new(Box::new(&mut long_lived))) += 10; + // (Scribble dtor runs here, after `&mut`-borrow above ends) + } + *scribbled(Scribble(&mut x)) += 10; + *boxed_scribbled(Box::new(Scribble(&mut x))) += 10; + *boxed_boxed_scribbled(Box::new(Box::new(Scribble(&mut x)))) += 10; +} From 469d6a819d3d7348fdd54d8c7ec1e694f2f43051 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 30 Jul 2018 15:38:18 +0200 Subject: [PATCH 15/23] Test for (previously uncaught) infinite loop identified by matthewjasper. --- .../ui/issue-45696-no-variant-box-recur.rs | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 src/test/ui/issue-45696-no-variant-box-recur.rs diff --git a/src/test/ui/issue-45696-no-variant-box-recur.rs b/src/test/ui/issue-45696-no-variant-box-recur.rs new file mode 100644 index 0000000000000..740e99c82a556 --- /dev/null +++ b/src/test/ui/issue-45696-no-variant-box-recur.rs @@ -0,0 +1,66 @@ +// 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. + +// rust-lang/rust#45696: This test checks the compiler won't infinite +// loop when you declare a variable of type `struct A(Box, ...);` +// (which is impossible to construct but *is* possible to declare; see +// also issues #4287, #44933, and #52852). +// +// We will explicitly test AST-borrowck, NLL, and migration modes; +// thus we will also skip the automated compare-mode=nll. + +// revisions: ast nll migrate +// ignore-compare-mode-nll + +#![cfg_attr(nll, feature(nll))] +//[migrate]compile-flags: -Z borrowck=migrate -Z two-phase-borrows + +// run-pass + +// This test has structs and functions that are by definiton unusable +// all over the place, so just go ahead and allow dead_code +#![allow(dead_code)] + +// direct regular recursion with indirect ownership via box +struct C { field: Box } + +// direct non-regular recursion with indirect ownership via box +struct D { field: Box<(D, D)> } + +// indirect regular recursion with indirect ownership via box. +struct E { field: F } +struct F { field: Box } + +// indirect non-regular recursion with indirect ownership via box. +struct G { field: (F, F) } +struct H { field: Box } + +// These enums are cases that are not currently hit by the +// `visit_terminator_drop` recursion down a type's structural +// definition. +// +// But it seems prudent to include them in this test as variants on +// the above, in that they are similarly non-constructable data types +// with destructors that would diverge. +enum I { One(Box) } +enum J { One(Box), Two(Box) } + +fn impossible_to_call_c(_c: C) { } +fn impossible_to_call_d(_d: D) { } +fn impossible_to_call_e(_e: E) { } +fn impossible_to_call_f(_f: F) { } +fn impossible_to_call_g(_g: G) { } +fn impossible_to_call_h(_h: H) { } +fn impossible_to_call_i(_i: I) { } +fn impossible_to_call_j(_j: J) { } + +fn main() { + +} From a1b8a93f81f4da89eaaa75f27df395f46c17c470 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 30 Jul 2018 16:17:04 +0200 Subject: [PATCH 16/23] Expand long-live-borrows-in-boxes test to include simplier illustrative cases. After talking about the PR with eddyb, I decided it was best to try to have some test cases that simplify the problem down to its core, so that people trying to understand what the issue is here will see those core examples first. --- .../issue-45696-long-live-borrows-in-boxes.rs | 40 ++++++++++++++++--- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/src/test/ui/issue-45696-long-live-borrows-in-boxes.rs b/src/test/ui/issue-45696-long-live-borrows-in-boxes.rs index e5326bb315ea3..881f37c2e0b0e 100644 --- a/src/test/ui/issue-45696-long-live-borrows-in-boxes.rs +++ b/src/test/ui/issue-45696-long-live-borrows-in-boxes.rs @@ -22,24 +22,54 @@ // run-pass -type Boxed<'a, 'b> = Box<(&'a mut u32, &'b mut u32)>; +// This function shows quite directly what is going on: We have a +// reborrow of contents within the box. +fn return_borrow_from_dropped_box_1(x: Box<&mut u32>) -> &mut u32 { &mut **x } -fn return_borrow_from_dropped_box<'a>(x: Boxed<'a, '_>) -> &'a mut u32 { +// This function is the way you'll probably see this in practice (the +// reborrow is now implicit). +fn return_borrow_from_dropped_box_2(x: Box<&mut u32>) -> &mut u32 { *x } + +// For the remaining tests we just add some fields or other +// indirection to ensure that the compiler isn't just special-casing +// the above `Box<&mut T>` as the only type that would work. + +// Here we add a tuple of indirection between the box and the +// reference. +type BoxedTup<'a, 'b> = Box<(&'a mut u32, &'b mut u32)>; + +fn return_borrow_of_field_from_dropped_box_1<'a>(x: BoxedTup<'a, '_>) -> &'a mut u32 { &mut *x.0 } -fn return_borrow_from_dropped_tupled_box<'a>(x: (Boxed<'a, '_>, &mut u32)) -> &'a mut u32 { +fn return_borrow_of_field_from_dropped_box_2<'a>(x: BoxedTup<'a, '_>) -> &'a mut u32 { + x.0 +} + +fn return_borrow_from_dropped_tupled_box_1<'a>(x: (BoxedTup<'a, '_>, &mut u32)) -> &'a mut u32 { &mut *(x.0).0 } +fn return_borrow_from_dropped_tupled_box_2<'a>(x: (BoxedTup<'a, '_>, &mut u32)) -> &'a mut u32 { + (x.0).0 +} + fn basic_tests() { let mut x = 2; let mut y = 3; let mut z = 4; - *return_borrow_from_dropped_box(Box::new((&mut x, &mut y))) += 10; + *return_borrow_from_dropped_box_1(Box::new(&mut x)) += 10; assert_eq!((x, y, z), (12, 3, 4)); - *return_borrow_from_dropped_tupled_box((Box::new((&mut x, &mut y)), &mut z)) += 10; + *return_borrow_from_dropped_box_2(Box::new(&mut x)) += 10; assert_eq!((x, y, z), (22, 3, 4)); + *return_borrow_of_field_from_dropped_box_1(Box::new((&mut x, &mut y))) += 10; + assert_eq!((x, y, z), (32, 3, 4)); + *return_borrow_of_field_from_dropped_box_2(Box::new((&mut x, &mut y))) += 10; + assert_eq!((x, y, z), (42, 3, 4)); + *return_borrow_from_dropped_tupled_box_1((Box::new((&mut x, &mut y)), &mut z)) += 10; + assert_eq!((x, y, z), (52, 3, 4)); + *return_borrow_from_dropped_tupled_box_2((Box::new((&mut x, &mut y)), &mut z)) += 10; + assert_eq!((x, y, z), (62, 3, 4)); } // These scribbling tests have been transcribed from From c02c00b8455d6ec6eff50ae94bebb4a424c95e02 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 31 Jul 2018 01:10:06 +0200 Subject: [PATCH 17/23] Fix bug in test pointed out during review. --- src/test/ui/issue-45696-no-variant-box-recur.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/ui/issue-45696-no-variant-box-recur.rs b/src/test/ui/issue-45696-no-variant-box-recur.rs index 740e99c82a556..da42e171fcc50 100644 --- a/src/test/ui/issue-45696-no-variant-box-recur.rs +++ b/src/test/ui/issue-45696-no-variant-box-recur.rs @@ -39,8 +39,8 @@ struct E { field: F } struct F { field: Box } // indirect non-regular recursion with indirect ownership via box. -struct G { field: (F, F) } -struct H { field: Box } +struct G { field: (H, H) } +struct H { field: Box } // These enums are cases that are not currently hit by the // `visit_terminator_drop` recursion down a type's structural From 01cf9bf159a11d3467b22df7dc1a7302b2b748e2 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Wed, 1 Aug 2018 09:42:20 -0700 Subject: [PATCH 18/23] Update LLVM submodule --- src/llvm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llvm b/src/llvm index 03684905101f0..f4130c026163c 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit 03684905101f0b7e49dfe530e54dc1aeac6ef0fb +Subproject commit f4130c026163c984bc1b8ef6d75903a62268a698 From 2488cb6b1027bf88e33dfdc7ce89472f5dc54714 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 2 Aug 2018 12:00:15 +0200 Subject: [PATCH 19/23] Explicitly label any named lifetimes mentioned in error messages. --- .../error_reporting/region_name.rs | 54 +++++++++++++++++-- .../static-return-lifetime-infered.nll.stderr | 2 + src/test/ui/issue-10291.nll.stderr | 2 + src/test/ui/issue-52213.nll.stderr | 5 ++ ...n-lbr-named-does-not-outlive-static.stderr | 2 + src/test/ui/nll/mir_check_cast_closure.stderr | 4 ++ src/test/ui/nll/mir_check_cast_unsize.stderr | 4 +- .../projection-one-region-closure.stderr | 15 ++++++ ...tion-one-region-trait-bound-closure.stderr | 15 ++++++ ...tion-two-region-trait-bound-closure.stderr | 5 ++ 10 files changed, 103 insertions(+), 5 deletions(-) diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs index 8505d8e1ef39c..79165276430d3 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs @@ -15,10 +15,10 @@ use rustc::hir::def_id::DefId; use rustc::infer::InferCtxt; use rustc::mir::Mir; use rustc::ty::subst::{Substs, UnpackedKind}; -use rustc::ty::{self, RegionVid, Ty, TyCtxt}; +use rustc::ty::{self, RegionKind, RegionVid, Ty, TyCtxt}; use rustc::util::ppaux::with_highlight_region; use rustc_errors::DiagnosticBuilder; -use syntax::ast::Name; +use syntax::ast::{Name, DUMMY_NODE_ID}; use syntax::symbol::keywords; use syntax_pos::symbol::InternedString; @@ -90,14 +90,21 @@ impl<'tcx> RegionInferenceContext<'tcx> { diag: &mut DiagnosticBuilder<'_>, ) -> Option { let error_region = self.to_error_region(fr)?; + debug!("give_region_a_name: error_region = {:?}", error_region); match error_region { - ty::ReEarlyBound(ebr) => Some(ebr.name), + ty::ReEarlyBound(ebr) => { + self.highlight_named_span(tcx, error_region, &ebr.name, diag); + Some(ebr.name) + }, ty::ReStatic => Some(keywords::StaticLifetime.name().as_interned_str()), ty::ReFree(free_region) => match free_region.bound_region { - ty::BoundRegion::BrNamed(_, name) => Some(name), + ty::BoundRegion::BrNamed(_, name) => { + self.highlight_named_span(tcx, error_region, &name, diag); + Some(name) + }, ty::BoundRegion::BrEnv => { let closure_span = tcx.hir.span_if_local(mir_def_id).unwrap(); @@ -123,6 +130,45 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } + /// Highlight a named span to provide context for error messages that + /// mention that span, for example: + /// + /// ``` + /// | + /// | fn two_regions<'a, 'b, T>(cell: Cell<&'a ()>, t: T) + /// | -- -- lifetime `'b` defined here + /// | | + /// | lifetime `'a` defined here + /// | + /// | with_signature(cell, t, |cell, t| require(cell, t)); + /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'b` must + /// | outlive `'a` + /// ``` + fn highlight_named_span( + &self, + tcx: TyCtxt<'_, '_, 'tcx>, + error_region: &RegionKind, + name: &InternedString, + diag: &mut DiagnosticBuilder<'_>, + ) { + let cm = tcx.sess.codemap(); + + let scope = error_region.free_region_binding_scope(tcx); + let node = tcx.hir.as_local_node_id(scope).unwrap_or(DUMMY_NODE_ID); + + let mut sp = cm.def_span(tcx.hir.span(node)); + if let Some(param) = tcx.hir.get_generics(scope).and_then(|generics| { + generics.get_named(name) + }) { + sp = param.span; + } + + diag.span_label( + sp, + format!("lifetime `{}` defined here", name), + ); + } + /// Find an argument that contains `fr` and label it with a fully /// elaborated type, returning something like `'1`. Result looks /// like: diff --git a/src/test/ui/impl-trait/static-return-lifetime-infered.nll.stderr b/src/test/ui/impl-trait/static-return-lifetime-infered.nll.stderr index bbc63e6fecaf5..c1e12978c5179 100644 --- a/src/test/ui/impl-trait/static-return-lifetime-infered.nll.stderr +++ b/src/test/ui/impl-trait/static-return-lifetime-infered.nll.stderr @@ -21,6 +21,8 @@ LL | self.x.iter().map(|a| a.0) error: unsatisfied lifetime constraints --> $DIR/static-return-lifetime-infered.rs:21:9 | +LL | fn iter_values<'a>(&'a self) -> impl Iterator { + | -- lifetime `'a` defined here LL | self.x.iter().map(|a| a.0) | ^^^^^^^^^^^^^ requires that `'a` must outlive `'static` diff --git a/src/test/ui/issue-10291.nll.stderr b/src/test/ui/issue-10291.nll.stderr index 6de00ffd48cc1..48dad040f9d0c 100644 --- a/src/test/ui/issue-10291.nll.stderr +++ b/src/test/ui/issue-10291.nll.stderr @@ -7,6 +7,8 @@ LL | x //~ ERROR E0312 error: unsatisfied lifetime constraints --> $DIR/issue-10291.rs:12:5 | +LL | fn test<'x>(x: &'x isize) { + | -- lifetime `'x` defined here LL | drop:: FnMut(&'z isize) -> &'z isize>>(Box::new(|z| { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'x` must outlive `'static` diff --git a/src/test/ui/issue-52213.nll.stderr b/src/test/ui/issue-52213.nll.stderr index 7dd513d1b712c..4e1efc96490bd 100644 --- a/src/test/ui/issue-52213.nll.stderr +++ b/src/test/ui/issue-52213.nll.stderr @@ -7,6 +7,11 @@ LL | match (&t,) { //~ ERROR cannot infer an appropriate lifetime error: unsatisfied lifetime constraints --> $DIR/issue-52213.rs:13:11 | +LL | fn transmute_lifetime<'a, 'b, T>(t: &'a (T,)) -> &'b T { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | match (&t,) { //~ ERROR cannot infer an appropriate lifetime LL | ((u,),) => u, | ^ requires that `'a` must outlive `'b` diff --git a/src/test/ui/nll/closure-requirements/region-lbr-named-does-not-outlive-static.stderr b/src/test/ui/nll/closure-requirements/region-lbr-named-does-not-outlive-static.stderr index b056271162738..116ff6ef02356 100644 --- a/src/test/ui/nll/closure-requirements/region-lbr-named-does-not-outlive-static.stderr +++ b/src/test/ui/nll/closure-requirements/region-lbr-named-does-not-outlive-static.stderr @@ -7,6 +7,8 @@ LL | &*x error: unsatisfied lifetime constraints --> $DIR/region-lbr-named-does-not-outlive-static.rs:19:5 | +LL | fn foo<'a>(x: &'a u32) -> &'static u32 { + | -- lifetime `'a` defined here LL | &*x | ^^^ requires that `'a` must outlive `'static` diff --git a/src/test/ui/nll/mir_check_cast_closure.stderr b/src/test/ui/nll/mir_check_cast_closure.stderr index fc2a3c43f7589..cdc407985fe63 100644 --- a/src/test/ui/nll/mir_check_cast_closure.stderr +++ b/src/test/ui/nll/mir_check_cast_closure.stderr @@ -7,6 +7,10 @@ LL | g error: unsatisfied lifetime constraints --> $DIR/mir_check_cast_closure.rs:16:28 | +LL | fn bar<'a, 'b>() -> fn(&'a u32, &'b u32) -> &'a u32 { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here LL | let g: fn(_, _) -> _ = |_x, y| y; | ^^^^^^^^^ cast requires that `'b` must outlive `'a` diff --git a/src/test/ui/nll/mir_check_cast_unsize.stderr b/src/test/ui/nll/mir_check_cast_unsize.stderr index 7bd0595f3b5cc..02ecd05e5f931 100644 --- a/src/test/ui/nll/mir_check_cast_unsize.stderr +++ b/src/test/ui/nll/mir_check_cast_unsize.stderr @@ -8,7 +8,9 @@ error: unsatisfied lifetime constraints --> $DIR/mir_check_cast_unsize.rs:17:46 | LL | fn bar<'a>(x: &'a u32) -> &'static dyn Debug { - | ______________________________________________^ + | ________--____________________________________^ + | | | + | | lifetime `'a` defined here LL | | //~^ ERROR unsatisfied lifetime constraints LL | | x LL | | //~^ WARNING not reporting region error due to nll diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr index ed8491349a257..2b0e682f85161 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr @@ -52,6 +52,11 @@ LL | | } error: unsatisfied lifetime constraints --> $DIR/projection-one-region-closure.rs:55:5 | +LL | fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T) + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a` @@ -101,6 +106,11 @@ LL | | } error: unsatisfied lifetime constraints --> $DIR/projection-one-region-closure.rs:67:5 | +LL | fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T) + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a` @@ -150,6 +160,11 @@ LL | | } error: unsatisfied lifetime constraints --> $DIR/projection-one-region-closure.rs:89:5 | +LL | fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T) + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a` diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr index 8318ce10745d3..739bde4a481c5 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr @@ -51,6 +51,11 @@ LL | | } error: unsatisfied lifetime constraints --> $DIR/projection-one-region-trait-bound-closure.rs:47:5 | +LL | fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T) + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a` @@ -91,6 +96,11 @@ LL | | } error: unsatisfied lifetime constraints --> $DIR/projection-one-region-trait-bound-closure.rs:58:5 | +LL | fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T) + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a` @@ -131,6 +141,11 @@ LL | | } error: unsatisfied lifetime constraints --> $DIR/projection-one-region-trait-bound-closure.rs:79:5 | +LL | fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T) + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a` diff --git a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr index 1452573d57a25..6838e0f3b3d01 100644 --- a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr @@ -259,6 +259,11 @@ LL | | } error: unsatisfied lifetime constraints --> $DIR/projection-two-region-trait-bound-closure.rs:108:5 | +LL | fn two_regions<'a, 'b, T>(cell: Cell<&'a ()>, t: T) + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a` From bb88c989faeace3dd50027a748aeb992739907e4 Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Tue, 3 Jul 2018 12:24:24 -0600 Subject: [PATCH 20/23] Add lldb to the build This optionally adds lldb (and clang, which it needs) to the build. Because rust uses LLVM 7, and because clang 7 is not yet released, a recent git master version of clang is used. The lldb that is used includes the Rust plugin. lldb is only built when asked for, or when doing a nightly build on macOS. Only macOS is done for now due to difficulties with the Python dependency. --- .gitmodules | 8 +++ config.toml.example | 4 ++ src/Cargo.lock | 2 +- src/bootstrap/builder.rs | 1 + src/bootstrap/config.rs | 3 + src/bootstrap/configure.py | 1 + src/bootstrap/dist.rs | 114 +++++++++++++++++++++++++++++++++++++ src/bootstrap/lib.rs | 43 +++++++++----- src/bootstrap/native.rs | 20 ++++++- src/clang | 1 + src/lldb | 1 + src/tools/rust-installer | 2 +- 12 files changed, 182 insertions(+), 18 deletions(-) create mode 160000 src/clang create mode 160000 src/lldb diff --git a/.gitmodules b/.gitmodules index f3eb902709ca7..02cbde25e629e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -56,3 +56,11 @@ [submodule "src/libbacktrace"] path = src/libbacktrace url = https://github.com/rust-lang-nursery/libbacktrace +[submodule "src/lldb"] + path = src/lldb + url = https://github.com/rust-lang-nursery/lldb/ + branch = rust-release-70 +[submodule "src/clang"] + path = src/clang + url = https://github.com/rust-lang-nursery/clang/ + branch = master diff --git a/config.toml.example b/config.toml.example index 99073416334f5..b095d6a98268f 100644 --- a/config.toml.example +++ b/config.toml.example @@ -354,6 +354,10 @@ # sysroot. #llvm-tools = false +# Indicates whether LLDB will be made available in the sysroot. +# This is only built if LLVM is also being built. +#lldb = false + # Whether to deny warnings in crates #deny-warnings = true diff --git a/src/Cargo.lock b/src/Cargo.lock index b2e41589893cc..58120aaf9e59a 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -1011,7 +1011,7 @@ name = "installer" version = "0.0.0" dependencies = [ "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", - "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 724d3b741903f..386b37c405e40 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -461,6 +461,7 @@ impl<'a> Builder<'a> { dist::Rustfmt, dist::Clippy, dist::LlvmTools, + dist::Lldb, dist::Extended, dist::HashSign ), diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 0a8a5c87d0da1..43e7a8aa82fa4 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -87,6 +87,7 @@ pub struct Config { pub llvm_link_jobs: Option, pub lld_enabled: bool, + pub lldb_enabled: bool, pub llvm_tools_enabled: bool, // rust codegen options @@ -310,6 +311,7 @@ struct Rust { codegen_backends_dir: Option, wasm_syscall: Option, lld: Option, + lldb: Option, llvm_tools: Option, deny_warnings: Option, backtrace_on_ice: Option, @@ -538,6 +540,7 @@ impl Config { } set(&mut config.wasm_syscall, rust.wasm_syscall); set(&mut config.lld_enabled, rust.lld); + set(&mut config.lldb_enabled, rust.lldb); set(&mut config.llvm_tools_enabled, rust.llvm_tools); config.rustc_parallel_queries = rust.experimental_parallel_queries.unwrap_or(false); config.rustc_default_linker = rust.default_linker.clone(); diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index 9fdba044f4be3..c2843101eb61a 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -335,6 +335,7 @@ def set(key, value): elif option.name == 'full-tools': set('rust.codegen-backends', ['llvm', 'emscripten']) set('rust.lld', True) + set('rust.lldb', True) set('rust.llvm-tools', True) set('build.extended', True) elif option.name == 'option-checking': diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 188e64cd668dd..ab3c67128302f 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -47,6 +47,8 @@ pub fn pkgname(builder: &Builder, component: &str) -> String { format!("{}-{}", component, builder.rustfmt_package_vers()) } else if component == "llvm-tools" { format!("{}-{}", component, builder.llvm_tools_package_vers()) + } else if component == "lldb" { + format!("{}-{}", component, builder.lldb_package_vers()) } else { assert!(component.starts_with("rust")); format!("{}-{}", component, builder.rust_package_vers()) @@ -1396,6 +1398,7 @@ impl Step for Extended { let rls_installer = builder.ensure(Rls { stage, target }); let llvm_tools_installer = builder.ensure(LlvmTools { stage, target }); let clippy_installer = builder.ensure(Clippy { stage, target }); + let lldb_installer = builder.ensure(Lldb { target }); let mingw_installer = builder.ensure(Mingw { host: target }); let analysis_installer = builder.ensure(Analysis { compiler: builder.compiler(stage, self.host), @@ -1435,6 +1438,7 @@ impl Step for Extended { tarballs.extend(clippy_installer.clone()); tarballs.extend(rustfmt_installer.clone()); tarballs.extend(llvm_tools_installer.clone()); + tarballs.extend(lldb_installer.clone()); tarballs.push(analysis_installer); tarballs.push(std_installer); if builder.config.docs { @@ -1869,6 +1873,7 @@ impl Step for HashSign { cmd.arg(builder.package_vers(&builder.release_num("clippy"))); cmd.arg(builder.package_vers(&builder.release_num("rustfmt"))); cmd.arg(builder.llvm_tools_package_vers()); + cmd.arg(builder.lldb_package_vers()); cmd.arg(addr); builder.create_dir(&distdir(builder)); @@ -1963,3 +1968,112 @@ impl Step for LlvmTools { Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target))) } } + +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub struct Lldb { + pub target: Interned, +} + +impl Step for Lldb { + type Output = Option; + const ONLY_HOSTS: bool = true; + const DEFAULT: bool = true; + + fn should_run(run: ShouldRun) -> ShouldRun { + run.path("src/lldb") + } + + fn make_run(run: RunConfig) { + run.builder.ensure(Lldb { + target: run.target, + }); + } + + fn run(self, builder: &Builder) -> Option { + let target = self.target; + + builder.info(&format!("Dist Lldb ({})", target)); + let src = builder.src.join("src/lldb"); + let name = pkgname(builder, "lldb"); + + let tmp = tmpdir(builder); + let image = tmp.join("lldb-image"); + drop(fs::remove_dir_all(&image)); + + // Prepare the image directory + let bindir = builder + .llvm_out(target) + .join("bin"); + let dst = image.join("bin"); + t!(fs::create_dir_all(&dst)); + for program in &["lldb", "lldb-argdumper", "lldb-mi", "lldb-server"] { + let exe = bindir.join(exe(program, &target)); + builder.install(&exe, &dst, 0o755); + } + + // The libraries. + let libdir = builder.llvm_out(target).join("lib"); + let dst = image.join("lib"); + t!(fs::create_dir_all(&dst)); + for entry in t!(fs::read_dir(&libdir)) { + // let entry = t!(entry); + let entry = entry.unwrap(); + if let Ok(name) = entry.file_name().into_string() { + if name.starts_with("liblldb.") && !name.ends_with(".a") { + if t!(entry.file_type()).is_symlink() { + builder.copy_to_folder(&entry.path(), &dst); + } else { + builder.install(&entry.path(), &dst, 0o755); + } + } + } + } + + // The lldb scripts might be installed in lib/python$version + // or in lib64/python$version. If lib64 exists, use it; + // otherwise lib. + let libdir = builder.llvm_out(target).join("lib64"); + let (libdir, libdir_name) = if libdir.exists() { + (libdir, "lib64") + } else { + (builder.llvm_out(target).join("lib"), "lib") + }; + for entry in t!(fs::read_dir(&libdir)) { + let entry = t!(entry); + if let Ok(name) = entry.file_name().into_string() { + if name.starts_with("python") { + let dst = image.join(libdir_name) + .join(entry.file_name()); + t!(fs::create_dir_all(&dst)); + builder.cp_r(&entry.path(), &dst); + break; + } + } + } + + // Prepare the overlay + let overlay = tmp.join("lldb-overlay"); + drop(fs::remove_dir_all(&overlay)); + builder.create_dir(&overlay); + builder.install(&src.join("LICENSE.TXT"), &overlay, 0o644); + builder.create(&overlay.join("version"), &builder.lldb_vers()); + + // Generate the installer tarball + let mut cmd = rust_installer(builder); + cmd.arg("generate") + .arg("--product-name=Rust") + .arg("--rel-manifest-dir=rustlib") + .arg("--success-message=lldb-installed.") + .arg("--image-dir").arg(&image) + .arg("--work-dir").arg(&tmpdir(builder)) + .arg("--output-dir").arg(&distdir(builder)) + .arg("--non-installed-overlay").arg(&overlay) + .arg(format!("--package-name={}-{}", name, target)) + .arg("--legacy-manifest-dirs=rustlib,cargo") + .arg("--component-name=lldb-preview"); + + + builder.run(&mut cmd); + Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target))) + } +} diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 1efff19dfb993..41834ba3165a8 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -151,6 +151,11 @@ use std::process::{self, Command}; use std::slice; use std::str; +#[cfg(unix)] +use std::os::unix::fs::symlink as symlink_file; +#[cfg(windows)] +use std::os::windows::fs::symlink_file; + use build_helper::{run_silent, run_suppressed, try_run_silent, try_run_suppressed, output, mtime}; use filetime::FileTime; @@ -1005,6 +1010,14 @@ impl Build { self.rust_version() } + fn lldb_package_vers(&self) -> String { + self.package_vers(&self.rust_version()) + } + + fn lldb_vers(&self) -> String { + self.rust_version() + } + /// Returns the `version` string associated with this compiler for Rust /// itself. /// @@ -1123,20 +1136,24 @@ impl Build { pub fn copy(&self, src: &Path, dst: &Path) { if self.config.dry_run { return; } let _ = fs::remove_file(&dst); - // Attempt to "easy copy" by creating a hard link (symlinks don't work on - // windows), but if that fails just fall back to a slow `copy` operation. - if let Ok(()) = fs::hard_link(src, dst) { - return - } - if let Err(e) = fs::copy(src, dst) { - panic!("failed to copy `{}` to `{}`: {}", src.display(), - dst.display(), e) + let metadata = t!(src.symlink_metadata()); + if metadata.file_type().is_symlink() { + let link = t!(fs::read_link(src)); + t!(symlink_file(link, dst)); + } else if let Ok(()) = fs::hard_link(src, dst) { + // Attempt to "easy copy" by creating a hard link + // (symlinks don't work on windows), but if that fails + // just fall back to a slow `copy` operation. + } else { + if let Err(e) = fs::copy(src, dst) { + panic!("failed to copy `{}` to `{}`: {}", src.display(), + dst.display(), e) + } + t!(fs::set_permissions(dst, metadata.permissions())); + let atime = FileTime::from_last_access_time(&metadata); + let mtime = FileTime::from_last_modification_time(&metadata); + t!(filetime::set_file_times(dst, atime, mtime)); } - let metadata = t!(src.metadata()); - t!(fs::set_permissions(dst, metadata.permissions())); - let atime = FileTime::from_last_access_time(&metadata); - let mtime = FileTime::from_last_modification_time(&metadata); - t!(filetime::set_file_times(dst, atime, mtime)); } /// Search-and-replaces within a file. (Not maximally efficiently: allocates a diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 9aeb4e0edaed5..e20dab5f077a3 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -149,7 +149,6 @@ impl Step for Llvm { .define("WITH_POLLY", "OFF") .define("LLVM_ENABLE_TERMINFO", "OFF") .define("LLVM_ENABLE_LIBEDIT", "OFF") - .define("LLVM_ENABLE_LIBXML2", "OFF") .define("LLVM_PARALLEL_COMPILE_JOBS", builder.jobs().to_string()) .define("LLVM_TARGET_ARCH", target.split('-').next().unwrap()) .define("LLVM_DEFAULT_TARGET_TRIPLE", target); @@ -163,6 +162,14 @@ impl Step for Llvm { cfg.define("LLVM_OCAML_INSTALL_PATH", env::var_os("LLVM_OCAML_INSTALL_PATH").unwrap_or_else(|| "usr/lib/ocaml".into())); + // Build clang and lldb if asked, or if doing a macOS nightly + // build. LLVM_ENABLE_PROJECTS allows them to be checked out + // parallel to src/llvm, and makes conditionally building them + // simpler. + let want_lldb = builder.config.lldb_enabled || + (target.contains("apple-darwin") && + builder.config.channel == "nightly"); + // This setting makes the LLVM tools link to the dynamic LLVM library, // which saves both memory during parallel links and overall disk space // for the tools. We don't distribute any of those tools, so this is @@ -170,12 +177,13 @@ impl Step for Llvm { // // If we are shipping llvm tools then we statically link them LLVM if (target.contains("linux-gnu") || target.contains("apple-darwin")) && - !builder.config.llvm_tools_enabled { + !builder.config.llvm_tools_enabled && + !want_lldb { cfg.define("LLVM_LINK_LLVM_DYLIB", "ON"); } // For distribution we want the LLVM tools to be *statically* linked to libstdc++ - if builder.config.llvm_tools_enabled { + if builder.config.llvm_tools_enabled || want_lldb { if !target.contains("windows") { if target.contains("apple") { cfg.define("CMAKE_EXE_LINKER_FLAGS", "-static-libstdc++"); @@ -196,6 +204,12 @@ impl Step for Llvm { cfg.define("LLVM_BUILD_32_BITS", "ON"); } + if want_lldb { + cfg.define("LLVM_ENABLE_PROJECTS", "clang;lldb"); + } else { + cfg.define("LLVM_ENABLE_LIBXML2", "OFF"); + } + if let Some(num_linkers) = builder.config.llvm_link_jobs { if num_linkers > 0 { cfg.define("LLVM_PARALLEL_LINK_JOBS", num_linkers.to_string()); diff --git a/src/clang b/src/clang new file mode 160000 index 0000000000000..6fda594059bd4 --- /dev/null +++ b/src/clang @@ -0,0 +1 @@ +Subproject commit 6fda594059bd48b6b2ddcb34eda0a278aee2214e diff --git a/src/lldb b/src/lldb new file mode 160000 index 0000000000000..3dbe998969d45 --- /dev/null +++ b/src/lldb @@ -0,0 +1 @@ +Subproject commit 3dbe998969d457c5cef245f61b48bdaed0f5c059 diff --git a/src/tools/rust-installer b/src/tools/rust-installer index 89414e44dc948..27dec6cae3a81 160000 --- a/src/tools/rust-installer +++ b/src/tools/rust-installer @@ -1 +1 @@ -Subproject commit 89414e44dc94844888e59c08bc31dcccb1792800 +Subproject commit 27dec6cae3a8132d8a073aad6775425c85095c99 From 4aa21d173dc9986076e51580eada6c62d7c61bff Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Thu, 26 Jul 2018 07:33:12 -0600 Subject: [PATCH 21/23] Ignore clang and lldb in tidy --- src/tools/tidy/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index bb041b39785ec..baf2d2ebbc959 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -56,8 +56,10 @@ pub mod libcoretest; fn filter_dirs(path: &Path) -> bool { let skip = [ + "src/clang", "src/dlmalloc", "src/jemalloc", + "src/lldb", "src/llvm", "src/llvm-emscripten", "src/libbacktrace", From 77075781f38bdfe90f025b6834e16cae586c5f69 Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Fri, 27 Jul 2018 07:55:50 -0600 Subject: [PATCH 22/23] Do not try to distribute lldb if it was not built --- src/bootstrap/dist.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index ab3c67128302f..c1ce0a6d3e327 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -1992,6 +1992,17 @@ impl Step for Lldb { fn run(self, builder: &Builder) -> Option { let target = self.target; + // Do nothing if lldb was not built. This is difficult to + // determine in should_run because the target is not available + // at that point. + let bindir = builder + .llvm_out(target) + .join("bin"); + let lldb_exe = bindir.join(exe("lldb", &target)); + if !lldb_exe.exists() { + return None; + } + builder.info(&format!("Dist Lldb ({})", target)); let src = builder.src.join("src/lldb"); let name = pkgname(builder, "lldb"); @@ -2001,9 +2012,6 @@ impl Step for Lldb { drop(fs::remove_dir_all(&image)); // Prepare the image directory - let bindir = builder - .llvm_out(target) - .join("bin"); let dst = image.join("bin"); t!(fs::create_dir_all(&dst)); for program in &["lldb", "lldb-argdumper", "lldb-mi", "lldb-server"] { From 1d43f251dfd91de276966fe74452282b95a7aae2 Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Fri, 27 Jul 2018 08:46:01 -0600 Subject: [PATCH 23/23] Handle the dry_run case in the lldb dist step --- src/bootstrap/dist.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index c1ce0a6d3e327..cff03e610e2a2 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -1992,9 +1992,10 @@ impl Step for Lldb { fn run(self, builder: &Builder) -> Option { let target = self.target; - // Do nothing if lldb was not built. This is difficult to - // determine in should_run because the target is not available - // at that point. + if builder.config.dry_run { + return None; + } + let bindir = builder .llvm_out(target) .join("bin");