ensure generics are still properly reported on EII *implementations*, and test this

This commit is contained in:
Jana Dönszelmann
2026-01-11 17:45:50 +01:00
parent b64a9be97e
commit b454f76bd1
5 changed files with 78 additions and 2 deletions
+5
View File
@@ -165,6 +165,11 @@ hir_analysis_drop_impl_reservation = reservation `Drop` impls are not supported
hir_analysis_duplicate_precise_capture = cannot capture parameter `{$name}` twice
.label = parameter captured again here
hir_analysis_eii_with_generics =
`{$impl_name}` cannot have generic parameters other than lifetimes
.label = required by this attribute
.help = `#[{$eii_name}]` marks the implementation of an "externally implementable item"
hir_analysis_empty_specialization = specialization impl does not specialize any associated items
.note = impl is a specialization of this impl
@@ -8,8 +8,9 @@
use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::{Applicability, E0806, struct_span_code_err};
use rustc_hir::attrs::{AttributeKind, EiiImplResolution};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::{self as hir, FnSig, HirId, ItemKind};
use rustc_hir::{self as hir, FnSig, HirId, ItemKind, find_attr};
use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::{ObligationCause, ObligationCauseCode};
use rustc_middle::ty::error::{ExpectedFound, TypeError};
@@ -24,7 +25,7 @@
use crate::check::compare_impl_item::{
CheckNumberOfEarlyBoundRegionsError, check_number_of_early_bound_regions,
};
use crate::errors::LifetimesOrBoundsMismatchOnEii;
use crate::errors::{EiiWithGenerics, LifetimesOrBoundsMismatchOnEii};
/// Checks whether the signature of some `external_impl`, matches
/// the signature of `declaration`, which it is supposed to be compatible
@@ -154,11 +155,44 @@ fn check_is_structurally_compatible<'tcx>(
eii_name: Symbol,
eii_attr_span: Span,
) -> Result<(), ErrorGuaranteed> {
check_no_generics(tcx, external_impl, declaration, eii_name, eii_attr_span)?;
check_number_of_arguments(tcx, external_impl, declaration, eii_name, eii_attr_span)?;
check_early_region_bounds(tcx, external_impl, declaration, eii_attr_span)?;
Ok(())
}
/// externally implementable items can't have generics
fn check_no_generics<'tcx>(
tcx: TyCtxt<'tcx>,
external_impl: LocalDefId,
_declaration: DefId,
eii_name: Symbol,
eii_attr_span: Span,
) -> Result<(), ErrorGuaranteed> {
let generics = tcx.generics_of(external_impl);
if generics.own_requires_monomorphization()
// When an EII implementation is automatically generated by the `#[eii]` macro,
// it will directly refer to the foreign item, not through a macro.
// We don't want to emit this error if it's an implementation that's generated by the `#[eii]` macro,
// since in that case it looks like a duplicate error: the declaration of the EII already can't contain generics.
// So, we check here if at least one of the eii impls has ImplResolution::Macro, which indicates it's
// not generated as part of the declaration.
&& find_attr!(
tcx.get_all_attrs(external_impl),
AttributeKind::EiiImpls(impls) if impls.iter().any(|i| matches!(i.resolution, EiiImplResolution::Macro(_)))
)
{
tcx.dcx().emit_err(EiiWithGenerics {
span: tcx.def_span(external_impl),
attr: eii_attr_span,
eii_name,
impl_name: tcx.item_name(external_impl),
});
}
Ok(())
}
fn check_early_region_bounds<'tcx>(
tcx: TyCtxt<'tcx>,
external_impl: LocalDefId,
+12
View File
@@ -1652,3 +1652,15 @@ pub(crate) struct LifetimesOrBoundsMismatchOnEii {
pub bounds_span: Vec<Span>,
pub ident: Symbol,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_eii_with_generics)]
#[help]
pub(crate) struct EiiWithGenerics {
#[primary_span]
pub span: Span,
#[label]
pub attr: Span,
pub eii_name: Symbol,
pub impl_name: Symbol,
}
@@ -0,0 +1,13 @@
//@ check-fail
// Check that type parameters on EIIs are properly rejected.
// Specifically a regression test for https://github.com/rust-lang/rust/issues/149983.
#![feature(extern_item_impls)]
#[eii]
fn foo();
#[foo]
fn foo_impl<T>() {}
//~^ ERROR `foo_impl` cannot have generic parameters other than lifetimes
fn main() {}
@@ -0,0 +1,12 @@
error: `foo_impl` cannot have generic parameters other than lifetimes
--> $DIR/generic_implementation.rs:10:1
|
LL | #[foo]
| ------ required by this attribute
LL | fn foo_impl<T>() {}
| ^^^^^^^^^^^^^^^^
|
= help: `#[foo]` marks the implementation of an "externally implementable item"
error: aborting due to 1 previous error