mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 14:55:26 +00:00
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
@ -277,8 +277,8 @@ 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) {
|
||||||
// allow calling functions marked with #[default_method_body_is_const].
|
// allow calling functions inside a trait marked with #[const_trait].
|
||||||
if !ecx.tcx.has_attr(def.did, sym::default_method_body_is_const) {
|
if !ecx.tcx.is_const_default_method(def.did) {
|
||||||
// We certainly do *not* want to actually call the fn
|
// We certainly do *not* want to actually call the fn
|
||||||
// though, so be sure we return here.
|
// though, so be sure we return here.
|
||||||
throw_unsup_format!("calling non-const function `{}`", instance)
|
throw_unsup_format!("calling non-const function `{}`", instance)
|
||||||
|
@ -9,6 +9,7 @@ Rust MIR: a lowered representation of Rust.
|
|||||||
#![feature(control_flow_enum)]
|
#![feature(control_flow_enum)]
|
||||||
#![feature(decl_macro)]
|
#![feature(decl_macro)]
|
||||||
#![feature(exact_size_is_empty)]
|
#![feature(exact_size_is_empty)]
|
||||||
|
#![feature(let_chains)]
|
||||||
#![feature(let_else)]
|
#![feature(let_else)]
|
||||||
#![feature(map_try_insert)]
|
#![feature(map_try_insert)]
|
||||||
#![feature(min_specialization)]
|
#![feature(min_specialization)]
|
||||||
|
@ -711,8 +711,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut nonconst_call_permission = false;
|
|
||||||
|
|
||||||
// Attempting to call a trait method?
|
// Attempting to call a trait method?
|
||||||
if let Some(trait_id) = tcx.trait_of_item(callee) {
|
if let Some(trait_id) = tcx.trait_of_item(callee) {
|
||||||
trace!("attempting to call a trait method");
|
trace!("attempting to call a trait method");
|
||||||
@ -774,13 +772,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ if !tcx.is_const_fn_raw(callee) => {
|
_ if !tcx.is_const_fn_raw(callee) => {
|
||||||
// At this point, it is only legal when the caller is marked with
|
// At this point, it is only legal when the caller is in a trait
|
||||||
// #[default_method_body_is_const], and the callee is in the same
|
// marked with #[const_trait], and the callee is in the same trait.
|
||||||
// trait.
|
let mut nonconst_call_permission = false;
|
||||||
let callee_trait = tcx.trait_of_item(callee);
|
if let Some(callee_trait) = tcx.trait_of_item(callee)
|
||||||
if callee_trait.is_some()
|
&& tcx.has_attr(callee_trait, sym::const_trait)
|
||||||
&& tcx.has_attr(caller.to_def_id(), sym::default_method_body_is_const)
|
&& Some(callee_trait) == tcx.trait_of_item(caller)
|
||||||
&& callee_trait == tcx.trait_of_item(caller)
|
|
||||||
// Can only call methods when it's `<Self as TheTrait>::f`.
|
// Can only call methods when it's `<Self as TheTrait>::f`.
|
||||||
&& tcx.types.self_param == substs.type_at(0)
|
&& tcx.types.self_param == substs.type_at(0)
|
||||||
{
|
{
|
||||||
@ -874,16 +871,10 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||||||
let is_intrinsic = tcx.is_intrinsic(callee);
|
let is_intrinsic = tcx.is_intrinsic(callee);
|
||||||
|
|
||||||
if !tcx.is_const_fn_raw(callee) {
|
if !tcx.is_const_fn_raw(callee) {
|
||||||
if tcx.trait_of_item(callee).is_some() {
|
if !tcx.is_const_default_method(callee) {
|
||||||
if tcx.has_attr(callee, sym::default_method_body_is_const) {
|
// To get to here we must have already found a const impl for the
|
||||||
// To get to here we must have already found a const impl for the
|
// trait, but for it to still be non-const can be that the impl is
|
||||||
// trait, but for it to still be non-const can be that the impl is
|
// using default method bodies.
|
||||||
// using default method bodies.
|
|
||||||
nonconst_call_permission = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !nonconst_call_permission {
|
|
||||||
self.check_op(ops::FnCallNonConst {
|
self.check_op(ops::FnCallNonConst {
|
||||||
caller,
|
caller,
|
||||||
callee,
|
callee,
|
||||||
|
@ -9,7 +9,7 @@ use rustc_hir as hir;
|
|||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
use rustc_middle::mir;
|
use rustc_middle::mir;
|
||||||
use rustc_middle::ty::{self, TyCtxt};
|
use rustc_middle::ty::{self, TyCtxt};
|
||||||
use rustc_span::{sym, Symbol};
|
use rustc_span::Symbol;
|
||||||
|
|
||||||
pub use self::qualifs::Qualif;
|
pub use self::qualifs::Qualif;
|
||||||
|
|
||||||
@ -84,10 +84,10 @@ pub fn rustc_allow_const_fn_unstable(
|
|||||||
// functions are subject to more stringent restrictions than "const-unstable" functions: They
|
// functions are subject to more stringent restrictions than "const-unstable" functions: They
|
||||||
// cannot use unstable features and can only call other "const-stable" functions.
|
// cannot use unstable features and can only call other "const-stable" functions.
|
||||||
pub fn is_const_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
pub fn is_const_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
||||||
// A default body marked const is not const-stable because const
|
// A default body in a `#[const_trait]` is not const-stable because const
|
||||||
// trait fns currently cannot be const-stable. We shouldn't
|
// trait fns currently cannot be const-stable. We shouldn't
|
||||||
// restrict default bodies to only call const-stable functions.
|
// restrict default bodies to only call const-stable functions.
|
||||||
if tcx.has_attr(def_id, sym::default_method_body_is_const) {
|
if tcx.is_const_default_method(def_id) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -473,9 +473,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||||||
),
|
),
|
||||||
// RFC 2632
|
// RFC 2632
|
||||||
gated!(
|
gated!(
|
||||||
default_method_body_is_const, Normal, template!(Word), WarnFollowing, const_trait_impl,
|
const_trait, Normal, template!(Word), WarnFollowing, const_trait_impl,
|
||||||
"`default_method_body_is_const` is a temporary placeholder for declaring default bodies \
|
"`const` is a temporary placeholder for marking a trait that is suitable for `const` \
|
||||||
as `const`, which may be removed or renamed in the future."
|
`impls` and all default bodies as `const`, which may be removed or renamed in the \
|
||||||
|
future."
|
||||||
),
|
),
|
||||||
// lang-team MCP 147
|
// lang-team MCP 147
|
||||||
gated!(
|
gated!(
|
||||||
|
@ -92,6 +92,7 @@ pub enum DefKind {
|
|||||||
/// [RFC 2593]: https://github.com/rust-lang/rfcs/pull/2593
|
/// [RFC 2593]: https://github.com/rust-lang/rfcs/pull/2593
|
||||||
Ctor(CtorOf, CtorKind),
|
Ctor(CtorOf, CtorKind),
|
||||||
/// Associated function: `impl MyStruct { fn associated() {} }`
|
/// Associated function: `impl MyStruct { fn associated() {} }`
|
||||||
|
/// or `trait Foo { fn associated() {} }`
|
||||||
AssocFn,
|
AssocFn,
|
||||||
/// Associated constant: `trait MyTrait { const ASSOC: usize; }`
|
/// Associated constant: `trait MyTrait { const ASSOC: usize; }`
|
||||||
AssocConst,
|
AssocConst,
|
||||||
|
@ -893,9 +893,9 @@ fn should_encode_mir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> (bool, bool) {
|
|||||||
let needs_inline = (generics.requires_monomorphization(tcx)
|
let needs_inline = (generics.requires_monomorphization(tcx)
|
||||||
|| tcx.codegen_fn_attrs(def_id).requests_inline())
|
|| tcx.codegen_fn_attrs(def_id).requests_inline())
|
||||||
&& tcx.sess.opts.output_types.should_codegen();
|
&& tcx.sess.opts.output_types.should_codegen();
|
||||||
// The function has a `const` modifier or is annotated with `default_method_body_is_const`.
|
// The function has a `const` modifier or is in a `#[const_trait]`.
|
||||||
let is_const_fn = tcx.is_const_fn_raw(def_id.to_def_id())
|
let is_const_fn = tcx.is_const_fn_raw(def_id.to_def_id())
|
||||||
|| tcx.has_attr(def_id.to_def_id(), sym::default_method_body_is_const);
|
|| tcx.is_const_default_method(def_id.to_def_id());
|
||||||
let always_encode_mir = tcx.sess.opts.debugging_opts.always_encode_mir;
|
let always_encode_mir = tcx.sess.opts.debugging_opts.always_encode_mir;
|
||||||
(is_const_fn, needs_inline || always_encode_mir)
|
(is_const_fn, needs_inline || always_encode_mir)
|
||||||
}
|
}
|
||||||
|
@ -494,9 +494,7 @@ impl<'hir> Map<'hir> {
|
|||||||
BodyOwnerKind::Fn if self.tcx.is_const_fn_raw(def_id.to_def_id()) => {
|
BodyOwnerKind::Fn if self.tcx.is_const_fn_raw(def_id.to_def_id()) => {
|
||||||
ConstContext::ConstFn
|
ConstContext::ConstFn
|
||||||
}
|
}
|
||||||
BodyOwnerKind::Fn
|
BodyOwnerKind::Fn if self.tcx.is_const_default_method(def_id.to_def_id()) => {
|
||||||
if self.tcx.has_attr(def_id.to_def_id(), sym::default_method_body_is_const) =>
|
|
||||||
{
|
|
||||||
ConstContext::ConstFn
|
ConstContext::ConstFn
|
||||||
}
|
}
|
||||||
BodyOwnerKind::Fn | BodyOwnerKind::Closure => return None,
|
BodyOwnerKind::Fn | BodyOwnerKind::Closure => return None,
|
||||||
|
@ -2303,6 +2303,11 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||||||
matches!(self.def_kind(def_id), DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..))
|
matches!(self.def_kind(def_id), DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..))
|
||||||
&& self.impl_constness(def_id) == hir::Constness::Const
|
&& self.impl_constness(def_id) == hir::Constness::Const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn is_const_default_method(self, def_id: DefId) -> bool {
|
||||||
|
matches!(self.trait_of_item(def_id), Some(trait_id) if self.has_attr(trait_id, sym::const_trait))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Yields the parent function's `LocalDefId` if `def_id` is an `impl Trait` definition.
|
/// Yields the parent function's `LocalDefId` if `def_id` is an `impl Trait` definition.
|
||||||
|
@ -122,9 +122,7 @@ impl CheckAttrVisitor<'_> {
|
|||||||
| 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 => {
|
sym::const_trait => self.check_const_trait(attr, span, target),
|
||||||
self.check_default_method_body_is_const(attr, span, target)
|
|
||||||
}
|
|
||||||
sym::must_not_suspend => self.check_must_not_suspend(&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::must_use => self.check_must_use(hir_id, &attr, span, target),
|
||||||
sym::rustc_pass_by_value => self.check_pass_by_value(&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.
|
/// `#[const_trait]` only applies to traits.
|
||||||
fn check_default_method_body_is_const(
|
fn check_const_trait(&self, attr: &Attribute, _span: Span, target: Target) -> bool {
|
||||||
&self,
|
|
||||||
attr: &Attribute,
|
|
||||||
span: Span,
|
|
||||||
target: Target,
|
|
||||||
) -> bool {
|
|
||||||
match target {
|
match target {
|
||||||
Target::Method(MethodKind::Trait { body: true }) => true,
|
Target::Trait => true,
|
||||||
_ => {
|
_ => {
|
||||||
self.tcx
|
self.tcx
|
||||||
.sess
|
.sess
|
||||||
.struct_span_err(
|
.struct_span_err(attr.span, "attribute should be applied to a trait")
|
||||||
attr.span,
|
|
||||||
"attribute should be applied to a trait method with body",
|
|
||||||
)
|
|
||||||
.span_label(span, "not a trait method or missing a body")
|
|
||||||
.emit();
|
.emit();
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
@ -2207,6 +2196,8 @@ impl CheckAttrVisitor<'_> {
|
|||||||
"attribute `{}` without any lints has no effect",
|
"attribute `{}` without any lints has no effect",
|
||||||
attr.name_or_empty()
|
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 {
|
} else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
@ -13,7 +13,6 @@ use rustc_hir as hir;
|
|||||||
use rustc_hir::def_id::LocalDefId;
|
use rustc_hir::def_id::LocalDefId;
|
||||||
use rustc_hir::intravisit::{self, Visitor};
|
use rustc_hir::intravisit::{self, Visitor};
|
||||||
use rustc_middle::hir::nested_filter;
|
use rustc_middle::hir::nested_filter;
|
||||||
use rustc_middle::ty;
|
|
||||||
use rustc_middle::ty::query::Providers;
|
use rustc_middle::ty::query::Providers;
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_session::parse::feature_err;
|
use rustc_session::parse::feature_err;
|
||||||
@ -64,66 +63,6 @@ pub(crate) fn provide(providers: &mut Providers) {
|
|||||||
*providers = Providers { check_mod_const_bodies, ..*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)]
|
#[derive(Copy, Clone)]
|
||||||
struct CheckConstVisitor<'tcx> {
|
struct CheckConstVisitor<'tcx> {
|
||||||
tcx: TyCtxt<'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>) {
|
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
|
||||||
intravisit::walk_item(self, item);
|
intravisit::walk_item(self, item);
|
||||||
check_item(self.tcx, item);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_anon_const(&mut self, anon: &'tcx hir::AnonConst) {
|
fn visit_anon_const(&mut self, anon: &'tcx hir::AnonConst) {
|
||||||
|
@ -505,6 +505,7 @@ symbols! {
|
|||||||
const_raw_ptr_deref,
|
const_raw_ptr_deref,
|
||||||
const_raw_ptr_to_usize_cast,
|
const_raw_ptr_to_usize_cast,
|
||||||
const_refs_to_cell,
|
const_refs_to_cell,
|
||||||
|
const_trait,
|
||||||
const_trait_bound_opt_out,
|
const_trait_bound_opt_out,
|
||||||
const_trait_impl,
|
const_trait_impl,
|
||||||
const_transmute,
|
const_transmute,
|
||||||
|
@ -5,7 +5,7 @@ use rustc_middle::ty::subst::Subst;
|
|||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
self, Binder, EarlyBinder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt,
|
self, Binder, EarlyBinder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt,
|
||||||
};
|
};
|
||||||
use rustc_span::{sym, Span};
|
use rustc_span::Span;
|
||||||
use rustc_trait_selection::traits;
|
use rustc_trait_selection::traits;
|
||||||
|
|
||||||
fn sized_constraint_for_ty<'tcx>(
|
fn sized_constraint_for_ty<'tcx>(
|
||||||
@ -153,7 +153,7 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
|
|||||||
let constness = match hir_id {
|
let constness = match hir_id {
|
||||||
Some(hir_id) => match tcx.hir().get(hir_id) {
|
Some(hir_id) => match tcx.hir().get(hir_id) {
|
||||||
hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. })
|
hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. })
|
||||||
if tcx.has_attr(def_id, sym::default_method_body_is_const) =>
|
if tcx.is_const_default_method(def_id) =>
|
||||||
{
|
{
|
||||||
hir::Constness::Const
|
hir::Constness::Const
|
||||||
}
|
}
|
||||||
|
@ -107,6 +107,7 @@ use crate::marker::Destruct;
|
|||||||
#[lang = "clone"]
|
#[lang = "clone"]
|
||||||
#[rustc_diagnostic_item = "Clone"]
|
#[rustc_diagnostic_item = "Clone"]
|
||||||
#[rustc_trivial_field_reads]
|
#[rustc_trivial_field_reads]
|
||||||
|
#[cfg_attr(not(bootstrap), const_trait)]
|
||||||
pub trait Clone: Sized {
|
pub trait Clone: Sized {
|
||||||
/// Returns a copy of the value.
|
/// Returns a copy of the value.
|
||||||
///
|
///
|
||||||
@ -129,7 +130,7 @@ pub trait Clone: Sized {
|
|||||||
/// allocations.
|
/// allocations.
|
||||||
#[inline]
|
#[inline]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[default_method_body_is_const]
|
#[cfg_attr(bootstrap, default_method_body_is_const)]
|
||||||
fn clone_from(&mut self, source: &Self)
|
fn clone_from(&mut self, source: &Self)
|
||||||
where
|
where
|
||||||
Self: ~const Destruct,
|
Self: ~const Destruct,
|
||||||
|
@ -214,6 +214,7 @@ use self::Ordering::*;
|
|||||||
append_const_msg,
|
append_const_msg,
|
||||||
)
|
)
|
||||||
)]
|
)]
|
||||||
|
#[cfg_attr(not(bootstrap), const_trait)]
|
||||||
#[rustc_diagnostic_item = "PartialEq"]
|
#[rustc_diagnostic_item = "PartialEq"]
|
||||||
pub trait PartialEq<Rhs: ?Sized = Self> {
|
pub trait PartialEq<Rhs: ?Sized = Self> {
|
||||||
/// This method tests for `self` and `other` values to be equal, and is used
|
/// This method tests for `self` and `other` values to be equal, and is used
|
||||||
@ -226,7 +227,7 @@ pub trait PartialEq<Rhs: ?Sized = Self> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[default_method_body_is_const]
|
#[cfg_attr(bootstrap, default_method_body_is_const)]
|
||||||
fn ne(&self, other: &Rhs) -> bool {
|
fn ne(&self, other: &Rhs) -> bool {
|
||||||
!self.eq(other)
|
!self.eq(other)
|
||||||
}
|
}
|
||||||
@ -1053,6 +1054,7 @@ impl PartialOrd for Ordering {
|
|||||||
append_const_msg,
|
append_const_msg,
|
||||||
)
|
)
|
||||||
)]
|
)]
|
||||||
|
#[cfg_attr(not(bootstrap), const_trait)]
|
||||||
#[rustc_diagnostic_item = "PartialOrd"]
|
#[rustc_diagnostic_item = "PartialOrd"]
|
||||||
pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
|
pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
|
||||||
/// This method returns an ordering between `self` and `other` values if one exists.
|
/// This method returns an ordering between `self` and `other` values if one exists.
|
||||||
@ -1096,7 +1098,7 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[default_method_body_is_const]
|
#[cfg_attr(bootstrap, default_method_body_is_const)]
|
||||||
fn lt(&self, other: &Rhs) -> bool {
|
fn lt(&self, other: &Rhs) -> bool {
|
||||||
matches!(self.partial_cmp(other), Some(Less))
|
matches!(self.partial_cmp(other), Some(Less))
|
||||||
}
|
}
|
||||||
@ -1116,7 +1118,7 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[default_method_body_is_const]
|
#[cfg_attr(bootstrap, default_method_body_is_const)]
|
||||||
fn le(&self, other: &Rhs) -> bool {
|
fn le(&self, other: &Rhs) -> bool {
|
||||||
// Pattern `Some(Less | Eq)` optimizes worse than negating `None | Some(Greater)`.
|
// Pattern `Some(Less | Eq)` optimizes worse than negating `None | Some(Greater)`.
|
||||||
// FIXME: The root cause was fixed upstream in LLVM with:
|
// FIXME: The root cause was fixed upstream in LLVM with:
|
||||||
@ -1139,7 +1141,7 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[default_method_body_is_const]
|
#[cfg_attr(bootstrap, default_method_body_is_const)]
|
||||||
fn gt(&self, other: &Rhs) -> bool {
|
fn gt(&self, other: &Rhs) -> bool {
|
||||||
matches!(self.partial_cmp(other), Some(Greater))
|
matches!(self.partial_cmp(other), Some(Greater))
|
||||||
}
|
}
|
||||||
@ -1159,7 +1161,7 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[default_method_body_is_const]
|
#[cfg_attr(bootstrap, default_method_body_is_const)]
|
||||||
fn ge(&self, other: &Rhs) -> bool {
|
fn ge(&self, other: &Rhs) -> bool {
|
||||||
matches!(self.partial_cmp(other), Some(Greater | Equal))
|
matches!(self.partial_cmp(other), Some(Greater | Equal))
|
||||||
}
|
}
|
||||||
|
@ -16,12 +16,12 @@ pub struct S<T>(T);
|
|||||||
// @has - '//pre[@class="rust trait"]/code/a[@class="trait"]' 'Clone'
|
// @has - '//pre[@class="rust trait"]/code/a[@class="trait"]' 'Clone'
|
||||||
// @!has - '//pre[@class="rust trait"]/code/span[@class="where"]' '~const'
|
// @!has - '//pre[@class="rust trait"]/code/span[@class="where"]' '~const'
|
||||||
// @has - '//pre[@class="rust trait"]/code/span[@class="where"]' ': Clone'
|
// @has - '//pre[@class="rust trait"]/code/span[@class="where"]' ': Clone'
|
||||||
|
#[const_trait]
|
||||||
pub trait Tr<T> {
|
pub trait Tr<T> {
|
||||||
// @!has - '//div[@id="method.a"]/h4[@class="code-header"]' '~const'
|
// @!has - '//div[@id="method.a"]/h4[@class="code-header"]' '~const'
|
||||||
// @has - '//div[@id="method.a"]/h4[@class="code-header"]/a[@class="trait"]' 'Clone'
|
// @has - '//div[@id="method.a"]/h4[@class="code-header"]/a[@class="trait"]' 'Clone'
|
||||||
// @!has - '//div[@id="method.a"]/h4[@class="code-header"]/span[@class="where"]' '~const'
|
// @!has - '//div[@id="method.a"]/h4[@class="code-header"]/span[@class="where"]' '~const'
|
||||||
// @has - '//div[@id="method.a"]/h4[@class="code-header"]/span[@class="where fmt-newline"]' ': Clone'
|
// @has - '//div[@id="method.a"]/h4[@class="code-header"]/span[@class="where fmt-newline"]' ': Clone'
|
||||||
#[default_method_body_is_const]
|
|
||||||
fn a<A: ~const Clone + ~const Destruct>()
|
fn a<A: ~const Clone + ~const Destruct>()
|
||||||
where
|
where
|
||||||
Option<A>: ~const Clone + ~const Destruct,
|
Option<A>: ~const Clone + ~const Destruct,
|
||||||
|
@ -1,13 +1,10 @@
|
|||||||
#![feature(const_trait_impl)]
|
#![feature(const_trait_impl)]
|
||||||
|
|
||||||
#[default_method_body_is_const] //~ ERROR attribute should be applied
|
#[const_trait]
|
||||||
trait A {
|
trait A {
|
||||||
#[default_method_body_is_const] //~ ERROR attribute should be applied
|
#[const_trait] //~ ERROR attribute should be applied
|
||||||
fn no_body(self);
|
fn foo(self);
|
||||||
|
|
||||||
#[default_method_body_is_const]
|
|
||||||
fn correct_use(&self) {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[default_method_body_is_const] //~ ERROR attribute should be applied
|
#[const_trait] //~ ERROR attribute should be applied
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
@ -1,32 +1,14 @@
|
|||||||
error: attribute should be applied to a trait method with body
|
error: attribute should be applied to a trait
|
||||||
--> $DIR/attr-misuse.rs:3:1
|
--> $DIR/attr-misuse.rs:9:1
|
||||||
|
|
|
|
||||||
LL | #[default_method_body_is_const]
|
LL | #[const_trait]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^
|
||||||
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
|
error: attribute should be applied to a trait
|
||||||
--> $DIR/attr-misuse.rs:12: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:5:5
|
--> $DIR/attr-misuse.rs:5:5
|
||||||
|
|
|
|
||||||
LL | #[default_method_body_is_const]
|
LL | #[const_trait]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^
|
||||||
LL | fn no_body(self);
|
|
||||||
| ----------------- not a trait method or missing a body
|
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#![feature(const_trait_impl)]
|
#![feature(const_trait_impl)]
|
||||||
|
|
||||||
|
#[const_trait]
|
||||||
pub trait MyTrait {
|
pub trait MyTrait {
|
||||||
#[default_method_body_is_const]
|
|
||||||
fn defaulted_func(&self) {}
|
fn defaulted_func(&self) {}
|
||||||
fn func(self);
|
fn func(self);
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
pub struct Int(i32);
|
pub struct Int(i32);
|
||||||
|
|
||||||
impl const std::ops::Add for i32 { //~ ERROR type annotations needed
|
impl const std::ops::Add for i32 {
|
||||||
//~^ ERROR only traits defined in the current crate can be implemented for primitive types
|
//~^ ERROR only traits defined in the current crate can be implemented for primitive types
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
|
|
||||||
@ -11,7 +11,7 @@ impl const std::ops::Add for i32 { //~ ERROR type annotations needed
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::ops::Add for Int { //~ ERROR type annotations needed
|
impl std::ops::Add for Int {
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
|
|
||||||
fn add(self, rhs: Self) -> Self {
|
fn add(self, rhs: Self) -> Self {
|
||||||
@ -19,7 +19,7 @@ impl std::ops::Add for Int { //~ ERROR type annotations needed
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl const std::ops::Add for Int { //~ ERROR type annotations needed
|
impl const std::ops::Add for Int {
|
||||||
//~^ ERROR conflicting implementations of trait
|
//~^ ERROR conflicting implementations of trait
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
|
|
||||||
|
@ -19,50 +19,7 @@ LL | impl std::ops::Add for Int {
|
|||||||
LL | impl const std::ops::Add for Int {
|
LL | impl const std::ops::Add for Int {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Int`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Int`
|
||||||
|
|
||||||
error[E0283]: type annotations needed
|
error: aborting due to 2 previous errors
|
||||||
--> $DIR/const-and-non-const-impl.rs:5:12
|
|
||||||
|
|
|
||||||
LL | impl const std::ops::Add for i32 {
|
|
||||||
| ^^^^^^^^^^^^^ cannot infer type for type `i32`
|
|
||||||
|
|
|
||||||
note: multiple `impl`s satisfying `i32: Add` found
|
|
||||||
--> $DIR/const-and-non-const-impl.rs:5:1
|
|
||||||
|
|
|
||||||
LL | impl const std::ops::Add for i32 {
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
= note: and another `impl` found in the `core` crate: `impl Add for i32;`
|
|
||||||
|
|
||||||
error[E0283]: type annotations needed
|
Some errors have detailed explanations: E0117, E0119.
|
||||||
--> $DIR/const-and-non-const-impl.rs:14:6
|
|
||||||
|
|
|
||||||
LL | impl std::ops::Add for Int {
|
|
||||||
| ^^^^^^^^^^^^^ cannot infer type for struct `Int`
|
|
||||||
|
|
|
||||||
note: multiple `impl`s satisfying `Int: Add` found
|
|
||||||
--> $DIR/const-and-non-const-impl.rs:14:1
|
|
||||||
|
|
|
||||||
LL | impl std::ops::Add for Int {
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
...
|
|
||||||
LL | impl const std::ops::Add for Int {
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error[E0283]: type annotations needed
|
|
||||||
--> $DIR/const-and-non-const-impl.rs:22:12
|
|
||||||
|
|
|
||||||
LL | impl const std::ops::Add for Int {
|
|
||||||
| ^^^^^^^^^^^^^ cannot infer type for struct `Int`
|
|
||||||
|
|
|
||||||
note: multiple `impl`s satisfying `Int: Add` found
|
|
||||||
--> $DIR/const-and-non-const-impl.rs:14:1
|
|
||||||
|
|
|
||||||
LL | impl std::ops::Add for Int {
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
...
|
|
||||||
LL | impl const std::ops::Add for Int {
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error: aborting due to 5 previous errors
|
|
||||||
|
|
||||||
Some errors have detailed explanations: E0117, E0119, E0283.
|
|
||||||
For more information about an error, try `rustc --explain E0117`.
|
For more information about an error, try `rustc --explain E0117`.
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
#![feature(const_trait_impl)]
|
#![feature(const_trait_impl)]
|
||||||
|
|
||||||
|
#[const_trait]
|
||||||
trait ConstDefaultFn: Sized {
|
trait ConstDefaultFn: Sized {
|
||||||
fn b(self);
|
fn b(self);
|
||||||
|
|
||||||
#[default_method_body_is_const]
|
|
||||||
fn a(self) {
|
fn a(self) {
|
||||||
self.b();
|
self.b();
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// This tests that `default_method_body_is_const` methods can
|
// This tests that `const_trait` default methods can
|
||||||
// be called from a const context when used across crates.
|
// be called from a const context when used across crates.
|
||||||
//
|
//
|
||||||
// check-pass
|
// check-pass
|
||||||
|
@ -5,8 +5,8 @@ impl Tr for () {}
|
|||||||
|
|
||||||
const fn foo<T>() where T: ~const Tr {}
|
const fn foo<T>() where T: ~const Tr {}
|
||||||
|
|
||||||
|
#[const_trait]
|
||||||
pub trait Foo {
|
pub trait Foo {
|
||||||
#[default_method_body_is_const]
|
|
||||||
fn foo() {
|
fn foo() {
|
||||||
foo::<()>();
|
foo::<()>();
|
||||||
//~^ ERROR the trait bound `(): ~const Tr` is not satisfied
|
//~^ ERROR the trait bound `(): ~const Tr` is not satisfied
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
#![feature(const_trait_impl)]
|
#![feature(const_trait_impl)]
|
||||||
|
|
||||||
|
#[const_trait]
|
||||||
pub trait Tr {
|
pub trait Tr {
|
||||||
#[default_method_body_is_const]
|
|
||||||
fn a(&self) {}
|
fn a(&self) {}
|
||||||
|
|
||||||
#[default_method_body_is_const]
|
|
||||||
fn b(&self) {
|
fn b(&self) {
|
||||||
().a()
|
().a()
|
||||||
//~^ ERROR the trait bound
|
//~^ ERROR the trait bound
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
error[E0277]: the trait bound `(): ~const Tr` is not satisfied
|
error[E0277]: the trait bound `(): ~const Tr` is not satisfied
|
||||||
--> $DIR/default-method-body-is-const-same-trait-ck.rs:9:12
|
--> $DIR/default-method-body-is-const-same-trait-ck.rs:8:12
|
||||||
|
|
|
|
||||||
LL | ().a()
|
LL | ().a()
|
||||||
| ^^^ the trait `~const Tr` is not implemented for `()`
|
| ^^^ the trait `~const Tr` is not implemented for `()`
|
||||||
|
|
|
|
||||||
note: the trait `Tr` is implemented for `()`, but that implementation is not `const`
|
note: the trait `Tr` is implemented for `()`, but that implementation is not `const`
|
||||||
--> $DIR/default-method-body-is-const-same-trait-ck.rs:9:12
|
--> $DIR/default-method-body-is-const-same-trait-ck.rs:8:12
|
||||||
|
|
|
|
||||||
LL | ().a()
|
LL | ().a()
|
||||||
| ^^^
|
| ^^^
|
||||||
|
|
||||||
error[E0015]: cannot call non-const fn `<() as Tr>::a` in constant functions
|
error[E0015]: cannot call non-const fn `<() as Tr>::a` in constant functions
|
||||||
--> $DIR/default-method-body-is-const-same-trait-ck.rs:9:12
|
--> $DIR/default-method-body-is-const-same-trait-ck.rs:8:12
|
||||||
|
|
|
|
||||||
LL | ().a()
|
LL | ().a()
|
||||||
| ^^^
|
| ^^^
|
||||||
|
@ -9,8 +9,8 @@
|
|||||||
#![feature(const_trait_impl)]
|
#![feature(const_trait_impl)]
|
||||||
#![stable(since = "1", feature = "foo")]
|
#![stable(since = "1", feature = "foo")]
|
||||||
|
|
||||||
|
#[const_trait]
|
||||||
trait Tr {
|
trait Tr {
|
||||||
#[default_method_body_is_const]
|
|
||||||
fn a() {}
|
fn a() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,32 +1,17 @@
|
|||||||
#![feature(const_trait_impl)]
|
#![feature(const_trait_impl)]
|
||||||
|
|
||||||
|
#[const_trait]
|
||||||
trait Tr {
|
trait Tr {
|
||||||
fn req(&self);
|
fn req(&self);
|
||||||
|
|
||||||
fn prov(&self) {
|
|
||||||
println!("lul");
|
|
||||||
self.req();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[default_method_body_is_const]
|
|
||||||
fn default() {}
|
fn default() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct S;
|
struct S;
|
||||||
|
|
||||||
impl const Tr for S {
|
|
||||||
fn req(&self) {}
|
|
||||||
} //~^^ ERROR const trait implementations may not use non-const default functions
|
|
||||||
|
|
||||||
impl const Tr for u16 {
|
impl const Tr for u16 {
|
||||||
fn prov(&self) {}
|
|
||||||
fn default() {}
|
fn default() {}
|
||||||
} //~^^^ ERROR not all trait items implemented
|
} //~^^ 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,26 +1,5 @@
|
|||||||
error: const trait implementations may not use non-const default functions
|
|
||||||
--> $DIR/impl-with-default-fn-fail.rs:17:1
|
|
||||||
|
|
|
||||||
LL | / impl const Tr for S {
|
|
||||||
LL | | fn req(&self) {}
|
|
||||||
LL | | }
|
|
||||||
| |_^
|
|
||||||
|
|
|
||||||
= note: `prov` not implemented
|
|
||||||
|
|
||||||
error: const trait implementations may not use non-const default functions
|
|
||||||
--> $DIR/impl-with-default-fn-fail.rs:27: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`
|
error[E0046]: not all trait items implemented, missing: `req`
|
||||||
--> $DIR/impl-with-default-fn-fail.rs:21:1
|
--> $DIR/impl-with-default-fn-fail.rs:12:1
|
||||||
|
|
|
|
||||||
LL | fn req(&self);
|
LL | fn req(&self);
|
||||||
| -------------- `req` from trait
|
| -------------- `req` from trait
|
||||||
@ -28,6 +7,6 @@ LL | fn req(&self);
|
|||||||
LL | impl const Tr for u16 {
|
LL | impl const Tr for u16 {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^ missing `req` in implementation
|
| ^^^^^^^^^^^^^^^^^^^^^ missing `req` in implementation
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
error: aborting due to previous error
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0046`.
|
For more information about this error, try `rustc --explain E0046`.
|
||||||
|
@ -2,28 +2,21 @@
|
|||||||
|
|
||||||
#![feature(const_trait_impl)]
|
#![feature(const_trait_impl)]
|
||||||
|
|
||||||
|
#[const_trait]
|
||||||
trait Tr {
|
trait Tr {
|
||||||
fn req(&self);
|
fn req(&self);
|
||||||
|
|
||||||
fn prov(&self) {
|
|
||||||
println!("lul");
|
|
||||||
self.req();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[default_method_body_is_const]
|
|
||||||
fn default() {}
|
fn default() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl const Tr for u8 {
|
impl const Tr for u8 {
|
||||||
fn req(&self) {}
|
fn req(&self) {}
|
||||||
fn prov(&self) {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_tr {
|
macro_rules! impl_tr {
|
||||||
($ty: ty) => {
|
($ty: ty) => {
|
||||||
impl const Tr for $ty {
|
impl const Tr for $ty {
|
||||||
fn req(&self) {}
|
fn req(&self) {}
|
||||||
fn prov(&self) {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,8 +37,8 @@ impl const FromResidual for T {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[stable(feature = "foo", since = "1.0")]
|
#[stable(feature = "foo", since = "1.0")]
|
||||||
|
#[const_trait]
|
||||||
pub trait Tr {
|
pub trait Tr {
|
||||||
#[default_method_body_is_const]
|
|
||||||
#[stable(feature = "foo", since = "1.0")]
|
#[stable(feature = "foo", since = "1.0")]
|
||||||
fn bar() -> T {
|
fn bar() -> T {
|
||||||
T?
|
T?
|
||||||
|
@ -6,8 +6,8 @@ trait Bar {
|
|||||||
fn bar() -> u8;
|
fn bar() -> u8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[const_trait]
|
||||||
trait Foo {
|
trait Foo {
|
||||||
#[default_method_body_is_const]
|
|
||||||
fn foo() -> u8 where Self: ~const Bar {
|
fn foo() -> u8 where Self: ~const Bar {
|
||||||
<Self as Bar>::bar() * 6
|
<Self as Bar>::bar() * 6
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user