Add #[default_method_body_is_const]
This commit is contained in:
parent
a84d1b21ae
commit
2db927d8d8
5 changed files with 82 additions and 22 deletions
|
@ -470,6 +470,11 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||||
|
|
||||||
rustc_attr!(rustc_promotable, AssumedUsed, template!(Word), IMPL_DETAIL),
|
rustc_attr!(rustc_promotable, AssumedUsed, template!(Word), IMPL_DETAIL),
|
||||||
rustc_attr!(rustc_legacy_const_generics, AssumedUsed, template!(List: "N"), INTERNAL_UNSTABLE),
|
rustc_attr!(rustc_legacy_const_generics, AssumedUsed, template!(List: "N"), INTERNAL_UNSTABLE),
|
||||||
|
gated!(
|
||||||
|
default_method_body_is_const, AssumedUsed, template!(Word), const_trait_impl,
|
||||||
|
"the `#[default_method_body_is_const]` attribute marks a default method of a trait \
|
||||||
|
as const, so it does not need to be duplicated by a const impl."
|
||||||
|
),
|
||||||
|
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
// Internal attributes, Layout related:
|
// Internal attributes, Layout related:
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
//! through, but errors for structured control flow in a `const` should be emitted here.
|
//! through, but errors for structured control flow in a `const` should be emitted here.
|
||||||
|
|
||||||
use rustc_attr as attr;
|
use rustc_attr as attr;
|
||||||
|
use rustc_data_structures::stable_set::FxHashSet;
|
||||||
use rustc_errors::struct_span_err;
|
use rustc_errors::struct_span_err;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::LocalDefId;
|
use rustc_hir::def_id::LocalDefId;
|
||||||
|
@ -85,34 +86,46 @@ impl<'tcx> hir::itemlikevisit::ItemLikeVisitor<'tcx> for CheckConstTraitVisitor<
|
||||||
if let hir::ItemKind::Impl(ref imp) = item.kind {
|
if let hir::ItemKind::Impl(ref imp) = item.kind {
|
||||||
if let hir::Constness::Const = imp.constness {
|
if let hir::Constness::Const = imp.constness {
|
||||||
let did = imp.of_trait.as_ref()?.trait_def_id()?;
|
let did = imp.of_trait.as_ref()?.trait_def_id()?;
|
||||||
let trait_fn_cnt = self
|
let mut to_implement = FxHashSet::default();
|
||||||
.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
|
for did in self.tcx.associated_item_def_ids(did) {
|
||||||
|
if let ty::AssocItem {
|
||||||
|
kind: ty::AssocKind::Fn, ident, defaultness, ..
|
||||||
|
} = self.tcx.associated_item(*did)
|
||||||
|
{
|
||||||
|
match (
|
||||||
|
self.tcx.has_attr(*did, sym::default_method_body_is_const),
|
||||||
|
defaultness.has_value(),
|
||||||
|
) {
|
||||||
|
(false, true) => {
|
||||||
|
to_implement.insert(ident);
|
||||||
|
}
|
||||||
|
// ignore functions that do not have default bodies
|
||||||
|
// if those are unimplemented it will be catched by
|
||||||
|
// typeck.
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for it in imp
|
||||||
.items
|
.items
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|it| matches!(it.kind, hir::AssocItemKind::Fn { .. }))
|
.filter(|it| matches!(it.kind, hir::AssocItemKind::Fn { .. }))
|
||||||
.count();
|
{
|
||||||
|
to_implement.remove(&it.ident);
|
||||||
|
}
|
||||||
|
|
||||||
// number of trait functions unequal to functions in impl,
|
// all nonconst trait functions (not marked with #[default_method_body_is_const])
|
||||||
// meaning that one or more provided/default functions of the
|
// must be implemented
|
||||||
// trait are used.
|
if !to_implement.is_empty() {
|
||||||
if trait_fn_cnt != impl_fn_cnt {
|
|
||||||
self.tcx
|
self.tcx
|
||||||
.sess
|
.sess
|
||||||
.struct_span_err(
|
.struct_span_err(
|
||||||
item.span,
|
item.span,
|
||||||
"const trait implementations may not use default functions",
|
"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("`, `")))
|
||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -462,6 +462,7 @@ symbols! {
|
||||||
decode,
|
decode,
|
||||||
default_alloc_error_handler,
|
default_alloc_error_handler,
|
||||||
default_lib_allocator,
|
default_lib_allocator,
|
||||||
|
default_method_body_is_const,
|
||||||
default_type_parameter_fallback,
|
default_type_parameter_fallback,
|
||||||
default_type_params,
|
default_type_params,
|
||||||
delay_span_bug_from_inside_query,
|
delay_span_bug_from_inside_query,
|
||||||
|
|
|
@ -8,13 +8,31 @@ trait Tr {
|
||||||
println!("lul");
|
println!("lul");
|
||||||
self.req();
|
self.req();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[default_method_body_is_const]
|
||||||
|
fn default() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct S;
|
struct S;
|
||||||
|
|
||||||
impl const Tr for S {
|
impl const Tr for S {
|
||||||
fn req(&self) {}
|
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) {}
|
||||||
}
|
}
|
||||||
//~^^^ ERROR const trait implementations may not use default functions
|
|
||||||
|
impl const Tr for u16 {
|
||||||
|
fn prov(&self) {}
|
||||||
|
fn default() {}
|
||||||
|
} //~^^^ ERROR not all trait items implemented
|
||||||
|
|
||||||
|
|
||||||
|
impl const Tr for u32 {
|
||||||
|
fn req(&self) {}
|
||||||
|
fn default() {}
|
||||||
|
} //~^^^ ERROR const trait implementations may not use non-const default functions
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -1,10 +1,33 @@
|
||||||
error: const trait implementations may not use default functions
|
error: const trait implementations may not use non-const default functions
|
||||||
--> $DIR/impl-with-default-fn.rs:15:1
|
--> $DIR/impl-with-default-fn.rs:18:1
|
||||||
|
|
|
|
||||||
LL | / impl const Tr for S {
|
LL | / impl const Tr for S {
|
||||||
LL | | fn req(&self) {}
|
LL | | fn req(&self) {}
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_^
|
| |_^
|
||||||
|
|
|
||||||
|
= note: `prov` not implemented
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: const trait implementations may not use non-const default functions
|
||||||
|
--> $DIR/impl-with-default-fn.rs:33:1
|
||||||
|
|
|
||||||
|
LL | / impl const Tr for u32 {
|
||||||
|
LL | | fn req(&self) {}
|
||||||
|
LL | | fn default() {}
|
||||||
|
LL | | }
|
||||||
|
| |_^
|
||||||
|
|
|
||||||
|
= note: `prov` not implemented
|
||||||
|
|
||||||
|
error[E0046]: not all trait items implemented, missing: `req`
|
||||||
|
--> $DIR/impl-with-default-fn.rs:27:1
|
||||||
|
|
|
||||||
|
LL | fn req(&self);
|
||||||
|
| -------------- `req` from trait
|
||||||
|
...
|
||||||
|
LL | impl const Tr for u16 {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^ missing `req` in implementation
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0046`.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue