diff --git a/compiler/rustc_hir_analysis/src/check/compare_eii.rs b/compiler/rustc_hir_analysis/src/check/compare_eii.rs index 9443aaac2258f..29213058d1d5e 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_eii.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_eii.rs @@ -9,6 +9,7 @@ use std::iter; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::{Applicability, E0806, struct_span_code_err}; use rustc_hir::attrs::EiiImplResolution; +use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{self as hir, FnSig, HirId, ItemKind, find_attr}; use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; @@ -37,6 +38,14 @@ pub(crate) fn compare_eii_function_types<'tcx>( eii_name: Symbol, eii_attr_span: Span, ) -> Result<(), ErrorGuaranteed> { + // Error recovery can resolve the EII target to another value item with the same name, + // such as a tuple-struct constructor. Skip the comparison in that case and rely on the + // earlier name-resolution error instead of ICEing while building EII diagnostics. + // See . + if !is_foreign_function(tcx, foreign_item) { + return Ok(()); + } + check_is_structurally_compatible(tcx, external_impl, foreign_item, eii_name, eii_attr_span)?; let external_impl_span = tcx.def_span(external_impl); @@ -442,3 +451,7 @@ fn get_declaration_sig<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Option<&' let hir_id: HirId = tcx.local_def_id_to_hir_id(def_id); tcx.hir_fn_sig_by_hir_id(hir_id) } + +fn is_foreign_function(tcx: TyCtxt<'_>, def_id: DefId) -> bool { + tcx.is_foreign_item(def_id) && matches!(tcx.def_kind(def_id), DefKind::Fn) +} diff --git a/tests/ui/eii/duplicate/eii-declaration-conflicts-with-constructor.rs b/tests/ui/eii/duplicate/eii-declaration-conflicts-with-constructor.rs new file mode 100644 index 0000000000000..23b930cddaa13 --- /dev/null +++ b/tests/ui/eii/duplicate/eii-declaration-conflicts-with-constructor.rs @@ -0,0 +1,11 @@ +#![feature(extern_item_impls)] + +// Regression test for : + +struct Foo(i32); + +#[eii] +pub fn Foo(x: u64) {} +//~^ ERROR the name `Foo` is defined multiple times + +fn main() {} diff --git a/tests/ui/eii/duplicate/eii-declaration-conflicts-with-constructor.stderr b/tests/ui/eii/duplicate/eii-declaration-conflicts-with-constructor.stderr new file mode 100644 index 0000000000000..e95ab395ff240 --- /dev/null +++ b/tests/ui/eii/duplicate/eii-declaration-conflicts-with-constructor.stderr @@ -0,0 +1,14 @@ +error[E0428]: the name `Foo` is defined multiple times + --> $DIR/eii-declaration-conflicts-with-constructor.rs:8:1 + | +LL | struct Foo(i32); + | ---------------- previous definition of the value `Foo` here +... +LL | pub fn Foo(x: u64) {} + | ^^^^^^^^^^^^^^^^^^ `Foo` redefined here + | + = note: `Foo` must be defined only once in the value namespace of this module + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0428`.