diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index 365cd55bdc38b..64edd3f9db06f 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -329,3 +329,15 @@ impl NoArgsAttributeParser for RustcOffloadKernelParser { const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcOffloadKernel; } + +pub(crate) struct RustcNonConstTraitMethodParser; + +impl NoArgsAttributeParser for RustcNonConstTraitMethodParser { + const PATH: &'static [Symbol] = &[sym::rustc_non_const_trait_method]; + const ON_DUPLICATE: OnDuplicate = 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; +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 20bdfa45a013d..f42f7bfbefd76 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -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::{ @@ -304,6 +304,7 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 95dbf42d4d441..57396b657a3fa 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -774,16 +774,16 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // Attempting to call a trait method? if let Some(trait_did) = tcx.trait_of_assoc(callee) { - // We can't determine the actual callee here, so we have to do different checks - // than usual. + // We can't determine the actual callee (the underlying impl of the trait) here, so we have + // to do different checks 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, diff --git a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs index cdf0dcff381fc..46cdca53ba8cf 100644 --- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs @@ -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), diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index ded8a5a4ae51c..182ef6816337f 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -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 an easier transition to const" + ), BuiltinAttribute { name: sym::rustc_diagnostic_item, diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 8a7dee15d4f48..15574b0b34b07 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -1101,6 +1101,9 @@ pub enum AttributeKind { /// Represents `#[rustc_no_implicit_autorefs]` RustcNoImplicitAutorefs, + /// Represents `#[rustc_non_const_trait_method]`. + RustcNonConstTraitMethod, + /// Represents `#[rustc_nounwind]` RustcNounwind, diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 356575416aded..5c6b3408daccb 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -128,6 +128,7 @@ impl AttributeKind { RustcMustImplementOneOf { .. } => No, RustcNeverReturnsNullPointer => Yes, RustcNoImplicitAutorefs => Yes, + RustcNonConstTraitMethod => No, // should be reported via other queries like `constness` RustcNounwind => No, RustcObjectLifetimeDefault => No, RustcOffloadKernel => Yes, diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 4534cfcf962e8..3dd89e69f50b2 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -218,7 +218,7 @@ fn compare_method_predicate_entailment<'tcx>( trait_m_predicates.instantiate_own(tcx, trait_to_impl_args).map(|(predicate, _)| predicate), ); - let is_conditionally_const = tcx.is_conditionally_const(impl_def_id); + let is_conditionally_const = tcx.is_conditionally_const(impl_m.def_id); if is_conditionally_const { // Augment the hybrid param-env with the const conditions // of the impl header and the trait method. diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index ce713dcf42f54..8adb99f7cc56a 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2180,8 +2180,16 @@ 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 } => { + let Some(trait_method_did) = self.trait_item_of(def_id) else { + return false; + }; + self.constness(trait_method_did) == 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:?}"), } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index cdd141f9233e8..ebb9f73e32345 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -313,6 +313,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::RustcMain | AttributeKind::RustcNeverReturnsNullPointer | AttributeKind::RustcNoImplicitAutorefs + | AttributeKind::RustcNonConstTraitMethod | AttributeKind::RustcNounwind | AttributeKind::RustcOffloadKernel | AttributeKind::RustcPassIndirectlyInNonRusticAbis(..) @@ -334,7 +335,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::Used { .. } | AttributeKind::WindowsSubsystem(..) // tidy-alphabetical-end - ) => { /* do nothing */ } Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 8fd228211f3c3..d190d3092566f 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1991,6 +1991,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, diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs index cdf81385bdafb..5d5c2659f0619 100644 --- a/library/core/src/iter/traits/collect.rs +++ b/library/core/src/iter/traits/collect.rs @@ -279,7 +279,8 @@ pub trait FromIterator: Sized { )] #[rustc_skip_during_method_dispatch(array, boxed_slice)] #[stable(feature = "rust1", since = "1.0.0")] -pub trait IntoIterator { +#[rustc_const_unstable(feature = "const_iter", issue = "92476")] +pub const trait IntoIterator { /// The type of the elements being iterated over. #[stable(feature = "rust1", since = "1.0.0")] type Item; @@ -311,7 +312,8 @@ pub trait IntoIterator { } #[stable(feature = "rust1", since = "1.0.0")] -impl IntoIterator for I { +#[rustc_const_unstable(feature = "const_iter", issue = "92476")] +impl const IntoIterator for I { type Item = I::Item; type IntoIter = I; diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index dc484e2a27f61..d919230d094d8 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -37,7 +37,8 @@ fn _assert_is_dyn_compatible(_: &dyn Iterator) {} #[lang = "iterator"] #[rustc_diagnostic_item = "Iterator"] #[must_use = "iterators are lazy and do nothing unless consumed"] -pub trait Iterator { +#[rustc_const_unstable(feature = "const_iter", issue = "92476")] +pub const trait Iterator { /// The type of the elements being iterated over. #[rustc_diagnostic_item = "IteratorItem"] #[stable(feature = "rust1", since = "1.0.0")] @@ -107,6 +108,7 @@ pub trait Iterator { /// ``` #[inline] #[unstable(feature = "iter_next_chunk", issue = "98326")] + #[rustc_non_const_trait_method] fn next_chunk( &mut self, ) -> Result<[Self::Item; N], array::IntoIter> @@ -219,6 +221,7 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_non_const_trait_method] fn count(self) -> usize where Self: Sized, @@ -251,6 +254,7 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_non_const_trait_method] fn last(self) -> Option where Self: Sized, @@ -298,6 +302,7 @@ pub trait Iterator { /// ``` #[inline] #[unstable(feature = "iter_advance_by", issue = "77404")] + #[rustc_non_const_trait_method] fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { /// Helper trait to specialize `advance_by` via `try_fold` for `Sized` iterators. trait SpecAdvanceBy { @@ -375,6 +380,7 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_non_const_trait_method] fn nth(&mut self, n: usize) -> Option { self.advance_by(n).ok()?; self.next() @@ -425,6 +431,7 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "iterator_step_by", since = "1.28.0")] + #[rustc_non_const_trait_method] fn step_by(self, step: usize) -> StepBy where Self: Sized, @@ -496,6 +503,7 @@ pub trait Iterator { /// [`OsStr`]: ../../std/ffi/struct.OsStr.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_non_const_trait_method] fn chain(self, other: U) -> Chain where Self: Sized, @@ -614,6 +622,7 @@ pub trait Iterator { /// [`zip`]: crate::iter::zip #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_non_const_trait_method] fn zip(self, other: U) -> Zip where Self: Sized, @@ -657,6 +666,7 @@ pub trait Iterator { /// [`intersperse_with`]: Iterator::intersperse_with #[inline] #[unstable(feature = "iter_intersperse", issue = "79524")] + #[rustc_non_const_trait_method] fn intersperse(self, separator: Self::Item) -> Intersperse where Self: Sized, @@ -715,6 +725,7 @@ pub trait Iterator { /// [`intersperse`]: Iterator::intersperse #[inline] #[unstable(feature = "iter_intersperse", issue = "79524")] + #[rustc_non_const_trait_method] fn intersperse_with(self, separator: G) -> IntersperseWith where Self: Sized, @@ -774,6 +785,7 @@ pub trait Iterator { #[rustc_diagnostic_item = "IteratorMap"] #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_non_const_trait_method] fn map(self, f: F) -> Map where Self: Sized, @@ -819,6 +831,7 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "iterator_for_each", since = "1.21.0")] + #[rustc_non_const_trait_method] fn for_each(self, f: F) where Self: Sized, @@ -894,6 +907,7 @@ pub trait Iterator { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "iter_filter"] + #[rustc_non_const_trait_method] fn filter

(self, predicate: P) -> Filter where Self: Sized, @@ -939,6 +953,7 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_non_const_trait_method] fn filter_map(self, f: F) -> FilterMap where Self: Sized, @@ -986,6 +1001,7 @@ pub trait Iterator { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "enumerate_method"] + #[rustc_non_const_trait_method] fn enumerate(self) -> Enumerate where Self: Sized, @@ -1057,6 +1073,7 @@ pub trait Iterator { /// [`next`]: Iterator::next #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_non_const_trait_method] fn peekable(self) -> Peekable where Self: Sized, @@ -1122,6 +1139,7 @@ pub trait Iterator { #[inline] #[doc(alias = "drop_while")] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_non_const_trait_method] fn skip_while

(self, predicate: P) -> SkipWhile where Self: Sized, @@ -1200,6 +1218,7 @@ pub trait Iterator { /// the iteration should stop, but wasn't placed back into the iterator. #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_non_const_trait_method] fn take_while

(self, predicate: P) -> TakeWhile where Self: Sized, @@ -1288,6 +1307,7 @@ pub trait Iterator { /// [`fuse`]: Iterator::fuse #[inline] #[stable(feature = "iter_map_while", since = "1.57.0")] + #[rustc_non_const_trait_method] fn map_while(self, predicate: P) -> MapWhile where Self: Sized, @@ -1317,6 +1337,7 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_non_const_trait_method] fn skip(self, n: usize) -> Skip where Self: Sized, @@ -1389,6 +1410,7 @@ pub trait Iterator { #[doc(alias = "limit")] #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_non_const_trait_method] fn take(self, n: usize) -> Take where Self: Sized, @@ -1436,6 +1458,7 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_non_const_trait_method] fn scan(self, initial_state: St, f: F) -> Scan where Self: Sized, @@ -1474,6 +1497,7 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_non_const_trait_method] fn flat_map(self, f: F) -> FlatMap where Self: Sized, @@ -1558,6 +1582,7 @@ pub trait Iterator { /// [`flat_map()`]: Iterator::flat_map #[inline] #[stable(feature = "iterator_flatten", since = "1.29.0")] + #[rustc_non_const_trait_method] fn flatten(self) -> Flatten where Self: Sized, @@ -1714,6 +1739,7 @@ pub trait Iterator { /// ``` #[inline] #[unstable(feature = "iter_map_windows", issue = "87155")] + #[rustc_non_const_trait_method] fn map_windows(self, f: F) -> MapWindows where Self: Sized, @@ -1776,6 +1802,7 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_non_const_trait_method] fn fuse(self) -> Fuse where Self: Sized, @@ -1860,6 +1887,7 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_non_const_trait_method] fn inspect(self, f: F) -> Inspect where Self: Sized, @@ -2019,6 +2047,7 @@ pub trait Iterator { #[stable(feature = "rust1", since = "1.0.0")] #[must_use = "if you really need to exhaust the iterator, consider `.for_each(drop)` instead"] #[rustc_diagnostic_item = "iterator_collect_fn"] + #[rustc_non_const_trait_method] fn collect>(self) -> B where Self: Sized, @@ -2106,6 +2135,7 @@ pub trait Iterator { /// [`collect`]: Iterator::collect #[inline] #[unstable(feature = "iterator_try_collect", issue = "94047")] + #[rustc_non_const_trait_method] fn try_collect(&mut self) -> ChangeOutputType where Self: Sized, @@ -2178,6 +2208,7 @@ pub trait Iterator { /// ``` #[inline] #[unstable(feature = "iter_collect_into", issue = "94780")] + #[rustc_non_const_trait_method] fn collect_into>(self, collection: &mut E) -> &mut E where Self: Sized, @@ -2210,6 +2241,7 @@ pub trait Iterator { /// assert_eq!(odd, [1, 3]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_non_const_trait_method] fn partition(self, f: F) -> (B, B) where Self: Sized, @@ -2272,6 +2304,7 @@ pub trait Iterator { /// assert!(a[i..].iter().all(|n| n % 2 == 1)); // odds /// ``` #[unstable(feature = "iter_partition_in_place", issue = "62543")] + #[rustc_non_const_trait_method] fn partition_in_place<'a, T: 'a, P>(mut self, ref mut predicate: P) -> usize where Self: Sized + DoubleEndedIterator, @@ -2329,6 +2362,7 @@ pub trait Iterator { /// assert!(!"IntoIterator".chars().is_partitioned(char::is_uppercase)); /// ``` #[unstable(feature = "iter_is_partitioned", issue = "62544")] + #[rustc_non_const_trait_method] fn is_partitioned

(mut self, mut predicate: P) -> bool where Self: Sized, @@ -2423,6 +2457,7 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "iterator_try_fold", since = "1.27.0")] + #[rustc_non_const_trait_method] fn try_fold(&mut self, init: B, mut f: F) -> R where Self: Sized, @@ -2481,6 +2516,7 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "iterator_try_fold", since = "1.27.0")] + #[rustc_non_const_trait_method] fn try_for_each(&mut self, f: F) -> R where Self: Sized, @@ -2600,6 +2636,7 @@ pub trait Iterator { #[doc(alias = "inject", alias = "foldl")] #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_non_const_trait_method] fn fold(mut self, init: B, mut f: F) -> B where Self: Sized, @@ -2637,6 +2674,7 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "iterator_fold_self", since = "1.51.0")] + #[rustc_non_const_trait_method] fn reduce(mut self, f: F) -> Option where Self: Sized, @@ -2708,6 +2746,7 @@ pub trait Iterator { /// ``` #[inline] #[unstable(feature = "iterator_try_reduce", issue = "87053")] + #[rustc_non_const_trait_method] fn try_reduce( &mut self, f: impl FnMut(Self::Item, Self::Item) -> R, @@ -2766,6 +2805,7 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_non_const_trait_method] fn all(&mut self, f: F) -> bool where Self: Sized, @@ -2819,6 +2859,7 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_non_const_trait_method] fn any(&mut self, f: F) -> bool where Self: Sized, @@ -2892,6 +2933,7 @@ pub trait Iterator { /// Note that `iter.find(f)` is equivalent to `iter.filter(f).next()`. #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_non_const_trait_method] fn find

(&mut self, predicate: P) -> Option where Self: Sized, @@ -2923,6 +2965,7 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "iterator_find_map", since = "1.30.0")] + #[rustc_non_const_trait_method] fn find_map(&mut self, f: F) -> Option where Self: Sized, @@ -2981,6 +3024,7 @@ pub trait Iterator { /// ``` #[inline] #[unstable(feature = "try_find", issue = "63178")] + #[rustc_non_const_trait_method] fn try_find( &mut self, f: impl FnMut(&Self::Item) -> R, @@ -3064,6 +3108,7 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_non_const_trait_method] fn position

(&mut self, predicate: P) -> Option where Self: Sized, @@ -3129,6 +3174,7 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_non_const_trait_method] fn rposition

(self) -> P where Self: Sized, @@ -3644,6 +3704,7 @@ pub trait Iterator { /// assert_eq!([1, 2].iter().cmp([1].iter()), Ordering::Greater); /// ``` #[stable(feature = "iter_order", since = "1.5.0")] + #[rustc_non_const_trait_method] fn cmp(self, other: I) -> Ordering where I: IntoIterator, @@ -3671,6 +3732,7 @@ pub trait Iterator { /// assert_eq!(xs.into_iter().cmp_by(ys, |x, y| (2 * x).cmp(&y)), Ordering::Greater); /// ``` #[unstable(feature = "iter_order_by", issue = "64295")] + #[rustc_non_const_trait_method] fn cmp_by(self, other: I, cmp: F) -> Ordering where Self: Sized, @@ -3727,6 +3789,7 @@ pub trait Iterator { /// ``` /// #[stable(feature = "iter_order", since = "1.5.0")] + #[rustc_non_const_trait_method] fn partial_cmp(self, other: I) -> Option where I: IntoIterator, @@ -3763,6 +3826,7 @@ pub trait Iterator { /// ); /// ``` #[unstable(feature = "iter_order_by", issue = "64295")] + #[rustc_non_const_trait_method] fn partial_cmp_by(self, other: I, partial_cmp: F) -> Option where Self: Sized, @@ -3796,6 +3860,7 @@ pub trait Iterator { /// assert_eq!([1].iter().eq([1, 2].iter()), false); /// ``` #[stable(feature = "iter_order", since = "1.5.0")] + #[rustc_non_const_trait_method] fn eq(self, other: I) -> bool where I: IntoIterator, @@ -3819,6 +3884,7 @@ pub trait Iterator { /// assert!(xs.iter().eq_by(ys, |x, y| x * x == y)); /// ``` #[unstable(feature = "iter_order_by", issue = "64295")] + #[rustc_non_const_trait_method] fn eq_by(self, other: I, eq: F) -> bool where Self: Sized, @@ -3848,6 +3914,7 @@ pub trait Iterator { /// assert_eq!([1].iter().ne([1, 2].iter()), true); /// ``` #[stable(feature = "iter_order", since = "1.5.0")] + #[rustc_non_const_trait_method] fn ne(self, other: I) -> bool where I: IntoIterator, @@ -3869,6 +3936,7 @@ pub trait Iterator { /// assert_eq!([1, 2].iter().lt([1, 2].iter()), false); /// ``` #[stable(feature = "iter_order", since = "1.5.0")] + #[rustc_non_const_trait_method] fn lt(self, other: I) -> bool where I: IntoIterator, @@ -3890,6 +3958,7 @@ pub trait Iterator { /// assert_eq!([1, 2].iter().le([1, 2].iter()), true); /// ``` #[stable(feature = "iter_order", since = "1.5.0")] + #[rustc_non_const_trait_method] fn le(self, other: I) -> bool where I: IntoIterator, @@ -3911,6 +3980,7 @@ pub trait Iterator { /// assert_eq!([1, 2].iter().gt([1, 2].iter()), false); /// ``` #[stable(feature = "iter_order", since = "1.5.0")] + #[rustc_non_const_trait_method] fn gt(self, other: I) -> bool where I: IntoIterator, @@ -3932,6 +4002,7 @@ pub trait Iterator { /// assert_eq!([1, 2].iter().ge([1, 2].iter()), true); /// ``` #[stable(feature = "iter_order", since = "1.5.0")] + #[rustc_non_const_trait_method] fn ge(self, other: I) -> bool where I: IntoIterator, @@ -3961,6 +4032,7 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "is_sorted", since = "1.82.0")] + #[rustc_non_const_trait_method] fn is_sorted(self) -> bool where Self: Sized, @@ -3987,6 +4059,7 @@ pub trait Iterator { /// assert!(std::iter::empty::().is_sorted_by(|a, b| true)); /// ``` #[stable(feature = "is_sorted", since = "1.82.0")] + #[rustc_non_const_trait_method] fn is_sorted_by(mut self, compare: F) -> bool where Self: Sized, @@ -4031,6 +4104,7 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "is_sorted", since = "1.82.0")] + #[rustc_non_const_trait_method] fn is_sorted_by_key(self, f: F) -> bool where Self: Sized, @@ -4046,6 +4120,7 @@ pub trait Iterator { #[inline] #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] + #[rustc_non_const_trait_method] unsafe fn __iterator_get_unchecked(&mut self, _idx: usize) -> Self::Item where Self: TrustedRandomAccessNoCoerce, diff --git a/library/core/src/option.rs b/library/core/src/option.rs index eb4f978b7c19d..b7c805f5855eb 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -2257,7 +2257,8 @@ impl const Default for Option { } #[stable(feature = "rust1", since = "1.0.0")] -impl IntoIterator for Option { +#[rustc_const_unstable(feature = "const_iter", issue = "92476")] +impl const IntoIterator for Option { type Item = T; type IntoIter = IntoIter; @@ -2429,7 +2430,8 @@ struct Item { opt: Option, } -impl Iterator for Item { +#[rustc_const_unstable(feature = "const_iter", issue = "92476")] +impl const Iterator for Item { type Item = A; #[inline] @@ -2439,7 +2441,7 @@ impl Iterator for Item { #[inline] fn size_hint(&self) -> (usize, Option) { - let len = self.len(); + let len = self.opt.len(); (len, Some(len)) } } @@ -2563,7 +2565,8 @@ pub struct IntoIter { } #[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for IntoIter { +#[rustc_const_unstable(feature = "const_iter", issue = "92476")] +impl const Iterator for IntoIter { type Item = A; #[inline] diff --git a/library/coretests/tests/iter/mod.rs b/library/coretests/tests/iter/mod.rs index 5b2769d04698d..f300f421f7c13 100644 --- a/library/coretests/tests/iter/mod.rs +++ b/library/coretests/tests/iter/mod.rs @@ -99,3 +99,18 @@ pub fn extend_for_unit() { } assert_eq!(x, 5); } + +#[test] +pub fn test_const_iter() { + const X: bool = { + let it = Some(42); + let mut run = false; + #[expect(for_loops_over_fallibles)] + for x in it { + assert!(x == 42); + run = true; + } + run + }; + assert_eq!(true, X); +} diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index 8cca714b73933..a24c83834edb1 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -27,6 +27,7 @@ #![feature(const_drop_in_place)] #![feature(const_eval_select)] #![feature(const_index)] +#![feature(const_iter)] #![feature(const_ops)] #![feature(const_option_ops)] #![feature(const_ref_cell)] diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md index daaaef42d9096..c2c363c1097ed 100644 --- a/src/doc/rustc-dev-guide/src/SUMMARY.md +++ b/src/doc/rustc-dev-guide/src/SUMMARY.md @@ -198,7 +198,7 @@ - [Inference details](./opaque-types-impl-trait-inference.md) - [Return Position Impl Trait In Trait](./return-position-impl-trait-in-trait.md) - [Region inference restrictions][opaque-infer] -- [Const condition checking](./effects.md) +- [Const traits and const condition checking](./effects.md) - [Pattern and exhaustiveness checking](./pat-exhaustive-checking.md) - [Unsafety checking](./unsafety-checking.md) - [MIR dataflow](./mir/dataflow.md) diff --git a/src/doc/rustc-dev-guide/src/effects.md b/src/doc/rustc-dev-guide/src/effects.md index 87b0103a7bc4b..732ba71531167 100644 --- a/src/doc/rustc-dev-guide/src/effects.md +++ b/src/doc/rustc-dev-guide/src/effects.md @@ -1,4 +1,4 @@ -# Effects and const condition checking +# Effects, const traits, and const condition checking ## The `HostEffect` predicate @@ -154,3 +154,18 @@ be dropped at compile time. [old solver]: https://doc.rust-lang.org/nightly/nightly-rustc/src/rustc_trait_selection/traits/effects.rs.html [new trait solver]: https://doc.rust-lang.org/nightly/nightly-rustc/src/rustc_next_trait_solver/solve/effect_goals.rs.html + +## More on const traits + +To be expanded later. + +### The `#[rustc_non_const_trait_method]` attribute + +This is intended for internal (standard library) usage only. With this attribute +applied to a trait method, the compiler will not check the default body of this +method for ability to run in compile time. Users of the trait will also not be +allowed to use this trait method in const contexts. This attribute is primarily +used for constifying large traits such as `Iterator` without having to make all +its methods `const` at the same time. + +This attribute should not be present while stabilizing the trait as `const`. diff --git a/tests/ui/traits/const-traits/partial/attr-gate.rs b/tests/ui/traits/const-traits/partial/attr-gate.rs new file mode 100644 index 0000000000000..c59a03de21530 --- /dev/null +++ b/tests/ui/traits/const-traits/partial/attr-gate.rs @@ -0,0 +1,7 @@ +trait A { + #[rustc_non_const_trait_method] + //~^ ERROR: use of an internal attribute + fn a(); +} + +fn main() {} diff --git a/tests/ui/traits/const-traits/partial/attr-gate.stderr b/tests/ui/traits/const-traits/partial/attr-gate.stderr new file mode 100644 index 0000000000000..e46e35d036bed --- /dev/null +++ b/tests/ui/traits/const-traits/partial/attr-gate.stderr @@ -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 an easier transition to const + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/traits/const-traits/partial/no-const-callers.rs b/tests/ui/traits/const-traits/partial/no-const-callers.rs new file mode 100644 index 0000000000000..286ed3ab1a2e0 --- /dev/null +++ b/tests/ui/traits/const-traits/partial/no-const-callers.rs @@ -0,0 +1,31 @@ +#![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() {} +} + +impl const A for u8 { + fn a() {} + fn b() { println!("hello"); } + //~^ ERROR: cannot call non-const function +} + +const fn foo() { + T::a(); + T::b(); + //~^ ERROR: cannot call non-const associated function + <()>::a(); + <()>::b(); + //~^ ERROR: cannot call non-const associated function + u8::a(); + u8::b(); + //~^ ERROR: cannot call non-const associated function +} + +fn main() {} diff --git a/tests/ui/traits/const-traits/partial/no-const-callers.stderr b/tests/ui/traits/const-traits/partial/no-const-callers.stderr new file mode 100644 index 0000000000000..ebb38c4bdcbfd --- /dev/null +++ b/tests/ui/traits/const-traits/partial/no-const-callers.stderr @@ -0,0 +1,38 @@ +error[E0015]: cannot call non-const function `std::io::_print` in constant functions + --> $DIR/no-const-callers.rs:15:14 + | +LL | fn b() { println!("hello"); } + | ^^^^^^^^^^^^^^^^^ + | +note: function `_print` is not const + --> $SRC_DIR/std/src/io/stdio.rs:LL:COL + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0015]: cannot call non-const associated function `::b` in constant functions + --> $DIR/no-const-callers.rs:21: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:24:5 + | +LL | <()>::b(); + | ^^^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + +error[E0015]: cannot call non-const associated function `::b` in constant functions + --> $DIR/no-const-callers.rs:27:5 + | +LL | u8::b(); + | ^^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/typeck/typeck_type_placeholder_item.stderr b/tests/ui/typeck/typeck_type_placeholder_item.stderr index 0b70ac97fd435..2772d55f953a8 100644 --- a/tests/ui/typeck/typeck_type_placeholder_item.stderr +++ b/tests/ui/typeck/typeck_type_placeholder_item.stderr @@ -684,13 +684,6 @@ error[E0015]: cannot call non-const method ` as Iterator>:: LL | const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x); | ^^^^^^^^^^^^^^^^^^^^^^ | -note: method `filter` is not const because trait `Iterator` is not const - --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL - | - = note: this trait is not const - ::: $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL - | - = note: this method is not const = note: calls in constants are limited to constant functions, tuple structs and tuple variants error[E0015]: cannot call non-const method `, {closure@$DIR/typeck_type_placeholder_item.rs:240:29: 240:32}> as Iterator>::map::` in constants @@ -699,13 +692,6 @@ error[E0015]: cannot call non-const method `, {closu LL | const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x); | ^^^^^^^^^^^^^^ | -note: method `map` is not const because trait `Iterator` is not const - --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL - | - = note: this trait is not const - ::: $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL - | - = note: this method is not const = note: calls in constants are limited to constant functions, tuple structs and tuple variants error: aborting due to 83 previous errors

(&mut self, predicate: P) -> Option where P: FnMut(Self::Item) -> bool, @@ -3178,6 +3224,7 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_non_const_trait_method] fn max(self) -> Option where Self: Sized, @@ -3214,6 +3261,7 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_non_const_trait_method] fn min(self) -> Option where Self: Sized, @@ -3236,6 +3284,7 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "iter_cmp_by_key", since = "1.6.0")] + #[rustc_non_const_trait_method] fn max_by_key(self, f: F) -> Option where Self: Sized, @@ -3269,6 +3318,7 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "iter_max_by", since = "1.15.0")] + #[rustc_non_const_trait_method] fn max_by(self, compare: F) -> Option where Self: Sized, @@ -3296,6 +3346,7 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "iter_cmp_by_key", since = "1.6.0")] + #[rustc_non_const_trait_method] fn min_by_key(self, f: F) -> Option where Self: Sized, @@ -3329,6 +3380,7 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "iter_min_by", since = "1.15.0")] + #[rustc_non_const_trait_method] fn min_by(self, compare: F) -> Option where Self: Sized, @@ -3366,6 +3418,7 @@ pub trait Iterator { #[inline] #[doc(alias = "reverse")] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_non_const_trait_method] fn rev(self) -> Rev where Self: Sized + DoubleEndedIterator, @@ -3402,6 +3455,7 @@ pub trait Iterator { /// assert_eq!(z, [3, 6]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_non_const_trait_method] fn unzip(self) -> (FromA, FromB) where FromA: Default + Extend, @@ -3433,6 +3487,7 @@ pub trait Iterator { /// ``` #[stable(feature = "iter_copied", since = "1.36.0")] #[rustc_diagnostic_item = "iter_copied"] + #[rustc_non_const_trait_method] fn copied<'a, T>(self) -> Copied where T: Copy + 'a, @@ -3481,6 +3536,7 @@ pub trait Iterator { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "iter_cloned"] + #[rustc_non_const_trait_method] fn cloned<'a, T>(self) -> Cloned where T: Clone + 'a, @@ -3512,6 +3568,7 @@ pub trait Iterator { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] + #[rustc_non_const_trait_method] fn cycle(self) -> Cycle where Self: Sized + Clone, @@ -3555,6 +3612,7 @@ pub trait Iterator { /// ``` #[track_caller] #[unstable(feature = "iter_array_chunks", issue = "100450")] + #[rustc_non_const_trait_method] fn array_chunks(self) -> ArrayChunks where Self: Sized, @@ -3591,6 +3649,7 @@ pub trait Iterator { /// assert_eq!(sum, -0.0_f32); /// ``` #[stable(feature = "iter_arith", since = "1.11.0")] + #[rustc_non_const_trait_method] fn sum(self) -> S where Self: Sized, @@ -3623,6 +3682,7 @@ pub trait Iterator { /// assert_eq!(factorial(5), 120); /// ``` #[stable(feature = "iter_arith", since = "1.11.0")] + #[rustc_non_const_trait_method] fn product