Skip to content

Commit 473cf1d

Browse files
Auto merge of #148863 - jdonszelmann:check-span-owners, r=<try>
Check span owners (span lowering) in debug builds and fix missing lowerings
2 parents 95aeb46 + 6eebed0 commit 473cf1d

File tree

8 files changed

+120
-3
lines changed

8 files changed

+120
-3
lines changed

‎compiler/rustc_ast_lowering/src/asm.rs‎

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -496,7 +496,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
496496
}
497497

498498
let operands = self.arena.alloc_from_iter(operands);
499-
let template = self.arena.alloc_from_iter(asm.template.iter().cloned());
499+
let template = self
500+
.arena
501+
.alloc_from_iter(asm.template.iter().map(|i| self.lower_inline_asm_template_piece(i)));
500502
let template_strs = self.arena.alloc_from_iter(
501503
asm.template_strs
502504
.iter()
@@ -514,4 +516,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
514516
};
515517
self.arena.alloc(hir_asm)
516518
}
519+
520+
fn lower_inline_asm_template_piece(
521+
&self,
522+
template: &InlineAsmTemplatePiece,
523+
) -> InlineAsmTemplatePiece {
524+
match template {
525+
InlineAsmTemplatePiece::String(cow) => InlineAsmTemplatePiece::String(cow.clone()),
526+
InlineAsmTemplatePiece::Placeholder { operand_idx, modifier, span } => {
527+
InlineAsmTemplatePiece::Placeholder {
528+
operand_idx: *operand_idx,
529+
modifier: *modifier,
530+
span: self.lower_span(*span),
531+
}
532+
}
533+
}
534+
}
517535
}

‎compiler/rustc_ast_lowering/src/item.rs‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
555555
// own its own names, we have to adjust the owner before
556556
// lowering the rest of the import.
557557
self.with_hir_id_owner(id, |this| {
558+
let vis_span = this.lower_span(vis_span);
559+
558560
// `prefix` is lowered multiple times, but in different HIR owners.
559561
// So each segment gets renewed `HirId` with the same
560562
// `ItemLocalId` and the new owner. (See `lower_node_id`)
@@ -570,6 +572,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
570572
span: this.lower_span(use_tree.span),
571573
has_delayed_lints: !this.delayed_lints.is_empty(),
572574
};
575+
573576
hir::OwnerNode::Item(this.arena.alloc(item))
574577
});
575578
}

‎compiler/rustc_ast_lowering/src/lib.rs‎

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838
use std::sync::Arc;
3939

4040
use rustc_ast::node_id::NodeMap;
41+
use rustc_ast::token::Token;
42+
use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree};
4143
use rustc_ast::{self as ast, *};
4244
use rustc_attr_parsing::{AttributeParser, Late, OmitDoc};
4345
use rustc_data_structures::fingerprint::Fingerprint;
@@ -1007,8 +1009,36 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
10071009
}
10081010
}
10091011

1010-
fn lower_delim_args(&self, args: &DelimArgs) -> DelimArgs {
1011-
args.clone()
1012+
fn lower_token_tree(&self, tt: &TokenTree) -> TokenTree {
1013+
match tt {
1014+
TokenTree::Token(Token { kind, span }, spacing) => {
1015+
TokenTree::Token(Token { kind: *kind, span: self.lower_span(*span) }, *spacing)
1016+
}
1017+
TokenTree::Delimited(delim_span, delim_spacing, delimiter, token_stream) => {
1018+
TokenTree::Delimited(
1019+
self.lower_delim_span(delim_span),
1020+
*delim_spacing,
1021+
*delimiter,
1022+
self.lower_token_stream(token_stream),
1023+
)
1024+
}
1025+
}
1026+
}
1027+
1028+
fn lower_token_stream(&self, ts: &TokenStream) -> TokenStream {
1029+
TokenStream::new(ts.iter().map(|i| self.lower_token_tree(i)).collect())
1030+
}
1031+
1032+
fn lower_delim_span(&self, DelimSpan { open, close }: &DelimSpan) -> DelimSpan {
1033+
DelimSpan { open: self.lower_span(*open), close: self.lower_span(*close) }
1034+
}
1035+
1036+
fn lower_delim_args(&self, DelimArgs { dspan, delim, tokens }: &DelimArgs) -> DelimArgs {
1037+
DelimArgs {
1038+
dspan: self.lower_delim_span(dspan),
1039+
delim: *delim,
1040+
tokens: self.lower_token_stream(tokens),
1041+
}
10121042
}
10131043

10141044
/// Lower an associated item constraint.

‎compiler/rustc_hir/src/stable_hash_impls.rs‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
22
use rustc_span::def_id::DefPathHash;
3+
#[cfg(debug_assertions)]
4+
use rustc_span::def_id::LocalDefId;
35

46
use crate::HashIgnoredAttrId;
57
use crate::hir::{
@@ -13,6 +15,9 @@ use crate::lints::DelayedLints;
1315
/// instead of implementing everything in `rustc_middle`.
1416
pub trait HashStableContext: rustc_ast::HashStableContext + rustc_abi::HashStableContext {
1517
fn hash_attr_id(&mut self, id: &HashIgnoredAttrId, hasher: &mut StableHasher);
18+
19+
#[cfg(debug_assertions)]
20+
fn set_current_owner_node_defid(&mut self, local_def_id: Option<LocalDefId>);
1621
}
1722

1823
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: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
//! from various crates in no particular order.
33
44
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
5+
#[cfg(debug_assertions)]
6+
use rustc_hir::def_id::LocalDefId;
57
use rustc_hir::{self as hir, HashIgnoredAttrId};
68
use rustc_span::SourceFile;
79
use smallvec::SmallVec;
@@ -39,6 +41,15 @@ impl<'ctx> rustc_hir::HashStableContext for StableHashingContext<'ctx> {
3941
fn hash_attr_id(&mut self, _id: &HashIgnoredAttrId, _hasher: &mut StableHasher) {
4042
/* we don't hash HashIgnoredAttrId, we ignore them */
4143
}
44+
45+
#[cfg(debug_assertions)]
46+
fn set_current_owner_node_defid(&mut self, local_def_id: Option<LocalDefId>) {
47+
if local_def_id.is_some() && self.current_owner_node_did.is_some() {
48+
panic!("already in owner node");
49+
}
50+
51+
self.current_owner_node_did = local_def_id;
52+
}
4253
}
4354

4455
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)