1
Fork 0

Add #[default_method_body_is_const]

This commit is contained in:
Deadbeef 2021-07-04 12:24:20 +08:00
parent a84d1b21ae
commit 2db927d8d8
No known key found for this signature in database
GPG key ID: 6525773485376D92
5 changed files with 82 additions and 22 deletions

View file

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

View file

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

View file

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

View file

@ -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() {}

View file

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