Skip to content

Commit fd76cce

Browse files
Rollup merge of rust-lang#153571 - TaKO8Ki:eii-ice-153502, r=jdonszelmann
Avoid ICE when an EII declaration conflicts with a constructor Fixes rust-lang#153502 When an `#[eii]` declaration conflicts with a tuple-struct constructor of the same name, error recovery can resolve the EII target to the constructor instead of the generated foreign item. `compare_eii_function_types` then assumes that target is a foreign function and later ICEs while building diagnostics. This pull request adds an early guard in `compare_eii_function_types` to skip EII signature comparison unless the resolved target is actually a foreign function.
2 parents a63150b + be78a0d commit fd76cce

3 files changed

Lines changed: 38 additions & 0 deletions

File tree

compiler/rustc_hir_analysis/src/check/compare_eii.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use std::iter;
99
use rustc_data_structures::fx::FxIndexSet;
1010
use rustc_errors::{Applicability, E0806, struct_span_code_err};
1111
use rustc_hir::attrs::EiiImplResolution;
12+
use rustc_hir::def::DefKind;
1213
use rustc_hir::def_id::{DefId, LocalDefId};
1314
use rustc_hir::{self as hir, FnSig, HirId, ItemKind, find_attr};
1415
use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
@@ -37,6 +38,14 @@ pub(crate) fn compare_eii_function_types<'tcx>(
3738
eii_name: Symbol,
3839
eii_attr_span: Span,
3940
) -> Result<(), ErrorGuaranteed> {
41+
// Error recovery can resolve the EII target to another value item with the same name,
42+
// such as a tuple-struct constructor. Skip the comparison in that case and rely on the
43+
// earlier name-resolution error instead of ICEing while building EII diagnostics.
44+
// See <https://github.com/rust-lang/rust/issues/153502>.
45+
if !is_foreign_function(tcx, foreign_item) {
46+
return Ok(());
47+
}
48+
4049
check_is_structurally_compatible(tcx, external_impl, foreign_item, eii_name, eii_attr_span)?;
4150

4251
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<&'
442451
let hir_id: HirId = tcx.local_def_id_to_hir_id(def_id);
443452
tcx.hir_fn_sig_by_hir_id(hir_id)
444453
}
454+
455+
fn is_foreign_function(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
456+
tcx.is_foreign_item(def_id) && matches!(tcx.def_kind(def_id), DefKind::Fn)
457+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#![feature(extern_item_impls)]
2+
3+
// Regression test for <https://github.com/rust-lang/rust/issues/153502>:
4+
5+
struct Foo(i32);
6+
7+
#[eii]
8+
pub fn Foo(x: u64) {}
9+
//~^ ERROR the name `Foo` is defined multiple times
10+
11+
fn main() {}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0428]: the name `Foo` is defined multiple times
2+
--> $DIR/eii-declaration-conflicts-with-constructor.rs:8:1
3+
|
4+
LL | struct Foo(i32);
5+
| ---------------- previous definition of the value `Foo` here
6+
...
7+
LL | pub fn Foo(x: u64) {}
8+
| ^^^^^^^^^^^^^^^^^^ `Foo` redefined here
9+
|
10+
= note: `Foo` must be defined only once in the value namespace of this module
11+
12+
error: aborting due to 1 previous error
13+
14+
For more information about this error, try `rustc --explain E0428`.

0 commit comments

Comments
 (0)