diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 74bf68362fc5..6a07d2988fdf 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -6,9 +6,10 @@ use hir::def_id::{DefId, DefIdMap, LocalDefId}; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan, pluralize, struct_span_code_err}; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::VisitorExt; -use rustc_hir::{self as hir, AmbigArg, GenericParamKind, ImplItemKind, intravisit}; +use rustc_hir::{self as hir, AmbigArg, GenericParamKind, ImplItemKind, find_attr, intravisit}; use rustc_infer::infer::{self, BoundRegionConversionTime, InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::util; use rustc_middle::ty::error::{ExpectedFound, TypeError}; @@ -1984,12 +1985,46 @@ fn compare_impl_const<'tcx>( trait_const_item: ty::AssocItem, impl_trait_ref: ty::TraitRef<'tcx>, ) -> Result<(), ErrorGuaranteed> { + compare_type_const(tcx, impl_const_item, trait_const_item)?; compare_number_of_generics(tcx, impl_const_item, trait_const_item, false)?; compare_generic_param_kinds(tcx, impl_const_item, trait_const_item, false)?; check_region_bounds_on_impl_item(tcx, impl_const_item, trait_const_item, false)?; compare_const_predicate_entailment(tcx, impl_const_item, trait_const_item, impl_trait_ref) } +fn compare_type_const<'tcx>( + tcx: TyCtxt<'tcx>, + impl_const_item: ty::AssocItem, + trait_const_item: ty::AssocItem, +) -> Result<(), ErrorGuaranteed> { + let impl_is_type_const = + find_attr!(tcx.get_all_attrs(impl_const_item.def_id), AttributeKind::TypeConst(_)); + let trait_type_const_span = find_attr!( + tcx.get_all_attrs(trait_const_item.def_id), + AttributeKind::TypeConst(sp) => *sp + ); + + if let Some(trait_type_const_span) = trait_type_const_span + && !impl_is_type_const + { + return Err(tcx + .dcx() + .struct_span_err( + tcx.def_span(impl_const_item.def_id), + "implementation of `#[type_const]` const must be marked with `#[type_const]`", + ) + .with_span_note( + MultiSpan::from_spans(vec![ + tcx.def_span(trait_const_item.def_id), + trait_type_const_span, + ]), + "trait declaration of const is marked with `#[type_const]`", + ) + .emit()); + } + Ok(()) +} + /// The equivalent of [compare_method_predicate_entailment], but for associated constants /// instead of associated functions. // FIXME(generic_const_items): If possible extract the common parts of `compare_{type,const}_predicate_entailment`. diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 84b0c20aaa10..2acccc1ae78e 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1600,8 +1600,12 @@ fn const_of_item<'tcx>( }; let ct_arg = match ct_rhs { hir::ConstItemRhs::TypeConst(ct_arg) => ct_arg, - hir::ConstItemRhs::Body(body_id) => { - bug!("cannot call const_of_item on a non-type_const {body_id:?}") + hir::ConstItemRhs::Body(_) => { + let e = tcx.dcx().span_delayed_bug( + tcx.def_span(def_id), + "cannot call const_of_item on a non-type_const", + ); + return ty::EarlyBinder::bind(Const::new_error(tcx, e)); } }; let icx = ItemCtxt::new(tcx, def_id); diff --git a/tests/crashes/140729.rs b/tests/crashes/140729.rs deleted file mode 100644 index a436ec58e8e8..000000000000 --- a/tests/crashes/140729.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ known-bug: #140729 -#![feature(min_generic_const_args)] - -const C: usize = 0; -pub struct A {} -impl A { - fn fun1() {} -} -impl A { - fn fun1() {} -} diff --git a/tests/crashes/140860.rs b/tests/crashes/140860.rs deleted file mode 100644 index 04da6bd832c3..000000000000 --- a/tests/crashes/140860.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ known-bug: #140860 -#![feature(min_generic_const_args)] -#![feature(unsized_const_params)] -#![feature(with_negative_coherence, negative_impls)] -trait a < const b : &'static str> {} trait c {} struct d< e >(e); -impl c for e where e: a<""> {} -impl c for d {} -impl !a for e {} -const f : &str = ""; -fn main() {} diff --git a/tests/ui/const-generics/mgca/const-arg-coherence-conflicting-methods.rs b/tests/ui/const-generics/mgca/const-arg-coherence-conflicting-methods.rs new file mode 100644 index 000000000000..68aa30bd65bb --- /dev/null +++ b/tests/ui/const-generics/mgca/const-arg-coherence-conflicting-methods.rs @@ -0,0 +1,17 @@ +// Regression test for #140729 + +#![expect(incomplete_features)] +#![feature(min_generic_const_args)] + +const C: usize = 0; +pub struct A {} +impl A { + fn fun1() {} + //~^ ERROR duplicate definitions with name `fun1` +} +impl A { + //~^ ERROR missing generics for struct `A` + fn fun1() {} +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/const-arg-coherence-conflicting-methods.stderr b/tests/ui/const-generics/mgca/const-arg-coherence-conflicting-methods.stderr new file mode 100644 index 000000000000..3d74d1db206e --- /dev/null +++ b/tests/ui/const-generics/mgca/const-arg-coherence-conflicting-methods.stderr @@ -0,0 +1,29 @@ +error[E0107]: missing generics for struct `A` + --> $DIR/const-arg-coherence-conflicting-methods.rs:12:6 + | +LL | impl A { + | ^ expected 1 generic argument + | +note: struct defined here, with 1 generic parameter: `M` + --> $DIR/const-arg-coherence-conflicting-methods.rs:7:12 + | +LL | pub struct A {} + | ^ -------------- +help: add missing generic argument + | +LL | impl A { + | +++ + +error[E0592]: duplicate definitions with name `fun1` + --> $DIR/const-arg-coherence-conflicting-methods.rs:9:5 + | +LL | fn fun1() {} + | ^^^^^^^^^ duplicate definitions for `fun1` +... +LL | fn fun1() {} + | --------- other definition for `fun1` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0107, E0592. +For more information about an error, try `rustc --explain E0107`. diff --git a/tests/crashes/mgca/type_const-only-in-trait.rs b/tests/ui/const-generics/mgca/type_const-only-in-trait.rs similarity index 73% rename from tests/crashes/mgca/type_const-only-in-trait.rs rename to tests/ui/const-generics/mgca/type_const-only-in-trait.rs index 109cf0ec670c..8c8ff6259cae 100644 --- a/tests/crashes/mgca/type_const-only-in-trait.rs +++ b/tests/ui/const-generics/mgca/type_const-only-in-trait.rs @@ -1,7 +1,3 @@ -//@ known-bug: #132980 -// Move this test to tests/ui/const-generics/mgca/type_const-only-in-trait.rs -// once fixed. - #![expect(incomplete_features)] #![feature(associated_const_equality, min_generic_const_args)] @@ -14,6 +10,7 @@ struct BadS; impl GoodTr for BadS { const NUM: usize = 42; + //~^ ERROR implementation of `#[type_const]` const must be marked with `#[type_const]` } fn accept_good_tr>(_x: &T) {} diff --git a/tests/ui/const-generics/mgca/type_const-only-in-trait.stderr b/tests/ui/const-generics/mgca/type_const-only-in-trait.stderr new file mode 100644 index 000000000000..29f1b724960a --- /dev/null +++ b/tests/ui/const-generics/mgca/type_const-only-in-trait.stderr @@ -0,0 +1,16 @@ +error: implementation of `#[type_const]` const must be marked with `#[type_const]` + --> $DIR/type_const-only-in-trait.rs:12:5 + | +LL | const NUM: usize = 42; + | ^^^^^^^^^^^^^^^^ + | +note: trait declaration of const is marked with `#[type_const]` + --> $DIR/type_const-only-in-trait.rs:5:5 + | +LL | #[type_const] + | ^^^^^^^^^^^^^ +LL | const NUM: usize; + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error +