Skip to content
Draft
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
11 changes: 11 additions & 0 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3155,10 +3155,21 @@ impl CoroutineKind {
#[derive(Copy, Clone, PartialEq, Eq, Hash, Encodable, Decodable, Debug)]
#[derive(StableHash, Walkable)]
pub enum Const {
Always(Span),
Yes(Span),
No,
}

impl Const {
pub fn descr(&self) -> &'static str {
match self {
Const::Always(_) => "#[comptime]",
Const::Yes(_) => "const",
Const::No => "",
}
}
}

/// Item defaultness.
/// For details see the [RFC #2532](https://github.com/rust-lang/rfcs/pull/2532).
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, StableHash, Walkable)]
Expand Down
11 changes: 0 additions & 11 deletions compiler/rustc_ast_lowering/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,17 +122,6 @@ pub(crate) struct AwaitOnlyInAsyncFnAndBlocks {
pub item_span: Option<Span>,
}

#[derive(Diagnostic)]
#[diag("a function cannot be both `comptime` and `const`")]
pub(crate) struct ConstComptimeFn {
#[primary_span]
#[suggestion("remove the `const`", applicability = "machine-applicable", code = "")]
#[note("`const` implies the function can be called at runtime, too")]
pub span: Span,
#[label("`comptime` because of this")]
pub attr_span: Span,
}

#[derive(Diagnostic)]
#[diag("too many parameters for a coroutine (expected 0 or 1 parameters)", code = E0628)]
pub(crate) struct CoroutineTooManyParameters {
Expand Down
18 changes: 2 additions & 16 deletions compiler/rustc_ast_lowering/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ use super::{
FnDeclKind, GenericArgsMode, ImplTraitContext, ImplTraitPosition, LoweringContext, ParamMode,
RelaxedBoundForbiddenReason, RelaxedBoundPolicy, ResolverAstLoweringExt,
};
use crate::diagnostics::ConstComptimeFn;

pub(super) struct ItemLowerer<'a, 'hir> {
pub(super) tcx: TyCtxt<'hir>,
Expand Down Expand Up @@ -1704,21 +1703,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
safety.into()
};

let mut constness = self.lower_constness(h.constness);
if let Some(&attr_span) = find_attr!(attrs, RustcComptime(span) => span) {
match std::mem::replace(&mut constness, rustc_hir::Constness::Const { always: true }) {
rustc_hir::Constness::Const { always: true } => {
unreachable!("lower_constness cannot produce comptime")
}
// A function can't be `const` and `comptime` at the same time
rustc_hir::Constness::Const { always: false } => {
let Const::Yes(span) = h.constness else { unreachable!() };
self.dcx().emit_err(ConstComptimeFn { span, attr_span });
}
// Good
rustc_hir::Constness::NotConst => {}
}
}
let constness = self.lower_constness(h.constness);

hir::FnHeader { safety, asyncness, constness, abi: self.lower_extern(h.ext) }
}
Expand Down Expand Up @@ -1782,6 +1767,7 @@ impl<'hir> LoweringContext<'_, 'hir> {

pub(super) fn lower_constness(&mut self, c: Const) -> hir::Constness {
match c {
Const::Always(_) => hir::Constness::Const { always: true },
Const::Yes(_) => hir::Constness::Const { always: false },
Const::No => hir::Constness::NotConst,
}
Expand Down
80 changes: 11 additions & 69 deletions compiler/rustc_ast_passes/src/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ enum SelfSemantic {
}

enum TraitOrImpl {
Trait { vis: Span, constness: Const },
TraitImpl { constness: Const, polarity: ImplPolarity, trait_ref_span: Span },
Trait { constness: Const },
TraitImpl { constness: Const },
Impl { constness: Const },
}

Expand Down Expand Up @@ -124,10 +124,10 @@ impl<'a> AstValidator<'a> {
self.outer_trait_or_trait_impl = old;
}

fn with_in_trait(&mut self, vis: Span, constness: Const, f: impl FnOnce(&mut Self)) {
fn with_in_trait(&mut self, constness: Const, f: impl FnOnce(&mut Self)) {
let old = mem::replace(
&mut self.outer_trait_or_trait_impl,
Some(TraitOrImpl::Trait { vis, constness }),
Some(TraitOrImpl::Trait { constness }),
);
f(self);
self.outer_trait_or_trait_impl = old;
Expand Down Expand Up @@ -267,66 +267,12 @@ impl<'a> AstValidator<'a> {
}
}

fn check_impl_fn_not_const(&self, constness: Const, parent_constness: Const) {
let Const::Yes(span) = constness else {
fn check_trait_fn_not_const(&self, constness: Const, _parent: &TraitOrImpl) {
let (Const::Yes(span) | Const::Always(span)) = constness else {
return;
};

let span = self.sess.source_map().span_extend_while_whitespace(span);

let Const::Yes(parent_constness) = parent_constness else {
return;
};

self.dcx().emit_err(diagnostics::ImplFnConst { span, parent_constness });
}

fn check_trait_fn_not_const(&self, constness: Const, parent: &TraitOrImpl) {
let Const::Yes(span) = constness else {
return;
};

let const_trait_impl = self.features.const_trait_impl();
let make_impl_const_sugg = if const_trait_impl
&& let TraitOrImpl::TraitImpl {
constness: Const::No,
polarity: ImplPolarity::Positive,
trait_ref_span,
..
} = parent
{
Some(trait_ref_span.shrink_to_lo())
} else {
None
};

let map = self.sess.source_map();

let make_trait_const_sugg = if const_trait_impl
&& let &TraitOrImpl::Trait { vis, constness: ast::Const::No } = parent
{
Some(map.span_extend_while_whitespace(vis).shrink_to_hi())
} else {
None
};

let parent_constness = parent.constness();
self.dcx().emit_err(diagnostics::TraitFnConst {
span,
in_impl: matches!(parent, TraitOrImpl::TraitImpl { .. }),
const_context_label: parent_constness,
remove_const_sugg: (
map.span_extend_while_whitespace(span),
match parent_constness {
Some(_) => rustc_errors::Applicability::MachineApplicable,
None => rustc_errors::Applicability::MaybeIncorrect,
},
),
requires_multiple_changes: make_impl_const_sugg.is_some()
|| make_trait_const_sugg.is_some(),
make_impl_const_sugg,
make_trait_const_sugg,
});
self.dcx().span_delayed_bug(span, "should have rejected this in def collection");
}

fn check_async_fn_in_const_trait_or_impl(&self, sig: &FnSig, parent: &TraitOrImpl) {
Expand Down Expand Up @@ -771,6 +717,7 @@ impl<'a> AstValidator<'a> {
None => (),
}
match constness {
Const::Always(span) => report_err(span, "comptime"),
Const::Yes(span) => report_err(span, "const"),
Const::No => (),
}
Expand Down Expand Up @@ -1257,11 +1204,7 @@ impl Visitor<'_> for AstValidator<'_> {
self.visit_ty(self_ty);

self.with_in_trait_or_impl(
Some(TraitOrImpl::TraitImpl {
constness: *constness,
polarity: *polarity,
trait_ref_span: t.path.span,
}),
Some(TraitOrImpl::TraitImpl { constness: *constness }),
|this| {
walk_list!(
this,
Expand Down Expand Up @@ -1414,7 +1357,7 @@ impl Visitor<'_> for AstValidator<'_> {
this.visit_generics(generics);
walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits)
});
self.with_in_trait(item.span, *constness, |this| {
self.with_in_trait(*constness, |this| {
walk_list!(this, visit_assoc_item, items, AssocCtxt::Trait);
});
}
Expand Down Expand Up @@ -1954,9 +1897,8 @@ impl Visitor<'_> for AstValidator<'_> {
self.check_async_fn_in_const_trait_or_impl(sig, parent);
}
}
Some(parent @ TraitOrImpl::Impl { constness }) => {
Some(parent @ TraitOrImpl::Impl { .. }) => {
if let AssocItemKind::Fn(Fn { sig, .. }) = &item.kind {
self.check_impl_fn_not_const(sig.header.constness, *constness);
self.check_async_fn_in_const_trait_or_impl(sig, parent);
}
}
Expand Down
51 changes: 1 addition & 50 deletions compiler/rustc_ast_passes/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use rustc_abi::ExternAbi;
use rustc_errors::codes::*;
use rustc_errors::{Applicability, Diag, EmissionGuarantee, Subdiagnostic};
use rustc_errors::{Diag, EmissionGuarantee, Subdiagnostic};
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_span::{Ident, Span, Symbol};

Expand All @@ -28,55 +28,6 @@ pub(crate) enum VisibilityNotPermittedNote {
#[note("place qualifiers on individual foreign items instead")]
IndividualForeignItems,
}
#[derive(Diagnostic)]
#[diag("redundant `const` fn marker in const impl")]
pub(crate) struct ImplFnConst {
#[primary_span]
#[suggestion("remove the `const`", code = "", applicability = "machine-applicable")]
pub span: Span,
#[label("this declares all associated functions implicitly const")]
pub parent_constness: Span,
}

#[derive(Diagnostic)]
#[diag("functions in {$in_impl ->
[true] trait impls
*[false] traits
} cannot be declared const", code = E0379)]
pub(crate) struct TraitFnConst {
#[primary_span]
#[label(
"functions in {$in_impl ->
[true] trait impls
*[false] traits
} cannot be const"
)]
pub span: Span,
pub in_impl: bool,
#[label("this declares all associated functions implicitly const")]
pub const_context_label: Option<Span>,
#[suggestion(
"remove the `const`{$requires_multiple_changes ->
[true] {\" ...\"}
*[false] {\"\"}
}",
code = ""
)]
pub remove_const_sugg: (Span, Applicability),
pub requires_multiple_changes: bool,
#[suggestion(
"... and declare the impl to be const instead",
code = "const ",
applicability = "maybe-incorrect"
)]
pub make_impl_const_sugg: Option<Span>,
#[suggestion(
"... and declare the trait to be const instead",
code = "const ",
applicability = "maybe-incorrect"
)]
pub make_trait_const_sugg: Option<Span>,
}

#[derive(Diagnostic)]
#[diag(
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_ast_pretty/src/pprust/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2297,6 +2297,8 @@ impl<'a> State<'a> {
match s {
ast::Const::No => {}
ast::Const::Yes(_) => self.word_nbsp("const"),
// Can only be set via an attribute, which we'll also print
ast::Const::Always(_) => {}
}
}

Expand Down
12 changes: 0 additions & 12 deletions compiler/rustc_attr_parsing/src/attributes/semantics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,3 @@ impl NoArgsAttributeParser for MayDangleParser {
const STABILITY: AttributeStability = unstable!(dropck_eyepatch);
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 STABILITY: AttributeStability = unstable!(rustc_attrs);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcComptime;
}
3 changes: 1 addition & 2 deletions compiler/rustc_attr_parsing/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ use crate::attributes::repr::*;
use crate::attributes::rustc_allocator::*;
use crate::attributes::rustc_dump::*;
use crate::attributes::rustc_internal::*;
use crate::attributes::semantics::{ComptimeParser, *};
use crate::attributes::semantics::*;
use crate::attributes::splat::*;
use crate::attributes::stability::*;
use crate::attributes::test_attrs::*;
Expand Down Expand Up @@ -240,7 +240,6 @@ attribute_parsers!(
Single<WithoutArgs<AutomaticallyDerivedParser>>,
Single<WithoutArgs<ColdParser>>,
Single<WithoutArgs<CompilerBuiltinsParser>>,
Single<WithoutArgs<ComptimeParser>>,
Single<WithoutArgs<ConstContinueParser>>,
Single<WithoutArgs<CoroutineParser>>,
Single<WithoutArgs<DefaultLibAllocatorParser>>,
Expand Down
45 changes: 45 additions & 0 deletions compiler/rustc_builtin_macros/src/comptime.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
use rustc_ast::ast;
use rustc_expand::base::{Annotatable, ExtCtxt};
use rustc_span::Span;

pub(crate) fn expand(
ecx: &mut ExtCtxt<'_>,
_expand_span: Span,
meta_item: &ast::MetaItem,
mut item: Annotatable,
) -> Vec<Annotatable> {
let constness = match &mut item {
Annotatable::Item(p) => match &mut p.kind {
ast::ItemKind::Fn(f) => Some(&mut f.sig.header.constness),
_ => None,
},
Annotatable::AssocItem(i, _assoc_ctxt) => match &mut i.kind {
ast::AssocItemKind::Fn(func) => Some(&mut func.sig.header.constness),
_ => None,
},
Annotatable::Stmt(s) => match &mut s.kind {
ast::StmtKind::Item(p) => match &mut p.kind {
ast::ItemKind::Fn(f) => Some(&mut f.sig.header.constness),
_ => None,
},
_ => None,
},
_ => None,
};

let ast::MetaItemKind::Word = meta_item.kind else {
ecx.dcx().span_err(meta_item.span, "comptime does not take any arguments");
return vec![item];
};

if let Some(constness) = constness {
if let ast::Const::Yes(span) = *constness {
ecx.dcx().span_err(span, "a function cannot be both `comptime` and `const`");
}
*constness = ast::Const::Always(meta_item.span);
} else {
ecx.dcx().span_err(meta_item.span, "only functions and methods may be comptime");
}

vec![item]
}
2 changes: 2 additions & 0 deletions compiler/rustc_builtin_macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ mod cfg_accessible;
mod cfg_eval;
mod cfg_select;
mod compile_error;
mod comptime;
mod concat;
mod concat_bytes;
mod define_opaque;
Expand Down Expand Up @@ -110,6 +111,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
bench: test::expand_bench,
cfg_accessible: cfg_accessible::Expander,
cfg_eval: cfg_eval::expand,
comptime: comptime::expand,
define_opaque: define_opaque::expand,
derive: derive::Expander { is_const: false },
derive_const: derive::Expander { is_const: true },
Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_feature/src/builtin_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,6 @@ pub static BUILTIN_ATTRIBUTES: &[Symbol] = &[
sym::rustc_no_implicit_autorefs,
sym::rustc_coherence_is_core,
sym::rustc_coinductive,
sym::rustc_comptime,
sym::rustc_allow_incoherent_impl,
sym::rustc_preserve_ub_checks,
sym::rustc_deny_explicit_impl,
Expand Down
Loading
Loading