1use rustc_abi::FIRST_VARIANT;
2use rustc_data_structures::unord::{UnordMap, UnordSet};
3use rustc_hiras hir;
4use rustc_hir::def::DefKind;
5use rustc_hir::find_attr;
6use rustc_middle::query::Providers;
7use rustc_middle::ty::{self, AdtDef, Instance, Ty, TyCtxt};
8use rustc_session::declare_lint;
9use rustc_span::{Span, Symbol};
10use tracing::{debug, instrument};
1112use crate::diagnostics::{BuiltinClashingExtern, BuiltinClashingExternSub};
13use crate::{LintVec, types};
1415pub(crate) fn provide(providers: &mut Providers) {
16*providers = Providers { clashing_extern_declarations, ..*providers };
17}
1819pub(crate) fn lint_vec() -> LintVec {
20::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[CLASHING_EXTERN_DECLARATIONS]))vec![CLASHING_EXTERN_DECLARATIONS]21}
2223fn clashing_extern_declarations(tcx: TyCtxt<'_>, (): ()) {
24let mut lint = ClashingExternDeclarations::new();
25for id in tcx.hir_crate_items(()).foreign_items() {
26 lint.check_foreign_item(tcx, id);
27 }
28}
2930#[doc =
r" The `clashing_extern_declarations` lint detects when an `extern fn`"]
#[doc = r" has been declared with the same name but different types."]
#[doc = r""]
#[doc = r" ### Example"]
#[doc = r""]
#[doc = r" ```rust"]
#[doc = r" mod m {"]
#[doc = r#" unsafe extern "C" {"#]
#[doc = r" fn foo();"]
#[doc = r" }"]
#[doc = r" }"]
#[doc = r""]
#[doc = r#" unsafe extern "C" {"#]
#[doc = r" fn foo(_: u32);"]
#[doc = r" }"]
#[doc = r" ```"]
#[doc = r""]
#[doc = r" {{produces}}"]
#[doc = r""]
#[doc = r" ### Explanation"]
#[doc = r""]
#[doc = r" Because two symbols of the same name cannot be resolved to two"]
#[doc =
r" different functions at link time, and one function cannot possibly"]
#[doc =
r" have two types, a clashing extern declaration is almost certainly a"]
#[doc =
r" mistake. Check to make sure that the `extern` definitions are correct"]
#[doc =
r" and equivalent, and possibly consider unifying them in one location."]
#[doc = r""]
#[doc = r" This lint does not run between crates because a project may have"]
#[doc =
r" dependencies which both rely on the same extern function, but declare"]
#[doc =
r" it in a different (but valid) way. For example, they may both declare"]
#[doc =
r" an opaque type for one or more of the arguments (which would end up"]
#[doc = r" distinct types), or use types that are valid conversions in the"]
#[doc =
r" language the `extern fn` is defined in. In these cases, the compiler"]
#[doc = r" can't say that the clashing declaration is incorrect."]
pub static CLASHING_EXTERN_DECLARATIONS: &::rustc_lint_defs::Lint =
&::rustc_lint_defs::Lint {
name: "CLASHING_EXTERN_DECLARATIONS",
default_level: ::rustc_lint_defs::Warn,
desc: "detects when an extern fn has been declared with the same name but different types",
is_externally_loaded: false,
..::rustc_lint_defs::Lint::default_fields_for_macro()
};declare_lint! {
31/// The `clashing_extern_declarations` lint detects when an `extern fn`
32 /// has been declared with the same name but different types.
33 ///
34 /// ### Example
35 ///
36 /// ```rust
37 /// mod m {
38 /// unsafe extern "C" {
39 /// fn foo();
40 /// }
41 /// }
42 ///
43 /// unsafe extern "C" {
44 /// fn foo(_: u32);
45 /// }
46 /// ```
47 ///
48 /// {{produces}}
49 ///
50 /// ### Explanation
51 ///
52 /// Because two symbols of the same name cannot be resolved to two
53 /// different functions at link time, and one function cannot possibly
54 /// have two types, a clashing extern declaration is almost certainly a
55 /// mistake. Check to make sure that the `extern` definitions are correct
56 /// and equivalent, and possibly consider unifying them in one location.
57 ///
58 /// This lint does not run between crates because a project may have
59 /// dependencies which both rely on the same extern function, but declare
60 /// it in a different (but valid) way. For example, they may both declare
61 /// an opaque type for one or more of the arguments (which would end up
62 /// distinct types), or use types that are valid conversions in the
63 /// language the `extern fn` is defined in. In these cases, the compiler
64 /// can't say that the clashing declaration is incorrect.
65pub CLASHING_EXTERN_DECLARATIONS,
66 Warn,
67"detects when an extern fn has been declared with the same name but different types"
68}6970struct ClashingExternDeclarations {
71/// Map of function symbol name to the first-seen hir id for that symbol name.. If seen_decls
72 /// contains an entry for key K, it means a symbol with name K has been seen by this lint and
73 /// the symbol should be reported as a clashing declaration.
74// FIXME: Technically, we could just store a &'tcx str here without issue; however, the
75 // `impl_lint_pass` macro doesn't currently support lints parametric over a lifetime.
76seen_decls: UnordMap<Symbol, hir::OwnerId>,
77}
7879/// Differentiate between whether the name for an extern decl came from the link_name attribute or
80/// just from declaration itself. This is important because we don't want to report clashes on
81/// symbol name if they don't actually clash because one or the other links against a symbol with a
82/// different name.
83enum SymbolName {
84/// The name of the symbol + the span of the annotation which introduced the link name.
85Link(Symbol, Span),
86/// No link name, so just the name of the symbol.
87Normal(Symbol),
88}
8990impl SymbolName {
91fn get_name(&self) -> Symbol {
92match self {
93 SymbolName::Link(s, _) | SymbolName::Normal(s) => *s,
94 }
95 }
96}
9798impl ClashingExternDeclarations {
99pub(crate) fn new() -> Self {
100ClashingExternDeclarations { seen_decls: Default::default() }
101 }
102103/// Insert a new foreign item into the seen set. If a symbol with the same name already exists
104 /// for the item, return its HirId without updating the set.
105fn insert(&mut self, tcx: TyCtxt<'_>, fi: hir::ForeignItemId) -> Option<hir::OwnerId> {
106let did = fi.owner_id.to_def_id();
107let instance = Instance::new_raw(did, ty::List::identity_for_item(tcx, did));
108let name = Symbol::intern(tcx.symbol_name(instance).name);
109if let Some(&existing_id) = self.seen_decls.get(&name) {
110// Avoid updating the map with the new entry when we do find a collision. We want to
111 // make sure we're always pointing to the first definition as the previous declaration.
112 // This lets us avoid emitting "knock-on" diagnostics.
113Some(existing_id)
114 } else {
115self.seen_decls.insert(name, fi.owner_id)
116 }
117 }
118119#[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("check_foreign_item",
"rustc_lint::foreign_modules", ::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/foreign_modules.rs"),
::tracing_core::__macro_support::Option::Some(119u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::foreign_modules"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("this_fi")
}> =
::tracing::__macro_support::FieldName::new("this_fi");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::TRACE <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&this_fi)
as &dyn ::tracing::field::Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: () = loop {};
return __tracing_attr_fake_return;
}
{
let DefKind::Fn = tcx.def_kind(this_fi.owner_id) else { return };
let Some(existing_did) =
self.insert(tcx, this_fi) else { return };
let existing_decl_ty = tcx.type_of(existing_did).skip_binder();
let this_decl_ty =
tcx.type_of(this_fi.owner_id).instantiate_identity().skip_norm_wip();
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_lint/src/foreign_modules.rs:126",
"rustc_lint::foreign_modules", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/foreign_modules.rs"),
::tracing_core::__macro_support::Option::Some(126u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::foreign_modules"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("ClashingExternDeclarations: Comparing existing {0:?}: {1:?} to this {2:?}: {3:?}",
existing_did, existing_decl_ty, this_fi.owner_id,
this_decl_ty) as &dyn ::tracing::field::Value))])
});
} else { ; }
};
if !structurally_same_type(tcx,
ty::TypingEnv::non_body_analysis(tcx, this_fi.owner_id),
existing_decl_ty, this_decl_ty) {
let orig = name_of_extern_decl(tcx, existing_did);
let this = tcx.item_name(this_fi.owner_id.to_def_id());
let orig = orig.get_name();
let previous_decl_label =
get_relevant_span(tcx, existing_did);
let mismatch_label = get_relevant_span(tcx, this_fi.owner_id);
let sub =
BuiltinClashingExternSub {
tcx,
expected: existing_decl_ty,
found: this_decl_ty,
};
let decorator =
if orig == this {
BuiltinClashingExtern::SameName {
this,
orig,
previous_decl_label,
mismatch_label,
sub,
}
} else {
BuiltinClashingExtern::DiffName {
this,
orig,
previous_decl_label,
mismatch_label,
sub,
}
};
tcx.emit_node_span_lint(CLASHING_EXTERN_DECLARATIONS,
this_fi.hir_id(), mismatch_label, decorator);
}
}
}
}#[instrument(level = "trace", skip(self, tcx))]120fn check_foreign_item<'tcx>(&mut self, tcx: TyCtxt<'tcx>, this_fi: hir::ForeignItemId) {
121let DefKind::Fn = tcx.def_kind(this_fi.owner_id) else { return };
122let Some(existing_did) = self.insert(tcx, this_fi) else { return };
123124let existing_decl_ty = tcx.type_of(existing_did).skip_binder();
125let this_decl_ty = tcx.type_of(this_fi.owner_id).instantiate_identity().skip_norm_wip();
126debug!(
127"ClashingExternDeclarations: Comparing existing {:?}: {:?} to this {:?}: {:?}",
128 existing_did, existing_decl_ty, this_fi.owner_id, this_decl_ty
129 );
130131// Check that the declarations match.
132if !structurally_same_type(
133 tcx,
134 ty::TypingEnv::non_body_analysis(tcx, this_fi.owner_id),
135 existing_decl_ty,
136 this_decl_ty,
137 ) {
138let orig = name_of_extern_decl(tcx, existing_did);
139140// Finally, emit the diagnostic.
141let this = tcx.item_name(this_fi.owner_id.to_def_id());
142let orig = orig.get_name();
143let previous_decl_label = get_relevant_span(tcx, existing_did);
144let mismatch_label = get_relevant_span(tcx, this_fi.owner_id);
145let sub =
146 BuiltinClashingExternSub { tcx, expected: existing_decl_ty, found: this_decl_ty };
147let decorator = if orig == this {
148 BuiltinClashingExtern::SameName {
149 this,
150 orig,
151 previous_decl_label,
152 mismatch_label,
153 sub,
154 }
155 } else {
156 BuiltinClashingExtern::DiffName {
157 this,
158 orig,
159 previous_decl_label,
160 mismatch_label,
161 sub,
162 }
163 };
164 tcx.emit_node_span_lint(
165 CLASHING_EXTERN_DECLARATIONS,
166 this_fi.hir_id(),
167 mismatch_label,
168 decorator,
169 );
170 }
171 }
172}
173174/// Get the name of the symbol that's linked against for a given extern declaration. That is,
175/// the name specified in a #[link_name = ...] attribute if one was specified, else, just the
176/// symbol's name.
177fn name_of_extern_decl(tcx: TyCtxt<'_>, fi: hir::OwnerId) -> SymbolName {
178if let Some((overridden_link_name, overridden_link_name_span)) =
179tcx.codegen_fn_attrs(fi).symbol_name.map(|overridden_link_name| {
180// FIXME: Instead of searching through the attributes again to get span
181 // information, we could have codegen_fn_attrs also give span information back for
182 // where the attribute was defined. However, until this is found to be a
183 // bottleneck, this does just fine.
184 (overridden_link_name, {
{
'done:
{
for i in ::rustc_attr_ir::HasAttrs::get_attrs(fi, &tcx) {
#[allow(unused_imports)]
use ::rustc_attr_ir::AttributeKind::*;
let i: &::rustc_attr_ir::Attribute = i;
match i {
::rustc_attr_ir::Attribute::Parsed(LinkName { span, .. }) =>
{
break 'done Some(*span);
}
::rustc_attr_ir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}
}find_attr!(tcx, fi, LinkName {span, ..} => *span).unwrap())
185 })
186 {
187 SymbolName::Link(overridden_link_name, overridden_link_name_span)
188 } else {
189 SymbolName::Normal(tcx.item_name(fi.to_def_id()))
190 }
191}
192193/// We want to ensure that we use spans for both decls that include where the
194/// name was defined, whether that was from the link_name attribute or not.
195fn get_relevant_span(tcx: TyCtxt<'_>, fi: hir::OwnerId) -> Span {
196match name_of_extern_decl(tcx, fi) {
197 SymbolName::Normal(_) => tcx.def_span(fi),
198 SymbolName::Link(_, annot_span) => annot_span,
199 }
200}
201202/// Checks whether two types are structurally the same enough that the declarations shouldn't
203/// clash. We need this so we don't emit a lint when two modules both declare an extern struct,
204/// with the same members (as the declarations shouldn't clash).
205fn structurally_same_type<'tcx>(
206 tcx: TyCtxt<'tcx>,
207 typing_env: ty::TypingEnv<'tcx>,
208 a: Ty<'tcx>,
209 b: Ty<'tcx>,
210) -> bool {
211let mut seen_types = UnordSet::default();
212let result = structurally_same_type_impl(&mut seen_types, tcx, typing_env, a, b);
213if truecfg!(debug_assertions) && result {
214// Sanity-check: must have same ABI, size and alignment.
215 // `extern` blocks cannot be generic, so we'll always get a layout here.
216let a_layout = tcx.layout_of(typing_env.as_query_input(a)).unwrap();
217let b_layout = tcx.layout_of(typing_env.as_query_input(b)).unwrap();
218{
match (&a_layout.backend_repr, &b_layout.backend_repr) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(a_layout.backend_repr, b_layout.backend_repr);
219{
match (&a_layout.size, &b_layout.size) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(a_layout.size, b_layout.size);
220{
match (&a_layout.align, &b_layout.align) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(a_layout.align, b_layout.align);
221 }
222result223}
224225fn structurally_same_type_impl<'tcx>(
226 seen_types: &mut UnordSet<(Ty<'tcx>, Ty<'tcx>)>,
227 tcx: TyCtxt<'tcx>,
228 typing_env: ty::TypingEnv<'tcx>,
229 a: Ty<'tcx>,
230 b: Ty<'tcx>,
231) -> bool {
232{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_lint/src/foreign_modules.rs:232",
"rustc_lint::foreign_modules", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/foreign_modules.rs"),
::tracing_core::__macro_support::Option::Some(232u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::foreign_modules"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("structurally_same_type_impl(tcx, a = {0:?}, b = {1:?})",
a, b) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("structurally_same_type_impl(tcx, a = {:?}, b = {:?})", a, b);
233234// Given a transparent newtype, reach through and grab the inner
235 // type unless the newtype makes the type non-null.
236let non_transparent_ty = |mut ty: Ty<'tcx>| -> Ty<'tcx> {
237loop {
238if let ty::Adt(def, args) = *ty.kind() {
239let is_transparent = def.repr().transparent();
240let is_non_null = types::nonnull_optimization_guaranteed(tcx, def);
241{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_lint/src/foreign_modules.rs:241",
"rustc_lint::foreign_modules", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/foreign_modules.rs"),
::tracing_core::__macro_support::Option::Some(241u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::foreign_modules"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("ty")
}> =
::tracing::__macro_support::FieldName::new("ty");
NAME.as_str()
},
{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("is_transparent")
}> =
::tracing::__macro_support::FieldName::new("is_transparent");
NAME.as_str()
},
{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("is_non_null")
}> =
::tracing::__macro_support::FieldName::new("is_non_null");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&ty)
as &dyn ::tracing::field::Value)),
(::tracing::__macro_support::Option::Some(&is_transparent as
&dyn ::tracing::field::Value)),
(::tracing::__macro_support::Option::Some(&is_non_null as
&dyn ::tracing::field::Value))])
});
} else { ; }
};debug!(?ty, is_transparent, is_non_null);
242if is_transparent && !is_non_null {
243if true {
{
match (&def.variants().len(), &1) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};
};debug_assert_eq!(def.variants().len(), 1);
244let v = &def.variant(FIRST_VARIANT);
245// continue with `ty`'s non-ZST field,
246 // otherwise `ty` is a ZST and we can return
247if let Some(field) = types::transparent_newtype_field(tcx, v) {
248ty = field.ty(tcx, args).skip_norm_wip();
249continue;
250 }
251 }
252 }
253{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_lint/src/foreign_modules.rs:253",
"rustc_lint::foreign_modules", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/foreign_modules.rs"),
::tracing_core::__macro_support::Option::Some(253u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::foreign_modules"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("non_transparent_ty -> {0:?}",
ty) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("non_transparent_ty -> {:?}", ty);
254return ty;
255 }
256 };
257258let a = non_transparent_ty(a);
259let b = non_transparent_ty(b);
260261if !seen_types.insert((a, b)) {
262// We've encountered a cycle. There's no point going any further -- the types are
263 // structurally the same.
264true
265} else if a == b {
266// All nominally-same types are structurally same, too.
267true
268} else {
269// Do a full, depth-first comparison between the two.
270let is_primitive_or_pointer =
271 |ty: Ty<'tcx>| ty.is_primitive() || #[allow(non_exhaustive_omitted_patterns)] match ty.kind() {
ty::RawPtr(..) | ty::Ref(..) => true,
_ => false,
}matches!(ty.kind(), ty::RawPtr(..) | ty::Ref(..));
272273match (a.kind(), b.kind()) {
274 (&ty::Adt(a_def, a_gen_args), &ty::Adt(b_def, b_gen_args)) => {
275// Only `repr(C)` types can be compared structurally.
276if !(a_def.repr().c() && b_def.repr().c()) {
277return false;
278 }
279// If the types differ in their packed-ness, align, or simd-ness they conflict.
280let repr_characteristica =
281 |def: AdtDef<'tcx>| (def.repr().pack, def.repr().align, def.repr().simd());
282if repr_characteristica(a_def) != repr_characteristica(b_def) {
283return false;
284 }
285286// Grab a flattened representation of all fields.
287let a_fields = a_def.variants().iter().flat_map(|v| v.fields.iter());
288let b_fields = b_def.variants().iter().flat_map(|v| v.fields.iter());
289290// Perform a structural comparison for each field.
291a_fields.eq_by(
292b_fields,
293 |&ty::FieldDef { did: a_did, .. }, &ty::FieldDef { did: b_did, .. }| {
294structurally_same_type_impl(
295seen_types,
296tcx,
297typing_env,
298tcx.type_of(a_did).instantiate(tcx, a_gen_args).skip_norm_wip(),
299tcx.type_of(b_did).instantiate(tcx, b_gen_args).skip_norm_wip(),
300 )
301 },
302 )
303 }
304 (ty::Array(a_ty, a_len), ty::Array(b_ty, b_len)) => {
305// For arrays, we also check the length.
306a_len == b_len307 && structurally_same_type_impl(seen_types, tcx, typing_env, *a_ty, *b_ty)
308 }
309 (ty::Slice(a_ty), ty::Slice(b_ty)) => {
310structurally_same_type_impl(seen_types, tcx, typing_env, *a_ty, *b_ty)
311 }
312 (ty::RawPtr(a_ty, a_mutbl), ty::RawPtr(b_ty, b_mutbl)) => {
313a_mutbl == b_mutbl314 && structurally_same_type_impl(seen_types, tcx, typing_env, *a_ty, *b_ty)
315 }
316 (ty::Ref(_a_region, a_ty, a_mut), ty::Ref(_b_region, b_ty, b_mut)) => {
317// For structural sameness, we don't need the region to be same.
318a_mut == b_mut319 && structurally_same_type_impl(seen_types, tcx, typing_env, *a_ty, *b_ty)
320 }
321 (ty::FnDef(..), ty::FnDef(..)) => {
322let a_poly_sig = a.fn_sig(tcx);
323let b_poly_sig = b.fn_sig(tcx);
324325// We don't compare regions, but leaving bound regions around ICEs, so
326 // we erase them.
327let a_sig = tcx.instantiate_bound_regions_with_erased(a_poly_sig);
328let b_sig = tcx.instantiate_bound_regions_with_erased(b_poly_sig);
329330// FIXME(splat): Is splatting ever repr(C)?
331 // Can two splatted functions to have the same structure?
332 // Can a splatted and non-splatted function have the same structure?
333 // For now, we require splatting to match exactly.
334if a_sig.splatted() != b_sig.splatted() {
335return false;
336 }
337338 (a_sig.abi(), a_sig.safety(), a_sig.c_variadic())
339 == (b_sig.abi(), b_sig.safety(), b_sig.c_variadic())
340 && a_sig.inputs().iter().eq_by(b_sig.inputs().iter(), |a, b| {
341structurally_same_type_impl(seen_types, tcx, typing_env, *a, *b)
342 })
343 && structurally_same_type_impl(
344seen_types,
345tcx,
346typing_env,
347a_sig.output(),
348b_sig.output(),
349 )
350 }
351 (ty::Tuple(..), ty::Tuple(..)) => {
352// Tuples are not `repr(C)` so these cannot be compared structurally.
353false
354}
355// For these, it's not quite as easy to define structural-sameness quite so easily.
356 // For the purposes of this lint, take the conservative approach and mark them as
357 // not structurally same.
358(ty::Dynamic(..), ty::Dynamic(..))
359 | (ty::Error(..), ty::Error(..))
360 | (ty::Closure(..), ty::Closure(..))
361 | (ty::Coroutine(..), ty::Coroutine(..))
362 | (ty::CoroutineWitness(..), ty::CoroutineWitness(..))
363 | (
364 ty::Alias(_, ty::AliasTy { kind: ty::Projection { .. }, .. }),
365 ty::Alias(_, ty::AliasTy { kind: ty::Projection { .. }, .. }),
366 )
367 | (
368 ty::Alias(_, ty::AliasTy { kind: ty::Inherent { .. }, .. }),
369 ty::Alias(_, ty::AliasTy { kind: ty::Inherent { .. }, .. }),
370 )
371 | (
372 ty::Alias(_, ty::AliasTy { kind: ty::Opaque { .. }, .. }),
373 ty::Alias(_, ty::AliasTy { kind: ty::Opaque { .. }, .. }),
374 ) => false,
375376// These definitely should have been caught above.
377(ty::Bool, ty::Bool)
378 | (ty::Char, ty::Char)
379 | (ty::Never, ty::Never)
380 | (ty::Str, ty::Str) => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
381382// An Adt and a primitive or pointer type. This can be FFI-safe if non-null
383 // enum layout optimisation is being applied.
384(ty::Adt(..) | ty::Pat(..), _) if is_primitive_or_pointer(b) => {
385if let Some(a_inner) = types::repr_nullable_ptr(tcx, typing_env, a) {
386a_inner == b387 } else {
388false
389}
390 }
391 (_, ty::Adt(..) | ty::Pat(..)) if is_primitive_or_pointer(a) => {
392if let Some(b_inner) = types::repr_nullable_ptr(tcx, typing_env, b) {
393b_inner == a394 } else {
395false
396}
397 }
398399_ => false,
400 }
401 }
402}