Skip to content

Commit 7014963

Browse files
committed
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.
2 parents fdd9a07 + 5e178b2 commit 7014963

9 files changed

+108
-0
lines changed

compiler/rustc_passes/src/check_const.rs

+62
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use rustc_hir as hir;
1313
use rustc_hir::def_id::LocalDefId;
1414
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
1515
use rustc_middle::hir::map::Map;
16+
use rustc_middle::ty;
1617
use rustc_middle::ty::query::Providers;
1718
use rustc_middle::ty::TyCtxt;
1819
use rustc_session::parse::feature_err;
@@ -59,12 +60,73 @@ impl NonConstExpr {
5960
fn check_mod_const_bodies(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
6061
let mut vis = CheckConstVisitor::new(tcx);
6162
tcx.hir().visit_item_likes_in_module(module_def_id, &mut vis.as_deep_visitor());
63+
tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckConstTraitVisitor::new(tcx));
6264
}
6365

6466
pub(crate) fn provide(providers: &mut Providers) {
6567
*providers = Providers { check_mod_const_bodies, ..*providers };
6668
}
6769

70+
struct CheckConstTraitVisitor<'tcx> {
71+
tcx: TyCtxt<'tcx>,
72+
}
73+
74+
impl<'tcx> CheckConstTraitVisitor<'tcx> {
75+
fn new(tcx: TyCtxt<'tcx>) -> Self {
76+
CheckConstTraitVisitor { tcx }
77+
}
78+
}
79+
80+
impl<'tcx> hir::itemlikevisit::ItemLikeVisitor<'tcx> for CheckConstTraitVisitor<'tcx> {
81+
/// check for const trait impls, and errors if the impl uses provided/default functions
82+
/// of the trait being implemented; as those provided functions can be non-const.
83+
fn visit_item(&mut self, item: &'hir hir::Item<'hir>) {
84+
let _: Option<_> = try {
85+
if let hir::ItemKind::Impl(ref imp) = item.kind {
86+
if let hir::Constness::Const = imp.constness {
87+
let did = imp.of_trait.as_ref()?.trait_def_id()?;
88+
let trait_fn_cnt = self
89+
.tcx
90+
.associated_item_def_ids(did)
91+
.iter()
92+
.filter(|did| {
93+
matches!(
94+
self.tcx.associated_item(**did),
95+
ty::AssocItem { kind: ty::AssocKind::Fn, .. }
96+
)
97+
})
98+
.count();
99+
100+
let impl_fn_cnt = imp
101+
.items
102+
.iter()
103+
.filter(|it| matches!(it.kind, hir::AssocItemKind::Fn { .. }))
104+
.count();
105+
106+
// number of trait functions unequal to functions in impl,
107+
// meaning that one or more provided/default functions of the
108+
// trait are used.
109+
if trait_fn_cnt != impl_fn_cnt {
110+
self.tcx
111+
.sess
112+
.struct_span_err(
113+
item.span,
114+
"const trait implementations may not use default functions",
115+
)
116+
.emit();
117+
}
118+
}
119+
}
120+
};
121+
}
122+
123+
fn visit_trait_item(&mut self, _: &'hir hir::TraitItem<'hir>) {}
124+
125+
fn visit_impl_item(&mut self, _: &'hir hir::ImplItem<'hir>) {}
126+
127+
fn visit_foreign_item(&mut self, _: &'hir hir::ForeignItem<'hir>) {}
128+
}
129+
68130
#[derive(Copy, Clone)]
69131
struct CheckConstVisitor<'tcx> {
70132
tcx: TyCtxt<'tcx>,

compiler/rustc_passes/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#![feature(iter_zip)]
1111
#![feature(nll)]
1212
#![feature(min_specialization)]
13+
#![feature(try_blocks)]
1314
#![recursion_limit = "256"]
1415

1516
#[macro_use]

src/test/ui/consts/const-float-classify.rs

+3
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ impl const PartialEq<NonDet> for bool {
5353
fn eq(&self, _: &NonDet) -> bool {
5454
true
5555
}
56+
fn ne(&self, _: &NonDet) -> bool {
57+
false
58+
}
5659
}
5760

5861
// The result of the `is_sign` methods are not checked for correctness, since LLVM does not

src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-pass.rs

+3
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ impl const PartialEq for Int {
1717
fn eq(&self, rhs: &Self) -> bool {
1818
self.0 == rhs.0
1919
}
20+
fn ne(&self, other: &Self) -> bool {
21+
!self.eq(other)
22+
}
2023
}
2124

2225
pub trait Plus {

src/test/ui/rfc-2632-const-trait-impl/call-generic-method-chain.rs

+3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ impl const PartialEq for S {
1212
fn eq(&self, _: &S) -> bool {
1313
true
1414
}
15+
fn ne(&self, other: &S) -> bool {
16+
!self.eq(other)
17+
}
1518
}
1619

1720
const fn equals_self<T: PartialEq>(t: &T) -> bool {

src/test/ui/rfc-2632-const-trait-impl/call-generic-method-dup-bound.rs

+3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ impl const PartialEq for S {
1111
fn eq(&self, _: &S) -> bool {
1212
true
1313
}
14+
fn ne(&self, other: &S) -> bool {
15+
!self.eq(other)
16+
}
1417
}
1518

1619
// This duplicate bound should not result in ambiguities. It should be equivalent to a single const

src/test/ui/rfc-2632-const-trait-impl/call-generic-method-pass.rs

+3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ impl const PartialEq for S {
1212
fn eq(&self, _: &S) -> bool {
1313
true
1414
}
15+
fn ne(&self, other: &S) -> bool {
16+
!self.eq(other)
17+
}
1518
}
1619

1720
const fn equals_self<T: PartialEq>(t: &T) -> bool {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#![feature(const_trait_impl)]
2+
#![allow(incomplete_features)]
3+
4+
trait Tr {
5+
fn req(&self);
6+
7+
fn prov(&self) {
8+
println!("lul");
9+
self.req();
10+
}
11+
}
12+
13+
struct S;
14+
15+
impl const Tr for S {
16+
fn req(&self) {}
17+
}
18+
//~^^^ ERROR const trait implementations may not use default functions
19+
20+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
error: const trait implementations may not use default functions
2+
--> $DIR/impl-with-default-fn.rs:15:1
3+
|
4+
LL | / impl const Tr for S {
5+
LL | | fn req(&self) {}
6+
LL | | }
7+
| |_^
8+
9+
error: aborting due to previous error
10+

0 commit comments

Comments
 (0)