Rollup merge of #89471 - nbdd0121:const3, r=fee1-dead
Use Ancestory to check default fn in const impl instead of comparing idents Fixes https://rust-lang.zulipchat.com/#narrow/stream/146212-t-compiler.2Fconst-eval/topic/Const.20trait.20impl.20inside.20macro
This commit is contained in:
commit
412301b26a
4 changed files with 63 additions and 25 deletions
|
@ -8,7 +8,6 @@
|
|||
//! through, but errors for structured control flow in a `const` should be emitted here.
|
||||
|
||||
use rustc_attr as attr;
|
||||
use rustc_data_structures::stable_set::FxHashSet;
|
||||
use rustc_errors::struct_span_err;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
|
@ -83,32 +82,41 @@ impl<'tcx> hir::itemlikevisit::ItemLikeVisitor<'tcx> for CheckConstTraitVisitor<
|
|||
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 mut to_implement = FxHashSet::default();
|
||||
let trait_def_id = imp.of_trait.as_ref()?.trait_def_id()?;
|
||||
let ancestors = self
|
||||
.tcx
|
||||
.trait_def(trait_def_id)
|
||||
.ancestors(self.tcx, item.def_id.to_def_id())
|
||||
.ok()?;
|
||||
let mut to_implement = Vec::new();
|
||||
|
||||
for did in self.tcx.associated_item_def_ids(did) {
|
||||
for trait_item in self.tcx.associated_items(trait_def_id).in_definition_order()
|
||||
{
|
||||
if let ty::AssocItem {
|
||||
kind: ty::AssocKind::Fn, ident, defaultness, ..
|
||||
} = self.tcx.associated_item(*did)
|
||||
} = trait_item
|
||||
{
|
||||
// we can ignore functions that do not have default bodies:
|
||||
// if those are unimplemented it will be catched by typeck.
|
||||
if defaultness.has_value()
|
||||
&& !self.tcx.has_attr(*did, sym::default_method_body_is_const)
|
||||
if !defaultness.has_value()
|
||||
|| self
|
||||
.tcx
|
||||
.has_attr(trait_item.def_id, sym::default_method_body_is_const)
|
||||
{
|
||||
to_implement.insert(ident);
|
||||
continue;
|
||||
}
|
||||
|
||||
let is_implemented = ancestors
|
||||
.leaf_def(self.tcx, trait_item.ident, trait_item.kind)
|
||||
.map(|node_item| !node_item.defining_node.is_from_trait())
|
||||
.unwrap_or(false);
|
||||
|
||||
if !is_implemented {
|
||||
to_implement.push(ident.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for it in imp
|
||||
.items
|
||||
.iter()
|
||||
.filter(|it| matches!(it.kind, hir::AssocItemKind::Fn { .. }))
|
||||
{
|
||||
to_implement.remove(&it.ident);
|
||||
}
|
||||
|
||||
// all nonconst trait functions (not marked with #[default_method_body_is_const])
|
||||
// must be implemented
|
||||
if !to_implement.is_empty() {
|
||||
|
@ -118,7 +126,7 @@ impl<'tcx> hir::itemlikevisit::ItemLikeVisitor<'tcx> for CheckConstTraitVisitor<
|
|||
item.span,
|
||||
"const trait implementations may not use non-const default functions",
|
||||
)
|
||||
.note(&format!("`{}` not implemented", to_implement.into_iter().map(|id| id.to_string()).collect::<Vec<_>>().join("`, `")))
|
||||
.note(&format!("`{}` not implemented", to_implement.join("`, `")))
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#![feature(const_trait_impl)]
|
||||
#![feature(const_fn_trait_bound)]
|
||||
|
||||
trait Tr {
|
||||
fn req(&self);
|
||||
|
@ -18,11 +19,6 @@ impl const Tr for S {
|
|||
fn req(&self) {}
|
||||
} //~^^ ERROR const trait implementations may not use non-const default functions
|
||||
|
||||
impl const Tr for u8 {
|
||||
fn req(&self) {}
|
||||
fn prov(&self) {}
|
||||
}
|
||||
|
||||
impl const Tr for u16 {
|
||||
fn prov(&self) {}
|
||||
fn default() {}
|
|
@ -1,5 +1,5 @@
|
|||
error: const trait implementations may not use non-const default functions
|
||||
--> $DIR/impl-with-default-fn.rs:17:1
|
||||
--> $DIR/impl-with-default-fn-fail.rs:18:1
|
||||
|
|
||||
LL | / impl const Tr for S {
|
||||
LL | | fn req(&self) {}
|
||||
|
@ -9,7 +9,7 @@ LL | | }
|
|||
= note: `prov` not implemented
|
||||
|
||||
error: const trait implementations may not use non-const default functions
|
||||
--> $DIR/impl-with-default-fn.rs:32:1
|
||||
--> $DIR/impl-with-default-fn-fail.rs:28:1
|
||||
|
|
||||
LL | / impl const Tr for u32 {
|
||||
LL | | fn req(&self) {}
|
||||
|
@ -20,7 +20,7 @@ LL | | }
|
|||
= note: `prov` not implemented
|
||||
|
||||
error[E0046]: not all trait items implemented, missing: `req`
|
||||
--> $DIR/impl-with-default-fn.rs:26:1
|
||||
--> $DIR/impl-with-default-fn-fail.rs:22:1
|
||||
|
|
||||
LL | fn req(&self);
|
||||
| -------------- `req` from trait
|
|
@ -0,0 +1,34 @@
|
|||
// check-pass
|
||||
|
||||
#![feature(const_trait_impl)]
|
||||
#![feature(const_fn_trait_bound)]
|
||||
|
||||
trait Tr {
|
||||
fn req(&self);
|
||||
|
||||
fn prov(&self) {
|
||||
println!("lul");
|
||||
self.req();
|
||||
}
|
||||
|
||||
#[default_method_body_is_const]
|
||||
fn default() {}
|
||||
}
|
||||
|
||||
impl const Tr for u8 {
|
||||
fn req(&self) {}
|
||||
fn prov(&self) {}
|
||||
}
|
||||
|
||||
macro_rules! impl_tr {
|
||||
($ty: ty) => {
|
||||
impl const Tr for $ty {
|
||||
fn req(&self) {}
|
||||
fn prov(&self) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_tr!(u64);
|
||||
|
||||
fn main() {}
|
Loading…
Add table
Add a link
Reference in a new issue