Rollup merge of #145297 - adwinwhite:recursive-debuginfo, r=wesleywiser

fix(debuginfo): handle false positives in overflow check

Fixes rust-lang/rust#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````
This commit is contained in:
Jacob Pratt
2025-08-21 01:12:16 -04:00
committed by GitHub
2 changed files with 47 additions and 16 deletions

View File

@@ -276,7 +276,7 @@ pub(super) fn build_type_with_children<'ll, 'tcx>(
&& let ty::Adt(adt_def, args) = ty.kind()
{
let def_id = adt_def.did();
// If any sub type reference the original type definition and the sub type has a type
// If any child type references the original type definition and the child type has a type
// parameter that strictly contains the original parameter, the original type is a recursive
// type that can expanding indefinitely. Example,
// ```
@@ -285,21 +285,43 @@ pub(super) fn build_type_with_children<'ll, 'tcx>(
// Item(T),
// }
// ```
let is_expanding_recursive = adt_def.is_enum()
&& debug_context(cx).adt_stack.borrow().iter().any(|(parent_def_id, parent_args)| {
if def_id == *parent_def_id {
args.iter().zip(parent_args.iter()).any(|(arg, parent_arg)| {
if let (Some(arg), Some(parent_arg)) = (arg.as_type(), parent_arg.as_type())
{
arg != parent_arg && arg.contains(parent_arg)
} else {
false
}
})
} else {
false
}
});
let is_expanding_recursive = {
let stack = debug_context(cx).adt_stack.borrow();
stack
.iter()
.enumerate()
.rev()
.skip(1)
.filter(|(_, (ancestor_def_id, _))| def_id == *ancestor_def_id)
.any(|(ancestor_index, (_, ancestor_args))| {
args.iter()
.zip(ancestor_args.iter())
.filter_map(|(arg, ancestor_arg)| arg.as_type().zip(ancestor_arg.as_type()))
.any(|(arg, ancestor_arg)|
// Strictly contains.
(arg != ancestor_arg && arg.contains(ancestor_arg))
// Check all types between current and ancestor use the
// ancestor_arg.
// Otherwise, duplicate wrappers in normal recursive type may be
// regarded as expanding.
// ```
// struct Recursive {
// a: Box<Box<Recursive>>,
// }
// ```
// It can produce an ADT stack like this,
// - Box<Recursive>
// - Recursive
// - Box<Box<Recursive>>
&& stack[ancestor_index + 1..stack.len()].iter().all(
|(_, intermediate_args)|
intermediate_args
.iter()
.filter_map(|arg| arg.as_type())
.any(|mid_arg| mid_arg.contains(ancestor_arg))
))
})
};
if is_expanding_recursive {
// FIXME: indicate that this is an expanding recursive type in stub metadata?
return DINodeCreationResult::new(stub_info.metadata, false);