Auto merge of #113734 - cjgillot:no-crate-lint, r=petrochenkov
Convert builtin "global" late lints to run per module The compiler currently has 4 non-incremental lints: 1. `clashing_extern_declarations`; 2. `missing_debug_implementations`; 3. ~`unnameable_test_items`;~ changed by https://github.com/rust-lang/rust/pull/114414 4. `missing_docs`. Non-incremental lints get reexecuted for each compilation, which is slow. Moreover, those lints are allow-by-default, so run for nothing most of the time. This PR attempts to make them more incremental-friendly. `clashing_extern_declarations` is moved to a standalone query. `missing_debug_implementation` can use `non_blanket_impls_for_ty` instead of recomputing it. `missing_docs` is harder as it needs to track if there is a `doc(hidden)` module surrounding. I hack around this using the lint level engine. That's easy to implement and allows to re-enable the lint for a re-exported module, while a more proper solution would reuse the same device as `unnameable_test_items`.
This commit is contained in:
commit
67626b8e89
16 changed files with 807 additions and 825 deletions
|
@ -846,10 +846,11 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
|
|||
},
|
||||
{
|
||||
sess.time("lint_checking", || {
|
||||
rustc_lint::check_crate(tcx, || {
|
||||
rustc_lint::BuiltinCombinedLateLintPass::new()
|
||||
});
|
||||
rustc_lint::check_crate(tcx);
|
||||
});
|
||||
},
|
||||
{
|
||||
tcx.ensure().clashing_extern_declarations(());
|
||||
}
|
||||
);
|
||||
},
|
||||
|
|
|
@ -24,10 +24,9 @@ use crate::fluent_generated as fluent;
|
|||
use crate::{
|
||||
errors::BuiltinEllipsisInclusiveRangePatterns,
|
||||
lints::{
|
||||
BuiltinAnonymousParams, BuiltinBoxPointers, BuiltinClashingExtern,
|
||||
BuiltinClashingExternSub, BuiltinConstNoMangle, BuiltinDeprecatedAttrLink,
|
||||
BuiltinDeprecatedAttrLinkSuggestion, BuiltinDeprecatedAttrUsed, BuiltinDerefNullptr,
|
||||
BuiltinEllipsisInclusiveRangePatternsLint, BuiltinExplicitOutlives,
|
||||
BuiltinAnonymousParams, BuiltinBoxPointers, BuiltinConstNoMangle,
|
||||
BuiltinDeprecatedAttrLink, BuiltinDeprecatedAttrLinkSuggestion, BuiltinDeprecatedAttrUsed,
|
||||
BuiltinDerefNullptr, BuiltinEllipsisInclusiveRangePatternsLint, BuiltinExplicitOutlives,
|
||||
BuiltinExplicitOutlivesSuggestion, BuiltinFeatureIssueNote, BuiltinIncompleteFeatures,
|
||||
BuiltinIncompleteFeaturesHelp, BuiltinInternalFeatures, BuiltinKeywordIdents,
|
||||
BuiltinMissingCopyImpl, BuiltinMissingDebugImpl, BuiltinMissingDoc,
|
||||
|
@ -40,8 +39,7 @@ use crate::{
|
|||
BuiltinUnstableFeatures, BuiltinUnusedDocComment, BuiltinUnusedDocCommentSub,
|
||||
BuiltinWhileTrue, SuggestChangingAssocTypes,
|
||||
},
|
||||
types::{transparent_newtype_field, CItemKind},
|
||||
EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext,
|
||||
EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext,
|
||||
};
|
||||
use hir::IsAsync;
|
||||
use rustc_ast::attr;
|
||||
|
@ -49,28 +47,26 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree};
|
|||
use rustc_ast::visit::{FnCtxt, FnKind};
|
||||
use rustc_ast::{self as ast, *};
|
||||
use rustc_ast_pretty::pprust::{self, expr_to_string};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_errors::{Applicability, DecorateLint, MultiSpan};
|
||||
use rustc_feature::{deprecated_attributes, AttributeGate, BuiltinAttribute, GateIssue, Stability};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
|
||||
use rustc_hir::intravisit::FnKind as HirFnKind;
|
||||
use rustc_hir::{Body, FnDecl, ForeignItemKind, GenericParamKind, Node, PatKind, PredicateOrigin};
|
||||
use rustc_hir::{Body, FnDecl, GenericParamKind, Node, PatKind, PredicateOrigin};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_middle::ty::layout::{LayoutError, LayoutOf};
|
||||
use rustc_middle::ty::layout::LayoutOf;
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_middle::ty::GenericArgKind;
|
||||
use rustc_middle::ty::TypeVisitableExt;
|
||||
use rustc_middle::ty::{self, Instance, Ty, TyCtxt, VariantDef};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, VariantDef};
|
||||
use rustc_session::config::ExpectedValues;
|
||||
use rustc_session::lint::{BuiltinLintDiagnostics, FutureIncompatibilityReason};
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
use rustc_span::{BytePos, InnerSpan, Span};
|
||||
use rustc_target::abi::{Abi, FIRST_VARIANT};
|
||||
use rustc_target::abi::Abi;
|
||||
use rustc_trait_selection::infer::{InferCtxtExt, TyCtxtInferExt};
|
||||
use rustc_trait_selection::traits::{self, misc::type_allowed_to_implement_copy};
|
||||
|
||||
|
@ -461,10 +457,7 @@ declare_lint! {
|
|||
report_in_external_macro
|
||||
}
|
||||
|
||||
pub struct MissingDoc {
|
||||
/// Stack of whether `#[doc(hidden)]` is set at each level which has lint attributes.
|
||||
doc_hidden_stack: Vec<bool>,
|
||||
}
|
||||
pub struct MissingDoc;
|
||||
|
||||
impl_lint_pass!(MissingDoc => [MISSING_DOCS]);
|
||||
|
||||
|
@ -493,14 +486,6 @@ fn has_doc(attr: &ast::Attribute) -> bool {
|
|||
}
|
||||
|
||||
impl MissingDoc {
|
||||
pub fn new() -> MissingDoc {
|
||||
MissingDoc { doc_hidden_stack: vec![false] }
|
||||
}
|
||||
|
||||
fn doc_hidden(&self) -> bool {
|
||||
*self.doc_hidden_stack.last().expect("empty doc_hidden_stack")
|
||||
}
|
||||
|
||||
fn check_missing_docs_attrs(
|
||||
&self,
|
||||
cx: &LateContext<'_>,
|
||||
|
@ -514,11 +499,6 @@ impl MissingDoc {
|
|||
return;
|
||||
}
|
||||
|
||||
// `#[doc(hidden)]` disables missing_docs check.
|
||||
if self.doc_hidden() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only check publicly-visible items, using the result from the privacy pass.
|
||||
// It's an option so the crate root can also use this function (it doesn't
|
||||
// have a `NodeId`).
|
||||
|
@ -541,23 +521,6 @@ impl MissingDoc {
|
|||
}
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for MissingDoc {
|
||||
#[inline]
|
||||
fn enter_lint_attrs(&mut self, _cx: &LateContext<'_>, attrs: &[ast::Attribute]) {
|
||||
let doc_hidden = self.doc_hidden()
|
||||
|| attrs.iter().any(|attr| {
|
||||
attr.has_name(sym::doc)
|
||||
&& match attr.meta_item_list() {
|
||||
None => false,
|
||||
Some(l) => attr::list_contains_name(&l, sym::hidden),
|
||||
}
|
||||
});
|
||||
self.doc_hidden_stack.push(doc_hidden);
|
||||
}
|
||||
|
||||
fn exit_lint_attrs(&mut self, _: &LateContext<'_>, _attrs: &[ast::Attribute]) {
|
||||
self.doc_hidden_stack.pop().expect("empty doc_hidden_stack");
|
||||
}
|
||||
|
||||
fn check_crate(&mut self, cx: &LateContext<'_>) {
|
||||
self.check_missing_docs_attrs(cx, CRATE_DEF_ID, "the", "crate");
|
||||
}
|
||||
|
@ -778,9 +741,7 @@ declare_lint! {
|
|||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct MissingDebugImplementations {
|
||||
impling_types: Option<LocalDefIdSet>,
|
||||
}
|
||||
pub(crate) struct MissingDebugImplementations;
|
||||
|
||||
impl_lint_pass!(MissingDebugImplementations => [MISSING_DEBUG_IMPLEMENTATIONS]);
|
||||
|
||||
|
@ -795,23 +756,20 @@ impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations {
|
|||
_ => return,
|
||||
}
|
||||
|
||||
let Some(debug) = cx.tcx.get_diagnostic_item(sym::Debug) else { return };
|
||||
|
||||
if self.impling_types.is_none() {
|
||||
let mut impls = LocalDefIdSet::default();
|
||||
cx.tcx.for_each_impl(debug, |d| {
|
||||
if let Some(ty_def) = cx.tcx.type_of(d).instantiate_identity().ty_adt_def() {
|
||||
if let Some(def_id) = ty_def.did().as_local() {
|
||||
impls.insert(def_id);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
self.impling_types = Some(impls);
|
||||
debug!("{:?}", self.impling_types);
|
||||
// Avoid listing trait impls if the trait is allowed.
|
||||
let (level, _) = cx.tcx.lint_level_at_node(MISSING_DEBUG_IMPLEMENTATIONS, item.hir_id());
|
||||
if level == Level::Allow {
|
||||
return;
|
||||
}
|
||||
|
||||
if !self.impling_types.as_ref().unwrap().contains(&item.owner_id.def_id) {
|
||||
let Some(debug) = cx.tcx.get_diagnostic_item(sym::Debug) else { return };
|
||||
|
||||
let has_impl = cx
|
||||
.tcx
|
||||
.non_blanket_impls_for_ty(debug, cx.tcx.type_of(item.owner_id).instantiate_identity())
|
||||
.next()
|
||||
.is_some();
|
||||
if !has_impl {
|
||||
cx.emit_spanned_lint(
|
||||
MISSING_DEBUG_IMPLEMENTATIONS,
|
||||
item.span,
|
||||
|
@ -2612,381 +2570,6 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
|
|||
}
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `clashing_extern_declarations` lint detects when an `extern fn`
|
||||
/// has been declared with the same name but different types.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust
|
||||
/// mod m {
|
||||
/// extern "C" {
|
||||
/// fn foo();
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// extern "C" {
|
||||
/// fn foo(_: u32);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// Because two symbols of the same name cannot be resolved to two
|
||||
/// different functions at link time, and one function cannot possibly
|
||||
/// have two types, a clashing extern declaration is almost certainly a
|
||||
/// mistake. Check to make sure that the `extern` definitions are correct
|
||||
/// and equivalent, and possibly consider unifying them in one location.
|
||||
///
|
||||
/// This lint does not run between crates because a project may have
|
||||
/// dependencies which both rely on the same extern function, but declare
|
||||
/// it in a different (but valid) way. For example, they may both declare
|
||||
/// an opaque type for one or more of the arguments (which would end up
|
||||
/// distinct types), or use types that are valid conversions in the
|
||||
/// language the `extern fn` is defined in. In these cases, the compiler
|
||||
/// can't say that the clashing declaration is incorrect.
|
||||
pub CLASHING_EXTERN_DECLARATIONS,
|
||||
Warn,
|
||||
"detects when an extern fn has been declared with the same name but different types"
|
||||
}
|
||||
|
||||
pub struct ClashingExternDeclarations {
|
||||
/// Map of function symbol name to the first-seen hir id for that symbol name.. If seen_decls
|
||||
/// contains an entry for key K, it means a symbol with name K has been seen by this lint and
|
||||
/// the symbol should be reported as a clashing declaration.
|
||||
// FIXME: Technically, we could just store a &'tcx str here without issue; however, the
|
||||
// `impl_lint_pass` macro doesn't currently support lints parametric over a lifetime.
|
||||
seen_decls: FxHashMap<Symbol, hir::OwnerId>,
|
||||
}
|
||||
|
||||
/// Differentiate between whether the name for an extern decl came from the link_name attribute or
|
||||
/// just from declaration itself. This is important because we don't want to report clashes on
|
||||
/// symbol name if they don't actually clash because one or the other links against a symbol with a
|
||||
/// different name.
|
||||
enum SymbolName {
|
||||
/// The name of the symbol + the span of the annotation which introduced the link name.
|
||||
Link(Symbol, Span),
|
||||
/// No link name, so just the name of the symbol.
|
||||
Normal(Symbol),
|
||||
}
|
||||
|
||||
impl SymbolName {
|
||||
fn get_name(&self) -> Symbol {
|
||||
match self {
|
||||
SymbolName::Link(s, _) | SymbolName::Normal(s) => *s,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ClashingExternDeclarations {
|
||||
pub(crate) fn new() -> Self {
|
||||
ClashingExternDeclarations { seen_decls: FxHashMap::default() }
|
||||
}
|
||||
|
||||
/// Insert a new foreign item into the seen set. If a symbol with the same name already exists
|
||||
/// for the item, return its HirId without updating the set.
|
||||
fn insert(&mut self, tcx: TyCtxt<'_>, fi: &hir::ForeignItem<'_>) -> Option<hir::OwnerId> {
|
||||
let did = fi.owner_id.to_def_id();
|
||||
let instance = Instance::new(did, ty::List::identity_for_item(tcx, did));
|
||||
let name = Symbol::intern(tcx.symbol_name(instance).name);
|
||||
if let Some(&existing_id) = self.seen_decls.get(&name) {
|
||||
// Avoid updating the map with the new entry when we do find a collision. We want to
|
||||
// make sure we're always pointing to the first definition as the previous declaration.
|
||||
// This lets us avoid emitting "knock-on" diagnostics.
|
||||
Some(existing_id)
|
||||
} else {
|
||||
self.seen_decls.insert(name, fi.owner_id)
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the name of the symbol that's linked against for a given extern declaration. That is,
|
||||
/// the name specified in a #[link_name = ...] attribute if one was specified, else, just the
|
||||
/// symbol's name.
|
||||
fn name_of_extern_decl(tcx: TyCtxt<'_>, fi: &hir::ForeignItem<'_>) -> SymbolName {
|
||||
if let Some((overridden_link_name, overridden_link_name_span)) =
|
||||
tcx.codegen_fn_attrs(fi.owner_id).link_name.map(|overridden_link_name| {
|
||||
// FIXME: Instead of searching through the attributes again to get span
|
||||
// information, we could have codegen_fn_attrs also give span information back for
|
||||
// where the attribute was defined. However, until this is found to be a
|
||||
// bottleneck, this does just fine.
|
||||
(overridden_link_name, tcx.get_attr(fi.owner_id, sym::link_name).unwrap().span)
|
||||
})
|
||||
{
|
||||
SymbolName::Link(overridden_link_name, overridden_link_name_span)
|
||||
} else {
|
||||
SymbolName::Normal(fi.ident.name)
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks whether two types are structurally the same enough that the declarations shouldn't
|
||||
/// clash. We need this so we don't emit a lint when two modules both declare an extern struct,
|
||||
/// with the same members (as the declarations shouldn't clash).
|
||||
fn structurally_same_type<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
a: Ty<'tcx>,
|
||||
b: Ty<'tcx>,
|
||||
ckind: CItemKind,
|
||||
) -> bool {
|
||||
fn structurally_same_type_impl<'tcx>(
|
||||
seen_types: &mut FxHashSet<(Ty<'tcx>, Ty<'tcx>)>,
|
||||
cx: &LateContext<'tcx>,
|
||||
a: Ty<'tcx>,
|
||||
b: Ty<'tcx>,
|
||||
ckind: CItemKind,
|
||||
) -> bool {
|
||||
debug!("structurally_same_type_impl(cx, a = {:?}, b = {:?})", a, b);
|
||||
let tcx = cx.tcx;
|
||||
|
||||
// Given a transparent newtype, reach through and grab the inner
|
||||
// type unless the newtype makes the type non-null.
|
||||
let non_transparent_ty = |mut ty: Ty<'tcx>| -> Ty<'tcx> {
|
||||
loop {
|
||||
if let ty::Adt(def, args) = *ty.kind() {
|
||||
let is_transparent = def.repr().transparent();
|
||||
let is_non_null = crate::types::nonnull_optimization_guaranteed(tcx, def);
|
||||
debug!(
|
||||
"non_transparent_ty({:?}) -- type is transparent? {}, type is non-null? {}",
|
||||
ty, is_transparent, is_non_null
|
||||
);
|
||||
if is_transparent && !is_non_null {
|
||||
debug_assert_eq!(def.variants().len(), 1);
|
||||
let v = &def.variant(FIRST_VARIANT);
|
||||
// continue with `ty`'s non-ZST field,
|
||||
// otherwise `ty` is a ZST and we can return
|
||||
if let Some(field) = transparent_newtype_field(tcx, v) {
|
||||
ty = field.ty(tcx, args);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
debug!("non_transparent_ty -> {:?}", ty);
|
||||
return ty;
|
||||
}
|
||||
};
|
||||
|
||||
let a = non_transparent_ty(a);
|
||||
let b = non_transparent_ty(b);
|
||||
|
||||
if !seen_types.insert((a, b)) {
|
||||
// We've encountered a cycle. There's no point going any further -- the types are
|
||||
// structurally the same.
|
||||
true
|
||||
} else if a == b {
|
||||
// All nominally-same types are structurally same, too.
|
||||
true
|
||||
} else {
|
||||
// Do a full, depth-first comparison between the two.
|
||||
use rustc_type_ir::sty::TyKind::*;
|
||||
let a_kind = a.kind();
|
||||
let b_kind = b.kind();
|
||||
|
||||
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)]
|
||||
let is_primitive_or_pointer = |kind: &ty::TyKind<'_>| {
|
||||
kind.is_primitive() || matches!(kind, RawPtr(..) | Ref(..))
|
||||
};
|
||||
|
||||
ensure_sufficient_stack(|| {
|
||||
match (a_kind, b_kind) {
|
||||
(Adt(a_def, _), Adt(b_def, _)) => {
|
||||
// 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());
|
||||
|
||||
// Perform a structural comparison for each field.
|
||||
a_fields.eq_by(
|
||||
b_fields,
|
||||
|&ty::FieldDef { did: a_did, .. },
|
||||
&ty::FieldDef { did: b_did, .. }| {
|
||||
structurally_same_type_impl(
|
||||
seen_types,
|
||||
cx,
|
||||
tcx.type_of(a_did).instantiate_identity(),
|
||||
tcx.type_of(b_did).instantiate_identity(),
|
||||
ckind,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
(Array(a_ty, a_const), Array(b_ty, b_const)) => {
|
||||
// For arrays, we also check the constness of the type.
|
||||
a_const.kind() == b_const.kind()
|
||||
&& structurally_same_type_impl(seen_types, cx, *a_ty, *b_ty, ckind)
|
||||
}
|
||||
(Slice(a_ty), Slice(b_ty)) => {
|
||||
structurally_same_type_impl(seen_types, cx, *a_ty, *b_ty, ckind)
|
||||
}
|
||||
(RawPtr(a_tymut), RawPtr(b_tymut)) => {
|
||||
a_tymut.mutbl == b_tymut.mutbl
|
||||
&& structurally_same_type_impl(
|
||||
seen_types, cx, a_tymut.ty, b_tymut.ty, ckind,
|
||||
)
|
||||
}
|
||||
(Ref(_a_region, a_ty, a_mut), Ref(_b_region, b_ty, b_mut)) => {
|
||||
// For structural sameness, we don't need the region to be same.
|
||||
a_mut == b_mut
|
||||
&& structurally_same_type_impl(seen_types, cx, *a_ty, *b_ty, ckind)
|
||||
}
|
||||
(FnDef(..), FnDef(..)) => {
|
||||
let a_poly_sig = a.fn_sig(tcx);
|
||||
let b_poly_sig = b.fn_sig(tcx);
|
||||
|
||||
// We don't compare regions, but leaving bound regions around ICEs, so
|
||||
// we erase them.
|
||||
let a_sig = tcx.erase_late_bound_regions(a_poly_sig);
|
||||
let b_sig = tcx.erase_late_bound_regions(b_poly_sig);
|
||||
|
||||
(a_sig.abi, a_sig.unsafety, a_sig.c_variadic)
|
||||
== (b_sig.abi, b_sig.unsafety, b_sig.c_variadic)
|
||||
&& a_sig.inputs().iter().eq_by(b_sig.inputs().iter(), |a, b| {
|
||||
structurally_same_type_impl(seen_types, cx, *a, *b, ckind)
|
||||
})
|
||||
&& structurally_same_type_impl(
|
||||
seen_types,
|
||||
cx,
|
||||
a_sig.output(),
|
||||
b_sig.output(),
|
||||
ckind,
|
||||
)
|
||||
}
|
||||
(Tuple(a_args), Tuple(b_args)) => {
|
||||
a_args.iter().eq_by(b_args.iter(), |a_ty, b_ty| {
|
||||
structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind)
|
||||
})
|
||||
}
|
||||
// For these, it's not quite as easy to define structural-sameness quite so easily.
|
||||
// For the purposes of this lint, take the conservative approach and mark them as
|
||||
// not structurally same.
|
||||
(Dynamic(..), Dynamic(..))
|
||||
| (Error(..), Error(..))
|
||||
| (Closure(..), Closure(..))
|
||||
| (Generator(..), Generator(..))
|
||||
| (GeneratorWitness(..), GeneratorWitness(..))
|
||||
| (Alias(ty::Projection, ..), Alias(ty::Projection, ..))
|
||||
| (Alias(ty::Inherent, ..), Alias(ty::Inherent, ..))
|
||||
| (Alias(ty::Opaque, ..), Alias(ty::Opaque, ..)) => false,
|
||||
|
||||
// These definitely should have been caught above.
|
||||
(Bool, Bool) | (Char, Char) | (Never, Never) | (Str, Str) => unreachable!(),
|
||||
|
||||
// An Adt and a primitive or pointer type. This can be FFI-safe if non-null
|
||||
// enum layout optimisation is being applied.
|
||||
(Adt(..), other_kind) | (other_kind, Adt(..))
|
||||
if is_primitive_or_pointer(other_kind) =>
|
||||
{
|
||||
let (primitive, adt) =
|
||||
if is_primitive_or_pointer(a.kind()) { (a, b) } else { (b, a) };
|
||||
if let Some(ty) = crate::types::repr_nullable_ptr(cx, adt, ckind) {
|
||||
ty == primitive
|
||||
} else {
|
||||
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).unwrap_or(false),
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
let mut seen_types = FxHashSet::default();
|
||||
structurally_same_type_impl(&mut seen_types, cx, a, b, ckind)
|
||||
}
|
||||
}
|
||||
|
||||
impl_lint_pass!(ClashingExternDeclarations => [CLASHING_EXTERN_DECLARATIONS]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for ClashingExternDeclarations {
|
||||
#[instrument(level = "trace", skip(self, cx))]
|
||||
fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, this_fi: &hir::ForeignItem<'_>) {
|
||||
if let ForeignItemKind::Fn(..) = this_fi.kind {
|
||||
let tcx = cx.tcx;
|
||||
if let Some(existing_did) = self.insert(tcx, this_fi) {
|
||||
let existing_decl_ty = tcx.type_of(existing_did).skip_binder();
|
||||
let this_decl_ty = tcx.type_of(this_fi.owner_id).instantiate_identity();
|
||||
debug!(
|
||||
"ClashingExternDeclarations: Comparing existing {:?}: {:?} to this {:?}: {:?}",
|
||||
existing_did, existing_decl_ty, this_fi.owner_id, this_decl_ty
|
||||
);
|
||||
// Check that the declarations match.
|
||||
if !Self::structurally_same_type(
|
||||
cx,
|
||||
existing_decl_ty,
|
||||
this_decl_ty,
|
||||
CItemKind::Declaration,
|
||||
) {
|
||||
let orig_fi = tcx.hir().expect_foreign_item(existing_did);
|
||||
let orig = Self::name_of_extern_decl(tcx, orig_fi);
|
||||
|
||||
// We want to ensure that we use spans for both decls that include where the
|
||||
// name was defined, whether that was from the link_name attribute or not.
|
||||
let get_relevant_span =
|
||||
|fi: &hir::ForeignItem<'_>| match Self::name_of_extern_decl(tcx, fi) {
|
||||
SymbolName::Normal(_) => fi.span,
|
||||
SymbolName::Link(_, annot_span) => fi.span.to(annot_span),
|
||||
};
|
||||
|
||||
// Finally, emit the diagnostic.
|
||||
let this = this_fi.ident.name;
|
||||
let orig = orig.get_name();
|
||||
let previous_decl_label = get_relevant_span(orig_fi);
|
||||
let mismatch_label = get_relevant_span(this_fi);
|
||||
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_spanned_lint(
|
||||
CLASHING_EXTERN_DECLARATIONS,
|
||||
this_fi.hir_id(),
|
||||
get_relevant_span(this_fi),
|
||||
decorator,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `deref_nullptr` lint detects when an null pointer is dereferenced,
|
||||
/// which causes [undefined behavior].
|
||||
|
|
402
compiler/rustc_lint/src/foreign_modules.rs
Normal file
402
compiler/rustc_lint/src/foreign_modules.rs
Normal file
|
@ -0,0 +1,402 @@
|
|||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::layout::LayoutError;
|
||||
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
|
||||
use rustc_session::lint::{lint_array, LintArray};
|
||||
use rustc_span::{sym, Span, Symbol};
|
||||
use rustc_target::abi::FIRST_VARIANT;
|
||||
|
||||
use crate::lints::{BuiltinClashingExtern, BuiltinClashingExternSub};
|
||||
use crate::types;
|
||||
|
||||
pub(crate) fn provide(providers: &mut Providers) {
|
||||
*providers = Providers { clashing_extern_declarations, ..*providers };
|
||||
}
|
||||
|
||||
pub(crate) fn get_lints() -> LintArray {
|
||||
lint_array!(CLASHING_EXTERN_DECLARATIONS)
|
||||
}
|
||||
|
||||
fn clashing_extern_declarations(tcx: TyCtxt<'_>, (): ()) {
|
||||
let mut lint = ClashingExternDeclarations::new();
|
||||
for id in tcx.hir_crate_items(()).foreign_items() {
|
||||
lint.check_foreign_item(tcx, id);
|
||||
}
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `clashing_extern_declarations` lint detects when an `extern fn`
|
||||
/// has been declared with the same name but different types.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust
|
||||
/// mod m {
|
||||
/// extern "C" {
|
||||
/// fn foo();
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// extern "C" {
|
||||
/// fn foo(_: u32);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// Because two symbols of the same name cannot be resolved to two
|
||||
/// different functions at link time, and one function cannot possibly
|
||||
/// have two types, a clashing extern declaration is almost certainly a
|
||||
/// mistake. Check to make sure that the `extern` definitions are correct
|
||||
/// and equivalent, and possibly consider unifying them in one location.
|
||||
///
|
||||
/// This lint does not run between crates because a project may have
|
||||
/// dependencies which both rely on the same extern function, but declare
|
||||
/// it in a different (but valid) way. For example, they may both declare
|
||||
/// an opaque type for one or more of the arguments (which would end up
|
||||
/// distinct types), or use types that are valid conversions in the
|
||||
/// language the `extern fn` is defined in. In these cases, the compiler
|
||||
/// can't say that the clashing declaration is incorrect.
|
||||
pub CLASHING_EXTERN_DECLARATIONS,
|
||||
Warn,
|
||||
"detects when an extern fn has been declared with the same name but different types"
|
||||
}
|
||||
|
||||
struct ClashingExternDeclarations {
|
||||
/// Map of function symbol name to the first-seen hir id for that symbol name.. If seen_decls
|
||||
/// contains an entry for key K, it means a symbol with name K has been seen by this lint and
|
||||
/// the symbol should be reported as a clashing declaration.
|
||||
// FIXME: Technically, we could just store a &'tcx str here without issue; however, the
|
||||
// `impl_lint_pass` macro doesn't currently support lints parametric over a lifetime.
|
||||
seen_decls: FxHashMap<Symbol, hir::OwnerId>,
|
||||
}
|
||||
|
||||
/// Differentiate between whether the name for an extern decl came from the link_name attribute or
|
||||
/// just from declaration itself. This is important because we don't want to report clashes on
|
||||
/// symbol name if they don't actually clash because one or the other links against a symbol with a
|
||||
/// different name.
|
||||
enum SymbolName {
|
||||
/// The name of the symbol + the span of the annotation which introduced the link name.
|
||||
Link(Symbol, Span),
|
||||
/// No link name, so just the name of the symbol.
|
||||
Normal(Symbol),
|
||||
}
|
||||
|
||||
impl SymbolName {
|
||||
fn get_name(&self) -> Symbol {
|
||||
match self {
|
||||
SymbolName::Link(s, _) | SymbolName::Normal(s) => *s,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ClashingExternDeclarations {
|
||||
pub(crate) fn new() -> Self {
|
||||
ClashingExternDeclarations { seen_decls: FxHashMap::default() }
|
||||
}
|
||||
|
||||
/// Insert a new foreign item into the seen set. If a symbol with the same name already exists
|
||||
/// for the item, return its HirId without updating the set.
|
||||
fn insert(&mut self, tcx: TyCtxt<'_>, fi: hir::ForeignItemId) -> Option<hir::OwnerId> {
|
||||
let did = fi.owner_id.to_def_id();
|
||||
let instance = Instance::new(did, ty::List::identity_for_item(tcx, did));
|
||||
let name = Symbol::intern(tcx.symbol_name(instance).name);
|
||||
if let Some(&existing_id) = self.seen_decls.get(&name) {
|
||||
// Avoid updating the map with the new entry when we do find a collision. We want to
|
||||
// make sure we're always pointing to the first definition as the previous declaration.
|
||||
// This lets us avoid emitting "knock-on" diagnostics.
|
||||
Some(existing_id)
|
||||
} else {
|
||||
self.seen_decls.insert(name, fi.owner_id)
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip(self, tcx))]
|
||||
fn check_foreign_item<'tcx>(&mut self, tcx: TyCtxt<'tcx>, this_fi: hir::ForeignItemId) {
|
||||
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();
|
||||
debug!(
|
||||
"ClashingExternDeclarations: Comparing existing {:?}: {:?} to this {:?}: {:?}",
|
||||
existing_did, existing_decl_ty, this_fi.owner_id, this_decl_ty
|
||||
);
|
||||
|
||||
// Check that the declarations match.
|
||||
if !structurally_same_type(
|
||||
tcx,
|
||||
tcx.param_env(this_fi.owner_id),
|
||||
existing_decl_ty,
|
||||
this_decl_ty,
|
||||
types::CItemKind::Declaration,
|
||||
) {
|
||||
let orig = name_of_extern_decl(tcx, existing_did);
|
||||
|
||||
// Finally, emit the diagnostic.
|
||||
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_spanned_lint(
|
||||
CLASHING_EXTERN_DECLARATIONS,
|
||||
this_fi.hir_id(),
|
||||
mismatch_label,
|
||||
decorator,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the name of the symbol that's linked against for a given extern declaration. That is,
|
||||
/// the name specified in a #[link_name = ...] attribute if one was specified, else, just the
|
||||
/// symbol's name.
|
||||
fn name_of_extern_decl(tcx: TyCtxt<'_>, fi: hir::OwnerId) -> SymbolName {
|
||||
if let Some((overridden_link_name, overridden_link_name_span)) =
|
||||
tcx.codegen_fn_attrs(fi).link_name.map(|overridden_link_name| {
|
||||
// FIXME: Instead of searching through the attributes again to get span
|
||||
// information, we could have codegen_fn_attrs also give span information back for
|
||||
// where the attribute was defined. However, until this is found to be a
|
||||
// bottleneck, this does just fine.
|
||||
(overridden_link_name, tcx.get_attr(fi, sym::link_name).unwrap().span)
|
||||
})
|
||||
{
|
||||
SymbolName::Link(overridden_link_name, overridden_link_name_span)
|
||||
} else {
|
||||
SymbolName::Normal(tcx.item_name(fi.to_def_id()))
|
||||
}
|
||||
}
|
||||
|
||||
/// We want to ensure that we use spans for both decls that include where the
|
||||
/// name was defined, whether that was from the link_name attribute or not.
|
||||
fn get_relevant_span(tcx: TyCtxt<'_>, fi: hir::OwnerId) -> Span {
|
||||
match name_of_extern_decl(tcx, fi) {
|
||||
SymbolName::Normal(_) => tcx.def_span(fi),
|
||||
SymbolName::Link(_, annot_span) => annot_span,
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks whether two types are structurally the same enough that the declarations shouldn't
|
||||
/// clash. We need this so we don't emit a lint when two modules both declare an extern struct,
|
||||
/// with the same members (as the declarations shouldn't clash).
|
||||
fn structurally_same_type<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
a: Ty<'tcx>,
|
||||
b: Ty<'tcx>,
|
||||
ckind: types::CItemKind,
|
||||
) -> bool {
|
||||
let mut seen_types = FxHashSet::default();
|
||||
structurally_same_type_impl(&mut seen_types, tcx, param_env, a, b, ckind)
|
||||
}
|
||||
|
||||
fn structurally_same_type_impl<'tcx>(
|
||||
seen_types: &mut FxHashSet<(Ty<'tcx>, Ty<'tcx>)>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
a: Ty<'tcx>,
|
||||
b: Ty<'tcx>,
|
||||
ckind: types::CItemKind,
|
||||
) -> bool {
|
||||
debug!("structurally_same_type_impl(tcx, a = {:?}, b = {:?})", a, b);
|
||||
|
||||
// Given a transparent newtype, reach through and grab the inner
|
||||
// type unless the newtype makes the type non-null.
|
||||
let non_transparent_ty = |mut ty: Ty<'tcx>| -> Ty<'tcx> {
|
||||
loop {
|
||||
if let ty::Adt(def, args) = *ty.kind() {
|
||||
let is_transparent = def.repr().transparent();
|
||||
let is_non_null = types::nonnull_optimization_guaranteed(tcx, def);
|
||||
debug!(
|
||||
"non_transparent_ty({:?}) -- type is transparent? {}, type is non-null? {}",
|
||||
ty, is_transparent, is_non_null
|
||||
);
|
||||
if is_transparent && !is_non_null {
|
||||
debug_assert_eq!(def.variants().len(), 1);
|
||||
let v = &def.variant(FIRST_VARIANT);
|
||||
// continue with `ty`'s non-ZST field,
|
||||
// otherwise `ty` is a ZST and we can return
|
||||
if let Some(field) = types::transparent_newtype_field(tcx, v) {
|
||||
ty = field.ty(tcx, args);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
debug!("non_transparent_ty -> {:?}", ty);
|
||||
return ty;
|
||||
}
|
||||
};
|
||||
|
||||
let a = non_transparent_ty(a);
|
||||
let b = non_transparent_ty(b);
|
||||
|
||||
if !seen_types.insert((a, b)) {
|
||||
// We've encountered a cycle. There's no point going any further -- the types are
|
||||
// structurally the same.
|
||||
true
|
||||
} else if a == b {
|
||||
// All nominally-same types are structurally same, too.
|
||||
true
|
||||
} else {
|
||||
// Do a full, depth-first comparison between the two.
|
||||
use rustc_type_ir::sty::TyKind::*;
|
||||
let a_kind = a.kind();
|
||||
let b_kind = b.kind();
|
||||
|
||||
let compare_layouts = |a, b| -> Result<bool, &'tcx LayoutError<'tcx>> {
|
||||
debug!("compare_layouts({:?}, {:?})", a, b);
|
||||
let a_layout = &tcx.layout_of(param_env.and(a))?.layout.abi();
|
||||
let b_layout = &tcx.layout_of(param_env.and(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)]
|
||||
let is_primitive_or_pointer =
|
||||
|kind: &ty::TyKind<'_>| kind.is_primitive() || matches!(kind, RawPtr(..) | Ref(..));
|
||||
|
||||
ensure_sufficient_stack(|| {
|
||||
match (a_kind, b_kind) {
|
||||
(Adt(a_def, _), Adt(b_def, _)) => {
|
||||
// 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());
|
||||
|
||||
// Perform a structural comparison for each field.
|
||||
a_fields.eq_by(
|
||||
b_fields,
|
||||
|&ty::FieldDef { did: a_did, .. }, &ty::FieldDef { did: b_did, .. }| {
|
||||
structurally_same_type_impl(
|
||||
seen_types,
|
||||
tcx,
|
||||
param_env,
|
||||
tcx.type_of(a_did).instantiate_identity(),
|
||||
tcx.type_of(b_did).instantiate_identity(),
|
||||
ckind,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
(Array(a_ty, a_const), Array(b_ty, b_const)) => {
|
||||
// For arrays, we also check the constness of the type.
|
||||
a_const.kind() == b_const.kind()
|
||||
&& structurally_same_type_impl(
|
||||
seen_types, tcx, param_env, *a_ty, *b_ty, ckind,
|
||||
)
|
||||
}
|
||||
(Slice(a_ty), Slice(b_ty)) => {
|
||||
structurally_same_type_impl(seen_types, tcx, param_env, *a_ty, *b_ty, ckind)
|
||||
}
|
||||
(RawPtr(a_tymut), RawPtr(b_tymut)) => {
|
||||
a_tymut.mutbl == b_tymut.mutbl
|
||||
&& structurally_same_type_impl(
|
||||
seen_types, tcx, param_env, a_tymut.ty, b_tymut.ty, ckind,
|
||||
)
|
||||
}
|
||||
(Ref(_a_region, a_ty, a_mut), Ref(_b_region, b_ty, b_mut)) => {
|
||||
// For structural sameness, we don't need the region to be same.
|
||||
a_mut == b_mut
|
||||
&& structurally_same_type_impl(
|
||||
seen_types, tcx, param_env, *a_ty, *b_ty, ckind,
|
||||
)
|
||||
}
|
||||
(FnDef(..), FnDef(..)) => {
|
||||
let a_poly_sig = a.fn_sig(tcx);
|
||||
let b_poly_sig = b.fn_sig(tcx);
|
||||
|
||||
// We don't compare regions, but leaving bound regions around ICEs, so
|
||||
// we erase them.
|
||||
let a_sig = tcx.erase_late_bound_regions(a_poly_sig);
|
||||
let b_sig = tcx.erase_late_bound_regions(b_poly_sig);
|
||||
|
||||
(a_sig.abi, a_sig.unsafety, a_sig.c_variadic)
|
||||
== (b_sig.abi, b_sig.unsafety, b_sig.c_variadic)
|
||||
&& a_sig.inputs().iter().eq_by(b_sig.inputs().iter(), |a, b| {
|
||||
structurally_same_type_impl(seen_types, tcx, param_env, *a, *b, ckind)
|
||||
})
|
||||
&& structurally_same_type_impl(
|
||||
seen_types,
|
||||
tcx,
|
||||
param_env,
|
||||
a_sig.output(),
|
||||
b_sig.output(),
|
||||
ckind,
|
||||
)
|
||||
}
|
||||
(Tuple(a_args), Tuple(b_args)) => {
|
||||
a_args.iter().eq_by(b_args.iter(), |a_ty, b_ty| {
|
||||
structurally_same_type_impl(seen_types, tcx, param_env, a_ty, b_ty, ckind)
|
||||
})
|
||||
}
|
||||
// For these, it's not quite as easy to define structural-sameness quite so easily.
|
||||
// For the purposes of this lint, take the conservative approach and mark them as
|
||||
// not structurally same.
|
||||
(Dynamic(..), Dynamic(..))
|
||||
| (Error(..), Error(..))
|
||||
| (Closure(..), Closure(..))
|
||||
| (Generator(..), Generator(..))
|
||||
| (GeneratorWitness(..), GeneratorWitness(..))
|
||||
| (Alias(ty::Projection, ..), Alias(ty::Projection, ..))
|
||||
| (Alias(ty::Inherent, ..), Alias(ty::Inherent, ..))
|
||||
| (Alias(ty::Opaque, ..), Alias(ty::Opaque, ..)) => false,
|
||||
|
||||
// These definitely should have been caught above.
|
||||
(Bool, Bool) | (Char, Char) | (Never, Never) | (Str, Str) => unreachable!(),
|
||||
|
||||
// An Adt and a primitive or pointer type. This can be FFI-safe if non-null
|
||||
// enum layout optimisation is being applied.
|
||||
(Adt(..), other_kind) | (other_kind, Adt(..))
|
||||
if is_primitive_or_pointer(other_kind) =>
|
||||
{
|
||||
let (primitive, adt) =
|
||||
if is_primitive_or_pointer(a.kind()) { (a, b) } else { (b, a) };
|
||||
if let Some(ty) = types::repr_nullable_ptr(tcx, param_env, adt, ckind) {
|
||||
ty == primitive
|
||||
} else {
|
||||
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).unwrap_or(false),
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -17,7 +17,7 @@
|
|||
use crate::{passes::LateLintPassObject, LateContext, LateLintPass, LintStore};
|
||||
use rustc_ast as ast;
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_data_structures::sync::{join, DynSend};
|
||||
use rustc_data_structures::sync::join;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_hir::intravisit as hir_visit;
|
||||
|
@ -336,7 +336,7 @@ macro_rules! impl_late_lint_pass {
|
|||
|
||||
crate::late_lint_methods!(impl_late_lint_pass, []);
|
||||
|
||||
pub(super) fn late_lint_mod<'tcx, T: LateLintPass<'tcx> + 'tcx>(
|
||||
pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx> + 'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
module_def_id: LocalDefId,
|
||||
builtin_lints: T,
|
||||
|
@ -376,6 +376,12 @@ fn late_lint_mod_inner<'tcx, T: LateLintPass<'tcx>>(
|
|||
let mut cx = LateContextAndPass { context, pass };
|
||||
|
||||
let (module, _span, hir_id) = tcx.hir().get_module(module_def_id);
|
||||
|
||||
// There is no module lint that will have the crate itself as an item, so check it here.
|
||||
if hir_id == hir::CRATE_HIR_ID {
|
||||
lint_callback!(cx, check_crate,);
|
||||
}
|
||||
|
||||
cx.process_mod(module, hir_id);
|
||||
|
||||
// Visit the crate attributes
|
||||
|
@ -383,10 +389,19 @@ fn late_lint_mod_inner<'tcx, T: LateLintPass<'tcx>>(
|
|||
for attr in tcx.hir().attrs(hir::CRATE_HIR_ID).iter() {
|
||||
cx.visit_attribute(attr)
|
||||
}
|
||||
lint_callback!(cx, check_crate_post,);
|
||||
}
|
||||
}
|
||||
|
||||
fn late_lint_crate<'tcx, T: LateLintPass<'tcx> + 'tcx>(tcx: TyCtxt<'tcx>, builtin_lints: T) {
|
||||
fn late_lint_crate<'tcx>(tcx: TyCtxt<'tcx>) {
|
||||
// Note: `passes` is often empty.
|
||||
let mut passes: Vec<_> =
|
||||
unerased_lint_store(tcx).late_passes.iter().map(|mk_pass| (mk_pass)(tcx)).collect();
|
||||
|
||||
if passes.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let context = LateContext {
|
||||
tcx,
|
||||
enclosing_body: None,
|
||||
|
@ -399,18 +414,8 @@ fn late_lint_crate<'tcx, T: LateLintPass<'tcx> + 'tcx>(tcx: TyCtxt<'tcx>, builti
|
|||
only_module: false,
|
||||
};
|
||||
|
||||
// Note: `passes` is often empty. In that case, it's faster to run
|
||||
// `builtin_lints` directly rather than bundling it up into the
|
||||
// `RuntimeCombinedLateLintPass`.
|
||||
let mut passes: Vec<_> =
|
||||
unerased_lint_store(tcx).late_passes.iter().map(|mk_pass| (mk_pass)(tcx)).collect();
|
||||
if passes.is_empty() {
|
||||
late_lint_crate_inner(tcx, context, builtin_lints);
|
||||
} else {
|
||||
passes.push(Box::new(builtin_lints));
|
||||
let pass = RuntimeCombinedLateLintPass { passes: &mut passes[..] };
|
||||
late_lint_crate_inner(tcx, context, pass);
|
||||
}
|
||||
let pass = RuntimeCombinedLateLintPass { passes: &mut passes[..] };
|
||||
late_lint_crate_inner(tcx, context, pass);
|
||||
}
|
||||
|
||||
fn late_lint_crate_inner<'tcx, T: LateLintPass<'tcx>>(
|
||||
|
@ -432,15 +437,12 @@ fn late_lint_crate_inner<'tcx, T: LateLintPass<'tcx>>(
|
|||
}
|
||||
|
||||
/// Performs lint checking on a crate.
|
||||
pub fn check_crate<'tcx, T: LateLintPass<'tcx> + 'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
builtin_lints: impl FnOnce() -> T + Send + DynSend,
|
||||
) {
|
||||
pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>) {
|
||||
join(
|
||||
|| {
|
||||
tcx.sess.time("crate_lints", || {
|
||||
// Run whole crate non-incremental lints
|
||||
late_lint_crate(tcx, builtin_lints());
|
||||
late_lint_crate(tcx);
|
||||
});
|
||||
},
|
||||
|| {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use crate::{
|
||||
builtin::MISSING_DOCS,
|
||||
context::{CheckLintNameResult, LintStore},
|
||||
fluent_generated as fluent,
|
||||
late::unerased_lint_store,
|
||||
|
@ -667,6 +668,16 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
|
|||
continue;
|
||||
}
|
||||
|
||||
// `#[doc(hidden)]` disables missing_docs check.
|
||||
if attr.has_name(sym::doc)
|
||||
&& attr
|
||||
.meta_item_list()
|
||||
.map_or(false, |l| ast::attr::list_contains_name(&l, sym::hidden))
|
||||
{
|
||||
self.insert(LintId::of(MISSING_DOCS), (Level::Allow, LintLevelSource::Default));
|
||||
continue;
|
||||
}
|
||||
|
||||
let level = match Level::from_attr(attr) {
|
||||
None => continue,
|
||||
// This is the only lint level with a `LintExpectationId` that can be created from an attribute
|
||||
|
|
|
@ -59,6 +59,7 @@ mod enum_intrinsics_non_enums;
|
|||
mod errors;
|
||||
mod expect;
|
||||
mod for_loops_over_fallibles;
|
||||
mod foreign_modules;
|
||||
pub mod hidden_unicode_codepoints;
|
||||
mod internal;
|
||||
mod invalid_from_utf8;
|
||||
|
@ -125,11 +126,11 @@ use types::*;
|
|||
use unused::*;
|
||||
|
||||
/// Useful for other parts of the compiler / Clippy.
|
||||
pub use builtin::SoftLints;
|
||||
pub use builtin::{MissingDoc, SoftLints};
|
||||
pub use context::{CheckLintNameResult, FindLintError, LintStore};
|
||||
pub use context::{EarlyContext, LateContext, LintContext};
|
||||
pub use early::{check_ast_node, EarlyCheckNode};
|
||||
pub use late::{check_crate, unerased_lint_store};
|
||||
pub use late::{check_crate, late_lint_mod, unerased_lint_store};
|
||||
pub use passes::{EarlyLintPass, LateLintPass};
|
||||
pub use rustc_session::lint::Level::{self, *};
|
||||
pub use rustc_session::lint::{BufferedEarlyLint, FutureIncompatibleInfo, Lint, LintId};
|
||||
|
@ -140,11 +141,12 @@ fluent_messages! { "../messages.ftl" }
|
|||
pub fn provide(providers: &mut Providers) {
|
||||
levels::provide(providers);
|
||||
expect::provide(providers);
|
||||
foreign_modules::provide(providers);
|
||||
*providers = Providers { lint_mod, ..*providers };
|
||||
}
|
||||
|
||||
fn lint_mod(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
|
||||
late::late_lint_mod(tcx, module_def_id, BuiltinCombinedModuleLateLintPass::new());
|
||||
late_lint_mod(tcx, module_def_id, BuiltinCombinedModuleLateLintPass::new());
|
||||
}
|
||||
|
||||
early_lint_methods!(
|
||||
|
@ -182,25 +184,6 @@ early_lint_methods!(
|
|||
]
|
||||
);
|
||||
|
||||
// FIXME: Make a separate lint type which does not require typeck tables.
|
||||
|
||||
late_lint_methods!(
|
||||
declare_combined_late_lint_pass,
|
||||
[
|
||||
pub BuiltinCombinedLateLintPass,
|
||||
[
|
||||
// Tracks attributes of parents
|
||||
MissingDoc: MissingDoc::new(),
|
||||
// Builds a global list of all impls of `Debug`.
|
||||
// FIXME: Turn the computation of types which implement Debug into a query
|
||||
// and change this to a module lint pass
|
||||
MissingDebugImplementations: MissingDebugImplementations::default(),
|
||||
// Keeps a global list of foreign declarations.
|
||||
ClashingExternDeclarations: ClashingExternDeclarations::new(),
|
||||
]
|
||||
]
|
||||
);
|
||||
|
||||
late_lint_methods!(
|
||||
declare_combined_late_lint_pass,
|
||||
[
|
||||
|
@ -253,6 +236,8 @@ late_lint_methods!(
|
|||
OpaqueHiddenInferredBound: OpaqueHiddenInferredBound,
|
||||
MultipleSupertraitUpcastable: MultipleSupertraitUpcastable,
|
||||
MapUnitFn: MapUnitFn,
|
||||
MissingDebugImplementations: MissingDebugImplementations,
|
||||
MissingDoc: MissingDoc,
|
||||
]
|
||||
]
|
||||
);
|
||||
|
@ -281,7 +266,7 @@ fn register_builtins(store: &mut LintStore) {
|
|||
store.register_lints(&BuiltinCombinedPreExpansionLintPass::get_lints());
|
||||
store.register_lints(&BuiltinCombinedEarlyLintPass::get_lints());
|
||||
store.register_lints(&BuiltinCombinedModuleLateLintPass::get_lints());
|
||||
store.register_lints(&BuiltinCombinedLateLintPass::get_lints());
|
||||
store.register_lints(&foreign_modules::get_lints());
|
||||
|
||||
add_lint_group!(
|
||||
"nonstandard_style",
|
||||
|
@ -521,20 +506,20 @@ fn register_internals(store: &mut LintStore) {
|
|||
store.register_lints(&LintPassImpl::get_lints());
|
||||
store.register_early_pass(|| Box::new(LintPassImpl));
|
||||
store.register_lints(&DefaultHashTypes::get_lints());
|
||||
store.register_late_pass(|_| Box::new(DefaultHashTypes));
|
||||
store.register_late_mod_pass(|_| Box::new(DefaultHashTypes));
|
||||
store.register_lints(&QueryStability::get_lints());
|
||||
store.register_late_pass(|_| Box::new(QueryStability));
|
||||
store.register_late_mod_pass(|_| Box::new(QueryStability));
|
||||
store.register_lints(&ExistingDocKeyword::get_lints());
|
||||
store.register_late_pass(|_| Box::new(ExistingDocKeyword));
|
||||
store.register_late_mod_pass(|_| Box::new(ExistingDocKeyword));
|
||||
store.register_lints(&TyTyKind::get_lints());
|
||||
store.register_late_pass(|_| Box::new(TyTyKind));
|
||||
store.register_late_mod_pass(|_| Box::new(TyTyKind));
|
||||
store.register_lints(&Diagnostics::get_lints());
|
||||
store.register_early_pass(|| Box::new(Diagnostics));
|
||||
store.register_late_pass(|_| Box::new(Diagnostics));
|
||||
store.register_late_mod_pass(|_| Box::new(Diagnostics));
|
||||
store.register_lints(&BadOptAccess::get_lints());
|
||||
store.register_late_pass(|_| Box::new(BadOptAccess));
|
||||
store.register_late_mod_pass(|_| Box::new(BadOptAccess));
|
||||
store.register_lints(&PassByValue::get_lints());
|
||||
store.register_late_pass(|_| Box::new(PassByValue));
|
||||
store.register_late_mod_pass(|_| Box::new(PassByValue));
|
||||
// FIXME(davidtwco): deliberately do not include `UNTRANSLATABLE_DIAGNOSTIC` and
|
||||
// `DIAGNOSTIC_OUTSIDE_OF_IMPL` here because `-Wrustc::internal` is provided to every crate and
|
||||
// these lints will trigger all of the time - change this once migration to diagnostic structs
|
||||
|
|
|
@ -815,8 +815,7 @@ pub fn transparent_newtype_field<'a, 'tcx>(
|
|||
}
|
||||
|
||||
/// Is type known to be non-null?
|
||||
fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: CItemKind) -> bool {
|
||||
let tcx = cx.tcx;
|
||||
fn ty_is_known_nonnull<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, mode: CItemKind) -> bool {
|
||||
match ty.kind() {
|
||||
ty::FnPtr(_) => true,
|
||||
ty::Ref(..) => true,
|
||||
|
@ -835,8 +834,8 @@ fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: CItemKi
|
|||
|
||||
def.variants()
|
||||
.iter()
|
||||
.filter_map(|variant| transparent_newtype_field(cx.tcx, variant))
|
||||
.any(|field| ty_is_known_nonnull(cx, field.ty(tcx, args), mode))
|
||||
.filter_map(|variant| transparent_newtype_field(tcx, variant))
|
||||
.any(|field| ty_is_known_nonnull(tcx, field.ty(tcx, args), mode))
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
|
@ -844,15 +843,12 @@ fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: CItemKi
|
|||
|
||||
/// Given a non-null scalar (or transparent) type `ty`, return the nullable version of that type.
|
||||
/// If the type passed in was not scalar, returns None.
|
||||
fn get_nullable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
|
||||
let tcx = cx.tcx;
|
||||
fn get_nullable_type<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
|
||||
Some(match *ty.kind() {
|
||||
ty::Adt(field_def, field_args) => {
|
||||
let inner_field_ty = {
|
||||
let mut first_non_zst_ty = field_def
|
||||
.variants()
|
||||
.iter()
|
||||
.filter_map(|v| transparent_newtype_field(cx.tcx, v));
|
||||
let mut first_non_zst_ty =
|
||||
field_def.variants().iter().filter_map(|v| transparent_newtype_field(tcx, v));
|
||||
debug_assert_eq!(
|
||||
first_non_zst_ty.clone().count(),
|
||||
1,
|
||||
|
@ -863,7 +859,7 @@ fn get_nullable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'t
|
|||
.expect("No non-zst fields in transparent type.")
|
||||
.ty(tcx, field_args)
|
||||
};
|
||||
return get_nullable_type(cx, inner_field_ty);
|
||||
return get_nullable_type(tcx, inner_field_ty);
|
||||
}
|
||||
ty::Int(ty) => Ty::new_int(tcx, ty),
|
||||
ty::Uint(ty) => Ty::new_uint(tcx, ty),
|
||||
|
@ -895,43 +891,44 @@ fn get_nullable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'t
|
|||
/// `core::ptr::NonNull`, and `#[repr(transparent)]` newtypes.
|
||||
/// FIXME: This duplicates code in codegen.
|
||||
pub(crate) fn repr_nullable_ptr<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
ckind: CItemKind,
|
||||
) -> Option<Ty<'tcx>> {
|
||||
debug!("is_repr_nullable_ptr(cx, ty = {:?})", ty);
|
||||
debug!("is_repr_nullable_ptr(tcx, ty = {:?})", ty);
|
||||
if let ty::Adt(ty_def, args) = ty.kind() {
|
||||
let field_ty = match &ty_def.variants().raw[..] {
|
||||
[var_one, var_two] => match (&var_one.fields.raw[..], &var_two.fields.raw[..]) {
|
||||
([], [field]) | ([field], []) => field.ty(cx.tcx, args),
|
||||
([], [field]) | ([field], []) => field.ty(tcx, args),
|
||||
_ => return None,
|
||||
},
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
if !ty_is_known_nonnull(cx, field_ty, ckind) {
|
||||
if !ty_is_known_nonnull(tcx, field_ty, ckind) {
|
||||
return None;
|
||||
}
|
||||
|
||||
// At this point, the field's type is known to be nonnull and the parent enum is Option-like.
|
||||
// If the computed size for the field and the enum are different, the nonnull optimization isn't
|
||||
// being applied (and we've got a problem somewhere).
|
||||
let compute_size_skeleton = |t| SizeSkeleton::compute(t, cx.tcx, cx.param_env).unwrap();
|
||||
let compute_size_skeleton = |t| SizeSkeleton::compute(t, tcx, param_env).unwrap();
|
||||
if !compute_size_skeleton(ty).same_size(compute_size_skeleton(field_ty)) {
|
||||
bug!("improper_ctypes: Option nonnull optimization not applied?");
|
||||
}
|
||||
|
||||
// Return the nullable type this Option-like enum can be safely represented with.
|
||||
let field_ty_abi = &cx.layout_of(field_ty).unwrap().abi;
|
||||
let field_ty_abi = &tcx.layout_of(param_env.and(field_ty)).unwrap().abi;
|
||||
if let Abi::Scalar(field_ty_scalar) = field_ty_abi {
|
||||
match field_ty_scalar.valid_range(cx) {
|
||||
match field_ty_scalar.valid_range(&tcx) {
|
||||
WrappingRange { start: 0, end }
|
||||
if end == field_ty_scalar.size(&cx.tcx).unsigned_int_max() - 1 =>
|
||||
if end == field_ty_scalar.size(&tcx).unsigned_int_max() - 1 =>
|
||||
{
|
||||
return Some(get_nullable_type(cx, field_ty).unwrap());
|
||||
return Some(get_nullable_type(tcx, field_ty).unwrap());
|
||||
}
|
||||
WrappingRange { start: 1, .. } => {
|
||||
return Some(get_nullable_type(cx, field_ty).unwrap());
|
||||
return Some(get_nullable_type(tcx, field_ty).unwrap());
|
||||
}
|
||||
WrappingRange { start, end } => {
|
||||
unreachable!("Unhandled start and end range: ({}, {})", start, end)
|
||||
|
@ -1116,7 +1113,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
|||
if !def.repr().c() && !def.repr().transparent() && def.repr().int.is_none()
|
||||
{
|
||||
// Special-case types like `Option<extern fn()>`.
|
||||
if repr_nullable_ptr(self.cx, ty, self.mode).is_none() {
|
||||
if repr_nullable_ptr(self.cx.tcx, self.cx.param_env, ty, self.mode)
|
||||
.is_none()
|
||||
{
|
||||
return FfiUnsafe {
|
||||
ty,
|
||||
reason: fluent::lint_improper_ctypes_enum_repr_reason,
|
||||
|
|
|
@ -1596,6 +1596,11 @@ rustc_queries! {
|
|||
separate_provide_extern
|
||||
}
|
||||
|
||||
/// Lint against `extern fn` declarations having incompatible types.
|
||||
query clashing_extern_declarations(_: ()) {
|
||||
desc { "checking `extern fn` declarations are compatible" }
|
||||
}
|
||||
|
||||
/// Identifies the entry-point (e.g., the `main` function) for a given
|
||||
/// crate, returning `None` if there is no entry point (such as for library crates).
|
||||
query entry_fn(_: ()) -> Option<(DefId, EntryFnType)> {
|
||||
|
|
|
@ -10,6 +10,7 @@ use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LocalDefId};
|
|||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_hir::{HirId, Path};
|
||||
use rustc_interface::interface;
|
||||
use rustc_lint::{late_lint_mod, MissingDoc};
|
||||
use rustc_middle::hir::nested_filter;
|
||||
use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
|
||||
use rustc_session::config::{self, CrateType, ErrorOutputType, ResolveDocLinks};
|
||||
|
@ -262,8 +263,9 @@ pub(crate) fn create_config(
|
|||
parse_sess_created: None,
|
||||
register_lints: Some(Box::new(crate::lint::register_lints)),
|
||||
override_queries: Some(|_sess, providers, _external_providers| {
|
||||
// We do not register late module lints, so this only runs `MissingDoc`.
|
||||
// Most lints will require typechecking, so just don't run them.
|
||||
providers.lint_mod = |_, _| {};
|
||||
providers.lint_mod = |tcx, module_def_id| late_lint_mod(tcx, module_def_id, MissingDoc);
|
||||
// hack so that `used_trait_imports` won't try to call typeck
|
||||
providers.used_trait_imports = |_, _| {
|
||||
static EMPTY_SET: LazyLock<UnordSet<LocalDefId>> = LazyLock::new(UnordSet::default);
|
||||
|
@ -317,9 +319,7 @@ pub(crate) fn run_global_ctxt(
|
|||
tcx.hir().for_each_module(|module| tcx.ensure().check_mod_item_types(module))
|
||||
});
|
||||
tcx.sess.abort_if_errors();
|
||||
tcx.sess.time("missing_docs", || {
|
||||
rustc_lint::check_crate(tcx, rustc_lint::builtin::MissingDoc::new);
|
||||
});
|
||||
tcx.sess.time("missing_docs", || rustc_lint::check_crate(tcx));
|
||||
tcx.sess.time("check_mod_attrs", || {
|
||||
tcx.hir().for_each_module(|module| tcx.ensure().check_mod_attrs(module))
|
||||
});
|
||||
|
|
|
@ -1,218 +1,3 @@
|
|||
warning: `clash` redeclared with a different signature
|
||||
--> $DIR/clashing-extern-fn.rs:14:13
|
||||
|
|
||||
LL | fn clash(x: u8);
|
||||
| ---------------- `clash` previously declared here
|
||||
...
|
||||
LL | fn clash(x: u64);
|
||||
| ^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
||||
|
|
||||
= note: expected `unsafe extern "C" fn(u8)`
|
||||
found `unsafe extern "C" fn(u64)`
|
||||
note: the lint level is defined here
|
||||
--> $DIR/clashing-extern-fn.rs:4:9
|
||||
|
|
||||
LL | #![warn(clashing_extern_declarations)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
warning: `extern_link_name` redeclared with a different signature
|
||||
--> $DIR/clashing-extern-fn.rs:52:9
|
||||
|
|
||||
LL | / #[link_name = "extern_link_name"]
|
||||
LL | | fn some_new_name(x: i16);
|
||||
| |_____________________________- `extern_link_name` previously declared here
|
||||
...
|
||||
LL | fn extern_link_name(x: u32);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
||||
|
|
||||
= note: expected `unsafe extern "C" fn(i16)`
|
||||
found `unsafe extern "C" fn(u32)`
|
||||
|
||||
warning: `some_other_extern_link_name` redeclares `some_other_new_name` with a different signature
|
||||
--> $DIR/clashing-extern-fn.rs:55:9
|
||||
|
|
||||
LL | fn some_other_new_name(x: i16);
|
||||
| ------------------------------- `some_other_new_name` previously declared here
|
||||
...
|
||||
LL | / #[link_name = "some_other_new_name"]
|
||||
LL | |
|
||||
LL | | fn some_other_extern_link_name(x: u32);
|
||||
| |_______________________________________________^ this signature doesn't match the previous declaration
|
||||
|
|
||||
= note: expected `unsafe extern "C" fn(i16)`
|
||||
found `unsafe extern "C" fn(u32)`
|
||||
|
||||
warning: `other_both_names_different` redeclares `link_name_same` with a different signature
|
||||
--> $DIR/clashing-extern-fn.rs:59:9
|
||||
|
|
||||
LL | / #[link_name = "link_name_same"]
|
||||
LL | | fn both_names_different(x: i16);
|
||||
| |____________________________________- `link_name_same` previously declared here
|
||||
...
|
||||
LL | / #[link_name = "link_name_same"]
|
||||
LL | |
|
||||
LL | | fn other_both_names_different(x: u32);
|
||||
| |______________________________________________^ this signature doesn't match the previous declaration
|
||||
|
|
||||
= note: expected `unsafe extern "C" fn(i16)`
|
||||
found `unsafe extern "C" fn(u32)`
|
||||
|
||||
warning: `different_mod` redeclared with a different signature
|
||||
--> $DIR/clashing-extern-fn.rs:72:9
|
||||
|
|
||||
LL | fn different_mod(x: u8);
|
||||
| ------------------------ `different_mod` previously declared here
|
||||
...
|
||||
LL | fn different_mod(x: u64);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
||||
|
|
||||
= note: expected `unsafe extern "C" fn(u8)`
|
||||
found `unsafe extern "C" fn(u64)`
|
||||
|
||||
warning: `variadic_decl` redeclared with a different signature
|
||||
--> $DIR/clashing-extern-fn.rs:82:9
|
||||
|
|
||||
LL | fn variadic_decl(x: u8, ...);
|
||||
| ----------------------------- `variadic_decl` previously declared here
|
||||
...
|
||||
LL | fn variadic_decl(x: u8);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
||||
|
|
||||
= note: expected `unsafe extern "C" fn(u8, ...)`
|
||||
found `unsafe extern "C" fn(u8)`
|
||||
|
||||
warning: `weigh_banana` redeclared with a different signature
|
||||
--> $DIR/clashing-extern-fn.rs:142:13
|
||||
|
|
||||
LL | fn weigh_banana(count: *const Banana) -> u64;
|
||||
| --------------------------------------------- `weigh_banana` previously declared here
|
||||
...
|
||||
LL | fn weigh_banana(count: *const Banana) -> u64;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
||||
|
|
||||
= note: expected `unsafe extern "C" fn(*const one::Banana) -> u64`
|
||||
found `unsafe extern "C" fn(*const three::Banana) -> u64`
|
||||
|
||||
warning: `draw_point` redeclared with a different signature
|
||||
--> $DIR/clashing-extern-fn.rs:171:13
|
||||
|
|
||||
LL | fn draw_point(p: Point);
|
||||
| ------------------------ `draw_point` previously declared here
|
||||
...
|
||||
LL | fn draw_point(p: Point);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
||||
|
|
||||
= note: expected `unsafe extern "C" fn(sameish_members::a::Point)`
|
||||
found `unsafe extern "C" fn(sameish_members::b::Point)`
|
||||
|
||||
warning: `origin` redeclared with a different signature
|
||||
--> $DIR/clashing-extern-fn.rs:197:13
|
||||
|
|
||||
LL | fn origin() -> Point3;
|
||||
| ---------------------- `origin` previously declared here
|
||||
...
|
||||
LL | fn origin() -> Point3;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
||||
|
|
||||
= note: expected `unsafe extern "C" fn() -> same_sized_members_clash::a::Point3`
|
||||
found `unsafe extern "C" fn() -> same_sized_members_clash::b::Point3`
|
||||
|
||||
warning: `transparent_incorrect` redeclared with a different signature
|
||||
--> $DIR/clashing-extern-fn.rs:220:13
|
||||
|
|
||||
LL | fn transparent_incorrect() -> T;
|
||||
| -------------------------------- `transparent_incorrect` previously declared here
|
||||
...
|
||||
LL | fn transparent_incorrect() -> isize;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
||||
|
|
||||
= note: expected `unsafe extern "C" fn() -> T`
|
||||
found `unsafe extern "C" fn() -> isize`
|
||||
|
||||
warning: `missing_return_type` redeclared with a different signature
|
||||
--> $DIR/clashing-extern-fn.rs:259:13
|
||||
|
|
||||
LL | fn missing_return_type() -> usize;
|
||||
| ---------------------------------- `missing_return_type` previously declared here
|
||||
...
|
||||
LL | fn missing_return_type();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
||||
|
|
||||
= note: expected `unsafe extern "C" fn() -> usize`
|
||||
found `unsafe extern "C" fn()`
|
||||
|
||||
warning: `non_zero_usize` redeclared with a different signature
|
||||
--> $DIR/clashing-extern-fn.rs:277:13
|
||||
|
|
||||
LL | fn non_zero_usize() -> core::num::NonZeroUsize;
|
||||
| ----------------------------------------------- `non_zero_usize` previously declared here
|
||||
...
|
||||
LL | fn non_zero_usize() -> usize;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
||||
|
|
||||
= note: expected `unsafe extern "C" fn() -> NonZeroUsize`
|
||||
found `unsafe extern "C" fn() -> usize`
|
||||
|
||||
warning: `non_null_ptr` redeclared with a different signature
|
||||
--> $DIR/clashing-extern-fn.rs:279:13
|
||||
|
|
||||
LL | fn non_null_ptr() -> core::ptr::NonNull<usize>;
|
||||
| ----------------------------------------------- `non_null_ptr` previously declared here
|
||||
...
|
||||
LL | fn non_null_ptr() -> *const usize;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
||||
|
|
||||
= note: expected `unsafe extern "C" fn() -> NonNull<usize>`
|
||||
found `unsafe extern "C" fn() -> *const usize`
|
||||
|
||||
warning: `option_non_zero_usize_incorrect` redeclared with a different signature
|
||||
--> $DIR/clashing-extern-fn.rs:377:13
|
||||
|
|
||||
LL | fn option_non_zero_usize_incorrect() -> usize;
|
||||
| ---------------------------------------------- `option_non_zero_usize_incorrect` previously declared here
|
||||
...
|
||||
LL | fn option_non_zero_usize_incorrect() -> isize;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
||||
|
|
||||
= note: expected `unsafe extern "C" fn() -> usize`
|
||||
found `unsafe extern "C" fn() -> isize`
|
||||
|
||||
warning: `option_non_null_ptr_incorrect` redeclared with a different signature
|
||||
--> $DIR/clashing-extern-fn.rs:379:13
|
||||
|
|
||||
LL | fn option_non_null_ptr_incorrect() -> *const usize;
|
||||
| --------------------------------------------------- `option_non_null_ptr_incorrect` previously declared here
|
||||
...
|
||||
LL | fn option_non_null_ptr_incorrect() -> *const isize;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
||||
|
|
||||
= note: expected `unsafe extern "C" fn() -> *const usize`
|
||||
found `unsafe extern "C" fn() -> *const isize`
|
||||
|
||||
warning: `hidden_niche_transparent_no_niche` redeclared with a different signature
|
||||
--> $DIR/clashing-extern-fn.rs:433:13
|
||||
|
|
||||
LL | fn hidden_niche_transparent_no_niche() -> usize;
|
||||
| ------------------------------------------------ `hidden_niche_transparent_no_niche` previously declared here
|
||||
...
|
||||
LL | fn hidden_niche_transparent_no_niche() -> Option<TransparentNoNiche>;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
||||
|
|
||||
= note: expected `unsafe extern "C" fn() -> usize`
|
||||
found `unsafe extern "C" fn() -> Option<TransparentNoNiche>`
|
||||
|
||||
warning: `hidden_niche_unsafe_cell` redeclared with a different signature
|
||||
--> $DIR/clashing-extern-fn.rs:437:13
|
||||
|
|
||||
LL | fn hidden_niche_unsafe_cell() -> usize;
|
||||
| --------------------------------------- `hidden_niche_unsafe_cell` previously declared here
|
||||
...
|
||||
LL | fn hidden_niche_unsafe_cell() -> Option<UnsafeCell<NonZeroUsize>>;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
||||
|
|
||||
= note: expected `unsafe extern "C" fn() -> usize`
|
||||
found `unsafe extern "C" fn() -> Option<UnsafeCell<NonZeroUsize>>`
|
||||
|
||||
warning: `extern` block uses type `Option<TransparentNoNiche>`, which is not FFI-safe
|
||||
--> $DIR/clashing-extern-fn.rs:433:55
|
||||
|
|
||||
|
@ -232,5 +17,214 @@ LL | fn hidden_niche_unsafe_cell() -> Option<UnsafeCell<NonZeroUsize
|
|||
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
|
||||
= note: enum has no representation hint
|
||||
|
||||
warning: `clash` redeclared with a different signature
|
||||
--> $DIR/clashing-extern-fn.rs:14:13
|
||||
|
|
||||
LL | fn clash(x: u8);
|
||||
| --------------- `clash` previously declared here
|
||||
...
|
||||
LL | fn clash(x: u64);
|
||||
| ^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
||||
|
|
||||
= note: expected `unsafe extern "C" fn(u8)`
|
||||
found `unsafe extern "C" fn(u64)`
|
||||
note: the lint level is defined here
|
||||
--> $DIR/clashing-extern-fn.rs:4:9
|
||||
|
|
||||
LL | #![warn(clashing_extern_declarations)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
warning: `extern_link_name` redeclared with a different signature
|
||||
--> $DIR/clashing-extern-fn.rs:52:9
|
||||
|
|
||||
LL | #[link_name = "extern_link_name"]
|
||||
| --------------------------------- `extern_link_name` previously declared here
|
||||
...
|
||||
LL | fn extern_link_name(x: u32);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
||||
|
|
||||
= note: expected `unsafe extern "C" fn(i16)`
|
||||
found `unsafe extern "C" fn(u32)`
|
||||
|
||||
warning: `some_other_extern_link_name` redeclares `some_other_new_name` with a different signature
|
||||
--> $DIR/clashing-extern-fn.rs:55:9
|
||||
|
|
||||
LL | fn some_other_new_name(x: i16);
|
||||
| ------------------------------ `some_other_new_name` previously declared here
|
||||
...
|
||||
LL | #[link_name = "some_other_new_name"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
||||
|
|
||||
= note: expected `unsafe extern "C" fn(i16)`
|
||||
found `unsafe extern "C" fn(u32)`
|
||||
|
||||
warning: `other_both_names_different` redeclares `link_name_same` with a different signature
|
||||
--> $DIR/clashing-extern-fn.rs:59:9
|
||||
|
|
||||
LL | #[link_name = "link_name_same"]
|
||||
| ------------------------------- `link_name_same` previously declared here
|
||||
...
|
||||
LL | #[link_name = "link_name_same"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
||||
|
|
||||
= note: expected `unsafe extern "C" fn(i16)`
|
||||
found `unsafe extern "C" fn(u32)`
|
||||
|
||||
warning: `different_mod` redeclared with a different signature
|
||||
--> $DIR/clashing-extern-fn.rs:72:9
|
||||
|
|
||||
LL | fn different_mod(x: u8);
|
||||
| ----------------------- `different_mod` previously declared here
|
||||
...
|
||||
LL | fn different_mod(x: u64);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
||||
|
|
||||
= note: expected `unsafe extern "C" fn(u8)`
|
||||
found `unsafe extern "C" fn(u64)`
|
||||
|
||||
warning: `variadic_decl` redeclared with a different signature
|
||||
--> $DIR/clashing-extern-fn.rs:82:9
|
||||
|
|
||||
LL | fn variadic_decl(x: u8, ...);
|
||||
| ---------------------------- `variadic_decl` previously declared here
|
||||
...
|
||||
LL | fn variadic_decl(x: u8);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
||||
|
|
||||
= note: expected `unsafe extern "C" fn(u8, ...)`
|
||||
found `unsafe extern "C" fn(u8)`
|
||||
|
||||
warning: `weigh_banana` redeclared with a different signature
|
||||
--> $DIR/clashing-extern-fn.rs:142:13
|
||||
|
|
||||
LL | fn weigh_banana(count: *const Banana) -> u64;
|
||||
| -------------------------------------------- `weigh_banana` previously declared here
|
||||
...
|
||||
LL | fn weigh_banana(count: *const Banana) -> u64;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
||||
|
|
||||
= note: expected `unsafe extern "C" fn(*const one::Banana) -> u64`
|
||||
found `unsafe extern "C" fn(*const three::Banana) -> u64`
|
||||
|
||||
warning: `draw_point` redeclared with a different signature
|
||||
--> $DIR/clashing-extern-fn.rs:171:13
|
||||
|
|
||||
LL | fn draw_point(p: Point);
|
||||
| ----------------------- `draw_point` previously declared here
|
||||
...
|
||||
LL | fn draw_point(p: Point);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
||||
|
|
||||
= note: expected `unsafe extern "C" fn(sameish_members::a::Point)`
|
||||
found `unsafe extern "C" fn(sameish_members::b::Point)`
|
||||
|
||||
warning: `origin` redeclared with a different signature
|
||||
--> $DIR/clashing-extern-fn.rs:197:13
|
||||
|
|
||||
LL | fn origin() -> Point3;
|
||||
| --------------------- `origin` previously declared here
|
||||
...
|
||||
LL | fn origin() -> Point3;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
||||
|
|
||||
= note: expected `unsafe extern "C" fn() -> same_sized_members_clash::a::Point3`
|
||||
found `unsafe extern "C" fn() -> same_sized_members_clash::b::Point3`
|
||||
|
||||
warning: `transparent_incorrect` redeclared with a different signature
|
||||
--> $DIR/clashing-extern-fn.rs:220:13
|
||||
|
|
||||
LL | fn transparent_incorrect() -> T;
|
||||
| ------------------------------- `transparent_incorrect` previously declared here
|
||||
...
|
||||
LL | fn transparent_incorrect() -> isize;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
||||
|
|
||||
= note: expected `unsafe extern "C" fn() -> T`
|
||||
found `unsafe extern "C" fn() -> isize`
|
||||
|
||||
warning: `missing_return_type` redeclared with a different signature
|
||||
--> $DIR/clashing-extern-fn.rs:259:13
|
||||
|
|
||||
LL | fn missing_return_type() -> usize;
|
||||
| --------------------------------- `missing_return_type` previously declared here
|
||||
...
|
||||
LL | fn missing_return_type();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
||||
|
|
||||
= note: expected `unsafe extern "C" fn() -> usize`
|
||||
found `unsafe extern "C" fn()`
|
||||
|
||||
warning: `non_zero_usize` redeclared with a different signature
|
||||
--> $DIR/clashing-extern-fn.rs:277:13
|
||||
|
|
||||
LL | fn non_zero_usize() -> core::num::NonZeroUsize;
|
||||
| ---------------------------------------------- `non_zero_usize` previously declared here
|
||||
...
|
||||
LL | fn non_zero_usize() -> usize;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
||||
|
|
||||
= note: expected `unsafe extern "C" fn() -> NonZeroUsize`
|
||||
found `unsafe extern "C" fn() -> usize`
|
||||
|
||||
warning: `non_null_ptr` redeclared with a different signature
|
||||
--> $DIR/clashing-extern-fn.rs:279:13
|
||||
|
|
||||
LL | fn non_null_ptr() -> core::ptr::NonNull<usize>;
|
||||
| ---------------------------------------------- `non_null_ptr` previously declared here
|
||||
...
|
||||
LL | fn non_null_ptr() -> *const usize;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
||||
|
|
||||
= note: expected `unsafe extern "C" fn() -> NonNull<usize>`
|
||||
found `unsafe extern "C" fn() -> *const usize`
|
||||
|
||||
warning: `option_non_zero_usize_incorrect` redeclared with a different signature
|
||||
--> $DIR/clashing-extern-fn.rs:377:13
|
||||
|
|
||||
LL | fn option_non_zero_usize_incorrect() -> usize;
|
||||
| --------------------------------------------- `option_non_zero_usize_incorrect` previously declared here
|
||||
...
|
||||
LL | fn option_non_zero_usize_incorrect() -> isize;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
||||
|
|
||||
= note: expected `unsafe extern "C" fn() -> usize`
|
||||
found `unsafe extern "C" fn() -> isize`
|
||||
|
||||
warning: `option_non_null_ptr_incorrect` redeclared with a different signature
|
||||
--> $DIR/clashing-extern-fn.rs:379:13
|
||||
|
|
||||
LL | fn option_non_null_ptr_incorrect() -> *const usize;
|
||||
| -------------------------------------------------- `option_non_null_ptr_incorrect` previously declared here
|
||||
...
|
||||
LL | fn option_non_null_ptr_incorrect() -> *const isize;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
||||
|
|
||||
= note: expected `unsafe extern "C" fn() -> *const usize`
|
||||
found `unsafe extern "C" fn() -> *const isize`
|
||||
|
||||
warning: `hidden_niche_transparent_no_niche` redeclared with a different signature
|
||||
--> $DIR/clashing-extern-fn.rs:433:13
|
||||
|
|
||||
LL | fn hidden_niche_transparent_no_niche() -> usize;
|
||||
| ----------------------------------------------- `hidden_niche_transparent_no_niche` previously declared here
|
||||
...
|
||||
LL | fn hidden_niche_transparent_no_niche() -> Option<TransparentNoNiche>;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
||||
|
|
||||
= note: expected `unsafe extern "C" fn() -> usize`
|
||||
found `unsafe extern "C" fn() -> Option<TransparentNoNiche>`
|
||||
|
||||
warning: `hidden_niche_unsafe_cell` redeclared with a different signature
|
||||
--> $DIR/clashing-extern-fn.rs:437:13
|
||||
|
|
||||
LL | fn hidden_niche_unsafe_cell() -> usize;
|
||||
| -------------------------------------- `hidden_niche_unsafe_cell` previously declared here
|
||||
...
|
||||
LL | fn hidden_niche_unsafe_cell() -> Option<UnsafeCell<NonZeroUsize>>;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
||||
|
|
||||
= note: expected `unsafe extern "C" fn() -> usize`
|
||||
found `unsafe extern "C" fn() -> Option<UnsafeCell<NonZeroUsize>>`
|
||||
|
||||
warning: 19 warnings emitted
|
||||
|
||||
|
|
|
@ -1,15 +1,3 @@
|
|||
error: type does not implement `Debug`; consider adding `#[derive(Debug)]` or a manual implementation
|
||||
--> $DIR/issue-111359.rs:7:5
|
||||
|
|
||||
LL | pub struct BarPub;
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/issue-111359.rs:1:8
|
||||
|
|
||||
LL | #[deny(missing_debug_implementations)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: type could implement `Copy`; consider adding `impl Copy`
|
||||
--> $DIR/issue-111359.rs:7:5
|
||||
|
|
||||
|
@ -22,5 +10,17 @@ note: the lint level is defined here
|
|||
LL | #[deny(missing_copy_implementations)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: type does not implement `Debug`; consider adding `#[derive(Debug)]` or a manual implementation
|
||||
--> $DIR/issue-111359.rs:7:5
|
||||
|
|
||||
LL | pub struct BarPub;
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/issue-111359.rs:1:8
|
||||
|
|
||||
LL | #[deny(missing_debug_implementations)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
@ -2,10 +2,10 @@ warning: `rust_task_is_unwinding` redeclared with a different signature
|
|||
--> $DIR/issue-1866.rs:23:13
|
||||
|
|
||||
LL | pub fn rust_task_is_unwinding(rt: *const rust_task) -> bool;
|
||||
| ------------------------------------------------------------ `rust_task_is_unwinding` previously declared here
|
||||
| ----------------------------------------------------------- `rust_task_is_unwinding` previously declared here
|
||||
...
|
||||
LL | pub fn rust_task_is_unwinding(rt: *const rust_task) -> bool;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
||||
|
|
||||
= note: expected `unsafe extern "C" fn(*const usize) -> bool`
|
||||
found `unsafe extern "C" fn(*const bool) -> bool`
|
||||
|
|
|
@ -34,12 +34,6 @@ note: the lint level is defined here
|
|||
LL | #![deny(missing_docs)]
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: missing documentation for a function
|
||||
--> $DIR/lint-attr-everywhere-late.rs:47:5
|
||||
|
|
||||
LL | pub fn missing_inner() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: missing documentation for an associated function
|
||||
--> $DIR/lint-attr-everywhere-late.rs:54:5
|
||||
|
|
||||
|
@ -142,52 +136,6 @@ note: the lint level is defined here
|
|||
LL | #[deny(missing_docs)]
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: missing documentation for a variant
|
||||
--> $DIR/lint-attr-everywhere-late.rs:112:5
|
||||
|
|
||||
LL | Variant1,
|
||||
| ^^^^^^^^
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/lint-attr-everywhere-late.rs:111:12
|
||||
|
|
||||
LL | #[deny(missing_docs)]
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: `clashing1` redeclared with a different signature
|
||||
--> $DIR/lint-attr-everywhere-late.rs:123:5
|
||||
|
|
||||
LL | fn clashing1();
|
||||
| --------------- `clashing1` previously declared here
|
||||
...
|
||||
LL | fn clashing1(_: i32);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
||||
|
|
||||
= note: expected `unsafe extern "C" fn()`
|
||||
found `unsafe extern "C" fn(i32)`
|
||||
note: the lint level is defined here
|
||||
--> $DIR/lint-attr-everywhere-late.rs:122:13
|
||||
|
|
||||
LL | #![deny(clashing_extern_declarations)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: `clashing2` redeclared with a different signature
|
||||
--> $DIR/lint-attr-everywhere-late.rs:128:5
|
||||
|
|
||||
LL | fn clashing2();
|
||||
| --------------- `clashing2` previously declared here
|
||||
...
|
||||
LL | fn clashing2(_: i32);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
||||
|
|
||||
= note: expected `unsafe extern "C" fn()`
|
||||
found `unsafe extern "C" fn(i32)`
|
||||
note: the lint level is defined here
|
||||
--> $DIR/lint-attr-everywhere-late.rs:127:12
|
||||
|
|
||||
LL | #[deny(clashing_extern_declarations)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: types that do not implement `Drop` can still have drop glue, consider instead using `std::mem::needs_drop` to detect whether a type is trivially dropped
|
||||
--> $DIR/lint-attr-everywhere-late.rs:93:38
|
||||
|
|
||||
|
@ -230,6 +178,18 @@ note: the lint level is defined here
|
|||
LL | #[deny(overflowing_literals)] const ASSOC_CONST: u8 = 1000;
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: missing documentation for a variant
|
||||
--> $DIR/lint-attr-everywhere-late.rs:112:5
|
||||
|
|
||||
LL | Variant1,
|
||||
| ^^^^^^^^
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/lint-attr-everywhere-late.rs:111:12
|
||||
|
|
||||
LL | #[deny(missing_docs)]
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: variable `PARAM` should have a snake case name
|
||||
--> $DIR/lint-attr-everywhere-late.rs:131:37
|
||||
|
|
||||
|
@ -436,5 +396,45 @@ note: the lint level is defined here
|
|||
LL | TupleStruct(#[deny(enum_intrinsics_non_enums)] discriminant::<i32>(&123));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: missing documentation for a function
|
||||
--> $DIR/lint-attr-everywhere-late.rs:47:5
|
||||
|
|
||||
LL | pub fn missing_inner() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: `clashing1` redeclared with a different signature
|
||||
--> $DIR/lint-attr-everywhere-late.rs:123:5
|
||||
|
|
||||
LL | fn clashing1();
|
||||
| -------------- `clashing1` previously declared here
|
||||
...
|
||||
LL | fn clashing1(_: i32);
|
||||
| ^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
||||
|
|
||||
= note: expected `unsafe extern "C" fn()`
|
||||
found `unsafe extern "C" fn(i32)`
|
||||
note: the lint level is defined here
|
||||
--> $DIR/lint-attr-everywhere-late.rs:122:13
|
||||
|
|
||||
LL | #![deny(clashing_extern_declarations)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: `clashing2` redeclared with a different signature
|
||||
--> $DIR/lint-attr-everywhere-late.rs:128:5
|
||||
|
|
||||
LL | fn clashing2();
|
||||
| -------------- `clashing2` previously declared here
|
||||
...
|
||||
LL | fn clashing2(_: i32);
|
||||
| ^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
||||
|
|
||||
= note: expected `unsafe extern "C" fn()`
|
||||
found `unsafe extern "C" fn(i32)`
|
||||
note: the lint level is defined here
|
||||
--> $DIR/lint-attr-everywhere-late.rs:127:12
|
||||
|
|
||||
LL | #[deny(clashing_extern_declarations)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 32 previous errors
|
||||
|
||||
|
|
|
@ -112,24 +112,6 @@ error: missing documentation for a static
|
|||
LL | pub static BAR4: u32 = 0;
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: missing documentation for a function
|
||||
--> $DIR/lint-missing-doc.rs:174:5
|
||||
|
|
||||
LL | pub fn undocumented1() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: missing documentation for a function
|
||||
--> $DIR/lint-missing-doc.rs:175:5
|
||||
|
|
||||
LL | pub fn undocumented2() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: missing documentation for a function
|
||||
--> $DIR/lint-missing-doc.rs:181:9
|
||||
|
|
||||
LL | pub fn also_undocumented1() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: missing documentation for a function
|
||||
--> $DIR/lint-missing-doc.rs:196:5
|
||||
|
|
||||
|
@ -154,5 +136,23 @@ error: missing documentation for a trait alias
|
|||
LL | pub trait T = Sync;
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error: missing documentation for a function
|
||||
--> $DIR/lint-missing-doc.rs:174:5
|
||||
|
|
||||
LL | pub fn undocumented1() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: missing documentation for a function
|
||||
--> $DIR/lint-missing-doc.rs:175:5
|
||||
|
|
||||
LL | pub fn undocumented2() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: missing documentation for a function
|
||||
--> $DIR/lint-missing-doc.rs:181:9
|
||||
|
|
||||
LL | pub fn also_undocumented1() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 25 previous errors
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
error: missing documentation for a macro
|
||||
--> $DIR/missing-doc-private-macro.rs:31:5
|
||||
--> $DIR/missing-doc-private-macro.rs:37:1
|
||||
|
|
||||
LL | macro_rules! exported_to_top_level {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | pub macro top_level_pub_macro {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/missing-doc-private-macro.rs:5:9
|
||||
|
@ -11,10 +11,10 @@ LL | #![deny(missing_docs)]
|
|||
| ^^^^^^^^^^^^
|
||||
|
||||
error: missing documentation for a macro
|
||||
--> $DIR/missing-doc-private-macro.rs:37:1
|
||||
--> $DIR/missing-doc-private-macro.rs:31:5
|
||||
|
|
||||
LL | pub macro top_level_pub_macro {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | macro_rules! exported_to_top_level {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
@ -35,4 +35,4 @@ struct PrivateStruct;
|
|||
enum PrivateEnum {}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct GenericType<T>(T);
|
||||
pub struct GenericType<T>(T);
|
||||
|
|
Loading…
Add table
Reference in a new issue