diff options
| author | Laurențiu Nicola <lnicola@users.noreply.github.com> | 2024-11-25 19:24:00 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-11-25 19:24:00 +0000 |
| commit | bbce06e92d517d264ae5a60da7e72b98fdd865d6 (patch) | |
| tree | 03c46ceca92d4f21c3c28abd2f03b3f0aa7bc3e3 /src/tools | |
| parent | b250e0f04397db4da776241dbc2463d574b495b7 (diff) | |
| parent | b4a23bb3fce5b661b6071deb0745a46f0b057868 (diff) | |
| download | rust-bbce06e92d517d264ae5a60da7e72b98fdd865d6.tar.gz rust-bbce06e92d517d264ae5a60da7e72b98fdd865d6.zip | |
Merge pull request #18559 from ChayimFriedman2/recur-unsized
fix: Fix a stack overflow when computing the sizedness of a struct that includes itself as the tail field
Diffstat (limited to 'src/tools')
| -rw-r--r-- | src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs | 36 | ||||
| -rw-r--r-- | src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs | 21 |
2 files changed, 47 insertions, 10 deletions
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs index e4881d75201..54aa18ce207 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs @@ -916,6 +916,32 @@ impl<'a> InferenceTable<'a> { /// Check if given type is `Sized` or not pub(crate) fn is_sized(&mut self, ty: &Ty) -> bool { + let mut ty = ty.clone(); + { + let mut structs = SmallVec::<[_; 8]>::new(); + // Must use a loop here and not recursion because otherwise users will conduct completely + // artificial examples of structs that have themselves as the tail field and complain r-a crashes. + while let Some((AdtId::StructId(id), subst)) = ty.as_adt() { + let struct_data = self.db.struct_data(id); + if let Some((last_field, _)) = struct_data.variant_data.fields().iter().next_back() + { + let last_field_ty = self.db.field_types(id.into())[last_field] + .clone() + .substitute(Interner, subst); + if structs.contains(&ty) { + // A struct recursively contains itself as a tail field somewhere. + return true; // Don't overload the users with too many errors. + } + structs.push(ty); + // Structs can have DST as its last field and such cases are not handled + // as unsized by the chalk, so we do this manually. + ty = last_field_ty; + } else { + break; + }; + } + } + // Early return for some obvious types if matches!( ty.kind(Interner), @@ -930,16 +956,6 @@ impl<'a> InferenceTable<'a> { return true; } - if let Some((AdtId::StructId(id), subst)) = ty.as_adt() { - let struct_data = self.db.struct_data(id); - if let Some((last_field, _)) = struct_data.variant_data.fields().iter().last() { - let last_field_ty = - self.db.field_types(id.into())[last_field].clone().substitute(Interner, subst); - // Structs can have DST as its last field and such cases are not handled - // as unsized by the chalk, so we do this manually - return self.is_sized(&last_field_ty); - } - } let Some(sized) = self .db .lang_item(self.trait_env.krate, LangItem::Sized) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs index 9b982a124e7..624148cab20 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs @@ -4790,3 +4790,24 @@ fn allowed3(baz: impl Baz<Assoc = Qux<impl Foo>>) {} "#]], ) } + +#[test] +fn recursive_tail_sized() { + check_infer( + r#" +struct WeirdFoo(WeirdBar); +struct WeirdBar(WeirdFoo); + +fn bar(v: *const ()) { + let _ = v as *const WeirdFoo; +} + "#, + expect![[r#" + 62..63 'v': *const () + 76..113 '{ ...Foo; }': () + 86..87 '_': *const WeirdFoo + 90..91 'v': *const () + 90..110 'v as *...irdFoo': *const WeirdFoo + "#]], + ); +} |
