Auto merge of #96964 - oli-obk:const_trait_mvp, r=compiler-errors
Replace `#[default_method_body_is_const]` with `#[const_trait]` pulled out of #96077 related issues: #67792 and #92158 cc `@fee1-dead` This is groundwork to only allowing `impl const Trait` for traits that are marked with `#[const_trait]`. This is necessary to prevent adding a new default method from becoming a breaking change (as it could be a non-const fn).
This commit is contained in:
commit
5c780b98d1
32 changed files with 82 additions and 260 deletions
|
@ -122,9 +122,7 @@ impl CheckAttrVisitor<'_> {
|
|||
| 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)
|
||||
}
|
||||
sym::const_trait => self.check_const_trait(attr, span, target),
|
||||
sym::must_not_suspend => self.check_must_not_suspend(&attr, span, target),
|
||||
sym::must_use => self.check_must_use(hir_id, &attr, span, target),
|
||||
sym::rustc_pass_by_value => self.check_pass_by_value(&attr, span, target),
|
||||
|
@ -2097,23 +2095,14 @@ impl CheckAttrVisitor<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
/// `#[const_trait]` only applies to traits.
|
||||
fn check_const_trait(&self, attr: &Attribute, _span: Span, target: Target) -> bool {
|
||||
match target {
|
||||
Target::Method(MethodKind::Trait { body: true }) => true,
|
||||
Target::Trait => 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")
|
||||
.struct_span_err(attr.span, "attribute should be applied to a trait")
|
||||
.emit();
|
||||
false
|
||||
}
|
||||
|
@ -2207,6 +2196,8 @@ impl CheckAttrVisitor<'_> {
|
|||
"attribute `{}` without any lints has no effect",
|
||||
attr.name_or_empty()
|
||||
)
|
||||
} else if attr.name_or_empty() == sym::default_method_body_is_const {
|
||||
format!("`default_method_body_is_const` has been replaced with `#[const_trait]` on traits")
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
|
|
|
@ -13,7 +13,6 @@ use rustc_hir as hir;
|
|||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_middle::hir::nested_filter;
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::query::Providers;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::parse::feature_err;
|
||||
|
@ -64,66 +63,6 @@ pub(crate) fn provide(providers: &mut Providers) {
|
|||
*providers = Providers { check_mod_const_bodies, ..*providers };
|
||||
}
|
||||
|
||||
fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
|
||||
let _: Option<_> = try {
|
||||
if let hir::ItemKind::Impl(ref imp) = item.kind && let hir::Constness::Const = imp.constness {
|
||||
let trait_def_id = imp.of_trait.as_ref()?.trait_def_id()?;
|
||||
let ancestors = tcx
|
||||
.trait_def(trait_def_id)
|
||||
.ancestors(tcx, item.def_id.to_def_id())
|
||||
.ok()?;
|
||||
let mut to_implement = Vec::new();
|
||||
|
||||
for trait_item in tcx.associated_items(trait_def_id).in_definition_order()
|
||||
{
|
||||
if let ty::AssocItem {
|
||||
kind: ty::AssocKind::Fn,
|
||||
defaultness,
|
||||
def_id: trait_item_id,
|
||||
..
|
||||
} = *trait_item
|
||||
{
|
||||
// we can ignore functions that do not have default bodies:
|
||||
// if those are unimplemented it will be caught by typeck.
|
||||
if !defaultness.has_value()
|
||||
|| tcx
|
||||
.has_attr(trait_item_id, sym::default_method_body_is_const)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
let is_implemented = ancestors
|
||||
.leaf_def(tcx, trait_item_id)
|
||||
.map(|node_item| !node_item.defining_node.is_from_trait())
|
||||
.unwrap_or(false);
|
||||
|
||||
if !is_implemented {
|
||||
to_implement.push(trait_item_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// all nonconst trait functions (not marked with #[default_method_body_is_const])
|
||||
// must be implemented
|
||||
if !to_implement.is_empty() {
|
||||
let not_implemented = to_implement
|
||||
.into_iter()
|
||||
.map(|did| tcx.item_name(did).to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join("`, `");
|
||||
tcx
|
||||
.sess
|
||||
.struct_span_err(
|
||||
item.span,
|
||||
"const trait implementations may not use non-const default functions",
|
||||
)
|
||||
.note(&format!("`{}` not implemented", not_implemented))
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct CheckConstVisitor<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
|
@ -254,7 +193,6 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> {
|
|||
|
||||
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
|
||||
intravisit::walk_item(self, item);
|
||||
check_item(self.tcx, item);
|
||||
}
|
||||
|
||||
fn visit_anon_const(&mut self, anon: &'tcx hir::AnonConst) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue