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
|
@ -349,6 +349,12 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||||
),
|
),
|
||||||
|
|
||||||
gated!(cmse_nonsecure_entry, AssumedUsed, template!(Word), experimental!(cmse_nonsecure_entry)),
|
gated!(cmse_nonsecure_entry, AssumedUsed, template!(Word), experimental!(cmse_nonsecure_entry)),
|
||||||
|
// RFC 2632
|
||||||
|
gated!(
|
||||||
|
default_method_body_is_const, AssumedUsed, template!(Word), const_trait_impl,
|
||||||
|
"`default_method_body_is_const` is a temporary placeholder for declaring default bodies \
|
||||||
|
as `const`, which may be removed or renamed in the future."
|
||||||
|
),
|
||||||
|
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
// Internal attributes: Stability, deprecation, and unsafe:
|
// Internal attributes: Stability, deprecation, and unsafe:
|
||||||
|
|
|
@ -952,6 +952,10 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
||||||
self.get_impl_data(id).defaultness
|
self.get_impl_data(id).defaultness
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_impl_constness(&self, id: DefIndex) -> hir::Constness {
|
||||||
|
self.get_impl_data(id).constness
|
||||||
|
}
|
||||||
|
|
||||||
fn get_coerce_unsized_info(&self, id: DefIndex) -> Option<ty::adjustment::CoerceUnsizedInfo> {
|
fn get_coerce_unsized_info(&self, id: DefIndex) -> Option<ty::adjustment::CoerceUnsizedInfo> {
|
||||||
self.get_impl_data(id).coerce_unsized_info
|
self.get_impl_data(id).coerce_unsized_info
|
||||||
}
|
}
|
||||||
|
|
|
@ -168,6 +168,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
|
||||||
is_no_builtins => { cdata.root.no_builtins }
|
is_no_builtins => { cdata.root.no_builtins }
|
||||||
symbol_mangling_version => { cdata.root.symbol_mangling_version }
|
symbol_mangling_version => { cdata.root.symbol_mangling_version }
|
||||||
impl_defaultness => { cdata.get_impl_defaultness(def_id.index) }
|
impl_defaultness => { cdata.get_impl_defaultness(def_id.index) }
|
||||||
|
impl_constness => { cdata.get_impl_constness(def_id.index) }
|
||||||
reachable_non_generics => {
|
reachable_non_generics => {
|
||||||
let reachable_non_generics = tcx
|
let reachable_non_generics = tcx
|
||||||
.exported_symbols(cdata.cnum)
|
.exported_symbols(cdata.cnum)
|
||||||
|
|
|
@ -1412,7 +1412,7 @@ impl EncodeContext<'a, 'tcx> {
|
||||||
adt_def.repr,
|
adt_def.repr,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
hir::ItemKind::Impl(hir::Impl { defaultness, .. }) => {
|
hir::ItemKind::Impl(hir::Impl { defaultness, constness, .. }) => {
|
||||||
let trait_ref = self.tcx.impl_trait_ref(def_id);
|
let trait_ref = self.tcx.impl_trait_ref(def_id);
|
||||||
let polarity = self.tcx.impl_polarity(def_id);
|
let polarity = self.tcx.impl_polarity(def_id);
|
||||||
let parent = if let Some(trait_ref) = trait_ref {
|
let parent = if let Some(trait_ref) = trait_ref {
|
||||||
|
@ -1437,8 +1437,13 @@ impl EncodeContext<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let data =
|
let data = ImplData {
|
||||||
ImplData { polarity, defaultness, parent_impl: parent, coerce_unsized_info };
|
polarity,
|
||||||
|
defaultness,
|
||||||
|
constness,
|
||||||
|
parent_impl: parent,
|
||||||
|
coerce_unsized_info,
|
||||||
|
};
|
||||||
|
|
||||||
EntryKind::Impl(self.lazy(data))
|
EntryKind::Impl(self.lazy(data))
|
||||||
}
|
}
|
||||||
|
|
|
@ -390,6 +390,7 @@ struct TraitData {
|
||||||
#[derive(TyEncodable, TyDecodable)]
|
#[derive(TyEncodable, TyDecodable)]
|
||||||
struct ImplData {
|
struct ImplData {
|
||||||
polarity: ty::ImplPolarity,
|
polarity: ty::ImplPolarity,
|
||||||
|
constness: hir::Constness,
|
||||||
defaultness: hir::Defaultness,
|
defaultness: hir::Defaultness,
|
||||||
parent_impl: Option<DefId>,
|
parent_impl: Option<DefId>,
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ use rustc_index::vec::Idx;
|
||||||
use rustc_span::def_id::StableCrateId;
|
use rustc_span::def_id::StableCrateId;
|
||||||
use rustc_span::hygiene::MacroKind;
|
use rustc_span::hygiene::MacroKind;
|
||||||
use rustc_span::source_map::Spanned;
|
use rustc_span::source_map::Spanned;
|
||||||
use rustc_span::symbol::{kw, Ident, Symbol};
|
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use rustc_target::spec::abi::Abi;
|
use rustc_target::spec::abi::Abi;
|
||||||
|
|
||||||
|
@ -465,6 +465,9 @@ impl<'hir> Map<'hir> {
|
||||||
/// Returns the `ConstContext` of the body associated with this `LocalDefId`.
|
/// Returns the `ConstContext` of the body associated with this `LocalDefId`.
|
||||||
///
|
///
|
||||||
/// Panics if `LocalDefId` does not have an associated body.
|
/// Panics if `LocalDefId` does not have an associated body.
|
||||||
|
///
|
||||||
|
/// This should only be used for determining the context of a body, a return
|
||||||
|
/// value of `Some` does not always suggest that the owner of the body is `const`.
|
||||||
pub fn body_const_context(&self, did: LocalDefId) -> Option<ConstContext> {
|
pub fn body_const_context(&self, did: LocalDefId) -> Option<ConstContext> {
|
||||||
let hir_id = self.local_def_id_to_hir_id(did);
|
let hir_id = self.local_def_id_to_hir_id(did);
|
||||||
let ccx = match self.body_owner_kind(hir_id) {
|
let ccx = match self.body_owner_kind(hir_id) {
|
||||||
|
@ -473,6 +476,11 @@ impl<'hir> Map<'hir> {
|
||||||
|
|
||||||
BodyOwnerKind::Fn if self.tcx.is_constructor(did.to_def_id()) => return None,
|
BodyOwnerKind::Fn if self.tcx.is_constructor(did.to_def_id()) => return None,
|
||||||
BodyOwnerKind::Fn if self.tcx.is_const_fn_raw(did.to_def_id()) => ConstContext::ConstFn,
|
BodyOwnerKind::Fn if self.tcx.is_const_fn_raw(did.to_def_id()) => ConstContext::ConstFn,
|
||||||
|
BodyOwnerKind::Fn
|
||||||
|
if self.tcx.has_attr(did.to_def_id(), sym::default_method_body_is_const) =>
|
||||||
|
{
|
||||||
|
ConstContext::ConstFn
|
||||||
|
}
|
||||||
BodyOwnerKind::Fn | BodyOwnerKind::Closure => return None,
|
BodyOwnerKind::Fn | BodyOwnerKind::Closure => return None,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1144,6 +1144,10 @@ rustc_queries! {
|
||||||
desc { |tcx| "looking up whether `{}` is a default impl", tcx.def_path_str(def_id) }
|
desc { |tcx| "looking up whether `{}` is a default impl", tcx.def_path_str(def_id) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
query impl_constness(def_id: DefId) -> hir::Constness {
|
||||||
|
desc { |tcx| "looking up whether `{}` is a const impl", tcx.def_path_str(def_id) }
|
||||||
|
}
|
||||||
|
|
||||||
query check_item_well_formed(key: LocalDefId) -> () {
|
query check_item_well_formed(key: LocalDefId) -> () {
|
||||||
desc { |tcx| "checking that `{}` is well-formed", tcx.def_path_str(key.to_def_id()) }
|
desc { |tcx| "checking that `{}` is well-formed", tcx.def_path_str(key.to_def_id()) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -235,12 +235,15 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
|
||||||
// sensitive check here. But we can at least rule out functions that are not const
|
// sensitive check here. But we can at least rule out functions that are not const
|
||||||
// at all.
|
// at all.
|
||||||
if !ecx.tcx.is_const_fn_raw(def.did) {
|
if !ecx.tcx.is_const_fn_raw(def.did) {
|
||||||
// Some functions we support even if they are non-const -- but avoid testing
|
// allow calling functions marked with #[default_method_body_is_const].
|
||||||
// that for const fn!
|
if !ecx.tcx.has_attr(def.did, sym::default_method_body_is_const) {
|
||||||
ecx.hook_panic_fn(instance, args)?;
|
// Some functions we support even if they are non-const -- but avoid testing
|
||||||
// We certainly do *not* want to actually call the fn
|
// that for const fn!
|
||||||
// though, so be sure we return here.
|
ecx.hook_panic_fn(instance, args)?;
|
||||||
throw_unsup_format!("calling non-const function `{}`", instance)
|
// We certainly do *not* want to actually call the fn
|
||||||
|
// though, so be sure we return here.
|
||||||
|
throw_unsup_format!("calling non-const function `{}`", instance)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// This is a const fn. Call it.
|
// This is a const fn. Call it.
|
||||||
|
|
|
@ -886,8 +886,34 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !tcx.is_const_fn_raw(callee) {
|
if !tcx.is_const_fn_raw(callee) {
|
||||||
self.check_op(ops::FnCallNonConst);
|
let mut permitted = false;
|
||||||
return;
|
|
||||||
|
let callee_trait = tcx.trait_of_item(callee);
|
||||||
|
if let Some(trait_id) = callee_trait {
|
||||||
|
if tcx.has_attr(caller, sym::default_method_body_is_const) {
|
||||||
|
// permit call to non-const fn when caller has default_method_body_is_const..
|
||||||
|
if tcx.trait_of_item(caller) == callee_trait {
|
||||||
|
// ..and caller and callee are in the same trait.
|
||||||
|
permitted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut const_impls = true;
|
||||||
|
tcx.for_each_relevant_impl(trait_id, substs.type_at(0), |imp| {
|
||||||
|
if const_impls {
|
||||||
|
if let hir::Constness::NotConst = tcx.impl_constness(imp) {
|
||||||
|
const_impls = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if const_impls {
|
||||||
|
permitted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !permitted {
|
||||||
|
self.check_op(ops::FnCallNonConst);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the `const fn` we are trying to call is not const-stable, ensure that we have
|
// If the `const fn` we are trying to call is not const-stable, ensure that we have
|
||||||
|
|
|
@ -98,6 +98,9 @@ impl CheckAttrVisitor<'tcx> {
|
||||||
| sym::rustc_if_this_changed
|
| sym::rustc_if_this_changed
|
||||||
| sym::rustc_then_this_would_need => self.check_rustc_dirty_clean(&attr),
|
| 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::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,
|
_ => true,
|
||||||
};
|
};
|
||||||
// lint-only checks
|
// 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> {
|
impl Visitor<'tcx> for CheckAttrVisitor<'tcx> {
|
||||||
|
|
|
@ -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,41 @@ 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)
|
||||||
|
{
|
||||||
|
// 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
|
.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,
|
||||||
|
|
|
@ -168,6 +168,16 @@ fn impl_defaultness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Defaultness {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn impl_constness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Constness {
|
||||||
|
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
|
||||||
|
let item = tcx.hir().expect_item(hir_id);
|
||||||
|
if let hir::ItemKind::Impl(impl_) = &item.kind {
|
||||||
|
impl_.constness
|
||||||
|
} else {
|
||||||
|
bug!("`impl_constness` called on {:?}", item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Calculates the `Sized` constraint.
|
/// Calculates the `Sized` constraint.
|
||||||
///
|
///
|
||||||
/// In fact, there are only a few options for the types in the constraint:
|
/// In fact, there are only a few options for the types in the constraint:
|
||||||
|
@ -535,6 +545,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
|
||||||
instance_def_size_estimate,
|
instance_def_size_estimate,
|
||||||
issue33140_self_ty,
|
issue33140_self_ty,
|
||||||
impl_defaultness,
|
impl_defaultness,
|
||||||
|
impl_constness,
|
||||||
conservative_is_privately_uninhabited: conservative_is_privately_uninhabited_raw,
|
conservative_is_privately_uninhabited: conservative_is_privately_uninhabited_raw,
|
||||||
..*providers
|
..*providers
|
||||||
};
|
};
|
||||||
|
|
14
src/test/ui/rfc-2632-const-trait-impl/attr-misuse.rs
Normal file
14
src/test/ui/rfc-2632-const-trait-impl/attr-misuse.rs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#![feature(const_trait_impl)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
|
#[default_method_body_is_const] //~ ERROR attribute should be applied
|
||||||
|
trait A {
|
||||||
|
#[default_method_body_is_const] //~ ERROR attribute should be applied
|
||||||
|
fn no_body(self);
|
||||||
|
|
||||||
|
#[default_method_body_is_const]
|
||||||
|
fn correct_use(&self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[default_method_body_is_const] //~ ERROR attribute should be applied
|
||||||
|
fn main() {}
|
32
src/test/ui/rfc-2632-const-trait-impl/attr-misuse.stderr
Normal file
32
src/test/ui/rfc-2632-const-trait-impl/attr-misuse.stderr
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
error: attribute should be applied to a trait method with body
|
||||||
|
--> $DIR/attr-misuse.rs:4:1
|
||||||
|
|
|
||||||
|
LL | #[default_method_body_is_const]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
LL | / trait A {
|
||||||
|
LL | | #[default_method_body_is_const]
|
||||||
|
LL | | fn no_body(self);
|
||||||
|
LL | |
|
||||||
|
LL | | #[default_method_body_is_const]
|
||||||
|
LL | | fn correct_use(&self) {}
|
||||||
|
LL | | }
|
||||||
|
| |_- not a trait method or missing a body
|
||||||
|
|
||||||
|
error: attribute should be applied to a trait method with body
|
||||||
|
--> $DIR/attr-misuse.rs:13:1
|
||||||
|
|
|
||||||
|
LL | #[default_method_body_is_const]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
LL | fn main() {}
|
||||||
|
| ------------ not a trait method or missing a body
|
||||||
|
|
||||||
|
error: attribute should be applied to a trait method with body
|
||||||
|
--> $DIR/attr-misuse.rs:6:5
|
||||||
|
|
|
||||||
|
LL | #[default_method_body_is_const]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
LL | fn no_body(self);
|
||||||
|
| ----------------- not a trait method or missing a body
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
#![feature(const_trait_impl)]
|
||||||
|
#![feature(const_fn_trait_bound)] // FIXME is this needed?
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
|
trait ConstDefaultFn: Sized {
|
||||||
|
fn b(self);
|
||||||
|
|
||||||
|
#[default_method_body_is_const]
|
||||||
|
fn a(self) {
|
||||||
|
self.b();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct NonConstImpl;
|
||||||
|
struct ConstImpl;
|
||||||
|
|
||||||
|
impl ConstDefaultFn for NonConstImpl {
|
||||||
|
fn b(self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl const ConstDefaultFn for ConstImpl {
|
||||||
|
fn b(self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
const fn test() {
|
||||||
|
NonConstImpl.a();
|
||||||
|
//~^ ERROR calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||||
|
ConstImpl.a();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,9 @@
|
||||||
|
error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||||
|
--> $DIR/const-default-method-bodies.rs:26:5
|
||||||
|
|
|
||||||
|
LL | NonConstImpl.a();
|
||||||
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0015`.
|
|
@ -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