diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index ca13433caec8d..1cb9d5d23dc51 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -277,6 +277,9 @@ pub mod primitive; // crate uses the this crate as its libcore. #[path = "../stdarch/crates/core_arch/src/mod.rs"] #[allow(missing_docs, missing_debug_implementations, dead_code, unused_imports)] +// FIXME: This annotation should be moved into rust-lang/stdarch after clashing_extern_decl is +// merged. It currently cannot because bootstrap fails as the lint hasn't been defined yet. +#[cfg_attr(not(bootstrap), allow(clashing_extern_decl))] #[unstable(feature = "stdsimd", issue = "48556")] mod core_arch; diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index e17e8b7b9640e..4a06e3a114454 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -26,15 +26,15 @@ use rustc_ast::attr::{self, HasAttrs}; use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_ast::visit::{FnCtxt, FnKind}; use rustc_ast_pretty::pprust::{self, expr_to_string}; -use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{Applicability, DiagnosticBuilder}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString}; use rustc_feature::{deprecated_attributes, AttributeGate, AttributeTemplate, AttributeType}; use rustc_feature::{GateIssue, Stability}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; -use rustc_hir::{GenericParamKind, PatKind}; -use rustc_hir::{HirIdSet, Node}; +use rustc_hir::{ForeignItemKind, GenericParamKind, PatKind}; +use rustc_hir::{HirId, HirIdSet, Node}; use rustc_middle::lint::LintDiagnosticBuilder; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -48,7 +48,7 @@ use rustc_trait_selection::traits::misc::can_type_implement_copy; use crate::nonstandard_style::{method_context, MethodLateContext}; -use log::debug; +use log::{debug, trace}; use std::fmt::Write; // hardwired lints from librustc_middle @@ -2049,3 +2049,225 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue { } } } + +declare_lint! { + pub CLASHING_EXTERN_DECL, + Warn, + "detects when an extern fn has been declared with the same name but different types" +} + +pub struct ClashingExternDecl { + seen_decls: FxHashMap, +} + +/// 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 ClashingExternDecl { + crate fn new() -> Self { + ClashingExternDecl { 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 { + let hid = fi.hir_id; + + let name = + &tcx.codegen_fn_attrs(tcx.hir().local_def_id(hid)).link_name.unwrap_or(fi.ident.name); + + if self.seen_decls.contains_key(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(*self.seen_decls.get(name).unwrap()) + } else { + self.seen_decls.insert(*name, hid) + } + } + + /// 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 { + let did = tcx.hir().local_def_id(fi.hir_id); + if let Some((overridden_link_name, overridden_link_name_span)) = + tcx.codegen_fn_attrs(did).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_attrs(did.to_def_id()) + .iter() + .find(|at| at.check_name(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<'a, 'tcx>( + cx: &LateContext<'a, 'tcx>, + a: Ty<'tcx>, + b: Ty<'tcx>, + ) -> bool { + let tcx = cx.tcx; + if a == b || rustc_middle::ty::TyS::same_type(a, b) { + // All nominally-same types are structurally same, too. + true + } else { + // Do a full, depth-first comparison between the two. + use rustc_middle::ty::TyKind::*; + let a_kind = &a.kind; + let b_kind = &b.kind; + + match (a_kind, b_kind) { + (Adt(..), Adt(..)) => { + // Adts are pretty straightforward: just compare the layouts. + use rustc_target::abi::LayoutOf; + let a_layout = cx.layout_of(a).unwrap().layout; + let b_layout = cx.layout_of(b).unwrap().layout; + a_layout == b_layout + } + (Array(a_ty, a_const), Array(b_ty, b_const)) => { + // For arrays, we also check the constness of the type. + a_const.val == b_const.val + && Self::structurally_same_type(cx, a_const.ty, b_const.ty) + && Self::structurally_same_type(cx, a_ty, b_ty) + } + (Slice(a_ty), Slice(b_ty)) => Self::structurally_same_type(cx, a_ty, b_ty), + (RawPtr(a_tymut), RawPtr(b_tymut)) => { + a_tymut.mutbl == a_tymut.mutbl + && Self::structurally_same_type(cx, &a_tymut.ty, &b_tymut.ty) + } + (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 && Self::structurally_same_type(cx, a_ty, b_ty) + } + (FnDef(..), FnDef(..)) => { + // As we don't compare regions, skip_binder is fine. + let a_poly_sig = a.fn_sig(tcx); + let b_poly_sig = b.fn_sig(tcx); + + let a_sig = a_poly_sig.skip_binder(); + let b_sig = b_poly_sig.skip_binder(); + + (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| { + Self::structurally_same_type(cx, a, b) + }) + && Self::structurally_same_type(cx, a_sig.output(), b_sig.output()) + } + (Tuple(a_substs), Tuple(b_substs)) => { + a_substs.types().eq_by(b_substs.types(), |a_ty, b_ty| { + Self::structurally_same_type(cx, a_ty, b_ty) + }) + } + // 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(..)) + | (Closure(..), Closure(..)) + | (Generator(..), Generator(..)) + | (GeneratorWitness(..), GeneratorWitness(..)) + | (Projection(..), Projection(..)) + | (Opaque(..), Opaque(..)) => false, + // These definitely should have been caught above. + (Bool, Bool) | (Char, Char) | (Never, Never) | (Str, Str) | (Error, Error) => { + unreachable!() + } + _ => false, + } + } + } +} + +impl_lint_pass!(ClashingExternDecl => [CLASHING_EXTERN_DECL]); + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ClashingExternDecl { + fn check_foreign_item(&mut self, cx: &LateContext<'a, 'tcx>, this_fi: &hir::ForeignItem<'_>) { + trace!("ClashingExternDecl: check_foreign_item: {:?}", this_fi); + if let ForeignItemKind::Fn(..) = this_fi.kind { + let tcx = *&cx.tcx; + if let Some(existing_hid) = self.insert(tcx, this_fi) { + let existing_decl_ty = tcx.type_of(tcx.hir().local_def_id(existing_hid)); + let this_decl_ty = tcx.type_of(tcx.hir().local_def_id(this_fi.hir_id)); + debug!( + "ClashingExternDecl: Comparing existing {:?}: {:?} to this {:?}: {:?}", + existing_hid, existing_decl_ty, this_fi.hir_id, this_decl_ty + ); + // Check that the declarations match. + if !Self::structurally_same_type(cx, existing_decl_ty, this_decl_ty) { + let orig_fi = tcx.hir().expect_foreign_item(existing_hid); + 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. + tcx.struct_span_lint_hir( + CLASHING_EXTERN_DECL, + this_fi.hir_id, + get_relevant_span(this_fi), + |lint| { + let mut expected_str = DiagnosticStyledString::new(); + expected_str.push(existing_decl_ty.fn_sig(tcx).to_string(), false); + let mut found_str = DiagnosticStyledString::new(); + found_str.push(this_decl_ty.fn_sig(tcx).to_string(), true); + + lint.build(&format!( + "`{}` redeclare{} with a different signature", + this_fi.ident.name, + if orig.get_name() == this_fi.ident.name { + "d".to_string() + } else { + format!("s `{}`", orig.get_name()) + } + )) + .span_label( + get_relevant_span(orig_fi), + &format!("`{}` previously declared here", orig.get_name()), + ) + .span_label( + get_relevant_span(this_fi), + "this signature doesn't match the previous declaration", + ) + .note_expected_found(&"", expected_str, &"", found_str) + .emit() + }, + ); + } + } + } + } +} diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index b791d313fc4f4..ca2ca3145abc8 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -30,6 +30,7 @@ #![feature(bool_to_option)] #![feature(box_syntax)] #![feature(crate_visibility_modifier)] +#![feature(iter_order_by)] #![feature(never_type)] #![feature(nll)] #![feature(or_patterns)] @@ -154,6 +155,7 @@ macro_rules! late_lint_passes { // and change this to a module lint pass MissingDebugImplementations: MissingDebugImplementations::default(), ArrayIntoIter: ArrayIntoIter, + ClashingExternDecl: ClashingExternDecl::new(), ] ); }; diff --git a/src/test/ui/issues/issue-1866.rs b/src/test/ui/issues/issue-1866.rs index e4fe26800eff3..668baefa5e4ad 100644 --- a/src/test/ui/issues/issue-1866.rs +++ b/src/test/ui/issues/issue-1866.rs @@ -1,6 +1,7 @@ // build-pass #![allow(dead_code)] #![allow(non_camel_case_types)] +#![warn(clashing_extern_decl)] // pretty-expanded FIXME #23616 @@ -20,6 +21,7 @@ mod b { use super::rust_task; extern { pub fn rust_task_is_unwinding(rt: *const rust_task) -> bool; + //~^ WARN `rust_task_is_unwinding` redeclared with a different signature } } } diff --git a/src/test/ui/issues/issue-1866.stderr b/src/test/ui/issues/issue-1866.stderr new file mode 100644 index 0000000000000..a47e910c9e610 --- /dev/null +++ b/src/test/ui/issues/issue-1866.stderr @@ -0,0 +1,19 @@ +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 +... +LL | pub fn rust_task_is_unwinding(rt: *const rust_task) -> bool; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration + | +note: the lint level is defined here + --> $DIR/issue-1866.rs:4:9 + | +LL | #![warn(clashing_extern_decl)] + | ^^^^^^^^^^^^^^^^^^^^ + = note: expected `unsafe extern "C" fn(*const usize) -> bool` + found `unsafe extern "C" fn(*const bool) -> bool` + +warning: 1 warning emitted + diff --git a/src/test/ui/issues/issue-5791.rs b/src/test/ui/issues/issue-5791.rs index 2f8bf1e936905..fda72a1b20e4a 100644 --- a/src/test/ui/issues/issue-5791.rs +++ b/src/test/ui/issues/issue-5791.rs @@ -1,11 +1,13 @@ // run-pass #![allow(dead_code)] +#![warn(clashing_extern_decl)] // pretty-expanded FIXME #23616 extern { #[link_name = "malloc"] fn malloc1(len: i32) -> *const u8; #[link_name = "malloc"] + //~^ WARN `malloc2` redeclares `malloc` with a different signature fn malloc2(len: i32, foo: i32) -> *const u8; } diff --git a/src/test/ui/issues/issue-5791.stderr b/src/test/ui/issues/issue-5791.stderr new file mode 100644 index 0000000000000..56032c97a2e43 --- /dev/null +++ b/src/test/ui/issues/issue-5791.stderr @@ -0,0 +1,21 @@ +warning: `malloc2` redeclares `malloc` with a different signature + --> $DIR/issue-5791.rs:9:5 + | +LL | / #[link_name = "malloc"] +LL | | fn malloc1(len: i32) -> *const u8; + | |______________________________________- `malloc` previously declared here +LL | / #[link_name = "malloc"] +LL | | +LL | | fn malloc2(len: i32, foo: i32) -> *const u8; + | |________________________________________________^ this signature doesn't match the previous declaration + | +note: the lint level is defined here + --> $DIR/issue-5791.rs:3:9 + | +LL | #![warn(clashing_extern_decl)] + | ^^^^^^^^^^^^^^^^^^^^ + = note: expected `unsafe extern "C" fn(i32) -> *const u8` + found `unsafe extern "C" fn(i32, i32) -> *const u8` + +warning: 1 warning emitted + diff --git a/src/test/ui/lint/auxiliary/external_extern_fn.rs b/src/test/ui/lint/auxiliary/external_extern_fn.rs new file mode 100644 index 0000000000000..b2caebc6fee0e --- /dev/null +++ b/src/test/ui/lint/auxiliary/external_extern_fn.rs @@ -0,0 +1,3 @@ +extern { + pub fn extern_fn(x: u8); +} diff --git a/src/test/ui/lint/clashing-extern-fn.rs b/src/test/ui/lint/clashing-extern-fn.rs new file mode 100644 index 0000000000000..32f3a78f4e980 --- /dev/null +++ b/src/test/ui/lint/clashing-extern-fn.rs @@ -0,0 +1,159 @@ +// check-pass +// aux-build:external_extern_fn.rs +#![crate_type = "lib"] +#![warn(clashing_extern_decl)] + +extern crate external_extern_fn; + +extern { + fn clash(x: u8); + fn no_clash(x: u8); +} + +fn redeclared_different_signature() { + extern { + fn clash(x: u64); //~ WARN `clash` redeclared with a different signature + } + + unsafe { + clash(123); + no_clash(123); + } +} + +fn redeclared_same_signature() { + extern { + fn no_clash(x: u8); + } + unsafe { + no_clash(123); + } +} + +extern { + fn extern_fn(x: u64); +} + +fn extern_clash() { + extern { + fn extern_fn(x: u32); //~ WARN `extern_fn` redeclared with a different signature + } + unsafe { + extern_fn(123); + } +} + +fn extern_no_clash() { + unsafe { + external_extern_fn::extern_fn(123); + crate::extern_fn(123); + } +} +extern { + fn some_other_new_name(x: i16); + + #[link_name = "extern_link_name"] + fn some_new_name(x: i16); + + #[link_name = "link_name_same"] + fn both_names_different(x: i16); +} + +fn link_name_clash() { + extern { + fn extern_link_name(x: u32); + //~^ WARN `extern_link_name` redeclared with a different signature + + #[link_name = "some_other_new_name"] + //~^ WARN `some_other_extern_link_name` redeclares `some_other_new_name` with a different + fn some_other_extern_link_name(x: u32); + + #[link_name = "link_name_same"] + //~^ WARN `other_both_names_different` redeclares `link_name_same` with a different + fn other_both_names_different(x: u32); + } +} + +mod a { + extern { + fn different_mod(x: u8); + } +} +mod b { + extern { + fn different_mod(x: u64); //~ WARN `different_mod` redeclared with a different signature + } +} + +extern { + fn variadic_decl(x: u8, ...); +} + +fn variadic_clash() { + extern { + fn variadic_decl(x: u8); //~ WARN `variadic_decl` redeclared with a different signature + } +} + +#[no_mangle] +fn no_mangle_name(x: u8) { } + +extern { + #[link_name = "unique_link_name"] + fn link_name_specified(x: u8); +} + +fn tricky_no_clash() { + extern { + // Shouldn't warn, because the declaration above actually declares a different symbol (and + // Rust's name resolution rules around shadowing will handle this gracefully). + fn link_name_specified() -> u32; + + // The case of a no_mangle name colliding with an extern decl (see #28179) is related but + // shouldn't be reported by ClashingExternDecl, because this is an example of unmangled + // name clash causing bad behaviour in functions with a defined body. + fn no_mangle_name() -> u32; + } +} + +mod banana { + mod one { + #[repr(C)] struct Banana { weight: u32, length: u16 } + extern "C" { fn weigh_banana(count: *const Banana) -> u64; } + } + + mod two { + #[repr(C)] struct Banana { weight: u32, length: u16 } // note: distinct type + // This should not trigger the lint because two::Banana is structurally equivalent to + // one::Banana. + extern "C" { fn weigh_banana(count: *const Banana) -> u64; } + } + + mod three { + // This _should_ trigger the lint, because repr(packed) should generate a struct that has a + // different layout. + #[repr(packed)] struct Banana { weight: u32, length: u16 } + #[allow(improper_ctypes)] + extern "C" { fn weigh_banana(count: *const Banana) -> u64; } + //~^ WARN `weigh_banana` redeclared with a different signature + } +} + +mod sameish_members { + mod a { + #[repr(C)] + struct Point { x: i16, y: i16 } + + extern "C" { fn draw_point(p: Point); } + } + mod b { + #[repr(C)] + struct Point { coordinates: [i16; 2] } + + // It's possible we are overconservative for this case, as accessing the elements of the + // coordinates array might end up correctly accessing `.x` and `.y`. However, this may not + // always be the case, for every architecture and situation. This is also a really odd + // thing to do anyway. + extern "C" { fn draw_point(p: Point); } //~ WARN `draw_point` redeclared with a different + } +} diff --git a/src/test/ui/lint/clashing-extern-fn.stderr b/src/test/ui/lint/clashing-extern-fn.stderr new file mode 100644 index 0000000000000..7e85e38a5b804 --- /dev/null +++ b/src/test/ui/lint/clashing-extern-fn.stderr @@ -0,0 +1,121 @@ +warning: `clash` redeclared with a different signature + --> $DIR/clashing-extern-fn.rs:15:9 + | +LL | fn clash(x: u8); + | ---------------- `clash` previously declared here +... +LL | fn clash(x: u64); + | ^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration + | +note: the lint level is defined here + --> $DIR/clashing-extern-fn.rs:4:9 + | +LL | #![warn(clashing_extern_decl)] + | ^^^^^^^^^^^^^^^^^^^^ + = note: expected `unsafe extern "C" fn(u8)` + found `unsafe extern "C" fn(u64)` + +warning: `extern_fn` redeclared with a different signature + --> $DIR/clashing-extern-fn.rs:39:9 + | +LL | fn extern_fn(x: u64); + | --------------------- `extern_fn` previously declared here +... +LL | fn extern_fn(x: u32); + | ^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration + | + = note: expected `unsafe extern "C" fn(u64)` + found `unsafe extern "C" fn(u32)` + +warning: `extern_link_name` redeclared with a different signature + --> $DIR/clashing-extern-fn.rs:64: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:67: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:71: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:84: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:94: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:137:22 + | +LL | extern "C" { fn weigh_banana(count: *const Banana) -> u64; } + | --------------------------------------------- `weigh_banana` previously declared here +... +LL | extern "C" { fn weigh_banana(count: *const Banana) -> u64; } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration + | + = note: expected `unsafe extern "C" fn(*const banana::one::Banana) -> u64` + found `unsafe extern "C" fn(*const banana::three::Banana) -> u64` + +warning: `draw_point` redeclared with a different signature + --> $DIR/clashing-extern-fn.rs:157:22 + | +LL | extern "C" { fn draw_point(p: Point); } + | ------------------------ `draw_point` previously declared here +... +LL | extern "C" { 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: 9 warnings emitted + diff --git a/src/test/ui/lint/dead-code/lint-dead-code-3.rs b/src/test/ui/lint/dead-code/lint-dead-code-3.rs index 6826d2cd67eb9..ff33abfa64586 100644 --- a/src/test/ui/lint/dead-code/lint-dead-code-3.rs +++ b/src/test/ui/lint/dead-code/lint-dead-code-3.rs @@ -1,5 +1,6 @@ #![allow(unused_variables)] #![allow(non_camel_case_types)] +#![allow(clashing_extern_decl)] #![deny(dead_code)] #![crate_type="lib"] diff --git a/src/test/ui/lint/dead-code/lint-dead-code-3.stderr b/src/test/ui/lint/dead-code/lint-dead-code-3.stderr index 6d174e8d9bc38..cf8f01ea19f0c 100644 --- a/src/test/ui/lint/dead-code/lint-dead-code-3.stderr +++ b/src/test/ui/lint/dead-code/lint-dead-code-3.stderr @@ -1,35 +1,35 @@ error: struct is never constructed: `Foo` - --> $DIR/lint-dead-code-3.rs:13:8 + --> $DIR/lint-dead-code-3.rs:14:8 | LL | struct Foo; | ^^^ | note: the lint level is defined here - --> $DIR/lint-dead-code-3.rs:3:9 + --> $DIR/lint-dead-code-3.rs:4:9 | LL | #![deny(dead_code)] | ^^^^^^^^^ error: associated function is never used: `foo` - --> $DIR/lint-dead-code-3.rs:15:8 + --> $DIR/lint-dead-code-3.rs:16:8 | LL | fn foo(&self) { | ^^^ error: function is never used: `bar` - --> $DIR/lint-dead-code-3.rs:20:4 + --> $DIR/lint-dead-code-3.rs:21:4 | LL | fn bar() { | ^^^ error: enum is never used: `c_void` - --> $DIR/lint-dead-code-3.rs:59:6 + --> $DIR/lint-dead-code-3.rs:60:6 | LL | enum c_void {} | ^^^^^^ error: function is never used: `free` - --> $DIR/lint-dead-code-3.rs:61:5 + --> $DIR/lint-dead-code-3.rs:62:5 | LL | fn free(p: *const c_void); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/parser/extern-abi-from-mac-literal-frag.rs b/src/test/ui/parser/extern-abi-from-mac-literal-frag.rs index 4ecb21d26ab9b..a516aa44c6576 100644 --- a/src/test/ui/parser/extern-abi-from-mac-literal-frag.rs +++ b/src/test/ui/parser/extern-abi-from-mac-literal-frag.rs @@ -1,3 +1,4 @@ +#![allow(clashing_extern_decl)] // check-pass // In this test we check that the parser accepts an ABI string when it