Skip to content

Commit 2d8a3b9

Browse files
committed
Auto merge of rust-lang#75944 - jumbatm:issue-75924-clashing-extern-decl-ice, r=spastorino
Fix ICE on unwrap of unknown layout in ClashingExternDeclarations. Fixes rust-lang#75924.
2 parents 48717b6 + 8c0128b commit 2d8a3b9

File tree

2 files changed

+47
-10
lines changed

2 files changed

+47
-10
lines changed

src/librustc_lint/builtin.rs

+24-10
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ use rustc_hir::{ForeignItemKind, GenericParamKind, PatKind};
4040
use rustc_hir::{HirId, HirIdSet, Node};
4141
use rustc_middle::lint::LintDiagnosticBuilder;
4242
use rustc_middle::ty::subst::{GenericArgKind, Subst};
43-
use rustc_middle::ty::{self, Ty, TyCtxt};
43+
use rustc_middle::ty::{self, layout::LayoutError, Ty, TyCtxt};
4444
use rustc_session::lint::FutureIncompatibleInfo;
4545
use rustc_session::Session;
4646
use rustc_span::edition::Edition;
@@ -2177,11 +2177,17 @@ impl ClashingExternDeclarations {
21772177
let a_kind = &a.kind;
21782178
let b_kind = &b.kind;
21792179

2180-
let compare_layouts = |a, b| -> bool {
2181-
let a_layout = &cx.layout_of(a).unwrap().layout.abi;
2182-
let b_layout = &cx.layout_of(b).unwrap().layout.abi;
2183-
debug!("{:?} == {:?} = {}", a_layout, b_layout, a_layout == b_layout);
2184-
a_layout == b_layout
2180+
let compare_layouts = |a, b| -> Result<bool, LayoutError<'tcx>> {
2181+
debug!("compare_layouts({:?}, {:?})", a, b);
2182+
let a_layout = &cx.layout_of(a)?.layout.abi;
2183+
let b_layout = &cx.layout_of(b)?.layout.abi;
2184+
debug!(
2185+
"comparing layouts: {:?} == {:?} = {}",
2186+
a_layout,
2187+
b_layout,
2188+
a_layout == b_layout
2189+
);
2190+
Ok(a_layout == b_layout)
21852191
};
21862192

21872193
#[allow(rustc::usage_of_ty_tykind)]
@@ -2196,11 +2202,19 @@ impl ClashingExternDeclarations {
21962202
let b = b.subst(cx.tcx, b_substs);
21972203
debug!("Comparing {:?} and {:?}", a, b);
21982204

2205+
// We can immediately rule out these types as structurally same if
2206+
// their layouts differ.
2207+
match compare_layouts(a, b) {
2208+
Ok(false) => return false,
2209+
_ => (), // otherwise, continue onto the full, fields comparison
2210+
}
2211+
21992212
// Grab a flattened representation of all fields.
22002213
let a_fields = a_def.variants.iter().flat_map(|v| v.fields.iter());
22012214
let b_fields = b_def.variants.iter().flat_map(|v| v.fields.iter());
2202-
compare_layouts(a, b)
2203-
&& a_fields.eq_by(
2215+
2216+
// Perform a structural comparison for each field.
2217+
a_fields.eq_by(
22042218
b_fields,
22052219
|&ty::FieldDef { did: a_did, .. },
22062220
&ty::FieldDef { did: b_did, .. }| {
@@ -2287,13 +2301,13 @@ impl ClashingExternDeclarations {
22872301
if let Some(ty) = crate::types::repr_nullable_ptr(cx, adt, ckind) {
22882302
ty == primitive
22892303
} else {
2290-
compare_layouts(a, b)
2304+
compare_layouts(a, b).unwrap_or(false)
22912305
}
22922306
}
22932307
// Otherwise, just compare the layouts. This may fail to lint for some
22942308
// incompatible types, but at the very least, will stop reads into
22952309
// uninitialised memory.
2296-
_ => compare_layouts(a, b),
2310+
_ => compare_layouts(a, b).unwrap_or(false),
22972311
}
22982312
})
22992313
}

src/test/ui/lint/clashing-extern-fn.rs

+23
Original file line numberDiff line numberDiff line change
@@ -285,3 +285,26 @@ mod null_optimised_enums {
285285
}
286286
}
287287
}
288+
289+
#[allow(improper_ctypes)]
290+
mod unknown_layout {
291+
mod a {
292+
extern "C" {
293+
pub fn generic(l: Link<u32>);
294+
}
295+
pub struct Link<T> {
296+
pub item: T,
297+
pub next: *const Link<T>,
298+
}
299+
}
300+
301+
mod b {
302+
extern "C" {
303+
pub fn generic(l: Link<u32>);
304+
}
305+
pub struct Link<T> {
306+
pub item: T,
307+
pub next: *const Link<T>,
308+
}
309+
}
310+
}

0 commit comments

Comments
 (0)