1
Fork 0

Rollup merge of #48682 - spastorino:make_causal_lazy, r=nikomatsakis

[NLL] Make causal tracking lazy

Close #46590

cc @nikomatsakis
This commit is contained in:
Manish Goregaokar 2018-03-08 11:25:56 -08:00 committed by GitHub
commit d7f44ac52c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
33 changed files with 1242 additions and 847 deletions

View file

@ -138,9 +138,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
self.explain_span(scope_decorated_tag, span) self.explain_span(scope_decorated_tag, span)
} }
ty::ReEarlyBound(_) | ty::ReFree(_) => self.msg_span_from_free_region(region), ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReStatic => {
self.msg_span_from_free_region(region)
ty::ReStatic => ("the static lifetime".to_owned(), None), }
ty::ReEmpty => ("the empty lifetime".to_owned(), None), ty::ReEmpty => ("the empty lifetime".to_owned(), None),
@ -175,6 +175,19 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
} }
fn msg_span_from_free_region(self, region: ty::Region<'tcx>) -> (String, Option<Span>) { fn msg_span_from_free_region(self, region: ty::Region<'tcx>) -> (String, Option<Span>) {
match *region {
ty::ReEarlyBound(_) | ty::ReFree(_) => {
self.msg_span_from_early_bound_and_free_regions(region)
},
ty::ReStatic => ("the static lifetime".to_owned(), None),
_ => bug!(),
}
}
fn msg_span_from_early_bound_and_free_regions(
self,
region: ty::Region<'tcx>,
) -> (String, Option<Span>) {
let scope = region.free_region_binding_scope(self); let scope = region.free_region_binding_scope(self);
let node = self.hir.as_local_node_id(scope).unwrap_or(DUMMY_NODE_ID); let node = self.hir.as_local_node_id(scope).unwrap_or(DUMMY_NODE_ID);
let unknown; let unknown;

File diff suppressed because it is too large Load diff

View file

@ -20,7 +20,7 @@ use lint::builtin::BuiltinLintDiagnostics;
use middle::allocator::AllocatorKind; use middle::allocator::AllocatorKind;
use middle::dependency_format; use middle::dependency_format;
use session::search_paths::PathKind; use session::search_paths::PathKind;
use session::config::{DebugInfoLevel, OutputType, Epoch}; use session::config::{DebugInfoLevel, Epoch, OutputType};
use ty::tls; use ty::tls;
use util::nodemap::{FxHashMap, FxHashSet}; use util::nodemap::{FxHashMap, FxHashSet};
use util::common::{duration_to_secs_str, ErrorReported}; use util::common::{duration_to_secs_str, ErrorReported};
@ -37,7 +37,7 @@ use syntax::parse;
use syntax::parse::ParseSess; use syntax::parse::ParseSess;
use syntax::{ast, codemap}; use syntax::{ast, codemap};
use syntax::feature_gate::AttributeType; use syntax::feature_gate::AttributeType;
use syntax_pos::{Span, MultiSpan}; use syntax_pos::{MultiSpan, Span};
use rustc_back::{LinkerFlavor, PanicStrategy}; use rustc_back::{LinkerFlavor, PanicStrategy};
use rustc_back::target::Target; use rustc_back::target::Target;
@ -87,7 +87,7 @@ pub struct Session {
pub plugin_attributes: RefCell<Vec<(String, AttributeType)>>, pub plugin_attributes: RefCell<Vec<(String, AttributeType)>>,
pub crate_types: RefCell<Vec<config::CrateType>>, pub crate_types: RefCell<Vec<config::CrateType>>,
pub dependency_formats: RefCell<dependency_format::Dependencies>, pub dependency_formats: RefCell<dependency_format::Dependencies>,
/// The crate_disambiguator is constructed out of all the `-C metadata` /// The crate_disambiguator is constructed out of all the `-C metadata`
/// arguments passed to the compiler. Its value together with the crate-name /// arguments passed to the compiler. Its value together with the crate-name
/// forms a unique global identifier for the crate. It is used to allow /// forms a unique global identifier for the crate. It is used to allow
/// multiple crates with the same name to coexist. See the /// multiple crates with the same name to coexist. See the
@ -141,7 +141,6 @@ pub struct Session {
out_of_fuel: Cell<bool>, out_of_fuel: Cell<bool>,
// The next two are public because the driver needs to read them. // The next two are public because the driver needs to read them.
/// If -zprint-fuel=crate, Some(crate). /// If -zprint-fuel=crate, Some(crate).
pub print_fuel_crate: Option<String>, pub print_fuel_crate: Option<String>,
/// Always set to zero and incremented so that we can print fuel expended by a crate. /// Always set to zero and incremented so that we can print fuel expended by a crate.
@ -175,7 +174,7 @@ enum DiagnosticBuilderMethod {
Note, Note,
SpanNote, SpanNote,
SpanSuggestion(String), // suggestion SpanSuggestion(String), // suggestion
// add more variants as needed to support one-time diagnostics // add more variants as needed to support one-time diagnostics
} }
/// Diagnostic message ID—used by `Session.one_time_diagnostics` to avoid /// Diagnostic message ID—used by `Session.one_time_diagnostics` to avoid
@ -184,7 +183,7 @@ enum DiagnosticBuilderMethod {
pub enum DiagnosticMessageId { pub enum DiagnosticMessageId {
ErrorId(u16), // EXXXX error code as integer ErrorId(u16), // EXXXX error code as integer
LintId(lint::LintId), LintId(lint::LintId),
StabilityId(u32) // issue number StabilityId(u32), // issue number
} }
impl From<&'static lint::Lint> for DiagnosticMessageId { impl From<&'static lint::Lint> for DiagnosticMessageId {
@ -201,33 +200,37 @@ impl Session {
} }
} }
pub fn struct_span_warn<'a, S: Into<MultiSpan>>(&'a self, pub fn struct_span_warn<'a, S: Into<MultiSpan>>(
sp: S, &'a self,
msg: &str) sp: S,
-> DiagnosticBuilder<'a> { msg: &str,
) -> DiagnosticBuilder<'a> {
self.diagnostic().struct_span_warn(sp, msg) self.diagnostic().struct_span_warn(sp, msg)
} }
pub fn struct_span_warn_with_code<'a, S: Into<MultiSpan>>(&'a self, pub fn struct_span_warn_with_code<'a, S: Into<MultiSpan>>(
sp: S, &'a self,
msg: &str, sp: S,
code: DiagnosticId) msg: &str,
-> DiagnosticBuilder<'a> { code: DiagnosticId,
) -> DiagnosticBuilder<'a> {
self.diagnostic().struct_span_warn_with_code(sp, msg, code) self.diagnostic().struct_span_warn_with_code(sp, msg, code)
} }
pub fn struct_warn<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> { pub fn struct_warn<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
self.diagnostic().struct_warn(msg) self.diagnostic().struct_warn(msg)
} }
pub fn struct_span_err<'a, S: Into<MultiSpan>>(&'a self, pub fn struct_span_err<'a, S: Into<MultiSpan>>(
sp: S, &'a self,
msg: &str) sp: S,
-> DiagnosticBuilder<'a> { msg: &str,
) -> DiagnosticBuilder<'a> {
self.diagnostic().struct_span_err(sp, msg) self.diagnostic().struct_span_err(sp, msg)
} }
pub fn struct_span_err_with_code<'a, S: Into<MultiSpan>>(&'a self, pub fn struct_span_err_with_code<'a, S: Into<MultiSpan>>(
sp: S, &'a self,
msg: &str, sp: S,
code: DiagnosticId) msg: &str,
-> DiagnosticBuilder<'a> { code: DiagnosticId,
) -> DiagnosticBuilder<'a> {
self.diagnostic().struct_span_err_with_code(sp, msg, code) self.diagnostic().struct_span_err_with_code(sp, msg, code)
} }
// FIXME: This method should be removed (every error should have an associated error code). // FIXME: This method should be removed (every error should have an associated error code).
@ -241,20 +244,22 @@ impl Session {
) -> DiagnosticBuilder<'a> { ) -> DiagnosticBuilder<'a> {
self.diagnostic().struct_err_with_code(msg, code) self.diagnostic().struct_err_with_code(msg, code)
} }
pub fn struct_span_fatal<'a, S: Into<MultiSpan>>(&'a self, pub fn struct_span_fatal<'a, S: Into<MultiSpan>>(
sp: S, &'a self,
msg: &str) sp: S,
-> DiagnosticBuilder<'a> { msg: &str,
) -> DiagnosticBuilder<'a> {
self.diagnostic().struct_span_fatal(sp, msg) self.diagnostic().struct_span_fatal(sp, msg)
} }
pub fn struct_span_fatal_with_code<'a, S: Into<MultiSpan>>(&'a self, pub fn struct_span_fatal_with_code<'a, S: Into<MultiSpan>>(
sp: S, &'a self,
msg: &str, sp: S,
code: DiagnosticId) msg: &str,
-> DiagnosticBuilder<'a> { code: DiagnosticId,
) -> DiagnosticBuilder<'a> {
self.diagnostic().struct_span_fatal_with_code(sp, msg, code) self.diagnostic().struct_span_fatal_with_code(sp, msg, code)
} }
pub fn struct_fatal<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> { pub fn struct_fatal<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
self.diagnostic().struct_fatal(msg) self.diagnostic().struct_fatal(msg)
} }
@ -267,7 +272,9 @@ impl Session {
msg: &str, msg: &str,
code: DiagnosticId, code: DiagnosticId,
) -> ! { ) -> ! {
self.diagnostic().span_fatal_with_code(sp, msg, code).raise() self.diagnostic()
.span_fatal_with_code(sp, msg, code)
.raise()
} }
pub fn fatal(&self, msg: &str) -> ! { pub fn fatal(&self, msg: &str) -> ! {
self.diagnostic().fatal(msg).raise() self.diagnostic().fatal(msg).raise()
@ -301,7 +308,8 @@ impl Session {
compile_result_from_err_count(self.err_count()) compile_result_from_err_count(self.err_count())
} }
pub fn track_errors<F, T>(&self, f: F) -> Result<T, ErrorReported> pub fn track_errors<F, T>(&self, f: F) -> Result<T, ErrorReported>
where F: FnOnce() -> T where
F: FnOnce() -> T,
{ {
let old_count = self.err_count(); let old_count = self.err_count();
let result = f(); let result = f();
@ -344,24 +352,31 @@ impl Session {
self.diagnostic().unimpl(msg) self.diagnostic().unimpl(msg)
} }
pub fn buffer_lint<S: Into<MultiSpan>>(&self, pub fn buffer_lint<S: Into<MultiSpan>>(
lint: &'static lint::Lint, &self,
id: ast::NodeId, lint: &'static lint::Lint,
sp: S, id: ast::NodeId,
msg: &str) { sp: S,
msg: &str,
) {
match *self.buffered_lints.borrow_mut() { match *self.buffered_lints.borrow_mut() {
Some(ref mut buffer) => buffer.add_lint(lint, id, sp.into(), Some(ref mut buffer) => {
msg, BuiltinLintDiagnostics::Normal), buffer.add_lint(lint, id, sp.into(), msg, BuiltinLintDiagnostics::Normal)
}
None => bug!("can't buffer lints after HIR lowering"), None => bug!("can't buffer lints after HIR lowering"),
} }
} }
pub fn buffer_lint_with_diagnostic<S: Into<MultiSpan>>(&self, pub fn buffer_lint_with_diagnostic<S: Into<MultiSpan>>(
lint: &'static lint::Lint, id: ast::NodeId, sp: S, &self,
msg: &str, diagnostic: BuiltinLintDiagnostics) { lint: &'static lint::Lint,
id: ast::NodeId,
sp: S,
msg: &str,
diagnostic: BuiltinLintDiagnostics,
) {
match *self.buffered_lints.borrow_mut() { match *self.buffered_lints.borrow_mut() {
Some(ref mut buffer) => buffer.add_lint(lint, id, sp.into(), Some(ref mut buffer) => buffer.add_lint(lint, id, sp.into(), msg, diagnostic),
msg, diagnostic),
None => bug!("can't buffer lints after HIR lowering"), None => bug!("can't buffer lints after HIR lowering"),
} }
} }
@ -373,7 +388,7 @@ impl Session {
Some(next) => { Some(next) => {
self.next_node_id.set(ast::NodeId::new(next)); self.next_node_id.set(ast::NodeId::new(next));
} }
None => bug!("Input too large, ran out of node ids!") None => bug!("Input too large, ran out of node ids!"),
} }
id id
@ -387,24 +402,27 @@ impl Session {
/// Analogous to calling methods on the given `DiagnosticBuilder`, but /// Analogous to calling methods on the given `DiagnosticBuilder`, but
/// deduplicates on lint ID, span (if any), and message for this `Session` /// deduplicates on lint ID, span (if any), and message for this `Session`
fn diag_once<'a, 'b>(&'a self, fn diag_once<'a, 'b>(
diag_builder: &'b mut DiagnosticBuilder<'a>, &'a self,
method: DiagnosticBuilderMethod, diag_builder: &'b mut DiagnosticBuilder<'a>,
msg_id: DiagnosticMessageId, method: DiagnosticBuilderMethod,
message: &str, msg_id: DiagnosticMessageId,
span_maybe: Option<Span>) { message: &str,
span_maybe: Option<Span>,
) {
let id_span_message = (msg_id, span_maybe, message.to_owned()); let id_span_message = (msg_id, span_maybe, message.to_owned());
let fresh = self.one_time_diagnostics.borrow_mut().insert(id_span_message); let fresh = self.one_time_diagnostics
.borrow_mut()
.insert(id_span_message);
if fresh { if fresh {
match method { match method {
DiagnosticBuilderMethod::Note => { DiagnosticBuilderMethod::Note => {
diag_builder.note(message); diag_builder.note(message);
}, }
DiagnosticBuilderMethod::SpanNote => { DiagnosticBuilderMethod::SpanNote => {
let span = span_maybe.expect("span_note needs a span"); let span = span_maybe.expect("span_note needs a span");
diag_builder.span_note(span, message); diag_builder.span_note(span, message);
}, }
DiagnosticBuilderMethod::SpanSuggestion(suggestion) => { DiagnosticBuilderMethod::SpanSuggestion(suggestion) => {
let span = span_maybe.expect("span_suggestion needs a span"); let span = span_maybe.expect("span_suggestion needs a span");
diag_builder.span_suggestion(span, message, suggestion); diag_builder.span_suggestion(span, message, suggestion);
@ -413,37 +431,66 @@ impl Session {
} }
} }
pub fn diag_span_note_once<'a, 'b>(&'a self, pub fn diag_span_note_once<'a, 'b>(
diag_builder: &'b mut DiagnosticBuilder<'a>, &'a self,
msg_id: DiagnosticMessageId, span: Span, message: &str) { diag_builder: &'b mut DiagnosticBuilder<'a>,
self.diag_once(diag_builder, DiagnosticBuilderMethod::SpanNote, msg_id: DiagnosticMessageId,
msg_id, message, Some(span)); span: Span,
message: &str,
) {
self.diag_once(
diag_builder,
DiagnosticBuilderMethod::SpanNote,
msg_id,
message,
Some(span),
);
} }
pub fn diag_note_once<'a, 'b>(&'a self, pub fn diag_note_once<'a, 'b>(
diag_builder: &'b mut DiagnosticBuilder<'a>, &'a self,
msg_id: DiagnosticMessageId, message: &str) { diag_builder: &'b mut DiagnosticBuilder<'a>,
self.diag_once(diag_builder, DiagnosticBuilderMethod::Note, msg_id, message, None); msg_id: DiagnosticMessageId,
message: &str,
) {
self.diag_once(
diag_builder,
DiagnosticBuilderMethod::Note,
msg_id,
message,
None,
);
} }
pub fn diag_span_suggestion_once<'a, 'b>(&'a self, pub fn diag_span_suggestion_once<'a, 'b>(
diag_builder: &'b mut DiagnosticBuilder<'a>, &'a self,
msg_id: DiagnosticMessageId, diag_builder: &'b mut DiagnosticBuilder<'a>,
span: Span, msg_id: DiagnosticMessageId,
message: &str, span: Span,
suggestion: String) { message: &str,
self.diag_once(diag_builder, DiagnosticBuilderMethod::SpanSuggestion(suggestion), suggestion: String,
msg_id, message, Some(span)); ) {
self.diag_once(
diag_builder,
DiagnosticBuilderMethod::SpanSuggestion(suggestion),
msg_id,
message,
Some(span),
);
} }
pub fn codemap<'a>(&'a self) -> &'a codemap::CodeMap { pub fn codemap<'a>(&'a self) -> &'a codemap::CodeMap {
self.parse_sess.codemap() self.parse_sess.codemap()
} }
pub fn verbose(&self) -> bool { self.opts.debugging_opts.verbose } pub fn verbose(&self) -> bool {
pub fn time_passes(&self) -> bool { self.opts.debugging_opts.time_passes } self.opts.debugging_opts.verbose
}
pub fn time_passes(&self) -> bool {
self.opts.debugging_opts.time_passes
}
pub fn profile_queries(&self) -> bool { pub fn profile_queries(&self) -> bool {
self.opts.debugging_opts.profile_queries || self.opts.debugging_opts.profile_queries
self.opts.debugging_opts.profile_queries_and_keys || self.opts.debugging_opts.profile_queries_and_keys
} }
pub fn profile_queries_and_keys(&self) -> bool { pub fn profile_queries_and_keys(&self) -> bool {
self.opts.debugging_opts.profile_queries_and_keys self.opts.debugging_opts.profile_queries_and_keys
@ -454,11 +501,21 @@ impl Session {
pub fn time_llvm_passes(&self) -> bool { pub fn time_llvm_passes(&self) -> bool {
self.opts.debugging_opts.time_llvm_passes self.opts.debugging_opts.time_llvm_passes
} }
pub fn trans_stats(&self) -> bool { self.opts.debugging_opts.trans_stats } pub fn trans_stats(&self) -> bool {
pub fn meta_stats(&self) -> bool { self.opts.debugging_opts.meta_stats } self.opts.debugging_opts.trans_stats
pub fn asm_comments(&self) -> bool { self.opts.debugging_opts.asm_comments } }
pub fn no_verify(&self) -> bool { self.opts.debugging_opts.no_verify } pub fn meta_stats(&self) -> bool {
pub fn borrowck_stats(&self) -> bool { self.opts.debugging_opts.borrowck_stats } self.opts.debugging_opts.meta_stats
}
pub fn asm_comments(&self) -> bool {
self.opts.debugging_opts.asm_comments
}
pub fn no_verify(&self) -> bool {
self.opts.debugging_opts.no_verify
}
pub fn borrowck_stats(&self) -> bool {
self.opts.debugging_opts.borrowck_stats
}
pub fn print_llvm_passes(&self) -> bool { pub fn print_llvm_passes(&self) -> bool {
self.opts.debugging_opts.print_llvm_passes self.opts.debugging_opts.print_llvm_passes
} }
@ -481,18 +538,11 @@ impl Session {
*(self.features.borrow_mut()) = Some(features); *(self.features.borrow_mut()) = Some(features);
} }
/// If true, we should gather causal information during NLL
/// checking. This will eventually be the normal thing, but right
/// now it is too unoptimized.
pub fn nll_dump_cause(&self) -> bool {
self.opts.debugging_opts.nll_dump_cause
}
/// Calculates the flavor of LTO to use for this compilation. /// Calculates the flavor of LTO to use for this compilation.
pub fn lto(&self) -> config::Lto { pub fn lto(&self) -> config::Lto {
// If our target has codegen requirements ignore the command line // If our target has codegen requirements ignore the command line
if self.target.target.options.requires_lto { if self.target.target.options.requires_lto {
return config::Lto::Fat return config::Lto::Fat;
} }
// If the user specified something, return that. If they only said `-C // If the user specified something, return that. If they only said `-C
@ -500,9 +550,7 @@ impl Session {
// then ensure we can't use a ThinLTO. // then ensure we can't use a ThinLTO.
match self.opts.cg.lto { match self.opts.cg.lto {
config::Lto::No => {} config::Lto::No => {}
config::Lto::Yes if self.opts.cli_forced_thinlto_off => { config::Lto::Yes if self.opts.cli_forced_thinlto_off => return config::Lto::Fat,
return config::Lto::Fat
}
other => return other, other => return other,
} }
@ -515,28 +563,28 @@ impl Session {
// If processing command line options determined that we're incompatible // If processing command line options determined that we're incompatible
// with ThinLTO (e.g. `-C lto --emit llvm-ir`) then return that option. // with ThinLTO (e.g. `-C lto --emit llvm-ir`) then return that option.
if self.opts.cli_forced_thinlto_off { if self.opts.cli_forced_thinlto_off {
return config::Lto::No return config::Lto::No;
} }
// If `-Z thinlto` specified process that, but note that this is mostly // If `-Z thinlto` specified process that, but note that this is mostly
// a deprecated option now that `-C lto=thin` exists. // a deprecated option now that `-C lto=thin` exists.
if let Some(enabled) = self.opts.debugging_opts.thinlto { if let Some(enabled) = self.opts.debugging_opts.thinlto {
if enabled { if enabled {
return config::Lto::ThinLocal return config::Lto::ThinLocal;
} else { } else {
return config::Lto::No return config::Lto::No;
} }
} }
// If there's only one codegen unit and LTO isn't enabled then there's // If there's only one codegen unit and LTO isn't enabled then there's
// no need for ThinLTO so just return false. // no need for ThinLTO so just return false.
if self.codegen_units() == 1 { if self.codegen_units() == 1 {
return config::Lto::No return config::Lto::No;
} }
// Right now ThinLTO isn't compatible with incremental compilation. // Right now ThinLTO isn't compatible with incremental compilation.
if self.opts.incremental.is_some() { if self.opts.incremental.is_some() {
return config::Lto::No return config::Lto::No;
} }
// Now we're in "defaults" territory. By default we enable ThinLTO for // Now we're in "defaults" territory. By default we enable ThinLTO for
@ -550,15 +598,23 @@ impl Session {
/// Returns the panic strategy for this compile session. If the user explicitly selected one /// Returns the panic strategy for this compile session. If the user explicitly selected one
/// using '-C panic', use that, otherwise use the panic strategy defined by the target. /// using '-C panic', use that, otherwise use the panic strategy defined by the target.
pub fn panic_strategy(&self) -> PanicStrategy { pub fn panic_strategy(&self) -> PanicStrategy {
self.opts.cg.panic.unwrap_or(self.target.target.options.panic_strategy) self.opts
.cg
.panic
.unwrap_or(self.target.target.options.panic_strategy)
} }
pub fn linker_flavor(&self) -> LinkerFlavor { pub fn linker_flavor(&self) -> LinkerFlavor {
self.opts.debugging_opts.linker_flavor.unwrap_or(self.target.target.linker_flavor) self.opts
.debugging_opts
.linker_flavor
.unwrap_or(self.target.target.linker_flavor)
} }
pub fn fewer_names(&self) -> bool { pub fn fewer_names(&self) -> bool {
let more_names = self.opts.output_types.contains_key(&OutputType::LlvmAssembly) || let more_names = self.opts
self.opts.output_types.contains_key(&OutputType::Bitcode); .output_types
.contains_key(&OutputType::LlvmAssembly)
|| self.opts.output_types.contains_key(&OutputType::Bitcode);
self.opts.debugging_opts.fewer_names || !more_names self.opts.debugging_opts.fewer_names || !more_names
} }
@ -572,7 +628,9 @@ impl Session {
self.opts.debugging_opts.enable_nonzeroing_move_hints self.opts.debugging_opts.enable_nonzeroing_move_hints
} }
pub fn overflow_checks(&self) -> bool { pub fn overflow_checks(&self) -> bool {
self.opts.cg.overflow_checks self.opts
.cg
.overflow_checks
.or(self.opts.debugging_opts.force_overflow_checks) .or(self.opts.debugging_opts.force_overflow_checks)
.unwrap_or(self.opts.debug_assertions) .unwrap_or(self.opts.debug_assertions)
} }
@ -603,50 +661,59 @@ impl Session {
} }
pub fn must_not_eliminate_frame_pointers(&self) -> bool { pub fn must_not_eliminate_frame_pointers(&self) -> bool {
self.opts.debuginfo != DebugInfoLevel::NoDebugInfo || self.opts.debuginfo != DebugInfoLevel::NoDebugInfo
!self.target.target.options.eliminate_frame_pointer || !self.target.target.options.eliminate_frame_pointer
} }
/// Returns the symbol name for the registrar function, /// Returns the symbol name for the registrar function,
/// given the crate Svh and the function DefIndex. /// given the crate Svh and the function DefIndex.
pub fn generate_plugin_registrar_symbol(&self, pub fn generate_plugin_registrar_symbol(&self, disambiguator: CrateDisambiguator) -> String {
disambiguator: CrateDisambiguator) format!(
-> String { "__rustc_plugin_registrar_{}__",
format!("__rustc_plugin_registrar_{}__", disambiguator.to_fingerprint().to_hex()) disambiguator.to_fingerprint().to_hex()
)
} }
pub fn generate_derive_registrar_symbol(&self, pub fn generate_derive_registrar_symbol(&self, disambiguator: CrateDisambiguator) -> String {
disambiguator: CrateDisambiguator) format!(
-> String { "__rustc_derive_registrar_{}__",
format!("__rustc_derive_registrar_{}__", disambiguator.to_fingerprint().to_hex()) disambiguator.to_fingerprint().to_hex()
)
} }
pub fn sysroot<'a>(&'a self) -> &'a Path { pub fn sysroot<'a>(&'a self) -> &'a Path {
match self.opts.maybe_sysroot { match self.opts.maybe_sysroot {
Some (ref sysroot) => sysroot, Some(ref sysroot) => sysroot,
None => self.default_sysroot.as_ref() None => self.default_sysroot
.expect("missing sysroot and default_sysroot in Session") .as_ref()
.expect("missing sysroot and default_sysroot in Session"),
} }
} }
pub fn target_filesearch(&self, kind: PathKind) -> filesearch::FileSearch { pub fn target_filesearch(&self, kind: PathKind) -> filesearch::FileSearch {
filesearch::FileSearch::new(self.sysroot(), filesearch::FileSearch::new(
&self.opts.target_triple, self.sysroot(),
&self.opts.search_paths, &self.opts.target_triple,
kind) &self.opts.search_paths,
kind,
)
} }
pub fn host_filesearch(&self, kind: PathKind) -> filesearch::FileSearch { pub fn host_filesearch(&self, kind: PathKind) -> filesearch::FileSearch {
filesearch::FileSearch::new( filesearch::FileSearch::new(
self.sysroot(), self.sysroot(),
config::host_triple(), config::host_triple(),
&self.opts.search_paths, &self.opts.search_paths,
kind) kind,
)
} }
pub fn set_incr_session_load_dep_graph(&self, load: bool) { pub fn set_incr_session_load_dep_graph(&self, load: bool) {
let mut incr_comp_session = self.incr_comp_session.borrow_mut(); let mut incr_comp_session = self.incr_comp_session.borrow_mut();
match *incr_comp_session { match *incr_comp_session {
IncrCompSession::Active { ref mut load_dep_graph, .. } => { IncrCompSession::Active {
ref mut load_dep_graph,
..
} => {
*load_dep_graph = load; *load_dep_graph = load;
} }
_ => {} _ => {}
@ -661,14 +728,20 @@ impl Session {
} }
} }
pub fn init_incr_comp_session(&self, pub fn init_incr_comp_session(
session_dir: PathBuf, &self,
lock_file: flock::Lock, session_dir: PathBuf,
load_dep_graph: bool) { lock_file: flock::Lock,
load_dep_graph: bool,
) {
let mut incr_comp_session = self.incr_comp_session.borrow_mut(); let mut incr_comp_session = self.incr_comp_session.borrow_mut();
if let IncrCompSession::NotInitialized = *incr_comp_session { } else { if let IncrCompSession::NotInitialized = *incr_comp_session {
bug!("Trying to initialize IncrCompSession `{:?}`", *incr_comp_session) } else {
bug!(
"Trying to initialize IncrCompSession `{:?}`",
*incr_comp_session
)
} }
*incr_comp_session = IncrCompSession::Active { *incr_comp_session = IncrCompSession::Active {
@ -681,8 +754,12 @@ impl Session {
pub fn finalize_incr_comp_session(&self, new_directory_path: PathBuf) { pub fn finalize_incr_comp_session(&self, new_directory_path: PathBuf) {
let mut incr_comp_session = self.incr_comp_session.borrow_mut(); let mut incr_comp_session = self.incr_comp_session.borrow_mut();
if let IncrCompSession::Active { .. } = *incr_comp_session { } else { if let IncrCompSession::Active { .. } = *incr_comp_session {
bug!("Trying to finalize IncrCompSession `{:?}`", *incr_comp_session) } else {
bug!(
"Trying to finalize IncrCompSession `{:?}`",
*incr_comp_session
)
} }
// Note: This will also drop the lock file, thus unlocking the directory // Note: This will also drop the lock file, thus unlocking the directory
@ -695,35 +772,42 @@ impl Session {
let mut incr_comp_session = self.incr_comp_session.borrow_mut(); let mut incr_comp_session = self.incr_comp_session.borrow_mut();
let session_directory = match *incr_comp_session { let session_directory = match *incr_comp_session {
IncrCompSession::Active { ref session_directory, .. } => { IncrCompSession::Active {
session_directory.clone() ref session_directory,
} ..
} => session_directory.clone(),
IncrCompSession::InvalidBecauseOfErrors { .. } => return, IncrCompSession::InvalidBecauseOfErrors { .. } => return,
_ => bug!("Trying to invalidate IncrCompSession `{:?}`", _ => bug!(
*incr_comp_session), "Trying to invalidate IncrCompSession `{:?}`",
*incr_comp_session
),
}; };
// Note: This will also drop the lock file, thus unlocking the directory // Note: This will also drop the lock file, thus unlocking the directory
*incr_comp_session = IncrCompSession::InvalidBecauseOfErrors { *incr_comp_session = IncrCompSession::InvalidBecauseOfErrors { session_directory };
session_directory,
};
} }
pub fn incr_comp_session_dir(&self) -> cell::Ref<PathBuf> { pub fn incr_comp_session_dir(&self) -> cell::Ref<PathBuf> {
let incr_comp_session = self.incr_comp_session.borrow(); let incr_comp_session = self.incr_comp_session.borrow();
cell::Ref::map(incr_comp_session, |incr_comp_session| { cell::Ref::map(
match *incr_comp_session { incr_comp_session,
IncrCompSession::NotInitialized => { |incr_comp_session| match *incr_comp_session {
bug!("Trying to get session directory from IncrCompSession `{:?}`", IncrCompSession::NotInitialized => bug!(
*incr_comp_session) "Trying to get session directory from IncrCompSession `{:?}`",
*incr_comp_session
),
IncrCompSession::Active {
ref session_directory,
..
} }
IncrCompSession::Active { ref session_directory, .. } | | IncrCompSession::Finalized {
IncrCompSession::Finalized { ref session_directory } | ref session_directory,
IncrCompSession::InvalidBecauseOfErrors { ref session_directory } => {
session_directory
} }
} | IncrCompSession::InvalidBecauseOfErrors {
}) ref session_directory,
} => session_directory,
},
)
} }
pub fn incr_comp_session_dir_opt(&self) -> Option<cell::Ref<PathBuf>> { pub fn incr_comp_session_dir_opt(&self) -> Option<cell::Ref<PathBuf>> {
@ -735,25 +819,39 @@ impl Session {
} }
pub fn print_perf_stats(&self) { pub fn print_perf_stats(&self) {
println!("Total time spent computing SVHs: {}", println!(
duration_to_secs_str(self.perf_stats.svh_time.get())); "Total time spent computing SVHs: {}",
println!("Total time spent computing incr. comp. hashes: {}", duration_to_secs_str(self.perf_stats.svh_time.get())
duration_to_secs_str(self.perf_stats.incr_comp_hashes_time.get())); );
println!("Total number of incr. comp. hashes computed: {}", println!(
self.perf_stats.incr_comp_hashes_count.get()); "Total time spent computing incr. comp. hashes: {}",
println!("Total number of bytes hashed for incr. comp.: {}", duration_to_secs_str(self.perf_stats.incr_comp_hashes_time.get())
self.perf_stats.incr_comp_bytes_hashed.get()); );
println!(
"Total number of incr. comp. hashes computed: {}",
self.perf_stats.incr_comp_hashes_count.get()
);
println!(
"Total number of bytes hashed for incr. comp.: {}",
self.perf_stats.incr_comp_bytes_hashed.get()
);
if self.perf_stats.incr_comp_hashes_count.get() != 0 { if self.perf_stats.incr_comp_hashes_count.get() != 0 {
println!("Average bytes hashed per incr. comp. HIR node: {}", println!(
self.perf_stats.incr_comp_bytes_hashed.get() / "Average bytes hashed per incr. comp. HIR node: {}",
self.perf_stats.incr_comp_hashes_count.get()); self.perf_stats.incr_comp_bytes_hashed.get()
/ self.perf_stats.incr_comp_hashes_count.get()
);
} else { } else {
println!("Average bytes hashed per incr. comp. HIR node: N/A"); println!("Average bytes hashed per incr. comp. HIR node: N/A");
} }
println!("Total time spent computing symbol hashes: {}", println!(
duration_to_secs_str(self.perf_stats.symbol_hash_time.get())); "Total time spent computing symbol hashes: {}",
println!("Total time spent decoding DefPath tables: {}", duration_to_secs_str(self.perf_stats.symbol_hash_time.get())
duration_to_secs_str(self.perf_stats.decode_def_path_tables_time.get())); );
println!(
"Total time spent decoding DefPath tables: {}",
duration_to_secs_str(self.perf_stats.decode_def_path_tables_time.get())
);
} }
/// We want to know if we're allowed to do an optimization for crate foo from -z fuel=foo=n. /// We want to know if we're allowed to do an optimization for crate foo from -z fuel=foo=n.
@ -768,15 +866,15 @@ impl Session {
println!("optimization-fuel-exhausted: {}", msg()); println!("optimization-fuel-exhausted: {}", msg());
self.out_of_fuel.set(true); self.out_of_fuel.set(true);
} else if fuel > 0 { } else if fuel > 0 {
self.optimization_fuel_limit.set(fuel-1); self.optimization_fuel_limit.set(fuel - 1);
} }
} }
_ => {} _ => {}
} }
match self.print_fuel_crate { match self.print_fuel_crate {
Some(ref c) if c == crate_name=> { Some(ref c) if c == crate_name => {
self.print_fuel.set(self.print_fuel.get()+1); self.print_fuel.set(self.print_fuel.get() + 1);
}, }
_ => {} _ => {}
} }
ret ret
@ -792,10 +890,10 @@ impl Session {
/// compilation /// compilation
pub fn codegen_units(&self) -> usize { pub fn codegen_units(&self) -> usize {
if let Some(n) = self.opts.cli_forced_codegen_units { if let Some(n) = self.opts.cli_forced_codegen_units {
return n return n;
} }
if let Some(n) = self.target.target.options.default_codegen_units { if let Some(n) = self.target.target.options.default_codegen_units {
return n as usize return n as usize;
} }
// Why is 16 codegen units the default all the time? // Why is 16 codegen units the default all the time?
@ -865,29 +963,34 @@ impl Session {
} }
} }
pub fn build_session(sopts: config::Options, pub fn build_session(
local_crate_source_file: Option<PathBuf>, sopts: config::Options,
registry: errors::registry::Registry) local_crate_source_file: Option<PathBuf>,
-> Session { registry: errors::registry::Registry,
) -> Session {
let file_path_mapping = sopts.file_path_mapping(); let file_path_mapping = sopts.file_path_mapping();
build_session_with_codemap(sopts, build_session_with_codemap(
local_crate_source_file, sopts,
registry, local_crate_source_file,
Lrc::new(codemap::CodeMap::new(file_path_mapping)), registry,
None) Lrc::new(codemap::CodeMap::new(file_path_mapping)),
None,
)
} }
pub fn build_session_with_codemap(sopts: config::Options, pub fn build_session_with_codemap(
local_crate_source_file: Option<PathBuf>, sopts: config::Options,
registry: errors::registry::Registry, local_crate_source_file: Option<PathBuf>,
codemap: Lrc<codemap::CodeMap>, registry: errors::registry::Registry,
emitter_dest: Option<Box<dyn Write + Send>>) codemap: Lrc<codemap::CodeMap>,
-> Session { emitter_dest: Option<Box<dyn Write + Send>>,
) -> Session {
// FIXME: This is not general enough to make the warning lint completely override // FIXME: This is not general enough to make the warning lint completely override
// normal diagnostic warnings, since the warning lint can also be denied and changed // normal diagnostic warnings, since the warning lint can also be denied and changed
// later via the source code. // later via the source code.
let warnings_allow = sopts.lint_opts let warnings_allow = sopts
.lint_opts
.iter() .iter()
.filter(|&&(ref key, _)| *key == "warnings") .filter(|&&(ref key, _)| *key == "warnings")
.map(|&(_, ref level)| *level == lint::Allow) .map(|&(_, ref level)| *level == lint::Allow)
@ -901,60 +1004,70 @@ pub fn build_session_with_codemap(sopts: config::Options,
let external_macro_backtrace = sopts.debugging_opts.external_macro_backtrace; let external_macro_backtrace = sopts.debugging_opts.external_macro_backtrace;
let emitter: Box<dyn Emitter> = match (sopts.error_format, emitter_dest) { let emitter: Box<dyn Emitter> =
(config::ErrorOutputType::HumanReadable(color_config), None) => { match (sopts.error_format, emitter_dest) {
Box::new(EmitterWriter::stderr(color_config, Some(codemap.clone()), (config::ErrorOutputType::HumanReadable(color_config), None) => Box::new(
false, sopts.debugging_opts.teach) EmitterWriter::stderr(
.ui_testing(sopts.debugging_opts.ui_testing)) color_config,
} Some(codemap.clone()),
(config::ErrorOutputType::HumanReadable(_), Some(dst)) => { false,
Box::new(EmitterWriter::new(dst, Some(codemap.clone()), sopts.debugging_opts.teach,
false, false) ).ui_testing(sopts.debugging_opts.ui_testing),
.ui_testing(sopts.debugging_opts.ui_testing)) ),
} (config::ErrorOutputType::HumanReadable(_), Some(dst)) => Box::new(
(config::ErrorOutputType::Json(pretty), None) => { EmitterWriter::new(dst, Some(codemap.clone()), false, false)
Box::new(JsonEmitter::stderr(Some(registry), codemap.clone(), .ui_testing(sopts.debugging_opts.ui_testing),
pretty, sopts.debugging_opts.approximate_suggestions) ),
.ui_testing(sopts.debugging_opts.ui_testing)) (config::ErrorOutputType::Json(pretty), None) => Box::new(
} JsonEmitter::stderr(
(config::ErrorOutputType::Json(pretty), Some(dst)) => { Some(registry),
Box::new(JsonEmitter::new(dst, Some(registry), codemap.clone(), codemap.clone(),
pretty, sopts.debugging_opts.approximate_suggestions) pretty,
.ui_testing(sopts.debugging_opts.ui_testing)) sopts.debugging_opts.approximate_suggestions,
} ).ui_testing(sopts.debugging_opts.ui_testing),
(config::ErrorOutputType::Short(color_config), None) => { ),
Box::new(EmitterWriter::stderr(color_config, Some(codemap.clone()), true, false)) (config::ErrorOutputType::Json(pretty), Some(dst)) => Box::new(
} JsonEmitter::new(
(config::ErrorOutputType::Short(_), Some(dst)) => { dst,
Box::new(EmitterWriter::new(dst, Some(codemap.clone()), true, false)) Some(registry),
} codemap.clone(),
}; pretty,
sopts.debugging_opts.approximate_suggestions,
).ui_testing(sopts.debugging_opts.ui_testing),
),
(config::ErrorOutputType::Short(color_config), None) => Box::new(
EmitterWriter::stderr(color_config, Some(codemap.clone()), true, false),
),
(config::ErrorOutputType::Short(_), Some(dst)) => {
Box::new(EmitterWriter::new(dst, Some(codemap.clone()), true, false))
}
};
let diagnostic_handler = let diagnostic_handler = errors::Handler::with_emitter_and_flags(
errors::Handler::with_emitter_and_flags( emitter,
emitter, errors::HandlerFlags {
errors::HandlerFlags { can_emit_warnings,
can_emit_warnings, treat_err_as_bug,
treat_err_as_bug, external_macro_backtrace,
external_macro_backtrace, ..Default::default()
.. Default::default() },
}); );
build_session_(sopts, build_session_(sopts, local_crate_source_file, diagnostic_handler, codemap)
local_crate_source_file,
diagnostic_handler,
codemap)
} }
pub fn build_session_(sopts: config::Options, pub fn build_session_(
local_crate_source_file: Option<PathBuf>, sopts: config::Options,
span_diagnostic: errors::Handler, local_crate_source_file: Option<PathBuf>,
codemap: Lrc<codemap::CodeMap>) span_diagnostic: errors::Handler,
-> Session { codemap: Lrc<codemap::CodeMap>,
) -> Session {
let host = match Target::search(config::host_triple()) { let host = match Target::search(config::host_triple()) {
Ok(t) => t, Ok(t) => t,
Err(e) => { Err(e) => {
span_diagnostic.fatal(&format!("Error loading host specification: {}", e)).raise(); span_diagnostic
.fatal(&format!("Error loading host specification: {}", e))
.raise();
} }
}; };
let target_cfg = config::build_target_config(&sopts, &span_diagnostic); let target_cfg = config::build_target_config(&sopts, &span_diagnostic);
@ -962,26 +1075,25 @@ pub fn build_session_(sopts: config::Options,
let p_s = parse::ParseSess::with_span_handler(span_diagnostic, codemap); let p_s = parse::ParseSess::with_span_handler(span_diagnostic, codemap);
let default_sysroot = match sopts.maybe_sysroot { let default_sysroot = match sopts.maybe_sysroot {
Some(_) => None, Some(_) => None,
None => Some(filesearch::get_or_default_sysroot()) None => Some(filesearch::get_or_default_sysroot()),
}; };
let file_path_mapping = sopts.file_path_mapping(); let file_path_mapping = sopts.file_path_mapping();
let local_crate_source_file = local_crate_source_file.map(|path| { let local_crate_source_file =
file_path_mapping.map_prefix(path).0 local_crate_source_file.map(|path| file_path_mapping.map_prefix(path).0);
});
let optimization_fuel_crate = sopts.debugging_opts.fuel.as_ref().map(|i| i.0.clone()); let optimization_fuel_crate = sopts.debugging_opts.fuel.as_ref().map(|i| i.0.clone());
let optimization_fuel_limit = Cell::new(sopts.debugging_opts.fuel.as_ref() let optimization_fuel_limit =
.map(|i| i.1).unwrap_or(0)); Cell::new(sopts.debugging_opts.fuel.as_ref().map(|i| i.1).unwrap_or(0));
let print_fuel_crate = sopts.debugging_opts.print_fuel.clone(); let print_fuel_crate = sopts.debugging_opts.print_fuel.clone();
let print_fuel = Cell::new(0); let print_fuel = Cell::new(0);
let working_dir = match env::current_dir() { let working_dir = match env::current_dir() {
Ok(dir) => dir, Ok(dir) => dir,
Err(e) => { Err(e) => p_s.span_diagnostic
p_s.span_diagnostic.fatal(&format!("Current directory is invalid: {}", e)).raise() .fatal(&format!("Current directory is invalid: {}", e))
} .raise(),
}; };
let working_dir = file_path_mapping.map_prefix(working_dir); let working_dir = file_path_mapping.map_prefix(working_dir);
@ -1090,15 +1202,11 @@ pub enum IncrCompSession {
}, },
/// This is the state after the session directory has been finalized. In this /// This is the state after the session directory has been finalized. In this
/// state, the contents of the directory must not be modified any more. /// state, the contents of the directory must not be modified any more.
Finalized { Finalized { session_directory: PathBuf },
session_directory: PathBuf,
},
/// This is an error state that is reached when some compilation error has /// This is an error state that is reached when some compilation error has
/// occurred. It indicates that the contents of the session directory must /// occurred. It indicates that the contents of the session directory must
/// not be used, since they might be invalid. /// not be used, since they might be invalid.
InvalidBecauseOfErrors { InvalidBecauseOfErrors { session_directory: PathBuf },
session_directory: PathBuf,
}
} }
pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! { pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! {
@ -1133,7 +1241,7 @@ pub fn early_warn(output: config::ErrorOutputType, msg: &str) {
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub enum CompileIncomplete { pub enum CompileIncomplete {
Stopped, Stopped,
Errored(ErrorReported) Errored(ErrorReported),
} }
impl From<ErrorReported> for CompileIncomplete { impl From<ErrorReported> for CompileIncomplete {
fn from(err: ErrorReported) -> CompileIncomplete { fn from(err: ErrorReported) -> CompileIncomplete {
@ -1160,23 +1268,27 @@ pub fn bug_fmt(file: &'static str, line: u32, args: fmt::Arguments) -> ! {
#[cold] #[cold]
#[inline(never)] #[inline(never)]
pub fn span_bug_fmt<S: Into<MultiSpan>>(file: &'static str, pub fn span_bug_fmt<S: Into<MultiSpan>>(
line: u32, file: &'static str,
span: S, line: u32,
args: fmt::Arguments) -> ! { span: S,
args: fmt::Arguments,
) -> ! {
opt_span_bug_fmt(file, line, Some(span), args); opt_span_bug_fmt(file, line, Some(span), args);
} }
fn opt_span_bug_fmt<S: Into<MultiSpan>>(file: &'static str, fn opt_span_bug_fmt<S: Into<MultiSpan>>(
line: u32, file: &'static str,
span: Option<S>, line: u32,
args: fmt::Arguments) -> ! { span: Option<S>,
args: fmt::Arguments,
) -> ! {
tls::with_opt(move |tcx| { tls::with_opt(move |tcx| {
let msg = format!("{}:{}: {}", file, line, args); let msg = format!("{}:{}: {}", file, line, args);
match (tcx, span) { match (tcx, span) {
(Some(tcx), Some(span)) => tcx.sess.diagnostic().span_bug(span, &msg), (Some(tcx), Some(span)) => tcx.sess.diagnostic().span_bug(span, &msg),
(Some(tcx), None) => tcx.sess.diagnostic().bug(&msg), (Some(tcx), None) => tcx.sess.diagnostic().bug(&msg),
(None, _) => panic!(msg) (None, _) => panic!(msg),
} }
}); });
unreachable!(); unreachable!();

View file

@ -124,6 +124,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
(place, span): (&Place<'tcx>, Span), (place, span): (&Place<'tcx>, Span),
borrow: &BorrowData<'tcx>, borrow: &BorrowData<'tcx>,
) { ) {
let tcx = self.tcx;
let value_msg = match self.describe_place(place) { let value_msg = match self.describe_place(place) {
Some(name) => format!("`{}`", name), Some(name) => format!("`{}`", name),
None => "value".to_owned(), None => "value".to_owned(),
@ -132,7 +133,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
Some(name) => format!("`{}`", name), Some(name) => format!("`{}`", name),
None => "value".to_owned(), None => "value".to_owned(),
}; };
let mut err = self.tcx.cannot_move_when_borrowed( let mut err = tcx.cannot_move_when_borrowed(
span, span,
&self.describe_place(place).unwrap_or("_".to_owned()), &self.describe_place(place).unwrap_or("_".to_owned()),
Origin::Mir, Origin::Mir,
@ -152,7 +153,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
(place, span): (&Place<'tcx>, Span), (place, span): (&Place<'tcx>, Span),
borrow: &BorrowData<'tcx>, borrow: &BorrowData<'tcx>,
) { ) {
let mut err = self.tcx.cannot_use_when_mutably_borrowed( let tcx = self.tcx;
let mut err = tcx.cannot_use_when_mutably_borrowed(
span, span,
&self.describe_place(place).unwrap_or("_".to_owned()), &self.describe_place(place).unwrap_or("_".to_owned()),
self.retrieve_borrow_span(borrow), self.retrieve_borrow_span(borrow),
@ -254,6 +256,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
.unwrap_or(issued_span); .unwrap_or(issued_span);
let desc_place = self.describe_place(place).unwrap_or("_".to_owned()); let desc_place = self.describe_place(place).unwrap_or("_".to_owned());
let tcx = self.tcx;
// FIXME: supply non-"" `opt_via` when appropriate // FIXME: supply non-"" `opt_via` when appropriate
let mut err = match ( let mut err = match (
@ -265,8 +268,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
"mutable", "mutable",
) { ) {
(BorrowKind::Shared, lft, _, BorrowKind::Mut { .. }, _, rgt) (BorrowKind::Shared, lft, _, BorrowKind::Mut { .. }, _, rgt)
| (BorrowKind::Mut { .. }, _, lft, BorrowKind::Shared, rgt, _) => self.tcx | (BorrowKind::Mut { .. }, _, lft, BorrowKind::Shared, rgt, _) => {
.cannot_reborrow_already_borrowed( tcx.cannot_reborrow_already_borrowed(
span, span,
&desc_place, &desc_place,
"", "",
@ -277,10 +280,11 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
"", "",
end_issued_loan_span, end_issued_loan_span,
Origin::Mir, Origin::Mir,
), )
}
(BorrowKind::Mut { .. }, _, _, BorrowKind::Mut { .. }, _, _) => self.tcx (BorrowKind::Mut { .. }, _, _, BorrowKind::Mut { .. }, _, _) => {
.cannot_mutably_borrow_multiply( tcx.cannot_mutably_borrow_multiply(
span, span,
&desc_place, &desc_place,
"", "",
@ -288,18 +292,20 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
"", "",
end_issued_loan_span, end_issued_loan_span,
Origin::Mir, Origin::Mir,
), )
}
(BorrowKind::Unique, _, _, BorrowKind::Unique, _, _) => self.tcx (BorrowKind::Unique, _, _, BorrowKind::Unique, _, _) => {
.cannot_uniquely_borrow_by_two_closures( tcx.cannot_uniquely_borrow_by_two_closures(
span, span,
&desc_place, &desc_place,
issued_span, issued_span,
end_issued_loan_span, end_issued_loan_span,
Origin::Mir, Origin::Mir,
), )
}
(BorrowKind::Unique, _, _, _, _, _) => self.tcx.cannot_uniquely_borrow_by_one_closure( (BorrowKind::Unique, _, _, _, _, _) => tcx.cannot_uniquely_borrow_by_one_closure(
span, span,
&desc_place, &desc_place,
"", "",
@ -310,8 +316,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
Origin::Mir, Origin::Mir,
), ),
(BorrowKind::Shared, lft, _, BorrowKind::Unique, _, _) => self.tcx (BorrowKind::Shared, lft, _, BorrowKind::Unique, _, _) => {
.cannot_reborrow_already_uniquely_borrowed( tcx.cannot_reborrow_already_uniquely_borrowed(
span, span,
&desc_place, &desc_place,
"", "",
@ -320,10 +326,11 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
"", "",
end_issued_loan_span, end_issued_loan_span,
Origin::Mir, Origin::Mir,
), )
}
(BorrowKind::Mut { .. }, _, lft, BorrowKind::Unique, _, _) => self.tcx (BorrowKind::Mut { .. }, _, lft, BorrowKind::Unique, _, _) => {
.cannot_reborrow_already_uniquely_borrowed( tcx.cannot_reborrow_already_uniquely_borrowed(
span, span,
&desc_place, &desc_place,
"", "",
@ -332,7 +339,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
"", "",
end_issued_loan_span, end_issued_loan_span,
Origin::Mir, Origin::Mir,
), )
}
(BorrowKind::Shared, _, _, BorrowKind::Shared, _, _) => unreachable!(), (BorrowKind::Shared, _, _, BorrowKind::Shared, _, _) => unreachable!(),
}; };
@ -466,11 +474,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
_proper_span: Span, _proper_span: Span,
end_span: Option<Span>, end_span: Option<Span>,
) { ) {
let mut err = self.tcx.path_does_not_live_long_enough( let tcx = self.tcx;
borrow_span, let mut err =
&format!("`{}`", name), tcx.path_does_not_live_long_enough(borrow_span, &format!("`{}`", name), Origin::Mir);
Origin::Mir,
);
err.span_label(borrow_span, "borrowed value does not live long enough"); err.span_label(borrow_span, "borrowed value does not live long enough");
err.span_label( err.span_label(
drop_span, drop_span,
@ -493,9 +499,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
proper_span: Span, proper_span: Span,
end_span: Option<Span>, end_span: Option<Span>,
) { ) {
let tcx = self.tcx;
let mut err = let mut err =
self.tcx tcx.path_does_not_live_long_enough(proper_span, "borrowed value", Origin::Mir);
.path_does_not_live_long_enough(proper_span, "borrowed value", Origin::Mir);
err.span_label(proper_span, "temporary value does not live long enough"); err.span_label(proper_span, "temporary value does not live long enough");
err.span_label( err.span_label(
drop_span, drop_span,
@ -527,16 +533,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
context, name, scope_tree, borrow, drop_span, borrow_span context, name, scope_tree, borrow, drop_span, borrow_span
); );
let mut err = self.tcx.path_does_not_live_long_enough( let tcx = self.tcx;
borrow_span, let mut err =
&format!("`{}`", name), tcx.path_does_not_live_long_enough(borrow_span, &format!("`{}`", name), Origin::Mir);
Origin::Mir,
);
err.span_label(borrow_span, "borrowed value does not live long enough"); err.span_label(borrow_span, "borrowed value does not live long enough");
err.span_label(drop_span, "borrowed value only lives until here"); err.span_label(drop_span, "borrowed value only lives until here");
if !self.tcx.nll() { if !tcx.nll() {
self.tcx.note_and_explain_region( tcx.note_and_explain_region(
scope_tree, scope_tree,
&mut err, &mut err,
"borrowed value must be valid for ", "borrowed value must be valid for ",
@ -566,14 +570,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
context, scope_tree, borrow, drop_span, proper_span context, scope_tree, borrow, drop_span, proper_span
); );
let tcx = self.tcx;
let mut err = let mut err =
self.tcx tcx.path_does_not_live_long_enough(proper_span, "borrowed value", Origin::Mir);
.path_does_not_live_long_enough(proper_span, "borrowed value", Origin::Mir);
err.span_label(proper_span, "temporary value does not live long enough"); err.span_label(proper_span, "temporary value does not live long enough");
err.span_label(drop_span, "temporary value only lives until here"); err.span_label(drop_span, "temporary value only lives until here");
if !self.tcx.nll() { if !tcx.nll() {
self.tcx.note_and_explain_region( tcx.note_and_explain_region(
scope_tree, scope_tree,
&mut err, &mut err,
"borrowed value must be valid for ", "borrowed value must be valid for ",
@ -592,7 +596,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
(place, span): (&Place<'tcx>, Span), (place, span): (&Place<'tcx>, Span),
loan: &BorrowData<'tcx>, loan: &BorrowData<'tcx>,
) { ) {
let mut err = self.tcx.cannot_assign_to_borrowed( let tcx = self.tcx;
let mut err = tcx.cannot_assign_to_borrowed(
span, span,
self.retrieve_borrow_span(loan), self.retrieve_borrow_span(loan),
&self.describe_place(place).unwrap_or("_".to_owned()), &self.describe_place(place).unwrap_or("_".to_owned()),

View file

@ -10,7 +10,7 @@
//! This query borrow-checks the MIR to (further) ensure it is not broken. //! This query borrow-checks the MIR to (further) ensure it is not broken.
use borrow_check::nll::region_infer::RegionInferenceContext; use borrow_check::nll::region_infer::{RegionCausalInfo, RegionInferenceContext};
use rustc::hir; use rustc::hir;
use rustc::hir::def_id::DefId; use rustc::hir::def_id::DefId;
use rustc::hir::map::definitions::DefPathData; use rustc::hir::map::definitions::DefPathData;
@ -231,6 +231,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
access_place_error_reported: FxHashSet(), access_place_error_reported: FxHashSet(),
reservation_error_reported: FxHashSet(), reservation_error_reported: FxHashSet(),
nonlexical_regioncx: opt_regioncx.clone(), nonlexical_regioncx: opt_regioncx.clone(),
nonlexical_cause_info: None,
}; };
let borrows = Borrows::new(tcx, mir, opt_regioncx, def_id, body_id); let borrows = Borrows::new(tcx, mir, opt_regioncx, def_id, body_id);
@ -311,6 +312,7 @@ pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
/// contains the results from region inference and lets us e.g. /// contains the results from region inference and lets us e.g.
/// find out which CFG points are contained in each borrow region. /// find out which CFG points are contained in each borrow region.
nonlexical_regioncx: Option<Rc<RegionInferenceContext<'tcx>>>, nonlexical_regioncx: Option<Rc<RegionInferenceContext<'tcx>>>,
nonlexical_cause_info: Option<RegionCausalInfo>,
} }
// Check that: // Check that:
@ -337,9 +339,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
) { ) {
debug!( debug!(
"MirBorrowckCtxt::process_statement({:?}, {:?}): {}", "MirBorrowckCtxt::process_statement({:?}, {:?}): {}",
location, location, stmt, flow_state
stmt,
flow_state
); );
let span = stmt.source_info.span; let span = stmt.source_info.span;
@ -441,9 +441,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
let loc = location; let loc = location;
debug!( debug!(
"MirBorrowckCtxt::process_terminator({:?}, {:?}): {}", "MirBorrowckCtxt::process_terminator({:?}, {:?}): {}",
location, location, term, flow_state
term,
flow_state
); );
let span = term.source_info.span; let span = term.source_info.span;
@ -582,8 +580,14 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
TerminatorKind::Goto { target: _ } TerminatorKind::Goto { target: _ }
| TerminatorKind::Abort | TerminatorKind::Abort
| TerminatorKind::Unreachable | TerminatorKind::Unreachable
| TerminatorKind::FalseEdges { real_target: _, imaginary_targets: _ } | TerminatorKind::FalseEdges {
| TerminatorKind::FalseUnwind { real_target: _, unwind: _ } => { real_target: _,
imaginary_targets: _,
}
| TerminatorKind::FalseUnwind {
real_target: _,
unwind: _,
} => {
// no data used, thus irrelevant to borrowck // no data used, thus irrelevant to borrowck
} }
} }
@ -683,7 +687,8 @@ enum LocalMutationIsAllowed {
struct AccessErrorsReported { struct AccessErrorsReported {
mutability_error: bool, mutability_error: bool,
#[allow(dead_code)] conflict_error: bool, #[allow(dead_code)]
conflict_error: bool,
} }
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
@ -719,9 +724,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
/// allowed to be split into separate Reservation and /// allowed to be split into separate Reservation and
/// Activation phases. /// Activation phases.
fn allow_two_phase_borrow(&self, kind: BorrowKind) -> bool { fn allow_two_phase_borrow(&self, kind: BorrowKind) -> bool {
self.tcx.two_phase_borrows() && self.tcx.two_phase_borrows()
(kind.allows_two_phase_borrow() || && (kind.allows_two_phase_borrow()
self.tcx.sess.opts.debugging_opts.two_phase_beyond_autoref) || self.tcx.sess.opts.debugging_opts.two_phase_beyond_autoref)
} }
/// Invokes `access_place` as appropriate for dropping the value /// Invokes `access_place` as appropriate for dropping the value
@ -753,16 +758,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
let field_ty = gcx.normalize_associated_type_in_env(&field_ty, self.param_env); let field_ty = gcx.normalize_associated_type_in_env(&field_ty, self.param_env);
let place = drop_place.clone().field(Field::new(index), field_ty); let place = drop_place.clone().field(Field::new(index), field_ty);
self.visit_terminator_drop( self.visit_terminator_drop(loc, term, flow_state, &place, field_ty, span);
loc,
term,
flow_state,
&place,
field_ty,
span,
);
} }
}, }
_ => { _ => {
// We have now refined the type of the value being // We have now refined the type of the value being
// dropped (potentially) to just the type of a // dropped (potentially) to just the type of a
@ -779,7 +777,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
flow_state, flow_state,
); );
} }
}, }
} }
} }
@ -801,8 +799,11 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
if let Activation(_, borrow_index) = rw { if let Activation(_, borrow_index) = rw {
if self.reservation_error_reported.contains(&place_span.0) { if self.reservation_error_reported.contains(&place_span.0) {
debug!("skipping access_place for activation of invalid reservation \ debug!(
place: {:?} borrow_index: {:?}", place_span.0, borrow_index); "skipping access_place for activation of invalid reservation \
place: {:?} borrow_index: {:?}",
place_span.0, borrow_index
);
return AccessErrorsReported { return AccessErrorsReported {
mutability_error: false, mutability_error: false,
conflict_error: true, conflict_error: true,
@ -810,9 +811,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
} }
} }
if self.access_place_error_reported.contains(&(place_span.0.clone(), place_span.1)) { if self.access_place_error_reported
debug!("access_place: suppressing error place_span=`{:?}` kind=`{:?}`", .contains(&(place_span.0.clone(), place_span.1))
place_span, kind); {
debug!(
"access_place: suppressing error place_span=`{:?}` kind=`{:?}`",
place_span, kind
);
return AccessErrorsReported { return AccessErrorsReported {
mutability_error: false, mutability_error: false,
conflict_error: true, conflict_error: true,
@ -825,9 +830,12 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
self.check_access_for_conflict(context, place_span, sd, rw, flow_state); self.check_access_for_conflict(context, place_span, sd, rw, flow_state);
if conflict_error || mutability_error { if conflict_error || mutability_error {
debug!("access_place: logging error place_span=`{:?}` kind=`{:?}`", debug!(
place_span, kind); "access_place: logging error place_span=`{:?}` kind=`{:?}`",
self.access_place_error_reported.insert((place_span.0.clone(), place_span.1)); place_span, kind
);
self.access_place_error_reported
.insert((place_span.0.clone(), place_span.1));
} }
AccessErrorsReported { AccessErrorsReported {
@ -875,8 +883,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
(Read(kind), BorrowKind::Unique) | (Read(kind), BorrowKind::Mut { .. }) => { (Read(kind), BorrowKind::Unique) | (Read(kind), BorrowKind::Mut { .. }) => {
// Reading from mere reservations of mutable-borrows is OK. // Reading from mere reservations of mutable-borrows is OK.
if this.allow_two_phase_borrow(borrow.kind) && index.is_reservation() if this.allow_two_phase_borrow(borrow.kind) && index.is_reservation() {
{
return Control::Continue; return Control::Continue;
} }
@ -915,15 +922,15 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
place_span.0 place_span.0
); );
this.reservation_error_reported.insert(place_span.0.clone()); this.reservation_error_reported.insert(place_span.0.clone());
}, }
Activation(_, activating) => { Activation(_, activating) => {
debug!( debug!(
"observing check_place for activation of \ "observing check_place for activation of \
borrow_index: {:?}", borrow_index: {:?}",
activating activating
); );
}, }
Read(..) | Write(..) => {}, Read(..) | Write(..) => {}
} }
match kind { match kind {
@ -1210,11 +1217,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
/// Reports an error if this is a borrow of local data. /// Reports an error if this is a borrow of local data.
/// This is called for all Yield statements on movable generators /// This is called for all Yield statements on movable generators
fn check_for_local_borrow( fn check_for_local_borrow(&mut self, borrow: &BorrowData<'tcx>, yield_span: Span) {
&mut self,
borrow: &BorrowData<'tcx>,
yield_span: Span)
{
fn borrow_of_local_data<'tcx>(place: &Place<'tcx>) -> bool { fn borrow_of_local_data<'tcx>(place: &Place<'tcx>) -> bool {
match place { match place {
Place::Static(..) => false, Place::Static(..) => false,
@ -1226,13 +1229,11 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
ProjectionElem::Deref => false, ProjectionElem::Deref => false,
// For interior references and downcasts, find out if the base is local // For interior references and downcasts, find out if the base is local
ProjectionElem::Field(..) | ProjectionElem::Field(..)
ProjectionElem::Index(..) | | ProjectionElem::Index(..)
ProjectionElem::ConstantIndex { .. } | | ProjectionElem::ConstantIndex { .. }
ProjectionElem::Subslice { .. } | | ProjectionElem::Subslice { .. }
ProjectionElem::Downcast(..) => { | ProjectionElem::Downcast(..) => borrow_of_local_data(&proj.base),
borrow_of_local_data(&proj.base)
}
} }
} }
} }
@ -1241,9 +1242,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
debug!("check_for_local_borrow({:?})", borrow); debug!("check_for_local_borrow({:?})", borrow);
if borrow_of_local_data(&borrow.borrowed_place) { if borrow_of_local_data(&borrow.borrowed_place) {
self.tcx.cannot_borrow_across_generator_yield(self.retrieve_borrow_span(borrow), self.tcx
yield_span, .cannot_borrow_across_generator_yield(
Origin::Mir).emit(); self.retrieve_borrow_span(borrow),
yield_span,
Origin::Mir,
)
.emit();
} }
} }
@ -1531,9 +1536,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
) -> bool { ) -> bool {
debug!( debug!(
"check_access_permissions({:?}, {:?}, {:?})", "check_access_permissions({:?}, {:?}, {:?})",
place, place, kind, is_local_mutation_allowed
kind,
is_local_mutation_allowed
); );
let mut error_reported = false; let mut error_reported = false;
match kind { match kind {
@ -1598,8 +1601,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
span, span,
&format!( &format!(
"Accessing `{:?}` with the kind `{:?}` shouldn't be possible", "Accessing `{:?}` with the kind `{:?}` shouldn't be possible",
place, place, kind
kind
), ),
); );
} }
@ -1699,9 +1701,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
let decl = &self.mir.upvar_decls[field.index()]; let decl = &self.mir.upvar_decls[field.index()];
debug!( debug!(
"decl.mutability={:?} local_mutation_is_allowed={:?} place={:?}", "decl.mutability={:?} local_mutation_is_allowed={:?} place={:?}",
decl, decl, is_local_mutation_allowed, place
is_local_mutation_allowed,
place
); );
match (decl.mutability, is_local_mutation_allowed) { match (decl.mutability, is_local_mutation_allowed) {
(Mutability::Not, LocalMutationIsAllowed::No) (Mutability::Not, LocalMutationIsAllowed::No)
@ -1722,7 +1722,6 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
} }
} }
/// If this is a field projection, and the field is being projected from a closure type, /// If this is a field projection, and the field is being projected from a closure type,
/// then returns the index of the field being projected. Note that this closure will always /// then returns the index of the field being projected. Note that this closure will always
/// be `self` in the current MIR, because that is the only time we directly access the fields /// be `self` in the current MIR, because that is the only time we directly access the fields
@ -1926,9 +1925,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
) -> bool { ) -> bool {
debug!( debug!(
"places_conflict({:?},{:?},{:?})", "places_conflict({:?},{:?},{:?})",
borrow_place, borrow_place, access_place, access
access_place,
access
); );
// Return all the prefixes of `place` in reverse order, including // Return all the prefixes of `place` in reverse order, including
@ -1954,8 +1951,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
let access_components = place_elements(access_place); let access_components = place_elements(access_place);
debug!( debug!(
"places_conflict: components {:?} / {:?}", "places_conflict: components {:?} / {:?}",
borrow_components, borrow_components, access_components
access_components
); );
let borrow_components = borrow_components let borrow_components = borrow_components
@ -2161,8 +2157,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
let borrowed = &data[i.borrow_index()]; let borrowed = &data[i.borrow_index()];
if self.places_conflict(&borrowed.borrowed_place, place, access) { if self.places_conflict(&borrowed.borrowed_place, place, access) {
debug!("each_borrow_involving_path: {:?} @ {:?} vs. {:?}/{:?}", debug!(
i, borrowed, place, access); "each_borrow_involving_path: {:?} @ {:?} vs. {:?}/{:?}",
i, borrowed, place, access
);
let ctrl = op(self, i, borrowed); let ctrl = op(self, i, borrowed);
if ctrl == Control::Break { if ctrl == Control::Break {
return; return;

View file

@ -18,19 +18,29 @@ use rustc_errors::DiagnosticBuilder;
use util::liveness::{self, DefUse, LivenessMode}; use util::liveness::{self, DefUse, LivenessMode};
impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
/// Adds annotations to `err` explaining *why* the borrow contains the
/// point from `context`. This is key for the "3-point errors"
/// [described in the NLL RFC][d].
///
/// [d]: https://rust-lang.github.io/rfcs/2094-nll.html#leveraging-intuition-framing-errors-in-terms-of-points
pub(in borrow_check) fn explain_why_borrow_contains_point( pub(in borrow_check) fn explain_why_borrow_contains_point(
&self, &mut self,
context: Context, context: Context,
borrow: &BorrowData<'tcx>, borrow: &BorrowData<'tcx>,
err: &mut DiagnosticBuilder<'_>, err: &mut DiagnosticBuilder<'_>,
) { ) {
if let Some(regioncx) = &self.nonlexical_regioncx { if let Some(regioncx) = &self.nonlexical_regioncx {
if let Some(cause) = regioncx.why_region_contains_point(borrow.region, context.loc) { let mir = self.mir;
let mir = self.mir;
if self.nonlexical_cause_info.is_none() {
self.nonlexical_cause_info = Some(regioncx.compute_causal_info(mir));
}
let cause_info = self.nonlexical_cause_info.as_ref().unwrap();
if let Some(cause) = cause_info.why_region_contains_point(borrow.region, context.loc) {
match *cause.root_cause() { match *cause.root_cause() {
Cause::LiveVar(local, location) => { Cause::LiveVar(local, location) => {
match find_regular_use(&mir, regioncx, borrow, location, local) { match find_regular_use(mir, regioncx, borrow, location, local) {
Some(p) => { Some(p) => {
err.span_label( err.span_label(
mir.source_info(p).span, mir.source_info(p).span,
@ -48,9 +58,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
} }
Cause::DropVar(local, location) => { Cause::DropVar(local, location) => {
match find_drop_use(&mir, regioncx, borrow, location, local) { match find_drop_use(mir, regioncx, borrow, location, local) {
Some(p) => { Some(p) => {
let local_name = &mir.local_decls[local].name.unwrap(); let local_name = mir.local_decls[local].name.unwrap();
err.span_label( err.span_label(
mir.source_info(p).span, mir.source_info(p).span,

View file

@ -124,6 +124,10 @@ pub(crate) enum Cause {
}, },
} }
pub(crate) struct RegionCausalInfo {
inferred_values: RegionValues,
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Constraint { pub struct Constraint {
// NB. The ordering here is not significant for correctness, but // NB. The ordering here is not significant for correctness, but
@ -250,16 +254,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
.map(|origin| RegionDefinition::new(origin)) .map(|origin| RegionDefinition::new(origin))
.collect(); .collect();
let nll_dump_cause = ty::tls::with(|tcx| tcx.sess.nll_dump_cause());
let mut result = Self { let mut result = Self {
definitions, definitions,
elements: elements.clone(), elements: elements.clone(),
liveness_constraints: RegionValues::new( liveness_constraints: RegionValues::new(elements, num_region_variables),
elements,
num_region_variables,
TrackCauses(nll_dump_cause),
),
inferred_values: None, inferred_values: None,
constraints: Vec::new(), constraints: Vec::new(),
type_tests: Vec::new(), type_tests: Vec::new(),
@ -348,17 +346,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
inferred_values.contains(r.to_region_vid(), p) inferred_values.contains(r.to_region_vid(), p)
} }
/// Returns the *reason* that the region `r` contains the given point.
pub(crate) fn why_region_contains_point<R>(&self, r: R, p: Location) -> Option<Rc<Cause>>
where
R: ToRegionVid,
{
let inferred_values = self.inferred_values
.as_ref()
.expect("region values not yet inferred");
inferred_values.cause(r.to_region_vid(), p)
}
/// Returns access to the value of `r` for debugging purposes. /// Returns access to the value of `r` for debugging purposes.
pub(super) fn region_value_str(&self, r: RegionVid) -> String { pub(super) fn region_value_str(&self, r: RegionVid) -> String {
let inferred_values = self.inferred_values let inferred_values = self.inferred_values
@ -449,13 +436,25 @@ impl<'tcx> RegionInferenceContext<'tcx> {
} }
} }
/// Re-execute the region inference, this time tracking causal information.
/// This is significantly slower, so it is done only when an error is being reported.
pub(super) fn compute_causal_info(&self, mir: &Mir<'tcx>) -> RegionCausalInfo {
let inferred_values = self.compute_region_values(mir, TrackCauses(true));
RegionCausalInfo { inferred_values }
}
/// Propagate the region constraints: this will grow the values /// Propagate the region constraints: this will grow the values
/// for each region variable until all the constraints are /// for each region variable until all the constraints are
/// satisfied. Note that some values may grow **too** large to be /// satisfied. Note that some values may grow **too** large to be
/// feasible, but we check this later. /// feasible, but we check this later.
fn propagate_constraints(&mut self, mir: &Mir<'tcx>) { fn propagate_constraints(&mut self, mir: &Mir<'tcx>) {
debug!("propagate_constraints()"); let inferred_values = self.compute_region_values(mir, TrackCauses(false));
debug!("propagate_constraints: constraints={:#?}", { self.inferred_values = Some(inferred_values);
}
fn compute_region_values(&self, mir: &Mir<'tcx>, track_causes: TrackCauses) -> RegionValues {
debug!("compute_region_values()");
debug!("compute_region_values: constraints={:#?}", {
let mut constraints: Vec<_> = self.constraints.iter().collect(); let mut constraints: Vec<_> = self.constraints.iter().collect();
constraints.sort(); constraints.sort();
constraints constraints
@ -463,7 +462,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// The initial values for each region are derived from the liveness // The initial values for each region are derived from the liveness
// constraints we have accumulated. // constraints we have accumulated.
let mut inferred_values = self.liveness_constraints.clone(); let mut inferred_values = self.liveness_constraints.duplicate(track_causes);
let dependency_map = self.build_dependency_map(); let dependency_map = self.build_dependency_map();
@ -507,7 +506,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
debug!("\n"); debug!("\n");
} }
self.inferred_values = Some(inferred_values); inferred_values
} }
/// Builds up a map from each region variable X to a vector with the /// Builds up a map from each region variable X to a vector with the
@ -1097,6 +1096,16 @@ impl<'tcx> RegionInferenceContext<'tcx> {
} }
} }
impl RegionCausalInfo {
/// Returns the *reason* that the region `r` contains the given point.
pub(super) fn why_region_contains_point<R>(&self, r: R, p: Location) -> Option<Rc<Cause>>
where
R: ToRegionVid,
{
self.inferred_values.cause(r.to_region_vid(), p)
}
}
impl<'tcx> RegionDefinition<'tcx> { impl<'tcx> RegionDefinition<'tcx> {
fn new(origin: RegionVariableOrigin) -> Self { fn new(origin: RegionVariableOrigin) -> Self {
// Create a new region definition. Note that, for free // Create a new region definition. Note that, for free

View file

@ -184,7 +184,6 @@ impl ToElementIndex for RegionElementIndex {
/// compact `SparseBitMatrix` representation, with one row per region /// compact `SparseBitMatrix` representation, with one row per region
/// variable. The columns consist of either universal regions or /// variable. The columns consist of either universal regions or
/// points in the CFG. /// points in the CFG.
#[derive(Clone)]
pub(super) struct RegionValues { pub(super) struct RegionValues {
elements: Rc<RegionValueElements>, elements: Rc<RegionValueElements>,
matrix: SparseBitMatrix<RegionVid, RegionElementIndex>, matrix: SparseBitMatrix<RegionVid, RegionElementIndex>,
@ -199,11 +198,10 @@ pub(super) struct RegionValues {
type CauseMap = FxHashMap<(RegionVid, RegionElementIndex), Rc<Cause>>; type CauseMap = FxHashMap<(RegionVid, RegionElementIndex), Rc<Cause>>;
impl RegionValues { impl RegionValues {
pub(super) fn new( /// Creates a new set of "region values" that tracks causal information.
elements: &Rc<RegionValueElements>, /// Each of the regions in num_region_variables will be initialized with an
num_region_variables: usize, /// empty set of points and no causal information.
track_causes: TrackCauses, pub(super) fn new(elements: &Rc<RegionValueElements>, num_region_variables: usize) -> Self {
) -> Self {
assert!( assert!(
elements.num_universal_regions <= num_region_variables, elements.num_universal_regions <= num_region_variables,
"universal regions are a subset of the region variables" "universal regions are a subset of the region variables"
@ -215,8 +213,22 @@ impl RegionValues {
RegionVid::new(num_region_variables), RegionVid::new(num_region_variables),
RegionElementIndex::new(elements.num_elements()), RegionElementIndex::new(elements.num_elements()),
), ),
causes: Some(CauseMap::default()),
}
}
/// Duplicates the region values. If track_causes is false, then the
/// resulting value will not track causal information (and any existing
/// causal information is dropped). Otherwise, the causal information is
/// preserved and maintained. Tracking the causal information makes region
/// propagation significantly slower, so we prefer not to do it until an
/// error is reported.
pub(super) fn duplicate(&self, track_causes: TrackCauses) -> Self {
Self {
elements: self.elements.clone(),
matrix: self.matrix.clone(),
causes: if track_causes.0 { causes: if track_causes.0 {
Some(CauseMap::default()) self.causes.clone()
} else { } else {
None None
}, },

View file

@ -6,6 +6,9 @@ LL | let mref = &mut u.s.a;
... ...
LL | let nref = &u.z.c; LL | let nref = &u.z.c;
| ^^^^^^ immutable borrow occurs here | ^^^^^^ immutable borrow occurs here
LL | //~^ ERROR cannot borrow `u.z.c` as immutable because it is also borrowed as mutable [E0502]
LL | println!("{} {}", mref, nref)
| ---- borrow later used here
error[E0502]: cannot borrow `u.s.a` as mutable because it is also borrowed as immutable error[E0502]: cannot borrow `u.s.a` as mutable because it is also borrowed as immutable
--> $DIR/issue-45157.rs:39:27 --> $DIR/issue-45157.rs:39:27
@ -14,7 +17,9 @@ LL | let nref = &u.z.c;
| ------ immutable borrow occurs here | ------ immutable borrow occurs here
LL | //~^ ERROR cannot borrow `u.z.c` as immutable because it is also borrowed as mutable [E0502] LL | //~^ ERROR cannot borrow `u.z.c` as immutable because it is also borrowed as mutable [E0502]
LL | println!("{} {}", mref, nref) LL | println!("{} {}", mref, nref)
| ^^^^ mutable borrow occurs here | ^^^^ ---- borrow later used here
| |
| mutable borrow occurs here
error: aborting due to 2 previous errors error: aborting due to 2 previous errors

View file

@ -8,8 +8,6 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
// compile-flags: -Znll-dump-cause
#![feature(nll)] #![feature(nll)]
fn gimme(x: &(u32,)) -> &u32 { fn gimme(x: &(u32,)) -> &u32 {

View file

@ -1,5 +1,5 @@
error[E0597]: `v` does not live long enough error[E0597]: `v` does not live long enough
--> $DIR/borrowed-local-error.rs:22:9 --> $DIR/borrowed-local-error.rs:20:9
| |
LL | let x = gimme({ LL | let x = gimme({
| _____________- | _____________-

View file

@ -10,6 +10,8 @@ LL | | //~^ cannot use `e` because it was mutably borrowed [E0503]
LL | | Xyz::B => println!("b"), LL | | Xyz::B => println!("b"),
LL | | }; LL | | };
| |_____^ use of borrowed `e` | |_____^ use of borrowed `e`
LL | *g = Xyz::B;
| ----------- borrow later used here
error[E0503]: cannot use `e` because it was mutably borrowed error[E0503]: cannot use `e` because it was mutably borrowed
--> $DIR/borrowed-match-issue-45045.rs:25:9 --> $DIR/borrowed-match-issue-45045.rs:25:9
@ -19,6 +21,9 @@ LL | let f = &mut e;
... ...
LL | Xyz::A => println!("a"), LL | Xyz::A => println!("a"),
| ^^^^^^ use of borrowed `e` | ^^^^^^ use of borrowed `e`
...
LL | *g = Xyz::B;
| ----------- borrow later used here
error: aborting due to 2 previous errors error: aborting due to 2 previous errors

View file

@ -6,6 +6,9 @@ LL | let x = &mut block;
LL | println!("{}", x.current); LL | println!("{}", x.current);
LL | let p: &'a u8 = &*block.current; LL | let p: &'a u8 = &*block.current;
| ^^^^^^^^^^^^^^^ immutable borrow occurs here | ^^^^^^^^^^^^^^^ immutable borrow occurs here
LL | //~^ ERROR cannot borrow `*block.current` as immutable because it is also borrowed as mutable
LL | drop(x);
| - borrow later used here
error: aborting due to previous error error: aborting due to previous error

View file

@ -8,8 +8,6 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
// compile-flags: -Znll-dump-cause
#![feature(nll)] #![feature(nll)]
fn gimme(x: &(u32,)) -> &u32 { fn gimme(x: &(u32,)) -> &u32 {

View file

@ -1,5 +1,5 @@
error[E0597]: borrowed value does not live long enough error[E0597]: borrowed value does not live long enough
--> $DIR/borrowed-temporary-error.rs:22:10 --> $DIR/borrowed-temporary-error.rs:20:10
| |
LL | &(v,) LL | &(v,)
| ^^^^ temporary value does not live long enough | ^^^^ temporary value does not live long enough

View file

@ -8,8 +8,6 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
// compile-flags: -Znll-dump-cause
#![feature(nll)] #![feature(nll)]
#![allow(warnings)] #![allow(warnings)]

View file

@ -1,5 +1,5 @@
error[E0597]: `v` does not live long enough error[E0597]: `v` does not live long enough
--> $DIR/borrowed-universal-error-2.rs:18:5 --> $DIR/borrowed-universal-error-2.rs:16:5
| |
LL | &v LL | &v
| ^^ borrowed value does not live long enough | ^^ borrowed value does not live long enough
@ -7,8 +7,8 @@ LL | //~^ ERROR `v` does not live long enough [E0597]
LL | } LL | }
| - borrowed value only lives until here | - borrowed value only lives until here
| |
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 16:1... note: borrowed value must be valid for the lifetime 'a as defined on the function body at 14:1...
--> $DIR/borrowed-universal-error-2.rs:16:1 --> $DIR/borrowed-universal-error-2.rs:14:1
| |
LL | fn foo<'a>(x: &'a (u32,)) -> &'a u32 { LL | fn foo<'a>(x: &'a (u32,)) -> &'a u32 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View file

@ -8,8 +8,6 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
// compile-flags: -Znll-dump-cause
#![feature(nll)] #![feature(nll)]
#![allow(warnings)] #![allow(warnings)]

View file

@ -1,5 +1,5 @@
error[E0597]: borrowed value does not live long enough error[E0597]: borrowed value does not live long enough
--> $DIR/borrowed-universal-error.rs:22:12 --> $DIR/borrowed-universal-error.rs:20:12
| |
LL | gimme(&(v,)) LL | gimme(&(v,))
| ^^^^ temporary value does not live long enough | ^^^^ temporary value does not live long enough
@ -7,8 +7,8 @@ LL | //~^ ERROR borrowed value does not live long enough [E0597]
LL | } LL | }
| - temporary value only lives until here | - temporary value only lives until here
| |
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 20:1... note: borrowed value must be valid for the lifetime 'a as defined on the function body at 18:1...
--> $DIR/borrowed-universal-error.rs:20:1 --> $DIR/borrowed-universal-error.rs:18:1
| |
LL | fn foo<'a>(x: &'a (u32,)) -> &'a u32 { LL | fn foo<'a>(x: &'a (u32,)) -> &'a u32 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View file

@ -8,8 +8,6 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
// compile-flags:-Znll-dump-cause
// Test that a structure which tries to store a pointer to `y` into // Test that a structure which tries to store a pointer to `y` into
// `p` (indirectly) fails to compile. // `p` (indirectly) fails to compile.

View file

@ -1,5 +1,5 @@
error[E0597]: `y` does not live long enough error[E0597]: `y` does not live long enough
--> $DIR/capture-ref-in-struct.rs:33:16 --> $DIR/capture-ref-in-struct.rs:31:16
| |
LL | y: &y, LL | y: &y,
| ^^ borrowed value does not live long enough | ^^ borrowed value does not live long enough

View file

@ -22,7 +22,7 @@
// basically checking that the MIR type checker correctly enforces the // basically checking that the MIR type checker correctly enforces the
// closure signature. // closure signature.
// compile-flags:-Znll -Zborrowck=mir -Znll-dump-cause -Zverbose // compile-flags:-Znll -Zborrowck=mir -Zverbose
#![feature(rustc_attrs)] #![feature(rustc_attrs)]

View file

@ -15,7 +15,7 @@
// //
// except that the closure does so via a second closure. // except that the closure does so via a second closure.
// compile-flags:-Znll -Zborrowck=mir -Znll-dump-cause -Zverbose // compile-flags:-Znll -Zborrowck=mir -Zverbose
#![feature(rustc_attrs)] #![feature(rustc_attrs)]

View file

@ -19,7 +19,7 @@
// `'b`. This relationship is propagated to the closure creator, // `'b`. This relationship is propagated to the closure creator,
// which reports an error. // which reports an error.
// compile-flags:-Znll -Zborrowck=mir -Znll-dump-cause -Zverbose // compile-flags:-Znll -Zborrowck=mir -Zverbose
#![feature(rustc_attrs)] #![feature(rustc_attrs)]

View file

@ -78,6 +78,8 @@ LL | let cell = Cell::new(&a);
... ...
LL | } LL | }
| - borrowed value only lives until here | - borrowed value only lives until here
|
= note: borrowed value must be valid for the static lifetime...
error: aborting due to 2 previous errors error: aborting due to 2 previous errors

View file

@ -13,7 +13,7 @@
// because of destructor. (Note that the stderr also identifies this // because of destructor. (Note that the stderr also identifies this
// destructor in the error message.) // destructor in the error message.)
// compile-flags:-Znll -Zborrowck=mir -Znll-dump-cause // compile-flags:-Znll -Zborrowck=mir
#![allow(warnings)] #![allow(warnings)]
#![feature(dropck_eyepatch)] #![feature(dropck_eyepatch)]

View file

@ -13,7 +13,7 @@
// a variety of errors from the older, AST-based machinery (notably // a variety of errors from the older, AST-based machinery (notably
// borrowck), and then we get the NLL error at the end. // borrowck), and then we get the NLL error at the end.
// compile-flags:-Znll -Zborrowck=compare -Znll-dump-cause // compile-flags:-Znll -Zborrowck=compare
struct Map { struct Map {
} }

View file

@ -6,6 +6,8 @@ LL | let t = &mut *s; // this borrow should last for the entire function
LL | let x = &t.0; LL | let x = &t.0;
LL | *s = (2,); //~ ERROR cannot assign to `*s` LL | *s = (2,); //~ ERROR cannot assign to `*s`
| ^^^^^^^^^ assignment to borrowed `*s` occurs here | ^^^^^^^^^ assignment to borrowed `*s` occurs here
LL | *x
| -- borrow later used here
error[E0621]: explicit lifetime required in the type of `s` error[E0621]: explicit lifetime required in the type of `s`
--> $DIR/guarantor-issue-46974.rs:25:5 --> $DIR/guarantor-issue-46974.rs:25:5

View file

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
//compile-flags: -Z emit-end-regions -Zborrowck=mir -Z nll -Znll-dump-cause //compile-flags: -Z emit-end-regions -Zborrowck=mir -Znll
#![allow(warnings)] #![allow(warnings)]

View file

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
//compile-flags: -Z emit-end-regions -Zborrowck=mir -Znll -Znll-dump-cause //compile-flags: -Z emit-end-regions -Zborrowck=mir -Znll
#![allow(warnings)] #![allow(warnings)]

View file

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
//compile-flags: -Z emit-end-regions -Zborrowck=mir -Znll -Znll-dump-cause //compile-flags: -Z emit-end-regions -Zborrowck=mir -Znll
#![allow(warnings)] #![allow(warnings)]

View file

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
//compile-flags: -Z emit-end-regions -Zborrowck=mir -Znll -Znll-dump-cause //compile-flags: -Z emit-end-regions -Zborrowck=mir -Znll
#![allow(warnings)] #![allow(warnings)]

View file

@ -1,11 +1,16 @@
error[E0597]: borrowed value does not live long enough error[E0597]: borrowed value does not live long enough
--> $DIR/return-ref-mut-issue-46557.rs:17:21 --> $DIR/return-ref-mut-issue-46557.rs:17:21
| |
LL | let ref mut x = 1234543; //~ ERROR borrowed value does not live long enough [E0597] LL | fn gimme_static_mut() -> &'static mut u32 {
| ^^^^^^^ temporary value does not live long enough | ___________________________________________-
LL | x LL | | let ref mut x = 1234543; //~ ERROR borrowed value does not live long enough [E0597]
LL | } | | ^^^^^^^ temporary value does not live long enough
| - temporary value only lives until here LL | | x
LL | | }
| | -
| | |
| |_temporary value only lives until here
| borrow later used here
error: aborting due to previous error error: aborting due to previous error