Skip to content

Commit 1419d3c

Browse files
Rollup merge of rust-lang#148820 - oli-obk:comptime, r=fee1-dead
Add very basic "comptime" fn implementation Implements functions that cannot be called at runtime (and thus also not from normal const functions, as those could be called from runtime). This is done via the internal attribute `rustc_comptime` that can be added to normal functions, turning them into compile-time-only functions. Because @fee1-dead and @compiler-errors did amazing work, we even get trait bounds that work inside comptime fns: via unconditionally-const `const Trait` bounds. Use cases are * rust-lang#146923 * const heap intrinsics * and the other various intrinsics (e.g. size_of 😆) that will just ICE in codegen or panic at runtime if they actually end up in runtime code project goal issue: rust-lang/rust-project-goals#406 no tracking issue until we have a feature gate and some sort of syntax cc @scottmcm as the T-lang goal champion
2 parents de70798 + 4089c2a commit 1419d3c

55 files changed

Lines changed: 414 additions & 105 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

compiler/rustc_ast_lowering/src/diagnostics.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,17 @@ pub(crate) struct AwaitOnlyInAsyncFnAndBlocks {
122122
pub item_span: Option<Span>,
123123
}
124124

125+
#[derive(Diagnostic)]
126+
#[diag("a function cannot be both `comptime` and `const`")]
127+
pub(crate) struct ConstComptimeFn {
128+
#[primary_span]
129+
#[suggestion("remove the `const`", applicability = "machine-applicable", code = "")]
130+
#[note("`const` implies the function can be called at runtime, too")]
131+
pub span: Span,
132+
#[label("`comptime` because of this")]
133+
pub attr_span: Span,
134+
}
135+
125136
#[derive(Diagnostic)]
126137
#[diag("too many parameters for a coroutine (expected 0 or 1 parameters)", code = E0628)]
127138
pub(crate) struct CoroutineTooManyParameters {

compiler/rustc_ast_lowering/src/item.rs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ use super::{
2727
AstOwner, FnDeclKind, GenericArgsMode, ImplTraitContext, ImplTraitPosition, LoweringContext,
2828
ParamMode, RelaxedBoundForbiddenReason, RelaxedBoundPolicy, ResolverAstLoweringExt,
2929
};
30+
use crate::diagnostics::ConstComptimeFn;
3031

3132
/// Wraps either IndexVec (during `hir_crate`), which acts like a primary
3233
/// storage for most of the MaybeOwners, or FxIndexMap during delayed AST -> HIR
@@ -1773,12 +1774,23 @@ impl<'hir> LoweringContext<'_, 'hir> {
17731774
safety.into()
17741775
};
17751776

1776-
hir::FnHeader {
1777-
safety,
1778-
asyncness,
1779-
constness: self.lower_constness(h.constness),
1780-
abi: self.lower_extern(h.ext),
1777+
let mut constness = self.lower_constness(h.constness);
1778+
if let Some(&attr_span) = find_attr!(attrs, RustcComptime(span) => span) {
1779+
match std::mem::replace(&mut constness, rustc_hir::Constness::Const { always: true }) {
1780+
rustc_hir::Constness::Const { always: true } => {
1781+
unreachable!("lower_constness cannot produce comptime")
1782+
}
1783+
// A function can't be `const` and `comptime` at the same time
1784+
rustc_hir::Constness::Const { always: false } => {
1785+
let Const::Yes(span) = h.constness else { unreachable!() };
1786+
self.dcx().emit_err(ConstComptimeFn { span, attr_span });
1787+
}
1788+
// Good
1789+
rustc_hir::Constness::NotConst => {}
1790+
}
17811791
}
1792+
1793+
hir::FnHeader { safety, asyncness, constness, abi: self.lower_extern(h.ext) }
17821794
}
17831795

17841796
pub(super) fn lower_abi(&mut self, abi_str: StrLit) -> ExternAbi {
@@ -1840,7 +1852,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
18401852

18411853
pub(super) fn lower_constness(&mut self, c: Const) -> hir::Constness {
18421854
match c {
1843-
Const::Yes(_) => hir::Constness::Const,
1855+
Const::Yes(_) => hir::Constness::Const { always: false },
18441856
Const::No => hir::Constness::NotConst,
18451857
}
18461858
}

compiler/rustc_attr_parsing/src/attributes/semantics.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,15 @@ impl NoArgsAttributeParser for MayDangleParser {
99
const STABILITY: AttributeStability = unstable!(dropck_eyepatch);
1010
const CREATE: fn(span: Span) -> AttributeKind = AttributeKind::MayDangle;
1111
}
12+
13+
pub(crate) struct ComptimeParser;
14+
impl NoArgsAttributeParser for ComptimeParser {
15+
const PATH: &[Symbol] = &[sym::rustc_comptime];
16+
const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;
17+
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
18+
Allow(Target::Method(MethodKind::Inherent)),
19+
Allow(Target::Fn),
20+
]);
21+
const STABILITY: AttributeStability = unstable!(rustc_attrs);
22+
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcComptime;
23+
}

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ use crate::attributes::repr::*;
5656
use crate::attributes::rustc_allocator::*;
5757
use crate::attributes::rustc_dump::*;
5858
use crate::attributes::rustc_internal::*;
59-
use crate::attributes::semantics::*;
59+
use crate::attributes::semantics::{ComptimeParser, *};
6060
use crate::attributes::stability::*;
6161
use crate::attributes::test_attrs::*;
6262
use crate::attributes::traits::*;
@@ -234,6 +234,7 @@ attribute_parsers!(
234234
Single<WithoutArgs<AutomaticallyDerivedParser>>,
235235
Single<WithoutArgs<ColdParser>>,
236236
Single<WithoutArgs<CompilerBuiltinsParser>>,
237+
Single<WithoutArgs<ComptimeParser>>,
237238
Single<WithoutArgs<ConstContinueParser>>,
238239
Single<WithoutArgs<CoroutineParser>>,
239240
Single<WithoutArgs<DefaultLibAllocatorParser>>,

compiler/rustc_const_eval/src/check_consts/check.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -779,7 +779,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
779779
// to do different checks than usual.
780780

781781
trace!("attempting to call a trait method");
782-
let is_const = tcx.constness(callee) == hir::Constness::Const;
782+
let is_const =
783+
matches!(tcx.constness(callee), hir::Constness::Const { always: false });
783784

784785
// Only consider a trait to be const if the const conditions hold.
785786
// Otherwise, it's really misleading to call something "conditionally"

compiler/rustc_const_eval/src/check_consts/ops.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,8 @@ fn build_error_for_const_call<'tcx>(
423423
err.help("const traits are not yet supported on stable Rust");
424424
}
425425
}
426-
} else if ccx.tcx.constness(callee) != hir::Constness::Const {
426+
} else if !matches!(ccx.tcx.constness(callee), hir::Constness::Const { always: false })
427+
{
427428
let name = ccx.tcx.item_name(callee);
428429
err.span_note(
429430
ccx.tcx.def_span(callee),

compiler/rustc_const_eval/src/const_eval/fn_queries.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@ fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Constness {
1111
let node = tcx.hir_node_by_def_id(def_id);
1212

1313
match node {
14-
Node::Ctor(VariantData::Tuple(..)) => Constness::Const,
14+
Node::Ctor(VariantData::Tuple(..)) => Constness::Const { always: false },
1515
Node::ForeignItem(item) if let ForeignItemKind::Fn(..) = item.kind => {
1616
// Foreign functions cannot be evaluated at compile-time.
1717
Constness::NotConst
1818
}
1919
Node::Expr(e) if let ExprKind::Closure(c) = e.kind => {
20-
if let Constness::Const = c.constness && tcx.hir_body_const_context(tcx.local_parent(def_id)).is_none() {
20+
if let Constness::Const { .. } = c.constness && tcx.hir_body_const_context(tcx.local_parent(def_id)).is_none() {
2121
tcx.dcx().span_err(tcx.def_span(def_id), "cannot use `const` closures outside of const contexts");
2222
return Constness::NotConst;
2323
}
@@ -37,7 +37,7 @@ fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Constness {
3737
..
3838
}) => {
3939
match sig.header.constness {
40-
Constness::Const => Constness::Const,
40+
Constness::Const { always } => Constness::Const { always },
4141
// inherent impl could be const
4242
Constness::NotConst => tcx.constness(tcx.local_parent(def_id)),
4343
}

compiler/rustc_feature/src/builtin_attrs.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,7 @@ pub static BUILTIN_ATTRIBUTES: &[Symbol] = &[
452452
sym::rustc_no_implicit_autorefs,
453453
sym::rustc_coherence_is_core,
454454
sym::rustc_coinductive,
455+
sym::rustc_comptime,
455456
sym::rustc_allow_incoherent_impl,
456457
sym::rustc_preserve_ub_checks,
457458
sym::rustc_deny_explicit_impl,

compiler/rustc_hir/src/attrs/data_structures.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1311,6 +1311,9 @@ pub enum AttributeKind {
13111311
/// Represents `#[rustc_coinductive]`.
13121312
RustcCoinductive,
13131313

1314+
/// Represents `#[rustc_comptime]`
1315+
RustcComptime(Span),
1316+
13141317
/// Represents `#[rustc_confusables]`.
13151318
RustcConfusables {
13161319
confusables: ThinVec<Symbol>,

compiler/rustc_hir/src/attrs/encode_cross_crate.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ impl AttributeKind {
112112
RustcClean { .. } => No,
113113
RustcCoherenceIsCore => No,
114114
RustcCoinductive => No,
115+
RustcComptime(..) => No, // Encoded directly in signature
115116
RustcConfusables { .. } => Yes,
116117
RustcConstStability { .. } => Yes,
117118
RustcConstStableIndirect => No,

0 commit comments

Comments
 (0)