Auto merge of #86571 - fee1-dead:const-trait-impl-fix, r=jackh726
deny using default function in impl const Trait Fixes #79450. I don't know if my implementation is correct: - The check is in `rustc_passes::check_const`, should I put it somewhere else instead? - Is my approach (to checking the impl) optimal? It works for the current tests, but it might have some issues or there might be a better way of doing this.
This commit is contained in:
commit
701496384f
@ -13,6 +13,7 @@
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
|
||||
use rustc_middle::hir::map::Map;
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::query::Providers;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::parse::feature_err;
|
||||
@ -59,12 +60,73 @@ fn required_feature_gates(self) -> Option<&'static [Symbol]> {
|
||||
fn check_mod_const_bodies(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
|
||||
let mut vis = CheckConstVisitor::new(tcx);
|
||||
tcx.hir().visit_item_likes_in_module(module_def_id, &mut vis.as_deep_visitor());
|
||||
tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckConstTraitVisitor::new(tcx));
|
||||
}
|
||||
|
||||
pub(crate) fn provide(providers: &mut Providers) {
|
||||
*providers = Providers { check_mod_const_bodies, ..*providers };
|
||||
}
|
||||
|
||||
struct CheckConstTraitVisitor<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> CheckConstTraitVisitor<'tcx> {
|
||||
fn new(tcx: TyCtxt<'tcx>) -> Self {
|
||||
CheckConstTraitVisitor { tcx }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> hir::itemlikevisit::ItemLikeVisitor<'tcx> for CheckConstTraitVisitor<'tcx> {
|
||||
/// check for const trait impls, and errors if the impl uses provided/default functions
|
||||
/// of the trait being implemented; as those provided functions can be non-const.
|
||||
fn visit_item(&mut self, item: &'hir hir::Item<'hir>) {
|
||||
let _: Option<_> = try {
|
||||
if let hir::ItemKind::Impl(ref imp) = item.kind {
|
||||
if let hir::Constness::Const = imp.constness {
|
||||
let did = imp.of_trait.as_ref()?.trait_def_id()?;
|
||||
let trait_fn_cnt = self
|
||||
.tcx
|
||||
.associated_item_def_ids(did)
|
||||
.iter()
|
||||
.filter(|did| {
|
||||
matches!(
|
||||
self.tcx.associated_item(**did),
|
||||
ty::AssocItem { kind: ty::AssocKind::Fn, .. }
|
||||
)
|
||||
})
|
||||
.count();
|
||||
|
||||
let impl_fn_cnt = imp
|
||||
.items
|
||||
.iter()
|
||||
.filter(|it| matches!(it.kind, hir::AssocItemKind::Fn { .. }))
|
||||
.count();
|
||||
|
||||
// number of trait functions unequal to functions in impl,
|
||||
// meaning that one or more provided/default functions of the
|
||||
// trait are used.
|
||||
if trait_fn_cnt != impl_fn_cnt {
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(
|
||||
item.span,
|
||||
"const trait implementations may not use default functions",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, _: &'hir hir::TraitItem<'hir>) {}
|
||||
|
||||
fn visit_impl_item(&mut self, _: &'hir hir::ImplItem<'hir>) {}
|
||||
|
||||
fn visit_foreign_item(&mut self, _: &'hir hir::ForeignItem<'hir>) {}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct CheckConstVisitor<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
|
@ -10,6 +10,7 @@
|
||||
#![feature(iter_zip)]
|
||||
#![feature(nll)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(try_blocks)]
|
||||
#![recursion_limit = "256"]
|
||||
|
||||
#[macro_use]
|
||||
|
@ -53,6 +53,9 @@ impl const PartialEq<NonDet> for bool {
|
||||
fn eq(&self, _: &NonDet) -> bool {
|
||||
true
|
||||
}
|
||||
fn ne(&self, _: &NonDet) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
// The result of the `is_sign` methods are not checked for correctness, since LLVM does not
|
||||
|
@ -17,6 +17,9 @@ impl const PartialEq for Int {
|
||||
fn eq(&self, rhs: &Self) -> bool {
|
||||
self.0 == rhs.0
|
||||
}
|
||||
fn ne(&self, other: &Self) -> bool {
|
||||
!self.eq(other)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Plus {
|
||||
|
@ -12,6 +12,9 @@ impl const PartialEq for S {
|
||||
fn eq(&self, _: &S) -> bool {
|
||||
true
|
||||
}
|
||||
fn ne(&self, other: &S) -> bool {
|
||||
!self.eq(other)
|
||||
}
|
||||
}
|
||||
|
||||
const fn equals_self<T: PartialEq>(t: &T) -> bool {
|
||||
|
@ -11,6 +11,9 @@ impl const PartialEq for S {
|
||||
fn eq(&self, _: &S) -> bool {
|
||||
true
|
||||
}
|
||||
fn ne(&self, other: &S) -> bool {
|
||||
!self.eq(other)
|
||||
}
|
||||
}
|
||||
|
||||
// This duplicate bound should not result in ambiguities. It should be equivalent to a single const
|
||||
|
@ -12,6 +12,9 @@ impl const PartialEq for S {
|
||||
fn eq(&self, _: &S) -> bool {
|
||||
true
|
||||
}
|
||||
fn ne(&self, other: &S) -> bool {
|
||||
!self.eq(other)
|
||||
}
|
||||
}
|
||||
|
||||
const fn equals_self<T: PartialEq>(t: &T) -> bool {
|
||||
|
@ -0,0 +1,20 @@
|
||||
#![feature(const_trait_impl)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
trait Tr {
|
||||
fn req(&self);
|
||||
|
||||
fn prov(&self) {
|
||||
println!("lul");
|
||||
self.req();
|
||||
}
|
||||
}
|
||||
|
||||
struct S;
|
||||
|
||||
impl const Tr for S {
|
||||
fn req(&self) {}
|
||||
}
|
||||
//~^^^ ERROR const trait implementations may not use default functions
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,10 @@
|
||||
error: const trait implementations may not use default functions
|
||||
--> $DIR/impl-with-default-fn.rs:15:1
|
||||
|
|
||||
LL | / impl const Tr for S {
|
||||
LL | | fn req(&self) {}
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
Loading…
Reference in New Issue
Block a user