Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion compiler/rustc_hir_analysis/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,9 @@ hir_analysis_duplicate_precise_capture = cannot capture parameter `{$name}` twic
.label = parameter captured again here
hir_analysis_eii_with_generics =
#[{$eii_name}] cannot have generic parameters other than lifetimes
`{$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
Expand Down
9 changes: 8 additions & 1 deletion compiler/rustc_hir_analysis/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -974,12 +974,19 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(),
(0, _) => ("const", "consts", None),
_ => ("type or const", "types or consts", None),
};
let name =
if find_attr!(tcx.get_all_attrs(def_id), AttributeKind::EiiForeignItem) {
"externally implementable items"
} else {
"foreign items"
};

let span = tcx.def_span(def_id);
struct_span_code_err!(
tcx.dcx(),
span,
E0044,
"foreign items may not have {kinds} parameters",
"{name} may not have {kinds} parameters",
)
.with_span_label(span, format!("can't have {kinds} parameters"))
.with_help(
Expand Down
17 changes: 15 additions & 2 deletions compiler/rustc_hir_analysis/src/check/compare_eii.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ use std::iter;

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};
Expand Down Expand Up @@ -169,11 +170,23 @@ fn check_no_generics<'tcx>(
eii_attr_span: Span,
) -> Result<(), ErrorGuaranteed> {
let generics = tcx.generics_of(external_impl);
if generics.own_requires_monomorphization() {
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),
});
}

Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_hir_analysis/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1655,10 +1655,12 @@ pub(crate) struct LifetimesOrBoundsMismatchOnEii {

#[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,
}
13 changes: 13 additions & 0 deletions tests/ui/eii/type_checking/generic_implementation.rs
Original file line number Diff line number Diff line change
@@ -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() {}
12 changes: 12 additions & 0 deletions tests/ui/eii/type_checking/generic_implementation.stderr
Original file line number Diff line number Diff line change
@@ -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

10 changes: 10 additions & 0 deletions tests/ui/eii/type_checking/type_params_149983.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
//@ 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<T>() {}
//~^ ERROR externally implementable items may not have type parameters

fn main() {}
11 changes: 11 additions & 0 deletions tests/ui/eii/type_checking/type_params_149983.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error[E0044]: externally implementable items may not have type parameters
--> $DIR/type_params_149983.rs:7:1
|
LL | fn foo<T>() {}
| ^^^^^^^^^^^ can't have type parameters
|
= help: replace the type parameters with concrete types like `u32`

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0044`.
Loading