Skip to content

Commit 2b6167d

Browse files
adwinwhitelcnr
authored andcommitted
EarlyBinder construction marks value as non-rigid
1 parent 5145758 commit 2b6167d

2 files changed

Lines changed: 186 additions & 1 deletion

File tree

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
use std::collections::hash_map::Entry;
2+
3+
use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext};
4+
use rustc_codegen_ssa::traits::*;
5+
use rustc_data_structures::fx::FxHashMap;
6+
use rustc_index::bit_set::DenseBitSet;
7+
use rustc_middle::mir::{Body, SourceScope};
8+
use rustc_middle::ty::layout::{FnAbiOf, HasTypingEnv};
9+
use rustc_middle::ty::{self, Instance};
10+
use rustc_session::config::DebugInfo;
11+
use rustc_span::{BytePos, DUMMY_SP, hygiene};
12+
13+
use super::metadata::file_metadata;
14+
use super::utils::DIB;
15+
use crate::common::CodegenCx;
16+
use crate::llvm;
17+
use crate::llvm::debuginfo::{DILocation, DIScope};
18+
19+
/// Produces DIScope DIEs for each MIR Scope which has variables defined in it.
20+
// FIXME(eddyb) almost all of this should be in `rustc_codegen_ssa::mir::debuginfo`.
21+
pub(crate) fn compute_mir_scopes<'ll, 'tcx>(
22+
cx: &CodegenCx<'ll, 'tcx>,
23+
instance: Instance<'tcx>,
24+
mir: &Body<'tcx>,
25+
debug_context: &mut FunctionDebugContext<'tcx, &'ll DIScope, &'ll DILocation>,
26+
) {
27+
// Find all scopes with variables defined in them.
28+
let variables = if cx.sess().opts.debuginfo == DebugInfo::Full {
29+
let mut vars = DenseBitSet::new_empty(mir.source_scopes.len());
30+
// FIXME(eddyb) take into account that arguments always have debuginfo,
31+
// irrespective of their name (assuming full debuginfo is enabled).
32+
// NOTE(eddyb) actually, on second thought, those are always in the
33+
// function scope, which always exists.
34+
for var_debug_info in &mir.var_debug_info {
35+
vars.insert(var_debug_info.source_info.scope);
36+
}
37+
Some(vars)
38+
} else {
39+
// Nothing to emit, of course.
40+
None
41+
};
42+
let mut instantiated = DenseBitSet::new_empty(mir.source_scopes.len());
43+
let mut discriminators = FxHashMap::default();
44+
// Instantiate all scopes.
45+
for scope in mir.source_scopes.indices() {
46+
make_mir_scope(
47+
cx,
48+
instance,
49+
mir,
50+
&variables,
51+
debug_context,
52+
&mut instantiated,
53+
&mut discriminators,
54+
scope,
55+
);
56+
}
57+
assert!(instantiated.count() == mir.source_scopes.len());
58+
}
59+
60+
fn make_mir_scope<'ll, 'tcx>(
61+
cx: &CodegenCx<'ll, 'tcx>,
62+
instance: Instance<'tcx>,
63+
mir: &Body<'tcx>,
64+
variables: &Option<DenseBitSet<SourceScope>>,
65+
debug_context: &mut FunctionDebugContext<'tcx, &'ll DIScope, &'ll DILocation>,
66+
instantiated: &mut DenseBitSet<SourceScope>,
67+
discriminators: &mut FxHashMap<BytePos, u32>,
68+
scope: SourceScope,
69+
) {
70+
if instantiated.contains(scope) {
71+
return;
72+
}
73+
74+
let scope_data = &mir.source_scopes[scope];
75+
let parent_scope = if let Some(parent) = scope_data.parent_scope {
76+
make_mir_scope(
77+
cx,
78+
instance,
79+
mir,
80+
variables,
81+
debug_context,
82+
instantiated,
83+
discriminators,
84+
parent,
85+
);
86+
debug_context.scopes[parent]
87+
} else {
88+
// The root is the function itself.
89+
let file = cx.sess().source_map().lookup_source_file(mir.span.lo());
90+
debug_context.scopes[scope] = DebugScope {
91+
file_start_pos: file.start_pos,
92+
file_end_pos: file.end_position(),
93+
..debug_context.scopes[scope]
94+
};
95+
instantiated.insert(scope);
96+
return;
97+
};
98+
99+
if let Some(vars) = variables
100+
&& !vars.contains(scope)
101+
&& scope_data.inlined.is_none()
102+
{
103+
// Do not create a DIScope if there are no variables defined in this
104+
// MIR `SourceScope`, and it's not `inlined`, to avoid debuginfo bloat.
105+
debug_context.scopes[scope] = parent_scope;
106+
instantiated.insert(scope);
107+
return;
108+
}
109+
110+
let loc = cx.lookup_debug_loc(scope_data.span.lo());
111+
let file_metadata = file_metadata(cx, &loc.file);
112+
113+
let dbg_scope = match scope_data.inlined {
114+
Some((callee, _)) => {
115+
// FIXME(eddyb) this would be `self.monomorphize(&callee)`
116+
// if this is moved to `rustc_codegen_ssa::mir::debuginfo`.
117+
let callee = cx.tcx.instantiate_and_normalize_erasing_regions(
118+
instance.args,
119+
cx.typing_env(),
120+
ty::EarlyBinder::bind(cx.tcx, callee),
121+
);
122+
debug_context.inlined_function_scopes.entry(callee).or_insert_with(|| {
123+
let callee_fn_abi = cx.fn_abi_of_instance(callee, ty::List::empty());
124+
cx.dbg_scope_fn(callee, callee_fn_abi, None)
125+
})
126+
}
127+
None => unsafe {
128+
llvm::LLVMDIBuilderCreateLexicalBlock(
129+
DIB(cx),
130+
parent_scope.dbg_scope,
131+
file_metadata,
132+
loc.line,
133+
loc.col,
134+
)
135+
},
136+
};
137+
138+
let inlined_at = scope_data.inlined.map(|(_, callsite_span)| {
139+
let callsite_span = hygiene::walk_chain_collapsed(callsite_span, mir.span);
140+
let callsite_scope = parent_scope.adjust_dbg_scope_for_span(cx, callsite_span);
141+
let loc = cx.dbg_loc(callsite_scope, parent_scope.inlined_at, callsite_span);
142+
143+
// NB: In order to produce proper debug info for variables (particularly
144+
// arguments) in multiply-inlined functions, LLVM expects to see a single
145+
// DILocalVariable with multiple different DILocations in the IR. While
146+
// the source information for each DILocation would be identical, their
147+
// inlinedAt attributes will be unique to the particular callsite.
148+
//
149+
// We generate DILocations here based on the callsite's location in the
150+
// source code. A single location in the source code usually can't
151+
// produce multiple distinct calls so this mostly works, until
152+
// macros get involved. A macro can generate multiple calls
153+
// at the same span, which breaks the assumption that we're going to
154+
// produce a unique DILocation for every scope we process here. We
155+
// have to explicitly add discriminators if we see inlines into the
156+
// same source code location.
157+
//
158+
// Note further that we can't key this hashtable on the span itself,
159+
// because these spans could have distinct SyntaxContexts. We have
160+
// to key on exactly what we're giving to LLVM.
161+
match discriminators.entry(callsite_span.lo()) {
162+
Entry::Occupied(mut o) => {
163+
*o.get_mut() += 1;
164+
// NB: We have to emit *something* here or we'll fail LLVM IR verification
165+
// in at least some circumstances (see issue #135322) so if the required
166+
// discriminant cannot be encoded fall back to the dummy location.
167+
unsafe { llvm::LLVMRustDILocationCloneWithBaseDiscriminator(loc, *o.get()) }
168+
.unwrap_or_else(|| {
169+
cx.dbg_loc(callsite_scope, parent_scope.inlined_at, DUMMY_SP)
170+
})
171+
}
172+
Entry::Vacant(v) => {
173+
v.insert(0);
174+
loc
175+
}
176+
}
177+
});
178+
179+
debug_context.scopes[scope] = DebugScope {
180+
dbg_scope,
181+
inlined_at: inlined_at.or(parent_scope.inlined_at),
182+
file_start_pos: loc.file.start_pos,
183+
file_end_pos: loc.file.end_position(),
184+
};
185+
instantiated.insert(scope);
186+
}

compiler/rustc_type_ir/src/binder.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,6 @@ generate!(
371371

372372
impl<I: Interner, T: TypeFoldable<I>> EarlyBinder<I, T> {
373373
pub fn bind(cx: I, value: T) -> EarlyBinder<I, T> {
374-
// Instantiation will require normalization.
375374
let value = ty::set_aliases_to_non_rigid(cx, value).skip_normalization();
376375
EarlyBinder { value, _tcx: PhantomData }
377376
}

0 commit comments

Comments
 (0)