Skip to content

Commit fb9dfa8

Browse files
committed
Auto merge of rust-lang#84762 - cjgillot:resolve-span-opt, r=petrochenkov
Encode spans relative to the enclosing item -- enable on nightly Follow-up to rust-lang#84373 with the flag `-Zincremental-relative-spans` set by default. This PR seeks to remove one of the main shortcomings of incremental: the handling of spans. Changing the contents of a function may require redoing part of the compilation process for another function in another file because of span information is changed. Within one file: all the spans in HIR change, so typechecking had to be re-done. Between files: spans of associated types/consts/functions change, so type-based resolution needs to be re-done (hygiene information is stored in the span). The flag `-Zincremental-relative-spans` encodes local spans relative to the span of an item, stored inside the `source_span` query. Trap: stashed diagnostics are referenced by the "raw" span, so stealing them requires to remove the span's parent. In order to avoid too much traffic in the span interner, span encoding uses the `ctxt_or_tag` field to encode: - the parent when the `SyntaxContext` is 0; - the `SyntaxContext` when the parent is `None`. Even with this, the PR creates a lot of traffic to the Span interner, when a Span has both a LocalDefId parent and a non-root SyntaxContext. They appear in lowering, when we add a parent to all spans, including those which come from macros, and during inlining when we mark inlined spans. The last commit changes how queries of `LocalDefId` manage their cache. I can put this in a separate PR if required. Possible future directions: - validate that all spans are marked in HIR validation; - mark macro-expanded spans relative to the def-site and not the use-site.
2 parents f89003e + 7b6ead2 commit fb9dfa8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+170
-205
lines changed

compiler/rustc_ast_lowering/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -776,7 +776,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
776776
/// Intercept all spans entering HIR.
777777
/// Mark a span as relative to the current owning item.
778778
fn lower_span(&self, span: Span) -> Span {
779-
if self.tcx.sess.opts.unstable_opts.incremental_relative_spans {
779+
if self.tcx.sess.opts.incremental_relative_spans() {
780780
span.with_parent(Some(self.current_hir_id_owner.def_id))
781781
} else {
782782
// Do not make spans relative when not using incremental compilation.

compiler/rustc_errors/src/lib.rs

+56-50
Original file line numberDiff line numberDiff line change
@@ -469,10 +469,12 @@ pub enum StashKey {
469469
CallAssocMethod,
470470
}
471471

472-
fn default_track_diagnostic(_: &Diagnostic) {}
472+
fn default_track_diagnostic(d: &mut Diagnostic, f: &mut dyn FnMut(&mut Diagnostic)) {
473+
(*f)(d)
474+
}
473475

474-
pub static TRACK_DIAGNOSTICS: AtomicRef<fn(&Diagnostic)> =
475-
AtomicRef::new(&(default_track_diagnostic as fn(&_)));
476+
pub static TRACK_DIAGNOSTICS: AtomicRef<fn(&mut Diagnostic, &mut dyn FnMut(&mut Diagnostic))> =
477+
AtomicRef::new(&(default_track_diagnostic as _));
476478

477479
#[derive(Copy, Clone, Default)]
478480
pub struct HandlerFlags {
@@ -654,17 +656,19 @@ impl Handler {
654656
/// Retrieve a stashed diagnostic with `steal_diagnostic`.
655657
pub fn stash_diagnostic(&self, span: Span, key: StashKey, diag: Diagnostic) {
656658
let mut inner = self.inner.borrow_mut();
657-
inner.stash((span, key), diag);
659+
inner.stash((span.with_parent(None), key), diag);
658660
}
659661

660662
/// Steal a previously stashed diagnostic with the given `Span` and [`StashKey`] as the key.
661663
pub fn steal_diagnostic(&self, span: Span, key: StashKey) -> Option<DiagnosticBuilder<'_, ()>> {
662664
let mut inner = self.inner.borrow_mut();
663-
inner.steal((span, key)).map(|diag| DiagnosticBuilder::new_diagnostic(self, diag))
665+
inner
666+
.steal((span.with_parent(None), key))
667+
.map(|diag| DiagnosticBuilder::new_diagnostic(self, diag))
664668
}
665669

666670
pub fn has_stashed_diagnostic(&self, span: Span, key: StashKey) -> bool {
667-
self.inner.borrow().stashed_diagnostics.get(&(span, key)).is_some()
671+
self.inner.borrow().stashed_diagnostics.get(&(span.with_parent(None), key)).is_some()
668672
}
669673

670674
/// Emit all stashed diagnostics.
@@ -1293,67 +1297,69 @@ impl HandlerInner {
12931297
&& !diagnostic.is_force_warn()
12941298
{
12951299
if diagnostic.has_future_breakage() {
1296-
(*TRACK_DIAGNOSTICS)(diagnostic);
1300+
(*TRACK_DIAGNOSTICS)(diagnostic, &mut |_| {});
12971301
}
12981302
return None;
12991303
}
13001304

1301-
(*TRACK_DIAGNOSTICS)(diagnostic);
1302-
13031305
if matches!(diagnostic.level, Level::Expect(_) | Level::Allow) {
1306+
(*TRACK_DIAGNOSTICS)(diagnostic, &mut |_| {});
13041307
return None;
13051308
}
13061309

1307-
if let Some(ref code) = diagnostic.code {
1308-
self.emitted_diagnostic_codes.insert(code.clone());
1309-
}
1310-
1311-
let already_emitted = |this: &mut Self| {
1312-
let mut hasher = StableHasher::new();
1313-
diagnostic.hash(&mut hasher);
1314-
let diagnostic_hash = hasher.finish();
1315-
!this.emitted_diagnostics.insert(diagnostic_hash)
1316-
};
1310+
let mut guaranteed = None;
1311+
(*TRACK_DIAGNOSTICS)(diagnostic, &mut |diagnostic| {
1312+
if let Some(ref code) = diagnostic.code {
1313+
self.emitted_diagnostic_codes.insert(code.clone());
1314+
}
13171315

1318-
// Only emit the diagnostic if we've been asked to deduplicate or
1319-
// haven't already emitted an equivalent diagnostic.
1320-
if !(self.flags.deduplicate_diagnostics && already_emitted(self)) {
1321-
debug!(?diagnostic);
1322-
debug!(?self.emitted_diagnostics);
1323-
let already_emitted_sub = |sub: &mut SubDiagnostic| {
1324-
debug!(?sub);
1325-
if sub.level != Level::OnceNote {
1326-
return false;
1327-
}
1316+
let already_emitted = |this: &mut Self| {
13281317
let mut hasher = StableHasher::new();
1329-
sub.hash(&mut hasher);
1318+
diagnostic.hash(&mut hasher);
13301319
let diagnostic_hash = hasher.finish();
1331-
debug!(?diagnostic_hash);
1332-
!self.emitted_diagnostics.insert(diagnostic_hash)
1320+
!this.emitted_diagnostics.insert(diagnostic_hash)
13331321
};
13341322

1335-
diagnostic.children.drain_filter(already_emitted_sub).for_each(|_| {});
1336-
1337-
self.emitter.emit_diagnostic(diagnostic);
1338-
if diagnostic.is_error() {
1339-
self.deduplicated_err_count += 1;
1340-
} else if let Warning(_) = diagnostic.level {
1341-
self.deduplicated_warn_count += 1;
1323+
// Only emit the diagnostic if we've been asked to deduplicate or
1324+
// haven't already emitted an equivalent diagnostic.
1325+
if !(self.flags.deduplicate_diagnostics && already_emitted(self)) {
1326+
debug!(?diagnostic);
1327+
debug!(?self.emitted_diagnostics);
1328+
let already_emitted_sub = |sub: &mut SubDiagnostic| {
1329+
debug!(?sub);
1330+
if sub.level != Level::OnceNote {
1331+
return false;
1332+
}
1333+
let mut hasher = StableHasher::new();
1334+
sub.hash(&mut hasher);
1335+
let diagnostic_hash = hasher.finish();
1336+
debug!(?diagnostic_hash);
1337+
!self.emitted_diagnostics.insert(diagnostic_hash)
1338+
};
1339+
1340+
diagnostic.children.drain_filter(already_emitted_sub).for_each(|_| {});
1341+
1342+
self.emitter.emit_diagnostic(diagnostic);
1343+
if diagnostic.is_error() {
1344+
self.deduplicated_err_count += 1;
1345+
} else if let Warning(_) = diagnostic.level {
1346+
self.deduplicated_warn_count += 1;
1347+
}
13421348
}
1343-
}
1344-
if diagnostic.is_error() {
1345-
if matches!(diagnostic.level, Level::Error { lint: true }) {
1346-
self.bump_lint_err_count();
1349+
if diagnostic.is_error() {
1350+
if matches!(diagnostic.level, Level::Error { lint: true }) {
1351+
self.bump_lint_err_count();
1352+
} else {
1353+
self.bump_err_count();
1354+
}
1355+
1356+
guaranteed = Some(ErrorGuaranteed::unchecked_claim_error_was_emitted());
13471357
} else {
1348-
self.bump_err_count();
1358+
self.bump_warn_count();
13491359
}
1360+
});
13501361

1351-
Some(ErrorGuaranteed::unchecked_claim_error_was_emitted())
1352-
} else {
1353-
self.bump_warn_count();
1354-
1355-
None
1356-
}
1362+
guaranteed
13571363
}
13581364

13591365
fn emit_artifact_notification(&mut self, path: &Path, artifact_type: &str) {

compiler/rustc_expand/src/expand.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -587,7 +587,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
587587
.resolver
588588
.visit_ast_fragment_with_placeholders(self.cx.current_expansion.id, &fragment);
589589

590-
if self.cx.sess.opts.unstable_opts.incremental_relative_spans {
590+
if self.cx.sess.opts.incremental_relative_spans() {
591591
for (invoc, _) in invocations.iter_mut() {
592592
let expn_id = invoc.expansion_data.id;
593593
let parent_def = self.cx.resolver.invocation_parent(expn_id);

compiler/rustc_hir_typeck/src/expr.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
395395
E0614,
396396
"type `{oprnd_t}` cannot be dereferenced",
397397
);
398-
let sp = tcx.sess.source_map().start_point(expr.span);
398+
let sp = tcx.sess.source_map().start_point(expr.span).with_parent(None);
399399
if let Some(sp) =
400400
tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp)
401401
{

compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -974,7 +974,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
974974
err: &mut Diagnostic,
975975
expr: &hir::Expr<'_>,
976976
) -> bool {
977-
let sp = self.tcx.sess.source_map().start_point(expr.span);
977+
let sp = self.tcx.sess.source_map().start_point(expr.span).with_parent(None);
978978
if let Some(sp) = self.tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp) {
979979
// `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`
980980
err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));

compiler/rustc_hir_typeck/src/method/suggest.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
339339
&mut err, item_name, rcvr_ty, cal, span,
340340
);
341341
}
342-
if let Some(span) = tcx.resolutions(()).confused_type_with_std_module.get(&span) {
342+
if let Some(span) =
343+
tcx.resolutions(()).confused_type_with_std_module.get(&span.with_parent(None))
344+
{
343345
err.span_suggestion(
344346
span.shrink_to_lo(),
345347
"you are looking for the module in `std`, not the primitive type",

compiler/rustc_hir_typeck/src/op.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -657,7 +657,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
657657
}
658658
}
659659

660-
let sp = self.tcx.sess.source_map().start_point(ex.span);
660+
let sp = self.tcx.sess.source_map().start_point(ex.span).with_parent(None);
661661
if let Some(sp) =
662662
self.tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp)
663663
{

compiler/rustc_interface/src/callbacks.rs

+11-2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
//! origin crate when the `TyCtxt` is not present in TLS.
1111
1212
use rustc_errors::{Diagnostic, TRACK_DIAGNOSTICS};
13+
use rustc_middle::dep_graph::TaskDepsRef;
1314
use rustc_middle::ty::tls;
1415
use std::fmt;
1516

@@ -26,14 +27,22 @@ fn track_span_parent(def_id: rustc_span::def_id::LocalDefId) {
2627
/// This is a callback from `rustc_ast` as it cannot access the implicit state
2728
/// in `rustc_middle` otherwise. It is used when diagnostic messages are
2829
/// emitted and stores them in the current query, if there is one.
29-
fn track_diagnostic(diagnostic: &Diagnostic) {
30+
fn track_diagnostic(diagnostic: &mut Diagnostic, f: &mut dyn FnMut(&mut Diagnostic)) {
3031
tls::with_context_opt(|icx| {
3132
if let Some(icx) = icx {
3233
if let Some(diagnostics) = icx.diagnostics {
3334
let mut diagnostics = diagnostics.lock();
3435
diagnostics.extend(Some(diagnostic.clone()));
36+
std::mem::drop(diagnostics);
3537
}
38+
39+
// Diagnostics are tracked, we can ignore the dependency.
40+
let icx = tls::ImplicitCtxt { task_deps: TaskDepsRef::Ignore, ..icx.clone() };
41+
return tls::enter_context(&icx, move |_| (*f)(diagnostic));
3642
}
43+
44+
// In any other case, invoke diagnostics anyway.
45+
(*f)(diagnostic);
3746
})
3847
}
3948

@@ -55,5 +64,5 @@ fn def_id_debug(def_id: rustc_hir::def_id::DefId, f: &mut fmt::Formatter<'_>) ->
5564
pub fn setup_callbacks() {
5665
rustc_span::SPAN_TRACK.swap(&(track_span_parent as fn(_)));
5766
rustc_hir::def_id::DEF_ID_DEBUG.swap(&(def_id_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
58-
TRACK_DIAGNOSTICS.swap(&(track_diagnostic as fn(&_)));
67+
TRACK_DIAGNOSTICS.swap(&(track_diagnostic as _));
5968
}

compiler/rustc_interface/src/tests.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -652,7 +652,6 @@ fn test_unstable_options_tracking_hash() {
652652
untracked!(future_incompat_test, true);
653653
untracked!(hir_stats, true);
654654
untracked!(identify_regions, true);
655-
untracked!(incremental_ignore_spans, true);
656655
untracked!(incremental_info, true);
657656
untracked!(incremental_verify_ich, true);
658657
untracked!(input_stats, true);
@@ -737,6 +736,7 @@ fn test_unstable_options_tracking_hash() {
737736
tracked!(fuel, Some(("abc".to_string(), 99)));
738737
tracked!(function_sections, Some(false));
739738
tracked!(human_readable_cgu_names, true);
739+
tracked!(incremental_ignore_spans, true);
740740
tracked!(inline_in_all_cgus, Some(true));
741741
tracked!(inline_mir, Some(true));
742742
tracked!(inline_mir_hint_threshold, Some(123));

compiler/rustc_middle/src/hir/map/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1160,7 +1160,7 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh {
11601160
hir_body_hash.hash_stable(&mut hcx, &mut stable_hasher);
11611161
upstream_crates.hash_stable(&mut hcx, &mut stable_hasher);
11621162
source_file_names.hash_stable(&mut hcx, &mut stable_hasher);
1163-
if tcx.sess.opts.unstable_opts.incremental_relative_spans {
1163+
if tcx.sess.opts.incremental_relative_spans() {
11641164
let definitions = tcx.definitions_untracked();
11651165
let mut owner_spans: Vec<_> = krate
11661166
.owners

compiler/rustc_query_system/src/dep_graph/graph.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -634,7 +634,7 @@ impl<K: DepKind> DepGraph<K> {
634634
if dep_node_debug.borrow().contains_key(&dep_node) {
635635
return;
636636
}
637-
let debug_str = debug_str_gen();
637+
let debug_str = self.with_ignore(debug_str_gen);
638638
dep_node_debug.borrow_mut().insert(dep_node, debug_str);
639639
}
640640

@@ -829,7 +829,9 @@ impl<K: DepKind> DepGraph<K> {
829829
);
830830

831831
if !side_effects.is_empty() {
832-
self.emit_side_effects(qcx, data, dep_node_index, side_effects);
832+
self.with_query_deserialization(|| {
833+
self.emit_side_effects(qcx, data, dep_node_index, side_effects)
834+
});
833835
}
834836

835837
// ... and finally storing a "Green" entry in the color map.

compiler/rustc_session/src/config.rs

+6
Original file line numberDiff line numberDiff line change
@@ -787,6 +787,12 @@ impl Options {
787787
pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion {
788788
self.cg.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy)
789789
}
790+
791+
#[allow(rustc::bad_opt_access)]
792+
pub fn incremental_relative_spans(&self) -> bool {
793+
self.unstable_opts.incremental_relative_spans
794+
|| (self.unstable_features.is_nightly_build() && self.incremental.is_some())
795+
}
790796
}
791797

792798
impl UnstableOptions {

compiler/rustc_session/src/options.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1332,11 +1332,12 @@ options! {
13321332
"generate human-readable, predictable names for codegen units (default: no)"),
13331333
identify_regions: bool = (false, parse_bool, [UNTRACKED],
13341334
"display unnamed regions as `'<id>`, using a non-ident unique id (default: no)"),
1335-
incremental_ignore_spans: bool = (false, parse_bool, [UNTRACKED],
1335+
incremental_ignore_spans: bool = (false, parse_bool, [TRACKED],
13361336
"ignore spans during ICH computation -- used for testing (default: no)"),
13371337
incremental_info: bool = (false, parse_bool, [UNTRACKED],
13381338
"print high-level information about incremental reuse (or the lack thereof) \
13391339
(default: no)"),
1340+
#[rustc_lint_opt_deny_field_access("use `Session::incremental_relative_spans` instead of this field")]
13401341
incremental_relative_spans: bool = (false, parse_bool, [TRACKED],
13411342
"hash spans relative to their parent item for incr. comp. (default: no)"),
13421343
incremental_verify_ich: bool = (false, parse_bool, [UNTRACKED],

compiler/rustc_span/src/hygiene.rs

+4
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,10 @@ fn assert_default_hashing_controls<CTX: HashStableContext>(ctx: &CTX, msg: &str)
104104
// `-Z incremental-ignore-spans` option. Normally, this option is disabled,
105105
// which will cause us to require that this method always be called with `Span` hashing
106106
// enabled.
107+
//
108+
// Span hashing can also be disabled without `-Z incremental-ignore-spans`.
109+
// This is the case for instance when building a hash for name mangling.
110+
// Such configuration must not be used for metadata.
107111
HashingControls { hash_spans }
108112
if hash_spans == !ctx.unstable_opts_incremental_ignore_spans() => {}
109113
other => panic!("Attempted hashing of {msg} with non-default HashingControls: {:?}", other),

0 commit comments

Comments
 (0)