diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index 370b15d2871a9..8a37b6a1ec605 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -50,6 +50,11 @@ ast_lowering_clobber_abi_not_supported = ast_lowering_closure_cannot_be_static = closures cannot be static +ast_lowering_const_comptime_fn = a function cannot be both `comptime` and `const` + .suggestion = remove the `const` + .label = `comptime` because of this + .note = `const` implies the function can be called at runtime, too + ast_lowering_coroutine_too_many_parameters = too many parameters for a coroutine (expected 0 or 1 parameters) diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index 9bfcd232221ba..79c2960fc7b0b 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -426,7 +426,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn generate_header_error(&self) -> hir::FnHeader { hir::FnHeader { safety: hir::Safety::Safe.into(), - constness: hir::Constness::NotConst, + constness: hir::Constness::Never, asyncness: hir::IsAsync::NotAsync, abi: ExternAbi::Rust, } diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index 83f3a976e83f7..5d9d313e3985a 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -3,6 +3,16 @@ use rustc_errors::codes::*; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{Ident, Span, Symbol}; +#[derive(Diagnostic)] +#[diag(ast_lowering_const_comptime_fn)] +pub(crate) struct ConstComptimeFn { + #[primary_span] + #[suggestion(applicability = "machine-applicable", code = "")] + pub span: Span, + #[label] + pub attr_span: Span, +} + #[derive(Diagnostic)] #[diag(ast_lowering_generic_type_with_parentheses, code = E0214)] pub(crate) struct GenericTypeWithParentheses { diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 524f8b054cb49..b253730226c42 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -766,7 +766,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn_decl_span: self.lower_span(fn_decl_span), fn_arg_span: None, kind: hir::ClosureKind::Coroutine(coroutine_kind), - constness: hir::Constness::NotConst, + constness: hir::Constness::Never, })) } @@ -1193,7 +1193,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // knows that a `FnDecl` output type like `-> &str` actually means // "coroutine that returns &str", rather than directly returning a `&str`. kind: hir::ClosureKind::CoroutineClosure(coroutine_desugaring), - constness: hir::Constness::NotConst, + constness: hir::Constness::Never, }); hir::ExprKind::Closure(c) } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index f5b7065247a08..479227529ce29 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -23,6 +23,7 @@ use super::{ AstOwner, FnDeclKind, ImplTraitContext, ImplTraitPosition, LoweringContext, ParamMode, RelaxedBoundForbiddenReason, RelaxedBoundPolicy, ResolverAstLoweringExt, }; +use crate::errors::ConstComptimeFn; pub(super) struct ItemLowerer<'a, 'hir> { pub(super) tcx: TyCtxt<'hir>, @@ -1537,12 +1538,23 @@ impl<'hir> LoweringContext<'_, 'hir> { safety.into() }; - hir::FnHeader { - safety, - asyncness, - constness: self.lower_constness(h.constness), - abi: self.lower_extern(h.ext), + let mut constness = self.lower_constness(h.constness); + if let Some(&attr_span) = find_attr!(attrs, AttributeKind::Comptime(span) => span) { + match std::mem::replace(&mut constness, rustc_hir::Constness::Always) { + rustc_hir::Constness::Always => { + unreachable!("lower_constness cannot produce comptime") + } + // A function can't be `const` and `comptime` at the same time + rustc_hir::Constness::Maybe => { + let Const::Yes(span) = h.constness else { unreachable!() }; + self.dcx().emit_err(ConstComptimeFn { span, attr_span }); + } + // Good + rustc_hir::Constness::Never => {} + } } + + hir::FnHeader { safety, asyncness, constness, abi: self.lower_extern(h.ext) } } pub(super) fn lower_abi(&mut self, abi_str: StrLit) -> ExternAbi { @@ -1604,8 +1616,8 @@ impl<'hir> LoweringContext<'_, 'hir> { pub(super) fn lower_constness(&mut self, c: Const) -> hir::Constness { match c { - Const::Yes(_) => hir::Constness::Const, - Const::No => hir::Constness::NotConst, + Const::Yes(_) => hir::Constness::Maybe, + Const::No => hir::Constness::Never, } } diff --git a/compiler/rustc_attr_parsing/src/attributes/semantics.rs b/compiler/rustc_attr_parsing/src/attributes/semantics.rs index d7f624832971f..0827bcf1bb0a7 100644 --- a/compiler/rustc_attr_parsing/src/attributes/semantics.rs +++ b/compiler/rustc_attr_parsing/src/attributes/semantics.rs @@ -7,3 +7,14 @@ impl NoArgsAttributeParser for MayDangleParser { const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); //FIXME Still checked fully in `check_attr.rs` const CREATE: fn(span: Span) -> AttributeKind = AttributeKind::MayDangle; } + +pub(crate) struct ComptimeParser; +impl NoArgsAttributeParser for ComptimeParser { + const PATH: &[Symbol] = &[sym::rustc_comptime]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Method(MethodKind::Inherent)), + Allow(Target::Fn), + ]); + const CREATE: fn(Span) -> AttributeKind = AttributeKind::Comptime; +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 99e6c748dbe90..ed510ded0d8cf 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -59,7 +59,7 @@ use crate::attributes::rustc_internal::{ RustcLayoutScalarValidRangeEndParser, RustcLayoutScalarValidRangeStartParser, RustcMainParser, RustcObjectLifetimeDefaultParser, RustcSimdMonomorphizeLaneLimitParser, }; -use crate::attributes::semantics::MayDangleParser; +use crate::attributes::semantics::{ComptimeParser, MayDangleParser}; use crate::attributes::stability::{ BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser, }; @@ -217,6 +217,7 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index f606158e40180..c7db1d550f5f8 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -402,7 +402,7 @@ fn build_error_for_const_call<'tcx>( err.help("const traits are not yet supported on stable Rust"); } } - } else if ccx.tcx.constness(callee) != hir::Constness::Const { + } else if ccx.tcx.constness(callee) != hir::Constness::Maybe { let name = ccx.tcx.item_name(callee); err.span_note( ccx.tcx.def_span(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 3e11541aace97..4e257d28b828d 100644 --- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs @@ -11,12 +11,12 @@ fn parent_impl_or_trait_constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::C DefKind::Impl { of_trait: false } => tcx.constness(parent_id), DefKind::Trait => { if tcx.is_const_trait(parent_id.into()) { - hir::Constness::Const + hir::Constness::Maybe } else { - hir::Constness::NotConst + hir::Constness::Never } } - _ => hir::Constness::NotConst, + _ => hir::Constness::Never, } } @@ -25,17 +25,17 @@ fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Constness { let node = tcx.hir_node_by_def_id(def_id); match node { - hir::Node::Ctor(hir::VariantData::Tuple(..)) => hir::Constness::Const, + hir::Node::Ctor(hir::VariantData::Tuple(..)) => hir::Constness::Maybe, hir::Node::ForeignItem(item) if let hir::ForeignItemKind::Fn(..) = item.kind => { // Foreign functions cannot be evaluated at compile-time. - hir::Constness::NotConst + hir::Constness::Never } hir::Node::Expr(e) if let hir::ExprKind::Closure(c) = e.kind => c.constness, hir::Node::Item(i) if let hir::ItemKind::Impl(impl_) = i.kind => impl_.constness, _ => { if let Some(fn_kind) = node.fn_kind() { - if fn_kind.constness() == hir::Constness::Const { - return hir::Constness::Const; + if fn_kind.constness() != hir::Constness::Never { + return fn_kind.constness(); } // If the function itself is not annotated with `const`, it may still be a `const fn` diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 6eefb2f48d127..5a5cfd5bf3191 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -1417,6 +1417,11 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_force_inline, Normal, template!(Word, NameValueStr: "reason"), WarnFollowing, EncodeCrossCrate::Yes, "`#[rustc_force_inline]` forces a free function to be inlined" ), + rustc_attr!( + rustc_comptime, Normal, template!(Word), ErrorFollowing, + EncodeCrossCrate::No, + "the `#[rustc_comptime]` attribute is just used to avoid adding syntax for `comptime fn`" + ), // ========================================================================== // Internal attributes, Testing: diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 708210ac6c6e4..f1615c27278fa 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -491,6 +491,9 @@ pub enum AttributeKind { /// Represents `#[cold]`. Cold(Span), + /// Represents `#[rustc_comptime]` + Comptime(Span), + /// Represents `#[rustc_confusables]`. Confusables { symbols: ThinVec, diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 74fc6c6af009e..e669a97605195 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -28,6 +28,7 @@ impl AttributeKind { BodyStability { .. } => No, Coinductive(..) => No, Cold(..) => No, + Comptime(..) => No, Confusables { .. } => Yes, ConstContinue(..) => No, ConstStability { .. } => Yes, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 0db3f456b60b8..d1702c3fad128 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2264,10 +2264,12 @@ pub enum ConstContext { /// - Array length expressions /// - Enum discriminants /// - Const generics - /// - /// For the most part, other contexts are treated just like a regular `const`, so they are - /// lumped into the same category. - Const { inline: bool }, + Const { + /// For backwards compatibility `const` items allow + /// calls to `const fn` to get promoted. + /// We forbid that in comptime fns and inline consts. + allow_const_fn_promotion: bool, + }, } impl ConstContext { @@ -4235,16 +4237,21 @@ impl fmt::Display for Safety { #[derive(Copy, Clone, PartialEq, Eq, Debug, Encodable, Decodable, HashStable_Generic)] #[derive(Default)] pub enum Constness { + /// The function can only be called at compile-time + Always, + /// The function can be called both at runtime or compile-time #[default] - Const, - NotConst, + Maybe, + /// The function can only be called at runtime + Never, } impl fmt::Display for Constness { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(match *self { - Self::Const => "const", - Self::NotConst => "non-const", + Self::Always => "comptime", + Self::Maybe => "const", + Self::Never => "non-const", }) } } @@ -4284,7 +4291,7 @@ impl FnHeader { } pub fn is_const(&self) -> bool { - matches!(self.constness, Constness::Const) + matches!(self.constness, Constness::Maybe) } pub fn is_unsafe(&self) -> bool { diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 0b83e7239a992..8641bd662700f 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -98,7 +98,7 @@ impl<'a> FnKind<'a> { } pub fn constness(self) -> Constness { - self.header().map_or(Constness::NotConst, |header| header.constness) + self.header().map_or(Constness::Never, |header| header.constness) } pub fn asyncness(self) -> IsAsync { diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 3cfcac5c72915..8037e6ce5b4d6 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1363,7 +1363,7 @@ fn check_impl_constness( constness: hir::Constness, hir_trait_ref: &hir::TraitRef<'_>, ) { - if let hir::Constness::NotConst = constness { + if let hir::Constness::Never = constness { return; } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index b818a697960ac..3c62a2c643fc1 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -703,7 +703,7 @@ impl<'a> State<'a> { match of_trait { None => { - if let hir::Constness::Const = constness { + if let hir::Constness::Maybe = constness { self.word_nbsp("const"); } impl_generics(self) @@ -720,7 +720,7 @@ impl<'a> State<'a> { impl_generics(self); - if let hir::Constness::Const = constness { + if let hir::Constness::Maybe = constness { self.word_nbsp("const"); } @@ -2529,7 +2529,7 @@ impl<'a> State<'a> { hir::FnHeader { safety: safety.into(), abi, - constness: hir::Constness::NotConst, + constness: hir::Constness::Never, asyncness: hir::IsAsync::NotAsync, }, name, @@ -2569,8 +2569,9 @@ impl<'a> State<'a> { fn print_constness(&mut self, s: hir::Constness) { match s { - hir::Constness::NotConst => {} - hir::Constness::Const => self.word_nbsp("const"), + hir::Constness::Never => {} + hir::Constness::Maybe => self.word_nbsp("const"), + hir::Constness::Always => { /* printed as an attribute */ } } } diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index f59fcab46661f..ad323cfb63dc9 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -904,6 +904,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { callee_did: DefId, callee_args: GenericArgsRef<'tcx>, ) { + let const_context = self.tcx.hir_body_const_context(self.body_id); + + if let hir::Constness::Always = self.tcx.constness(callee_did) { + match const_context { + Some(hir::ConstContext::Const { .. } | hir::ConstContext::Static(_)) => {} + Some(hir::ConstContext::ConstFn) | None => { + self.dcx().span_err(span, "comptime fns can only be called at compile time"); + } + } + } + // FIXME(const_trait_impl): We should be enforcing these effects unconditionally. // This can be done as soon as we convert the standard library back to // using const traits, since if we were to enforce these conditions now, @@ -917,7 +928,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; } - let host = match self.tcx.hir_body_const_context(self.body_id) { + let host = match const_context { Some(hir::ConstContext::Const { .. } | hir::ConstContext::Static(_)) => { ty::BoundConstness::Const } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 9fac68039f52c..58d84c946a237 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1524,7 +1524,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } if should_encode_constness(def_kind) { let constness = self.tcx.constness(def_id); - self.tables.constness.set(def_id.index, constness); + self.tables.constness.set(def_id.index, constness) } if let DefKind::Fn | DefKind::AssocFn = def_kind { let asyncness = tcx.asyncness(def_id); diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs index 4ce313f32a75d..23a3995256019 100644 --- a/compiler/rustc_metadata/src/rmeta/table.rs +++ b/compiler/rustc_metadata/src/rmeta/table.rs @@ -232,8 +232,9 @@ defaulted_enum! { defaulted_enum! { hir::Constness { - ( Const ) - ( NotConst ) + ( Maybe ) + ( Never ) + ( Always ) } } diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index 430cd329408f5..d7eb7a60287f8 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -314,12 +314,18 @@ impl<'tcx> TyCtxt<'tcx> { pub fn hir_body_const_context(self, def_id: LocalDefId) -> Option { let def_id = def_id.into(); let ccx = match self.hir_body_owner_kind(def_id) { - BodyOwnerKind::Const { inline } => ConstContext::Const { inline }, + BodyOwnerKind::Const { inline } => { + ConstContext::Const { allow_const_fn_promotion: !inline } + } BodyOwnerKind::Static(mutability) => ConstContext::Static(mutability), BodyOwnerKind::Fn if self.is_constructor(def_id) => return None, BodyOwnerKind::Fn | BodyOwnerKind::Closure if self.is_const_fn(def_id) => { - ConstContext::ConstFn + if self.constness(def_id) == rustc_hir::Constness::Always { + ConstContext::Const { allow_const_fn_promotion: false } + } else { + ConstContext::ConstFn + } } BodyOwnerKind::Fn if self.is_const_default_method(def_id) => ConstContext::ConstFn, BodyOwnerKind::Fn | BodyOwnerKind::Closure | BodyOwnerKind::GlobalAsm => return None, diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 510c546f82a4e..4a97c35f82ffd 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -247,8 +247,9 @@ impl<'tcx> rustc_type_ir::inherent::AdtDef> for AdtDef<'tcx> { fn destructor(self, tcx: TyCtxt<'tcx>) -> Option { Some(match tcx.constness(self.destructor(tcx)?.did) { - hir::Constness::Const => AdtDestructorKind::Const, - hir::Constness::NotConst => AdtDestructorKind::NotConst, + hir::Constness::Always => todo!("FIXME(comptime)"), + hir::Constness::Maybe => AdtDestructorKind::Const, + hir::Constness::Never => AdtDestructorKind::NotConst, }) } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 3092c6e76c030..4a6d808fd2434 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -3463,7 +3463,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Whether the trait impl is marked const. This does not consider stability or feature gates. pub fn is_const_trait_impl(self, def_id: DefId) -> bool { self.def_kind(def_id) == DefKind::Impl { of_trait: true } - && self.impl_trait_header(def_id).constness == hir::Constness::Const + && self.impl_trait_header(def_id).constness == hir::Constness::Maybe } pub fn is_sdylib_interface_build(self) -> bool { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 61b3059ab4253..042a68f2de8ce 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2138,7 +2138,10 @@ impl<'tcx> TyCtxt<'tcx> { matches!( self.def_kind(def_id), DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::Closure - ) && self.constness(def_id) == hir::Constness::Const + ) && match self.constness(def_id) { + hir::Constness::Always | hir::Constness::Maybe => true, + hir::Constness::Never => false, + } } /// Whether this item is conditionally constant for the purposes of the @@ -2152,12 +2155,12 @@ impl<'tcx> TyCtxt<'tcx> { match self.def_kind(def_id) { DefKind::Impl { of_trait: true } => { let header = self.impl_trait_header(def_id); - header.constness == hir::Constness::Const + header.constness == hir::Constness::Maybe && self.is_const_trait(header.trait_ref.skip_binder().def_id) } - DefKind::Impl { of_trait: false } => self.constness(def_id) == hir::Constness::Const, + DefKind::Impl { of_trait: false } => self.constness(def_id) == hir::Constness::Maybe, DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) => { - self.constness(def_id) == hir::Constness::Const + self.constness(def_id) == hir::Constness::Maybe } DefKind::TraitAlias | DefKind::Trait => self.is_const_trait(def_id), DefKind::AssocTy => { @@ -2174,7 +2177,7 @@ impl<'tcx> TyCtxt<'tcx> { let parent_def_id = self.parent(def_id); match self.def_kind(parent_def_id) { DefKind::Impl { of_trait: false } => { - self.constness(def_id) == hir::Constness::Const + self.constness(def_id) == hir::Constness::Maybe } DefKind::Impl { of_trait: true } | DefKind::Trait => { self.is_conditionally_const(parent_def_id) @@ -2221,7 +2224,7 @@ impl<'tcx> TyCtxt<'tcx> { #[inline] pub fn is_const_trait(self, def_id: DefId) -> bool { - self.trait_def(def_id).constness == hir::Constness::Const + self.trait_def(def_id).constness == hir::Constness::Maybe } #[inline] diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 18b798c01faab..2ba988b9f3d79 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -258,7 +258,7 @@ fn remap_mir_for_const_eval_select<'tcx>( let fields = ty.tuple_fields(); let num_args = fields.len(); let func = - if context == hir::Constness::Const { called_in_const } else { called_at_rt }; + if context == hir::Constness::Maybe { called_in_const } else { called_at_rt }; let (method, place): (fn(Place<'tcx>) -> Operand<'tcx>, Place<'tcx>) = match tupled_args.node { Operand::Constant(_) => { @@ -429,7 +429,7 @@ fn mir_promoted( let const_qualifs = match tcx.def_kind(def) { DefKind::Fn | DefKind::AssocFn | DefKind::Closure - if tcx.constness(def) == hir::Constness::Const + if tcx.constness(def) == hir::Constness::Maybe || tcx.is_const_default_method(def.to_def_id()) => { tcx.mir_const_qualif(def) @@ -503,7 +503,7 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> { None => bug!("`mir_for_ctfe` called on non-const {def:?}"), }; - let mut body = remap_mir_for_const_eval_select(tcx, body, hir::Constness::Const); + let mut body = remap_mir_for_const_eval_select(tcx, body, hir::Constness::Maybe); pm::run_passes(tcx, &mut body, &[&ctfe_limit::CtfeLimit], None, pm::Optimizations::Allowed); body @@ -797,7 +797,7 @@ fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> { } debug!("about to call mir_drops_elaborated..."); let body = tcx.mir_drops_elaborated_and_const_checked(did).steal(); - let mut body = remap_mir_for_const_eval_select(tcx, body, hir::Constness::NotConst); + let mut body = remap_mir_for_const_eval_select(tcx, body, hir::Constness::Never); if body.tainted_by_errors.is_some() { return body; diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index 6b0c331ff5415..2c64bcbba9dc7 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -667,7 +667,10 @@ impl<'tcx> Validator<'_, 'tcx> { // backwards compatibility reason to allow more promotion inside of them. let promote_all_fn = matches!( self.const_kind, - Some(hir::ConstContext::Static(_) | hir::ConstContext::Const { inline: false }) + Some( + hir::ConstContext::Static(_) + | hir::ConstContext::Const { allow_const_fn_promotion: true } + ) ); if !promote_all_fn { return Err(Unpromotable); diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index cba600594cda4..86935193fdf1c 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -236,6 +236,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::Marker(..) | AttributeKind::SkipDuringMethodDispatch { .. } | AttributeKind::Coinductive(..) + | AttributeKind::Comptime(..) | AttributeKind::DenyExplicitImpl(..) | AttributeKind::DoNotImplementViaObject(..) | AttributeKind::SpecializationTrait(..) @@ -535,8 +536,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { if matches!(target, Target::Impl { of_trait: true }) { match item.unwrap() { ItemLike::Item(it) => match it.expect_impl().constness { - Constness::Const => {} - Constness::NotConst => return, + Constness::Maybe | Constness::Always => {} + Constness::Never => return, }, ItemLike::ForeignItem => {} } diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index b7e6e2d451e3f..48a462b20e1b9 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -658,7 +658,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { } if features.const_trait_impl() - && let hir::Constness::Const = constness + && let hir::Constness::Maybe = constness { let stable_or_implied_stable = match const_stab { None => true, @@ -702,7 +702,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { } } - if let hir::Constness::Const = constness + if let hir::Constness::Maybe = constness && let Some(def_id) = of_trait.trait_ref.trait_def_id() { // FIXME(const_trait_impl): Improve the span here. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index f2b13dad1fd90..ed3eaaf6df5b1 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1911,6 +1911,7 @@ symbols! { rustc_clean, rustc_coherence_is_core, rustc_coinductive, + rustc_comptime, rustc_confusables, rustc_const_stable, rustc_const_stable_indirect, diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs index d661c585d68e8..067d455729274 100644 --- a/compiler/rustc_trait_selection/src/traits/effects.rs +++ b/compiler/rustc_trait_selection/src/traits/effects.rs @@ -435,10 +435,11 @@ fn evaluate_host_effect_for_destruct_goal<'tcx>( .map(|field| ty::TraitRef::new(tcx, destruct_def_id, [field.ty(tcx, args)])) .collect(); match adt_def.destructor(tcx).map(|dtor| tcx.constness(dtor.did)) { + Some(hir::Constness::Always) => todo!("FIXME(comptime)"), // `Drop` impl exists, but it's not const. Type cannot be `[const] Destruct`. - Some(hir::Constness::NotConst) => return Err(EvaluationFailure::NoSolution), + Some(hir::Constness::Never) => return Err(EvaluationFailure::NoSolution), // `Drop` impl exists, and it's const. Require `Ty: [const] Drop` to hold. - Some(hir::Constness::Const) => { + Some(hir::Constness::Maybe) => { let drop_def_id = tcx.require_lang_item(LangItem::Drop, obligation.cause.span); let drop_trait_ref = ty::TraitRef::new(tcx, drop_def_id, [self_ty]); const_conditions.push(drop_trait_ref); @@ -530,7 +531,9 @@ fn evaluate_host_effect_for_fn_goal<'tcx>( }; match tcx.constness(def) { - hir::Constness::Const => Ok(tcx + // FIXME(comptime) + hir::Constness::Always => Err(EvaluationFailure::NoSolution), + hir::Constness::Maybe => Ok(tcx .const_conditions(def) .instantiate(tcx, args) .into_iter() @@ -546,7 +549,7 @@ fn evaluate_host_effect_for_fn_goal<'tcx>( ) }) .collect()), - hir::Constness::NotConst => Err(EvaluationFailure::NoSolution), + hir::Constness::Never => Err(EvaluationFailure::NoSolution), } } @@ -561,7 +564,7 @@ fn evaluate_host_effect_from_selection_candidate<'tcx>( Err(_) => Err(EvaluationFailure::NoSolution), Ok(Some(source)) => match source { ImplSource::UserDefined(impl_) => { - if tcx.impl_trait_header(impl_.impl_def_id).constness != hir::Constness::Const { + if tcx.impl_trait_header(impl_.impl_def_id).constness != hir::Constness::Maybe { return Err(EvaluationFailure::NoSolution); } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index f1b0f4a68beaa..647ec91d1fbe7 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -704,12 +704,12 @@ impl Item { && let ty::AssocContainer::Trait | ty::AssocContainer::TraitImpl(_) = assoc.container { - hir::Constness::NotConst + hir::Constness::Never } else { - hir::Constness::Const + hir::Constness::Maybe } } else { - hir::Constness::NotConst + hir::Constness::Never }; let asyncness = match asyncness { ty::Asyncness::Yes => hir::IsAsync::Async(DUMMY_SP), @@ -738,9 +738,9 @@ impl Item { }, abi, constness: if tcx.is_const_fn(def_id) { - hir::Constness::Const + hir::Constness::Maybe } else { - hir::Constness::NotConst + hir::Constness::Never }, asyncness: hir::IsAsync::NotAsync, } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index eee13ff2b0dc0..6b23ce4cb1a8c 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -1479,20 +1479,24 @@ pub(crate) fn print_constness_with_space( const_stab: Option, ) -> &'static str { match c { - hir::Constness::Const => match (overall_stab, const_stab) { + hir::Constness::Always | hir::Constness::Maybe => match (overall_stab, const_stab) { // const stable... (_, Some(ConstStability { level: StabilityLevel::Stable { .. }, .. })) // ...or when feature(staged_api) is not set... | (_, None) // ...or when const unstable, but overall unstable too | (None, Some(ConstStability { level: StabilityLevel::Unstable { .. }, .. })) => { - "const " + match c { + hir::Constness::Always => "", + hir::Constness::Maybe => "const ", + _ => unreachable!(), + } } // const unstable (and overall stable) (Some(_), Some(ConstStability { level: StabilityLevel::Unstable { .. }, .. })) => "", }, // not const - hir::Constness::NotConst => "", + hir::Constness::Never => "", } } diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs index 1507f1ed30539..a79c3d89de0a4 100644 --- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs +++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs @@ -56,7 +56,7 @@ impl<'tcx> LateLintPass<'tcx> for DefaultNumericFallback { // Inline const supports type inference. let is_parent_const = matches!( cx.tcx.hir_body_const_context(cx.tcx.hir_body_owner_def_id(body.id())), - Some(ConstContext::Const { inline: false } | ConstContext::Static(_)) + Some(ConstContext::Const { allow_const_fn_promotion: true } | ConstContext::Static(_)) ); let mut visitor = NumericFallbackVisitor::new(cx, is_parent_const); visitor.visit_body(body); diff --git a/src/tools/clippy/clippy_lints/src/derivable_impls.rs b/src/tools/clippy/clippy_lints/src/derivable_impls.rs index 6b8a6aec92fab..3cc378ba815d1 100644 --- a/src/tools/clippy/clippy_lints/src/derivable_impls.rs +++ b/src/tools/clippy/clippy_lints/src/derivable_impls.rs @@ -248,7 +248,7 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls { && !attrs.iter().any(|attr| attr.doc_str().is_some()) && cx.tcx.hir_attrs(impl_item_hir).is_empty() { - let is_const = constness == hir::Constness::Const; + let is_const = constness != hir::Constness::Never; if adt_def.is_struct() { check_struct( cx, diff --git a/src/tools/clippy/clippy_lints/src/manual_float_methods.rs b/src/tools/clippy/clippy_lints/src/manual_float_methods.rs index a81c4dc6a7931..af9294531c68b 100644 --- a/src/tools/clippy/clippy_lints/src/manual_float_methods.rs +++ b/src/tools/clippy/clippy_lints/src/manual_float_methods.rs @@ -127,7 +127,7 @@ fn is_not_const(tcx: TyCtxt<'_>, def_id: DefId) -> bool { | DefKind::Ctor(..) | DefKind::AssocConst => false, - DefKind::Fn | DefKind::AssocFn | DefKind::Closure => tcx.constness(def_id) == Constness::NotConst, + DefKind::Fn | DefKind::AssocFn | DefKind::Closure => tcx.constness(def_id) == Constness::Never, } } diff --git a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs index a63ad97862627..cd7be4db4dae5 100644 --- a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs +++ b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs @@ -187,7 +187,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { // We don't have to lint on something that's already `const` #[must_use] fn already_const(header: hir::FnHeader) -> bool { - header.constness == Constness::Const + header.constness != Constness::Never } fn could_be_const_with_abi(cx: &LateContext<'_>, msrv: Msrv, abi: ExternAbi) -> bool { diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index c9302b17eb7ec..85ae8156b5682 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -249,7 +249,7 @@ pub fn is_inside_always_const_context(tcx: TyCtxt<'_>, hir_id: HirId) -> bool { }; match ctx { ConstFn => false, - Static(_) | Const { inline: _ } => true, + Static(_) | Const { allow_const_fn_promotion: _ } => true, } } diff --git a/tests/ui/comptime/const_comptime.rs b/tests/ui/comptime/const_comptime.rs new file mode 100644 index 0000000000000..827e4dfcf545b --- /dev/null +++ b/tests/ui/comptime/const_comptime.rs @@ -0,0 +1,7 @@ +#![feature(rustc_attrs)] + +#[rustc_comptime] +const fn foo() {} +//~^ ERROR a function cannot be both `comptime` and `const` + +fn main() {} diff --git a/tests/ui/comptime/const_comptime.stderr b/tests/ui/comptime/const_comptime.stderr new file mode 100644 index 0000000000000..7d7d13a6291f8 --- /dev/null +++ b/tests/ui/comptime/const_comptime.stderr @@ -0,0 +1,10 @@ +error: a function cannot be both `comptime` and `const` + --> $DIR/const_comptime.rs:4:1 + | +LL | #[rustc_comptime] + | ----------------- `comptime` because of this +LL | const fn foo() {} + | ^^^^^ help: remove the `const` + +error: aborting due to 1 previous error + diff --git a/tests/ui/comptime/not_callable.rs b/tests/ui/comptime/not_callable.rs new file mode 100644 index 0000000000000..c06e643d5403e --- /dev/null +++ b/tests/ui/comptime/not_callable.rs @@ -0,0 +1,22 @@ +#![feature(rustc_attrs, const_trait_impl)] + +#[rustc_comptime] +fn foo() {} + +fn main() { + // Ok + const { foo() }; + // Not Ok + foo(); //~ ERROR: comptime fns can only be called at compile time +} + +const fn bar() { + // Not Ok + foo(); //~ ERROR: comptime fns can only be called at compile time +} + +#[rustc_comptime] +fn baz() { + // Ok + foo(); +} diff --git a/tests/ui/comptime/not_callable.stderr b/tests/ui/comptime/not_callable.stderr new file mode 100644 index 0000000000000..8a2c3fb2bf00f --- /dev/null +++ b/tests/ui/comptime/not_callable.stderr @@ -0,0 +1,14 @@ +error: comptime fns can only be called at compile time + --> $DIR/not_callable.rs:10:5 + | +LL | foo(); + | ^^^^^ + +error: comptime fns can only be called at compile time + --> $DIR/not_callable.rs:15:5 + | +LL | foo(); + | ^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/comptime/trait_bounds.rs b/tests/ui/comptime/trait_bounds.rs new file mode 100644 index 0000000000000..3df2f41558fcc --- /dev/null +++ b/tests/ui/comptime/trait_bounds.rs @@ -0,0 +1,25 @@ +#![feature(rustc_attrs, const_trait_impl)] + +const trait Trait { + fn method() {} +} + +#[rustc_comptime] +fn always_const() { + T::method() +} + +#[rustc_comptime] +fn conditionally_const() { + //~^ ERROR: `[const]` is not allowed here + T::method() + //~^ ERROR: `T: const Trait` is not satisfied +} + +#[rustc_comptime] +fn non_const() { + T::method() + //~^ ERROR: `T: const Trait` is not satisfied +} + +fn main() {} diff --git a/tests/ui/comptime/trait_bounds.stderr b/tests/ui/comptime/trait_bounds.stderr new file mode 100644 index 0000000000000..c5a03af2c0c2c --- /dev/null +++ b/tests/ui/comptime/trait_bounds.stderr @@ -0,0 +1,27 @@ +error: `[const]` is not allowed here + --> $DIR/trait_bounds.rs:13:27 + | +LL | fn conditionally_const() { + | ^^^^^^^ + | +note: this function is not `const`, so it cannot have `[const]` trait bounds + --> $DIR/trait_bounds.rs:13:4 + | +LL | fn conditionally_const() { + | ^^^^^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `T: const Trait` is not satisfied + --> $DIR/trait_bounds.rs:15:5 + | +LL | T::method() + | ^ + +error[E0277]: the trait bound `T: const Trait` is not satisfied + --> $DIR/trait_bounds.rs:21:5 + | +LL | T::method() + | ^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/comptime/trait_comptime.rs b/tests/ui/comptime/trait_comptime.rs new file mode 100644 index 0000000000000..a42e85c49f702 --- /dev/null +++ b/tests/ui/comptime/trait_comptime.rs @@ -0,0 +1,26 @@ +#![feature(rustc_attrs)] + +trait Foo { + #[rustc_comptime] + //~^ ERROR: cannot be used on required trait methods + fn foo(); + + #[rustc_comptime] + //~^ ERROR: cannot be used on provided trait methods + fn bar() {} +} + +struct Bar; + +impl Bar { + #[rustc_comptime] + fn foo() {} +} + +impl Foo for Bar { + #[rustc_comptime] + //~^ ERROR: cannot be used on trait methods + fn foo() {} +} + +fn main() {} diff --git a/tests/ui/comptime/trait_comptime.stderr b/tests/ui/comptime/trait_comptime.stderr new file mode 100644 index 0000000000000..77ff09674d2bd --- /dev/null +++ b/tests/ui/comptime/trait_comptime.stderr @@ -0,0 +1,26 @@ +error: `#[rustc_comptime]` attribute cannot be used on required trait methods + --> $DIR/trait_comptime.rs:4:5 + | +LL | #[rustc_comptime] + | ^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_comptime]` can be applied to functions and inherent methods + +error: `#[rustc_comptime]` attribute cannot be used on provided trait methods + --> $DIR/trait_comptime.rs:8:5 + | +LL | #[rustc_comptime] + | ^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_comptime]` can be applied to functions and inherent methods + +error: `#[rustc_comptime]` attribute cannot be used on trait methods in impl blocks + --> $DIR/trait_comptime.rs:21:5 + | +LL | #[rustc_comptime] + | ^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_comptime]` can be applied to functions and inherent methods + +error: aborting due to 3 previous errors +