about summary refs log tree commit diff
path: root/src/tools
diff options
context:
space:
mode:
authorLaurențiu Nicola <lnicola@users.noreply.github.com>2024-11-25 19:24:00 +0000
committerGitHub <noreply@github.com>2024-11-25 19:24:00 +0000
commitbbce06e92d517d264ae5a60da7e72b98fdd865d6 (patch)
tree03c46ceca92d4f21c3c28abd2f03b3f0aa7bc3e3 /src/tools
parentb250e0f04397db4da776241dbc2463d574b495b7 (diff)
parentb4a23bb3fce5b661b6071deb0745a46f0b057868 (diff)
downloadrust-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.rs36
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs21
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
+        "#]],
+    );
+}