Skip to content

Commit e13e1e4

Browse files
committed
fix(debuginfo): handle false positives in overflow check
1 parent 61cb1e9 commit e13e1e4

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)