Skip to content

Commit 537d5f4

Browse files
authored
Rollup merge of #145297 - adwinwhite:recursive-debuginfo, r=wesleywiser
fix(debuginfo): handle false positives in overflow check Fixes #144636. Duplicate wrappers and normal recursive types can lead to false positives. ```rust struct Recursive { a: Box<Box<Recursive>>, } ``` The ADT stack can be: - `Box<Recursive>` - `Recursive` - `Box<Box<Recursive>>` (`Box` now detected as expanding) We can filter them out by tracing the generic arg back through the stack, as true expanding recursive types must have their expanding arg used as generic arg throughout. r? ````@wesleywiser````
2 parents b0dd772 + e13e1e4 commit 537d5f4

File tree

2 files changed

+47
-16
lines changed

2 files changed

+47
-16
lines changed

compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ pub(super) fn build_type_with_children<'ll, 'tcx>(
276276
&& let ty::Adt(adt_def, args) = ty.kind()
277277
{
278278
let def_id = adt_def.did();
279-
// If any sub type reference the original type definition and the sub type has a type
279+
// If any child type references the original type definition and the child type has a type
280280
// parameter that strictly contains the original parameter, the original type is a recursive
281281
// type that can expanding indefinitely. Example,
282282
// ```
@@ -285,21 +285,43 @@ pub(super) fn build_type_with_children<'ll, 'tcx>(
285285
// Item(T),
286286
// }
287287
// ```
288-
let is_expanding_recursive = adt_def.is_enum()
289-
&& debug_context(cx).adt_stack.borrow().iter().any(|(parent_def_id, parent_args)| {
290-
if def_id == *parent_def_id {
291-
args.iter().zip(parent_args.iter()).any(|(arg, parent_arg)| {
292-
if let (Some(arg), Some(parent_arg)) = (arg.as_type(), parent_arg.as_type())
293-
{
294-
arg != parent_arg && arg.contains(parent_arg)
295-
} else {
296-
false
297-
}
298-
})
299-
} else {
300-
false
301-
}
302-
});
288+
let is_expanding_recursive = {
289+
let stack = debug_context(cx).adt_stack.borrow();
290+
stack
291+
.iter()
292+
.enumerate()
293+
.rev()
294+
.skip(1)
295+
.filter(|(_, (ancestor_def_id, _))| def_id == *ancestor_def_id)
296+
.any(|(ancestor_index, (_, ancestor_args))| {
297+
args.iter()
298+
.zip(ancestor_args.iter())
299+
.filter_map(|(arg, ancestor_arg)| arg.as_type().zip(ancestor_arg.as_type()))
300+
.any(|(arg, ancestor_arg)|
301+
// Strictly contains.
302+
(arg != ancestor_arg && arg.contains(ancestor_arg))
303+
// Check all types between current and ancestor use the
304+
// ancestor_arg.
305+
// Otherwise, duplicate wrappers in normal recursive type may be
306+
// regarded as expanding.
307+
// ```
308+
// struct Recursive {
309+
// a: Box<Box<Recursive>>,
310+
// }
311+
// ```
312+
// It can produce an ADT stack like this,
313+
// - Box<Recursive>
314+
// - Recursive
315+
// - Box<Box<Recursive>>
316+
&& stack[ancestor_index + 1..stack.len()].iter().all(
317+
|(_, intermediate_args)|
318+
intermediate_args
319+
.iter()
320+
.filter_map(|arg| arg.as_type())
321+
.any(|mid_arg| mid_arg.contains(ancestor_arg))
322+
))
323+
})
324+
};
303325
if is_expanding_recursive {
304326
// FIXME: indicate that this is an expanding recursive type in stub metadata?
305327
return DINodeCreationResult::new(stub_info.metadata, false);

tests/debuginfo/recursive-struct.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262

6363
use self::Opt::{Empty, Val};
6464
use std::boxed::Box as B;
65+
use std::marker::PhantomData;
6566

6667
enum Opt<T> {
6768
Empty,
@@ -98,6 +99,11 @@ struct LongCycleWithAnonymousTypes {
9899
value: usize,
99100
}
100101

102+
struct Expanding<T> {
103+
a: PhantomData<T>,
104+
b: *const Expanding<(T, T)>,
105+
}
106+
101107
// This test case makes sure that recursive structs are properly described. The Node structs are
102108
// generic so that we can have a new type (that newly needs to be described) for the different
103109
// cases. The potential problem with recursive types is that the DI generation algorithm gets
@@ -205,6 +211,9 @@ fn main() {
205211
value: 30
206212
})))));
207213

214+
// This type can generate new instances infinitely if not handled properly.
215+
std::hint::black_box(Expanding::<()> { a: PhantomData, b: std::ptr::null() });
216+
208217
zzz(); // #break
209218
}
210219

0 commit comments

Comments
 (0)