add #[rustc_non_const_trait_method]
This commit is contained in:
parent
e823167aa6
commit
38ee80d48e
14 changed files with 107 additions and 10 deletions
|
|
@ -388,3 +388,15 @@ impl<S: Stage> CombineAttributeParser<S> for RustcLayoutParser {
|
|||
result
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct RustcNonConstTraitMethodParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcNonConstTraitMethodParser {
|
||||
const PATH: &'static [Symbol] = &[sym::rustc_non_const_trait_method];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Method(MethodKind::Trait { body: true })),
|
||||
Allow(Target::Method(MethodKind::Trait { body: false })),
|
||||
]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNonConstTraitMethod;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,9 +79,9 @@ use crate::attributes::rustc_internal::{
|
|||
RustcLayoutScalarValidRangeStartParser, RustcLegacyConstGenericsParser,
|
||||
RustcLintOptDenyFieldAccessParser, RustcLintOptTyParser, RustcLintQueryInstabilityParser,
|
||||
RustcLintUntrackedQueryInformationParser, RustcMainParser, RustcMustImplementOneOfParser,
|
||||
RustcNeverReturnsNullPointerParser, RustcNoImplicitAutorefsParser, RustcNounwindParser,
|
||||
RustcObjectLifetimeDefaultParser, RustcOffloadKernelParser, RustcScalableVectorParser,
|
||||
RustcSimdMonomorphizeLaneLimitParser,
|
||||
RustcNeverReturnsNullPointerParser, RustcNoImplicitAutorefsParser,
|
||||
RustcNonConstTraitMethodParser, RustcNounwindParser, RustcObjectLifetimeDefaultParser,
|
||||
RustcOffloadKernelParser, RustcScalableVectorParser, RustcSimdMonomorphizeLaneLimitParser,
|
||||
};
|
||||
use crate::attributes::semantics::MayDangleParser;
|
||||
use crate::attributes::stability::{
|
||||
|
|
@ -305,6 +305,7 @@ attribute_parsers!(
|
|||
Single<WithoutArgs<RustcMainParser>>,
|
||||
Single<WithoutArgs<RustcNeverReturnsNullPointerParser>>,
|
||||
Single<WithoutArgs<RustcNoImplicitAutorefsParser>>,
|
||||
Single<WithoutArgs<RustcNonConstTraitMethodParser>>,
|
||||
Single<WithoutArgs<RustcNounwindParser>>,
|
||||
Single<WithoutArgs<RustcOffloadKernelParser>>,
|
||||
Single<WithoutArgs<RustcPassIndirectlyInNonRusticAbisParser>>,
|
||||
|
|
|
|||
|
|
@ -778,12 +778,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
// than usual.
|
||||
|
||||
trace!("attempting to call a trait method");
|
||||
let trait_is_const = tcx.is_const_trait(trait_did);
|
||||
let is_const = tcx.constness(callee) == hir::Constness::Const;
|
||||
|
||||
// Only consider a trait to be const if the const conditions hold.
|
||||
// Otherwise, it's really misleading to call something "conditionally"
|
||||
// const when it's very obviously not conditionally const.
|
||||
if trait_is_const && has_const_conditions == Some(ConstConditionsHold::Yes) {
|
||||
if is_const && has_const_conditions == Some(ConstConditionsHold::Yes) {
|
||||
// Trait calls are always conditionally-const.
|
||||
self.check_op(ops::ConditionallyConstCall {
|
||||
callee,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::{
|
||||
Constness, ExprKind, ForeignItemKind, ImplItem, ImplItemImplKind, ImplItemKind, Item, ItemKind,
|
||||
Node, TraitItem, TraitItemKind, VariantData,
|
||||
Node, TraitItem, TraitItemKind, VariantData, find_attr,
|
||||
};
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
|
|
@ -36,7 +37,13 @@ fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Constness {
|
|||
Constness::NotConst => tcx.constness(tcx.local_parent(def_id)),
|
||||
}
|
||||
}
|
||||
Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(..), .. }) => tcx.trait_def(tcx.local_parent(def_id)).constness,
|
||||
Node::TraitItem(ti @ TraitItem { kind: TraitItemKind::Fn(..), .. }) => {
|
||||
if find_attr!(tcx.hir_attrs(ti.hir_id()), AttributeKind::RustcNonConstTraitMethod) {
|
||||
Constness::NotConst
|
||||
} else {
|
||||
tcx.trait_def(tcx.local_parent(def_id)).constness
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
tcx.dcx().span_bug(
|
||||
tcx.def_span(def_id),
|
||||
|
|
|
|||
|
|
@ -1329,6 +1329,12 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
"`#[rustc_has_incoherent_inherent_impls]` allows the addition of incoherent inherent impls for \
|
||||
the given type by annotating all impl items with `#[rustc_allow_incoherent_impl]`"
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_non_const_trait_method, AttributeType::Normal, template!(Word),
|
||||
ErrorFollowing, EncodeCrossCrate::No,
|
||||
"`#[rustc_non_const_trait_method]` should only used by the standard library to mark trait methods \
|
||||
as non-const to allow large traits to easier transition to const"
|
||||
),
|
||||
|
||||
BuiltinAttribute {
|
||||
name: sym::rustc_diagnostic_item,
|
||||
|
|
|
|||
|
|
@ -1096,6 +1096,9 @@ pub enum AttributeKind {
|
|||
/// Represents `#[rustc_no_implicit_autorefs]`
|
||||
RustcNoImplicitAutorefs,
|
||||
|
||||
/// Represents `#[rustc_non_const_trait_method]`.
|
||||
RustcNonConstTraitMethod,
|
||||
|
||||
/// Represents `#[rustc_nounwind]`
|
||||
RustcNounwind,
|
||||
|
||||
|
|
|
|||
|
|
@ -124,6 +124,7 @@ impl AttributeKind {
|
|||
RustcMustImplementOneOf { .. } => No,
|
||||
RustcNeverReturnsNullPointer => Yes,
|
||||
RustcNoImplicitAutorefs => Yes,
|
||||
RustcNonConstTraitMethod => No, // should be reported via other queries like `constness`
|
||||
RustcNounwind => No,
|
||||
RustcObjcClass { .. } => No,
|
||||
RustcObjcSelector { .. } => No,
|
||||
|
|
|
|||
|
|
@ -2086,8 +2086,13 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
DefKind::Impl { of_trait: false } => {
|
||||
self.constness(def_id) == hir::Constness::Const
|
||||
}
|
||||
DefKind::Impl { of_trait: true } | DefKind::Trait => {
|
||||
self.is_conditionally_const(parent_def_id)
|
||||
DefKind::Impl { of_trait: true } => {
|
||||
self.constness(self.trait_item_of(def_id).unwrap()) == hir::Constness::Const
|
||||
&& self.is_conditionally_const(parent_def_id)
|
||||
}
|
||||
DefKind::Trait => {
|
||||
self.constness(def_id) == hir::Constness::Const
|
||||
&& self.is_conditionally_const(parent_def_id)
|
||||
}
|
||||
_ => bug!("unexpected parent item of associated fn: {parent_def_id:?}"),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -310,6 +310,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
| AttributeKind::RustcMain
|
||||
| AttributeKind::RustcNeverReturnsNullPointer
|
||||
| AttributeKind::RustcNoImplicitAutorefs
|
||||
| AttributeKind::RustcNonConstTraitMethod
|
||||
| AttributeKind::RustcNounwind
|
||||
| AttributeKind::RustcObjcClass { .. }
|
||||
| AttributeKind::RustcObjcSelector { .. }
|
||||
|
|
@ -335,7 +336,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
| AttributeKind::Used { .. }
|
||||
| AttributeKind::WindowsSubsystem(..)
|
||||
// tidy-alphabetical-end
|
||||
|
||||
) => { /* do nothing */ }
|
||||
Attribute::Unparsed(attr_item) => {
|
||||
style = Some(attr_item.style);
|
||||
|
|
|
|||
|
|
@ -1995,6 +1995,7 @@ symbols! {
|
|||
rustc_no_implicit_autorefs,
|
||||
rustc_no_implicit_bounds,
|
||||
rustc_no_mir_inline,
|
||||
rustc_non_const_trait_method,
|
||||
rustc_nonnull_optimization_guaranteed,
|
||||
rustc_nounwind,
|
||||
rustc_objc_class,
|
||||
|
|
|
|||
7
tests/ui/traits/const-traits/partial/attr-gate.rs
Normal file
7
tests/ui/traits/const-traits/partial/attr-gate.rs
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
trait A {
|
||||
#[rustc_non_const_trait_method]
|
||||
//~^ ERROR: use of an internal attribute
|
||||
fn a();
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
13
tests/ui/traits/const-traits/partial/attr-gate.stderr
Normal file
13
tests/ui/traits/const-traits/partial/attr-gate.stderr
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
error[E0658]: use of an internal attribute
|
||||
--> $DIR/attr-gate.rs:2:5
|
||||
|
|
||||
LL | #[rustc_non_const_trait_method]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
|
||||
= note: the `#[rustc_non_const_trait_method]` attribute is an internal implementation detail that will never be stable
|
||||
= note: `#[rustc_non_const_trait_method]` should only used by the standard library to mark trait methods as non-const to allow large traits to easier transition to const
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
22
tests/ui/traits/const-traits/partial/no-const-callers.rs
Normal file
22
tests/ui/traits/const-traits/partial/no-const-callers.rs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
#![feature(const_trait_impl, rustc_attrs)]
|
||||
|
||||
const trait A {
|
||||
fn a();
|
||||
#[rustc_non_const_trait_method]
|
||||
fn b() { println!("hi"); }
|
||||
}
|
||||
|
||||
impl const A for () {
|
||||
fn a() {}
|
||||
}
|
||||
|
||||
const fn foo<T: [const] A>() {
|
||||
T::a();
|
||||
T::b();
|
||||
//~^ ERROR: cannot call non-const associated function
|
||||
<()>::a();
|
||||
<()>::b();
|
||||
//~^ ERROR: cannot call non-const associated function
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
19
tests/ui/traits/const-traits/partial/no-const-callers.stderr
Normal file
19
tests/ui/traits/const-traits/partial/no-const-callers.stderr
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
error[E0015]: cannot call non-const associated function `<T as A>::b` in constant functions
|
||||
--> $DIR/no-const-callers.rs:15:5
|
||||
|
|
||||
LL | T::b();
|
||||
| ^^^^^^
|
||||
|
|
||||
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||
|
||||
error[E0015]: cannot call non-const associated function `<() as A>::b` in constant functions
|
||||
--> $DIR/no-const-callers.rs:18:5
|
||||
|
|
||||
LL | <()>::b();
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0015`.
|
||||
Loading…
Add table
Add a link
Reference in a new issue