Skip to content

Commit 060666d

Browse files
committed
Address code review comments.
- Make `is_repr_nullable_ptr` freestanding again to avoid usage of ImproperCTypesVisitor in ClashingExternDeclarations (and don't accidentally revert the ParamEnv::reveal_all() fix from a week earlier) - Revise match condition for 1 Adt, 1 primitive - Generalise check for non-null type so that it would also work for ranges which exclude any single value (all bits set, for example) - Make is_repr_nullable_ptr return the representable type instead of just a boolean, to avoid adding an additional, independent "source of truth" about the FFI-compatibility of Option-like enums. Also, rename to `repr_nullable_ptr`.
1 parent 5e52edc commit 060666d

File tree

5 files changed

+202
-147
lines changed

5 files changed

+202
-147
lines changed

src/librustc_lint/builtin.rs

Lines changed: 46 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@
2020
//! If you define a new `LateLintPass`, you will also need to add it to the
2121
//! `late_lint_methods!` invocation in `lib.rs`.
2222
23-
use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
23+
use crate::{
24+
types::CItemKind, EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext,
25+
};
2426
use rustc_ast::ast::{self, Expr};
2527
use rustc_ast::attr::{self, HasAttrs};
2628
use rustc_ast::tokenstream::{TokenStream, TokenTree};
@@ -2144,7 +2146,13 @@ impl ClashingExternDeclarations {
21442146
/// Checks whether two types are structurally the same enough that the declarations shouldn't
21452147
/// clash. We need this so we don't emit a lint when two modules both declare an extern struct,
21462148
/// with the same members (as the declarations shouldn't clash).
2147-
fn structurally_same_type<'tcx>(cx: &LateContext<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
2149+
fn structurally_same_type<'tcx>(
2150+
cx: &LateContext<'tcx>,
2151+
a: Ty<'tcx>,
2152+
b: Ty<'tcx>,
2153+
ckind: CItemKind,
2154+
) -> bool {
2155+
debug!("structurally_same_type(cx, a = {:?}, b = {:?})", a, b);
21482156
let tcx = cx.tcx;
21492157
if a == b || rustc_middle::ty::TyS::same_type(a, b) {
21502158
// All nominally-same types are structurally same, too.
@@ -2156,29 +2164,30 @@ impl ClashingExternDeclarations {
21562164
let b_kind = &b.kind;
21572165

21582166
use rustc_target::abi::LayoutOf;
2159-
let compare_layouts = |a, b| {
2160-
let a_layout = &cx.layout_of(a).unwrap().layout.abi;
2161-
let b_layout = &cx.layout_of(b).unwrap().layout.abi;
2162-
let result = a_layout == b_layout;
2163-
result
2167+
let compare_layouts = |a, b| -> bool {
2168+
&cx.layout_of(a).unwrap().layout.abi == &cx.layout_of(b).unwrap().layout.abi
21642169
};
21652170

2171+
#[allow(rustc::usage_of_ty_tykind)]
2172+
let is_primitive_or_pointer =
2173+
|kind: &ty::TyKind<'_>| kind.is_primitive() || matches!(kind, RawPtr(..));
2174+
21662175
match (a_kind, b_kind) {
21672176
(Adt(..), Adt(..)) => compare_layouts(a, b),
21682177
(Array(a_ty, a_const), Array(b_ty, b_const)) => {
21692178
// For arrays, we also check the constness of the type.
21702179
a_const.val == b_const.val
2171-
&& Self::structurally_same_type(cx, a_const.ty, b_const.ty)
2172-
&& Self::structurally_same_type(cx, a_ty, b_ty)
2180+
&& Self::structurally_same_type(cx, a_const.ty, b_const.ty, ckind)
2181+
&& Self::structurally_same_type(cx, a_ty, b_ty, ckind)
21732182
}
2174-
(Slice(a_ty), Slice(b_ty)) => Self::structurally_same_type(cx, a_ty, b_ty),
2183+
(Slice(a_ty), Slice(b_ty)) => Self::structurally_same_type(cx, a_ty, b_ty, ckind),
21752184
(RawPtr(a_tymut), RawPtr(b_tymut)) => {
21762185
a_tymut.mutbl == a_tymut.mutbl
2177-
&& Self::structurally_same_type(cx, &a_tymut.ty, &b_tymut.ty)
2186+
&& Self::structurally_same_type(cx, &a_tymut.ty, &b_tymut.ty, ckind)
21782187
}
21792188
(Ref(_a_region, a_ty, a_mut), Ref(_b_region, b_ty, b_mut)) => {
21802189
// For structural sameness, we don't need the region to be same.
2181-
a_mut == b_mut && Self::structurally_same_type(cx, a_ty, b_ty)
2190+
a_mut == b_mut && Self::structurally_same_type(cx, a_ty, b_ty, ckind)
21822191
}
21832192
(FnDef(..), FnDef(..)) => {
21842193
let a_poly_sig = a.fn_sig(tcx);
@@ -2191,13 +2200,13 @@ impl ClashingExternDeclarations {
21912200
(a_sig.abi, a_sig.unsafety, a_sig.c_variadic)
21922201
== (b_sig.abi, b_sig.unsafety, b_sig.c_variadic)
21932202
&& a_sig.inputs().iter().eq_by(b_sig.inputs().iter(), |a, b| {
2194-
Self::structurally_same_type(cx, a, b)
2203+
Self::structurally_same_type(cx, a, b, ckind)
21952204
})
2196-
&& Self::structurally_same_type(cx, a_sig.output(), b_sig.output())
2205+
&& Self::structurally_same_type(cx, a_sig.output(), b_sig.output(), ckind)
21972206
}
21982207
(Tuple(a_substs), Tuple(b_substs)) => {
21992208
a_substs.types().eq_by(b_substs.types(), |a_ty, b_ty| {
2200-
Self::structurally_same_type(cx, a_ty, b_ty)
2209+
Self::structurally_same_type(cx, a_ty, b_ty, ckind)
22012210
})
22022211
}
22032212
// For these, it's not quite as easy to define structural-sameness quite so easily.
@@ -2210,58 +2219,27 @@ impl ClashingExternDeclarations {
22102219
| (GeneratorWitness(..), GeneratorWitness(..))
22112220
| (Projection(..), Projection(..))
22122221
| (Opaque(..), Opaque(..)) => false,
2222+
22132223
// These definitely should have been caught above.
22142224
(Bool, Bool) | (Char, Char) | (Never, Never) | (Str, Str) => unreachable!(),
22152225

2216-
// Disjoint kinds.
2217-
(_, _) => {
2218-
// First, check if the conversion is FFI-safe. This can happen if the type is an
2219-
// enum with a non-null field (see improper_ctypes).
2220-
let is_primitive_or_pointer =
2221-
|ty: Ty<'tcx>| ty.is_primitive() || matches!(ty.kind, RawPtr(..));
2222-
if (is_primitive_or_pointer(a) || is_primitive_or_pointer(b))
2223-
&& !(is_primitive_or_pointer(a) && is_primitive_or_pointer(b))
2224-
&& (matches!(a_kind, Adt(..)) || matches!(b_kind, Adt(..)))
2225-
/* ie, 1 adt and 1 primitive */
2226-
{
2227-
let (primitive_ty, adt_ty) =
2228-
if is_primitive_or_pointer(a) { (a, b) } else { (b, a) };
2229-
// First, check that the Adt is FFI-safe to use.
2230-
use crate::types::{ImproperCTypesMode, ImproperCTypesVisitor};
2231-
let vis =
2232-
ImproperCTypesVisitor { cx, mode: ImproperCTypesMode::Declarations };
2233-
2234-
if let Adt(def, substs) = adt_ty.kind {
2235-
let repr_nullable = vis.is_repr_nullable_ptr(adt_ty, def, substs);
2236-
if let Some(safe_ty) = repr_nullable {
2237-
let safe_ty_layout = &cx.layout_of(safe_ty).unwrap();
2238-
let primitive_ty_layout = &cx.layout_of(primitive_ty).unwrap();
2239-
2240-
use rustc_target::abi::Abi::*;
2241-
match (&safe_ty_layout.abi, &primitive_ty_layout.abi) {
2242-
(Scalar(safe), Scalar(primitive)) => {
2243-
// The two types are safe to convert between if `safe` is
2244-
// the non-zero version of `primitive`.
2245-
use std::ops::RangeInclusive;
2246-
2247-
let safe_range: &RangeInclusive<_> = &safe.valid_range;
2248-
let primitive_range: &RangeInclusive<_> =
2249-
&primitive.valid_range;
2250-
2251-
return primitive_range.end() == safe_range.end()
2252-
// This check works for both signed and unsigned types due to wraparound.
2253-
&& *safe_range.start() == 1
2254-
&& *primitive_range.start() == 0;
2255-
}
2256-
_ => {}
2257-
}
2258-
}
2259-
}
2226+
// An Adt and a primitive type. This can be FFI-safe is the ADT is an enum with a
2227+
// non-null field.
2228+
(Adt(..), other_kind) | (other_kind, Adt(..))
2229+
if is_primitive_or_pointer(other_kind) =>
2230+
{
2231+
let (primitive, adt) =
2232+
if is_primitive_or_pointer(&a.kind) { (a, b) } else { (b, a) };
2233+
if let Some(ty) = crate::types::repr_nullable_ptr(cx, adt, ckind) {
2234+
ty == primitive
2235+
} else {
2236+
compare_layouts(a, b)
22602237
}
2261-
// Otherwise, just compare the layouts. This may be underapproximate, but at
2262-
// the very least, will stop reads into uninitialised memory.
2263-
compare_layouts(a, b)
22642238
}
2239+
// Otherwise, just compare the layouts. This may fail to lint for some
2240+
// incompatible types, but at the very least, will stop reads into
2241+
// uninitialised memory.
2242+
_ => compare_layouts(a, b),
22652243
}
22662244
}
22672245
}
@@ -2282,7 +2260,12 @@ impl<'tcx> LateLintPass<'tcx> for ClashingExternDeclarations {
22822260
existing_hid, existing_decl_ty, this_fi.hir_id, this_decl_ty
22832261
);
22842262
// Check that the declarations match.
2285-
if !Self::structurally_same_type(cx, existing_decl_ty, this_decl_ty) {
2263+
if !Self::structurally_same_type(
2264+
cx,
2265+
existing_decl_ty,
2266+
this_decl_ty,
2267+
CItemKind::Declaration,
2268+
) {
22862269
let orig_fi = tcx.hir().expect_foreign_item(existing_hid);
22872270
let orig = Self::name_of_extern_decl(tcx, orig_fi);
22882271

0 commit comments

Comments
 (0)