Check that impls of #[type_const] consts also have the attr

This commit is contained in:
Noah Lev 2025-11-08 17:32:35 -05:00
parent 9ba89327df
commit db2fbdb714
8 changed files with 105 additions and 28 deletions

View file

@ -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`.

View file

@ -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);

View file

@ -1,11 +0,0 @@
//@ known-bug: #140729
#![feature(min_generic_const_args)]
const C: usize = 0;
pub struct A<const M: usize> {}
impl A<C> {
fn fun1() {}
}
impl A {
fn fun1() {}
}

View file

@ -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<e> c for e where e: a<""> {}
impl<e> c for d<e> {}
impl<e> !a<f> for e {}
const f : &str = "";
fn main() {}

View file

@ -0,0 +1,17 @@
// Regression test for #140729
#![expect(incomplete_features)]
#![feature(min_generic_const_args)]
const C: usize = 0;
pub struct A<const M: usize> {}
impl A<C> {
fn fun1() {}
//~^ ERROR duplicate definitions with name `fun1`
}
impl A {
//~^ ERROR missing generics for struct `A`
fn fun1() {}
}
fn main() {}

View file

@ -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<const M: usize> {}
| ^ --------------
help: add missing generic argument
|
LL | impl A<M> {
| +++
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`.

View file

@ -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<const N: usize, T: GoodTr<NUM = { N }>>(_x: &T) {}

View file

@ -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