Auto merge of #86857 - fee1-dead:add-attr, r=oli-obk
Add #[default_method_body_is_const] `@rustbot` label F-const_trait_impl
This commit is contained in:
commit
394804bb23
19 changed files with 265 additions and 34 deletions
|
@ -98,6 +98,9 @@ impl CheckAttrVisitor<'tcx> {
|
|||
| sym::rustc_if_this_changed
|
||||
| sym::rustc_then_this_would_need => self.check_rustc_dirty_clean(&attr),
|
||||
sym::cmse_nonsecure_entry => self.check_cmse_nonsecure_entry(attr, span, target),
|
||||
sym::default_method_body_is_const => {
|
||||
self.check_default_method_body_is_const(attr, span, target)
|
||||
}
|
||||
_ => true,
|
||||
};
|
||||
// lint-only checks
|
||||
|
@ -1465,6 +1468,29 @@ impl CheckAttrVisitor<'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// default_method_body_is_const should only be applied to trait methods with default bodies.
|
||||
fn check_default_method_body_is_const(
|
||||
&self,
|
||||
attr: &Attribute,
|
||||
span: &Span,
|
||||
target: Target,
|
||||
) -> bool {
|
||||
match target {
|
||||
Target::Method(MethodKind::Trait { body: true }) => true,
|
||||
_ => {
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(
|
||||
attr.span,
|
||||
"attribute should be applied to a trait method with body",
|
||||
)
|
||||
.span_label(*span, "not a trait method or missing a body")
|
||||
.emit();
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Visitor<'tcx> for CheckAttrVisitor<'tcx> {
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
//! 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;
|
||||
|
@ -85,34 +86,41 @@ impl<'tcx> hir::itemlikevisit::ItemLikeVisitor<'tcx> for CheckConstTraitVisitor<
|
|||
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 mut to_implement = FxHashSet::default();
|
||||
|
||||
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)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
to_implement.insert(ident);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for it in imp
|
||||
.items
|
||||
.iter()
|
||||
.filter(|it| matches!(it.kind, hir::AssocItemKind::Fn { .. }))
|
||||
.count();
|
||||
{
|
||||
to_implement.remove(&it.ident);
|
||||
}
|
||||
|
||||
// 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 {
|
||||
// all nonconst trait functions (not marked with #[default_method_body_is_const])
|
||||
// must be implemented
|
||||
if !to_implement.is_empty() {
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue