Skip to content

Commit 517448d

Browse files
committed
check span owners in debug builds
1 parent 00426d6 commit 517448d

File tree

5 files changed

+63
-1
lines changed

5 files changed

+63
-1
lines changed

compiler/rustc_hir/src/stable_hash_impls.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
2-
use rustc_span::def_id::DefPathHash;
2+
use rustc_span::def_id::{DefPathHash, LocalDefId};
33

44
use crate::HashIgnoredAttrId;
55
use crate::hir::{
@@ -13,6 +13,8 @@ use crate::lints::DelayedLints;
1313
/// instead of implementing everything in `rustc_middle`.
1414
pub trait HashStableContext: rustc_ast::HashStableContext + rustc_abi::HashStableContext {
1515
fn hash_attr_id(&mut self, id: &HashIgnoredAttrId, hasher: &mut StableHasher);
16+
17+
fn set_current_owner_node_defid(&mut self, local_def_id: Option<LocalDefId>);
1618
}
1719

1820
impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for BodyId {

compiler/rustc_middle/src/hir/mod.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,12 +177,27 @@ impl<'tcx> TyCtxt<'tcx> {
177177
}
178178

179179
self.with_stable_hashing_context(|mut hcx| {
180+
// With debug assertions on, *while hashing*,
181+
// we will check whether spans properly set their parent to the current node's defid
182+
// For that we set the defid here to check against
183+
#[cfg(debug_assertions)]
184+
if self.sess.opts.incremental.is_some() && !matches!(node, OwnerNode::Synthetic) {
185+
hcx.set_current_owner_node_defid(Some(node.def_id().def_id));
186+
}
187+
180188
let mut stable_hasher = StableHasher::new();
181189
node.hash_stable(&mut hcx, &mut stable_hasher);
182190
// Bodies are stored out of line, so we need to pull them explicitly in the hash.
183191
bodies.hash_stable(&mut hcx, &mut stable_hasher);
184192
let h1 = stable_hasher.finish();
185193

194+
// At the start of hashing an owner node we set this to the node's defid.
195+
// We clear it again here, ending checking of spans.
196+
#[cfg(debug_assertions)]
197+
if self.sess.opts.incremental.is_some() {
198+
hcx.set_current_owner_node_defid(None);
199+
}
200+
186201
let mut stable_hasher = StableHasher::new();
187202
attrs.hash_stable(&mut hcx, &mut stable_hasher);
188203

compiler/rustc_query_system/src/ich/hcx.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ pub struct StableHashingContext<'a> {
2121
// The value of `-Z incremental-ignore-spans`.
2222
// This field should only be used by `unstable_opts_incremental_ignore_span`
2323
incremental_ignore_spans: bool,
24+
25+
#[cfg(debug_assertions)]
26+
pub(crate) current_owner_node_did: Option<LocalDefId>,
27+
2428
// Very often, we are hashing something that does not need the
2529
// `CachingSourceMapView`, so we initialize it lazily.
2630
raw_source_map: &'a SourceMap,
@@ -36,6 +40,8 @@ impl<'a> StableHashingContext<'a> {
3640
StableHashingContext {
3741
untracked,
3842
incremental_ignore_spans: sess.opts.unstable_opts.incremental_ignore_spans,
43+
#[cfg(debug_assertions)]
44+
current_owner_node_did: None,
3945
caching_source_map: None,
4046
raw_source_map: sess.source_map(),
4147
hashing_controls: HashingControls { hash_spans: hash_spans_initial },
@@ -126,6 +132,26 @@ impl<'a> rustc_span::HashStableContext for StableHashingContext<'a> {
126132
fn hashing_controls(&self) -> HashingControls {
127133
self.hashing_controls.clone()
128134
}
135+
136+
#[cfg(debug_assertions)]
137+
fn validate_span_parent(&self, span: Span) {
138+
// If we're hashing an owner node right now...
139+
let Some(current_owner_node_did) = self.current_owner_node_did else {
140+
return;
141+
};
142+
143+
// we don't care about the dummy span
144+
if span.is_dummy() {
145+
return;
146+
}
147+
148+
// then the parent must be set and match that defid.
149+
assert!(
150+
span.parent().is_some_and(|i| i == current_owner_node_did),
151+
"Expected span to be lowered. Lowered spans have their parent set to their enclosing owner node. However, contained in the owner node with defid={current_owner_node_did:?} a span={span:?} was found whose parent is {:?}.",
152+
span.parent()
153+
)
154+
}
129155
}
130156

131157
impl<'a> rustc_session::HashStableContext for StableHashingContext<'a> {}

compiler/rustc_query_system/src/ich/impls_syntax.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
//! from various crates in no particular order.
33
44
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
5+
use rustc_hir::def_id::LocalDefId;
56
use rustc_hir::{self as hir, HashIgnoredAttrId};
67
use rustc_span::SourceFile;
78
use smallvec::SmallVec;
@@ -39,6 +40,15 @@ impl<'ctx> rustc_hir::HashStableContext for StableHashingContext<'ctx> {
3940
fn hash_attr_id(&mut self, _id: &HashIgnoredAttrId, _hasher: &mut StableHasher) {
4041
/* we don't hash HashIgnoredAttrId, we ignore them */
4142
}
43+
44+
#[cfg(debug_assertions)]
45+
fn set_current_owner_node_defid(&mut self, local_def_id: Option<LocalDefId>) {
46+
if local_def_id.is_some() && self.current_owner_node_did.is_some() {
47+
panic!("already in owner node");
48+
}
49+
50+
self.current_owner_node_did = local_def_id;
51+
}
4252
}
4353

4454
impl<'a> HashStable<StableHashingContext<'a>> for SourceFile {

compiler/rustc_span/src/lib.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2634,6 +2634,9 @@ pub trait HashStableContext {
26342634
span: &SpanData,
26352635
) -> Option<(StableSourceFileId, usize, BytePos, usize, BytePos)>;
26362636
fn hashing_controls(&self) -> HashingControls;
2637+
2638+
#[cfg(debug_assertions)]
2639+
fn validate_span_parent(&self, span: Span);
26372640
}
26382641

26392642
impl<CTX> HashStable<CTX> for Span
@@ -2663,6 +2666,12 @@ where
26632666
span.ctxt.hash_stable(ctx, hasher);
26642667
span.parent.hash_stable(ctx, hasher);
26652668

2669+
// check whether the span is lowered correctly when hashing
2670+
#[cfg(debug_assertions)]
2671+
{
2672+
ctx.validate_span_parent(*self);
2673+
}
2674+
26662675
if span.is_dummy() {
26672676
Hash::hash(&TAG_INVALID_SPAN, hasher);
26682677
return;

0 commit comments

Comments
 (0)