Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions compiler/rustc_ast_lowering/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_ast_lowering/src/delegation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
Expand Down
10 changes: 10 additions & 0 deletions compiler/rustc_ast_lowering/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_ast_lowering/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}))
}

Expand Down Expand Up @@ -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)
}
Expand Down
26 changes: 19 additions & 7 deletions compiler/rustc_ast_lowering/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>,
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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,
}
}

Expand Down
11 changes: 11 additions & 0 deletions compiler/rustc_attr_parsing/src/attributes/semantics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,14 @@ impl<S: Stage> NoArgsAttributeParser<S> 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<S: Stage> NoArgsAttributeParser<S> for ComptimeParser {
const PATH: &[Symbol] = &[sym::rustc_comptime];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Method(MethodKind::Inherent)),
Allow(Target::Fn),
]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::Comptime;
}
3 changes: 2 additions & 1 deletion compiler/rustc_attr_parsing/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand Down Expand Up @@ -217,6 +217,7 @@ attribute_parsers!(
Single<WithoutArgs<AutomaticallyDerivedParser>>,
Single<WithoutArgs<CoinductiveParser>>,
Single<WithoutArgs<ColdParser>>,
Single<WithoutArgs<ComptimeParser>>,
Single<WithoutArgs<ConstContinueParser>>,
Single<WithoutArgs<ConstStabilityIndirectParser>>,
Single<WithoutArgs<CoroutineParser>>,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_const_eval/src/check_consts/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit sus

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What part? The rename or the inequality?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The inequality. I feel like this should be if == hir::Constness::NotConst?

let name = ccx.tcx.item_name(callee);
err.span_note(
ccx.tcx.def_span(callee),
Expand Down
14 changes: 7 additions & 7 deletions compiler/rustc_const_eval/src/const_eval/fn_queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
}

Expand All @@ -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`
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_feature/src/builtin_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_hir/src/attrs/data_structures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,9 @@ pub enum AttributeKind {
/// Represents `#[cold]`.
Cold(Span),

/// Represents `#[rustc_comptime]`
Comptime(Span),

/// Represents `#[rustc_confusables]`.
Confusables {
symbols: ThinVec<Symbol>,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir/src/attrs/encode_cross_crate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ impl AttributeKind {
BodyStability { .. } => No,
Coinductive(..) => No,
Cold(..) => No,
Comptime(..) => No,
Confusables { .. } => Yes,
ConstContinue(..) => No,
ConstStability { .. } => Yes,
Expand Down
25 changes: 16 additions & 9 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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",
})
}
}
Expand Down Expand Up @@ -4284,7 +4291,7 @@ impl FnHeader {
}

pub fn is_const(&self) -> bool {
matches!(self.constness, Constness::Const)
matches!(self.constness, Constness::Maybe)
}
Comment on lines 4293 to 4295
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we might want to audit usages of this. Leave a FIXME?


pub fn is_unsafe(&self) -> bool {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir/src/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
11 changes: 6 additions & 5 deletions compiler/rustc_hir_pretty/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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");
}

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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 */ }
}
}

Expand Down
13 changes: 12 additions & 1 deletion compiler/rustc_hir_typeck/src/callee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_metadata/src/rmeta/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

? (please revert)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rebase fallout

}
if let DefKind::Fn | DefKind::AssocFn = def_kind {
let asyncness = tcx.asyncness(def_id);
Expand Down
5 changes: 3 additions & 2 deletions compiler/rustc_metadata/src/rmeta/table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,8 +232,9 @@ defaulted_enum! {

defaulted_enum! {
hir::Constness {
( Const )
( NotConst )
( Maybe )
( Never )
( Always )
Comment on lines +235 to +237
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
( Maybe )
( Never )
( Always )
( Maybe )
( Never )
( Always )

}
}

Expand Down
10 changes: 8 additions & 2 deletions compiler/rustc_middle/src/hir/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -314,12 +314,18 @@ impl<'tcx> TyCtxt<'tcx> {
pub fn hir_body_const_context(self, def_id: LocalDefId) -> Option<ConstContext> {
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,
Expand Down
Loading
Loading