about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-08-26 20:31:44 +0000
committerbors <bors@rust-lang.org>2020-08-26 20:31:44 +0000
commit2d8a3b9181f41d3af9b9f016c5d73b2553e344bf (patch)
treee165cb7eae6fe81601f57b91f8672d1866ec9743
parent48717b6f3ce661d2a0d64f7bdfdfb5fd3484ee5b (diff)
parent8c0128bb02ef528588777bda1e818e72749a7006 (diff)
downloadrust-2d8a3b9181f41d3af9b9f016c5d73b2553e344bf.tar.gz
rust-2d8a3b9181f41d3af9b9f016c5d73b2553e344bf.zip
Auto merge of #75944 - jumbatm:issue-75924-clashing-extern-decl-ice, r=spastorino
Fix ICE on unwrap of unknown layout in ClashingExternDeclarations.

Fixes #75924.
-rw-r--r--src/librustc_lint/builtin.rs34
-rw-r--r--src/test/ui/lint/clashing-extern-fn.rs23
2 files changed, 47 insertions, 10 deletions
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index b337bf0a3f9..4bcf31ef0bf 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -40,7 +40,7 @@ use rustc_hir::{ForeignItemKind, GenericParamKind, PatKind};
 use rustc_hir::{HirId, HirIdSet, Node};
 use rustc_middle::lint::LintDiagnosticBuilder;
 use rustc_middle::ty::subst::{GenericArgKind, Subst};
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, layout::LayoutError, Ty, TyCtxt};
 use rustc_session::lint::FutureIncompatibleInfo;
 use rustc_session::Session;
 use rustc_span::edition::Edition;
@@ -2177,11 +2177,17 @@ impl ClashingExternDeclarations {
                 let a_kind = &a.kind;
                 let b_kind = &b.kind;
 
-                let compare_layouts = |a, b| -> bool {
-                    let a_layout = &cx.layout_of(a).unwrap().layout.abi;
-                    let b_layout = &cx.layout_of(b).unwrap().layout.abi;
-                    debug!("{:?} == {:?} = {}", a_layout, b_layout, a_layout == b_layout);
-                    a_layout == b_layout
+                let compare_layouts = |a, b| -> Result<bool, LayoutError<'tcx>> {
+                    debug!("compare_layouts({:?}, {:?})", a, b);
+                    let a_layout = &cx.layout_of(a)?.layout.abi;
+                    let b_layout = &cx.layout_of(b)?.layout.abi;
+                    debug!(
+                        "comparing layouts: {:?} == {:?} = {}",
+                        a_layout,
+                        b_layout,
+                        a_layout == b_layout
+                    );
+                    Ok(a_layout == b_layout)
                 };
 
                 #[allow(rustc::usage_of_ty_tykind)]
@@ -2196,11 +2202,19 @@ impl ClashingExternDeclarations {
                             let b = b.subst(cx.tcx, b_substs);
                             debug!("Comparing {:?} and {:?}", a, b);
 
+                            // We can immediately rule out these types as structurally same if
+                            // their layouts differ.
+                            match compare_layouts(a, b) {
+                                Ok(false) => return false,
+                                _ => (), // otherwise, continue onto the full, fields comparison
+                            }
+
                             // Grab a flattened representation of all fields.
                             let a_fields = a_def.variants.iter().flat_map(|v| v.fields.iter());
                             let b_fields = b_def.variants.iter().flat_map(|v| v.fields.iter());
-                            compare_layouts(a, b)
-                            && a_fields.eq_by(
+
+                            // Perform a structural comparison for each field.
+                            a_fields.eq_by(
                                 b_fields,
                                 |&ty::FieldDef { did: a_did, .. },
                                  &ty::FieldDef { did: b_did, .. }| {
@@ -2287,13 +2301,13 @@ impl ClashingExternDeclarations {
                             if let Some(ty) = crate::types::repr_nullable_ptr(cx, adt, ckind) {
                                 ty == primitive
                             } else {
-                                compare_layouts(a, b)
+                                compare_layouts(a, b).unwrap_or(false)
                             }
                         }
                         // Otherwise, just compare the layouts. This may fail to lint for some
                         // incompatible types, but at the very least, will stop reads into
                         // uninitialised memory.
-                        _ => compare_layouts(a, b),
+                        _ => compare_layouts(a, b).unwrap_or(false),
                     }
                 })
             }
diff --git a/src/test/ui/lint/clashing-extern-fn.rs b/src/test/ui/lint/clashing-extern-fn.rs
index d6ac7ccccc7..44cef19b0d3 100644
--- a/src/test/ui/lint/clashing-extern-fn.rs
+++ b/src/test/ui/lint/clashing-extern-fn.rs
@@ -285,3 +285,26 @@ mod null_optimised_enums {
         }
     }
 }
+
+#[allow(improper_ctypes)]
+mod unknown_layout {
+    mod a {
+        extern "C" {
+            pub fn generic(l: Link<u32>);
+        }
+        pub struct Link<T> {
+            pub item: T,
+            pub next: *const Link<T>,
+        }
+    }
+
+    mod b {
+        extern "C" {
+            pub fn generic(l: Link<u32>);
+        }
+        pub struct Link<T> {
+            pub item: T,
+            pub next: *const Link<T>,
+        }
+    }
+}