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
2 changes: 1 addition & 1 deletion compiler/rustc_ast_lowering/src/asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
}
InlineAsmOperand::Const { anon_const } => hir::InlineAsmOperand::Const {
anon_const: self.lower_const_block(anon_const),
anon_const: self.lower_const_block(anon_const, &[]),
Copy link
Contributor

Choose a reason for hiding this comment

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

you can put at least some atributes on const operands. Iirc recently cfg was stabilized here? Though that one is of course expanded out early. Still wonder where those attributes go and whether they should be forwarded here 🤔

Copy link
Contributor

Choose a reason for hiding this comment

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

even if in this case it only matters for their stability attrs

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't know where the attribute would go. If it's on the anon const, it will end up as part of its body's expression. You can't add attrs on operands, at least the ast has nowhere to put them. This change should be behaviour-preserving, but I could add a FIXME

},
InlineAsmOperand::Sym { sym } => {
let static_def_id = self
Expand Down
16 changes: 13 additions & 3 deletions compiler/rustc_ast_lowering/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,9 @@ impl<'hir> LoweringContext<'_, 'hir> {

let kind = match &e.kind {
ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)),
ExprKind::ConstBlock(c) => hir::ExprKind::ConstBlock(self.lower_const_block(c)),
ExprKind::ConstBlock(c) => {
hir::ExprKind::ConstBlock(self.lower_const_block(c, attrs))
}
ExprKind::Repeat(expr, count) => {
let expr = self.lower_expr(expr);
let count = self.lower_array_length_to_const_arg(count);
Expand Down Expand Up @@ -391,12 +393,20 @@ impl<'hir> LoweringContext<'_, 'hir> {
})
}

pub(crate) fn lower_const_block(&mut self, c: &AnonConst) -> hir::ConstBlock {
pub(crate) fn lower_const_block(
&mut self,
c: &AnonConst,
attrs: &'hir [hir::Attribute],
) -> hir::ConstBlock {
self.with_new_scopes(c.value.span, |this| {
let def_id = this.local_def_id(c.id);
let hir_id = this.lower_node_id(c.id);
if !attrs.is_empty() {
this.attrs.insert(hir_id.local_id, attrs);
}
hir::ConstBlock {
def_id,
hir_id: this.lower_node_id(c.id),
hir_id,
body: this.lower_const_body(c.value.span, Some(&c.value)),
}
})
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_ast_lowering/src/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
ExprKind::Lit(lit) => {
hir::PatExprKind::Lit { lit: self.lower_lit(lit, span), negated: false }
}
ExprKind::ConstBlock(c) => hir::PatExprKind::ConstBlock(self.lower_const_block(c)),
ExprKind::ConstBlock(c) => hir::PatExprKind::ConstBlock(self.lower_const_block(c, &[])),
ExprKind::IncludedBytes(byte_sym) => hir::PatExprKind::Lit {
lit: respan(span, LitKind::ByteStr(*byte_sym, StrStyle::Cooked)),
negated: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ impl<S: Stage> CombineAttributeParser<S> for AllowConstFnUnstableParser {
Allow(Target::Method(MethodKind::Inherent)),
Allow(Target::Method(MethodKind::Trait { body: true })),
Allow(Target::Method(MethodKind::TraitImpl)),
Allow(Target::Expression), // FIXME: should only allow inline consts
]);
const TEMPLATE: AttributeTemplate = template!(Word, List: &["feat1, feat2, ..."]);

Expand Down
17 changes: 16 additions & 1 deletion compiler/rustc_attr_parsing/src/attributes/stability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,22 @@ impl<S: Stage> AttributeParser<S> for ConstStabilityParser {
this.promotable = true;
}),
];
const ALLOWED_TARGETS: AllowedTargets = ALLOWED_TARGETS;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::Method(MethodKind::Inherent)),
Allow(Target::Method(MethodKind::TraitImpl)),
Allow(Target::Method(MethodKind::Trait { body: true })),
Allow(Target::Impl { of_trait: false }),
Allow(Target::Impl { of_trait: true }),
Allow(Target::Use), // FIXME I don't think this does anything?
Allow(Target::Const),
Allow(Target::AssocConst),
Allow(Target::Trait),
Allow(Target::Static),
Allow(Target::Expression), // FIXME: we really only want to allow inline consts
Copy link
Contributor

Choose a reason for hiding this comment

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

we could make up a new target for that 🤷‍♀️ . This would be its current only use but it's not that hard to do otherwise

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yea I had that, but I felt I already changed enough in this PR 😅

Allow(Target::Crate),
Allow(Target::MacroDef), // FIXME(oli-obk): remove this and eliminate the manual check for it
]);

fn finalize(mut self, cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
if self.promotable {
Expand Down
8 changes: 5 additions & 3 deletions compiler/rustc_const_eval/src/check_consts/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,11 @@ impl<'mir, 'tcx> ConstCx<'mir, 'tcx> {
pub fn enforce_recursive_const_stability(&self) -> bool {
// We can skip this if neither `staged_api` nor `-Zforce-unstable-if-unmarked` are enabled,
// since in such crates `lookup_const_stability` will always be `None`.
self.const_kind == Some(hir::ConstContext::ConstFn)
&& (self.tcx.features().staged_api()
|| self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked)
matches!(
self.const_kind,
Some(hir::ConstContext::ConstFn | hir::ConstContext::Const { inline: true })
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Only a partial fix. I can remove the inline limitation here, but it has a lot of fallout that I haven't analyzed yet. I'll do that in a follow-up

) && (self.tcx.features().staged_api()
|| self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked)
&& is_fn_or_trait_safe_to_expose_on_stable(self.tcx, self.def_id().to_def_id())
}

Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_passes/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -576,6 +576,11 @@ passes_unstable_attr_for_already_stable_feature =
.item = the stability attribute annotates this item
.help = consider removing the attribute

passes_unstable_inline_const_in_const =
const stability of inline consts must match const stability of containing item
.help = did you mean to use `rustc_allow_const_fn_unstable`?
.note = stability marker of containing item defined here

passes_unsupported_attributes_in_where =
most attributes are not supported in `where` clauses
.help = only `#[cfg]` and `#[cfg_attr]` are supported
Expand Down
10 changes: 10 additions & 0 deletions compiler/rustc_passes/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1065,6 +1065,16 @@ pub(crate) struct MissingConstErr {
pub fn_sig_span: Span,
}

#[derive(Diagnostic)]
#[diag(passes_unstable_inline_const_in_const)]
pub(crate) struct UnstableInlineConstInConst {
#[primary_span]
#[help]
pub span: Span,
#[note]
pub parent_span: Option<Span>,
}

#[derive(Diagnostic)]
#[diag(passes_const_stable_not_stable)]
pub(crate) struct ConstStableNotStable {
Expand Down
23 changes: 20 additions & 3 deletions compiler/rustc_passes/src/stability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -334,9 +334,12 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> {

macro_rules! find_attr_span {
($name:ident) => {{
let attrs = self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id(def_id));
find_attr_span!($name, def_id)
}};
($name:ident, $id: expr) => {{
let attrs = self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id($id));
find_attr!(attrs, AttributeKind::$name { span, .. } => *span)
}}
}};
}

if stab.is_none()
Expand Down Expand Up @@ -398,6 +401,16 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> {
self.tcx.dcx().emit_err(errors::MissingConstErr { fn_sig_span: fn_sig.span });
}

if let DefKind::InlineConst = self.tcx.def_kind(def_id)
&& const_stab.is_some()
&& let parent = self.tcx.local_parent(def_id)
&& self.tcx.lookup_const_stability(parent) != const_stab
&& let Some(span) = find_attr_span!(ConstStability)
{
let parent_span = find_attr_span!(ConstStability, parent);
self.tcx.dcx().emit_err(errors::UnstableInlineConstInConst { span, parent_span });
}

// If this is marked const *stable*, it must also be regular-stable.
if let Some(const_stab) = const_stab
&& let Some(fn_sig) = fn_sig
Expand Down Expand Up @@ -478,6 +491,11 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> {
intravisit::walk_item(self, i)
}

fn visit_inline_const(&mut self, c: &'tcx rustc_hir::ConstBlock) -> Self::Result {
self.check_compatible_stability(c.def_id);
intravisit::walk_inline_const(self, c)
}

fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) {
self.check_compatible_stability(ti.owner_id.def_id);
self.check_missing_stability(ti.owner_id.def_id);
Expand Down Expand Up @@ -601,7 +619,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
let attrs = self.tcx.hir_attrs(item.hir_id());
let stab = find_attr!(attrs, AttributeKind::Stability{stability, span} => (*stability, *span));

// FIXME(jdonszelmann): make it impossible to miss the or_else in the typesystem
let const_stab = find_attr!(attrs, AttributeKind::ConstStability{stability, ..} => *stability);

let unstable_feature_stab =
Expand Down
7 changes: 6 additions & 1 deletion library/alloc/src/boxed/thin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,12 @@ impl<H> WithHeader<H> {
// of the header, past the padding, so the assigned type makes sense.
// It also ensures that the address at the end of the header is sufficiently
// aligned for T.
let alloc: &<Dyn as Pointee>::Metadata = const {
// We generate the vtable in a const block instead of having the compiler
// generate it for us. The basics to allocate new memory during ctfe are
// unstable, but we can always change the intrinsic logic to support the
// needs of new_unsize_zst in the future.
let alloc: &<Dyn as Pointee>::Metadata = #[rustc_allow_const_fn_unstable(const_heap)]
const {
// FIXME: just call `WithHeader::alloc_layout` with size reset to 0.
// Currently that's blocked on `Layout::extend` not being `const fn`.

Expand Down
5 changes: 4 additions & 1 deletion library/core/src/any.rs
Original file line number Diff line number Diff line change
Expand Up @@ -864,7 +864,10 @@ impl fmt::Debug for TypeId {
#[stable(feature = "type_name", since = "1.38.0")]
#[rustc_const_unstable(feature = "const_type_name", issue = "63084")]
pub const fn type_name<T: ?Sized>() -> &'static str {
const { intrinsics::type_name::<T>() }
#[rustc_const_unstable(feature = "const_type_name", issue = "63084")]
Copy link
Member

Choose a reason for hiding this comment

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

What does rustc_const_unstable on a const block mean?

It would help to see e.g. a patch updating the dev guide on these attributes, to understand the intended behavior without having to reverse engineer it from the implementation.

const {
intrinsics::type_name::<T>()
}
}

/// Returns the type name of the pointed-to value as a string slice.
Expand Down
1 change: 0 additions & 1 deletion library/core/src/array/drain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ impl<'l, 'f, T, U, const N: usize, F: FnMut(T) -> U> Drain<'l, 'f, T, N, F> {
}

/// See [`Drain::new`]; this is our fake iterator.
#[rustc_const_unstable(feature = "array_try_map", issue = "79711")]
#[unstable(feature = "array_try_map", issue = "79711")]
pub(super) struct Drain<'l, 'f, T, const N: usize, F> {
// FIXME(const-hack): This is essentially a slice::IterMut<'static>, replace when possible.
Expand Down
1 change: 1 addition & 0 deletions library/core/src/intrinsics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2881,6 +2881,7 @@ pub const fn type_name<T: ?Sized>() -> &'static str;
#[rustc_nounwind]
#[unstable(feature = "core_intrinsics", issue = "none")]
#[rustc_intrinsic]
#[rustc_intrinsic_const_stable_indirect]
pub const fn type_id<T: ?Sized + 'static>() -> crate::any::TypeId;
Copy link
Member

Choose a reason for hiding this comment

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

And neither is this const-stable.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is const stable. TypeId::of is const stable

Copy link
Member

Choose a reason for hiding this comment

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

Ah fair, somehow I didn't find that one.

Copy link
Member

Choose a reason for hiding this comment

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

For the record, the t-lang FCP that justifies adding this attribute passed here.

Maybe we should have a separate PR just adding that attribute? This PR shouldn't add any more since we don't have FCP for any of the others.


/// Tests (at compile-time) if two [`crate::any::TypeId`] instances identify the
Expand Down
5 changes: 4 additions & 1 deletion library/core/src/mem/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1229,7 +1229,10 @@ pub const fn discriminant<T>(v: &T) -> Discriminant<T> {
#[rustc_const_unstable(feature = "variant_count", issue = "73662")]
#[rustc_diagnostic_item = "mem_variant_count"]
pub const fn variant_count<T>() -> usize {
const { intrinsics::variant_count::<T>() }
#[rustc_const_unstable(feature = "variant_count", issue = "73662")]
const {
intrinsics::variant_count::<T>()
}
}

/// Provides associated constants for various useful properties of types,
Expand Down
47 changes: 47 additions & 0 deletions tests/ui/consts/min_const_fn/const-fn-lang-feature-inline-const.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//! Ensure we reject invalid combinations of feature gating inline consts

#![feature(staged_api, abi_unadjusted)]
#![stable(feature = "rust_test", since = "1.0.0")]

#[unstable(feature = "abi_unadjusted", issue = "42")]
#[rustc_const_unstable(feature = "abi_unadjusted", issue = "42")]
const fn my_fun() {}

#[stable(feature = "asdf", since = "99.0.0")]
#[rustc_const_stable(feature = "asdf", since = "99.0.0")]
const fn my_fun2() {
#[rustc_const_unstable(feature = "abi_unadjusted", issue = "42")]
//~^ ERROR: must match const stability of containing item
const {
my_fun()
}
}

// Check that const stable const blocks can only call const stable things
#[stable(feature = "asdf", since = "99.0.0")]
#[rustc_const_stable(feature = "asdf", since = "99.0.0")]
const fn my_fun3() {
#[rustc_const_stable(feature = "asdf", since = "99.0.0")]
const {
my_fun()
//~^ ERROR: (indirectly) exposed to stable
}
}

// Check that const stable const blocks can only call const stable things
#[stable(feature = "asdf", since = "99.0.0")]
#[rustc_const_stable(feature = "asdf", since = "99.0.0")]
const fn my_fun4() {
const {
my_fun()
//~^ ERROR: (indirectly) exposed to stable
}
}

fn main() {
#[rustc_const_unstable(feature = "abi_unadjusted", issue = "42")]
//~^ ERROR: must match const stability of containing item
const {
my_fun2()
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
error: const stability of inline consts must match const stability of containing item.
--> $DIR/const-fn-lang-feature-inline-const.rs:13:5
|
LL | #[rustc_const_unstable(feature = "abi_unadjusted", issue = "42")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: did you mean to use `rustc_allow_const_fn_unstable`?
--> $DIR/const-fn-lang-feature-inline-const.rs:13:5
|
LL | #[rustc_const_unstable(feature = "abi_unadjusted", issue = "42")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: stability marker of containing item defined here
--> $DIR/const-fn-lang-feature-inline-const.rs:11:1
|
LL | #[rustc_const_stable(feature = "asdf", since = "99.0.0")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: const stability of inline consts must match const stability of containing item.
--> $DIR/const-fn-lang-feature-inline-const.rs:42:5
|
LL | #[rustc_const_unstable(feature = "abi_unadjusted", issue = "42")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: did you mean to use `rustc_allow_const_fn_unstable`?
--> $DIR/const-fn-lang-feature-inline-const.rs:42:5
|
LL | #[rustc_const_unstable(feature = "abi_unadjusted", issue = "42")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: const function that might be (indirectly) exposed to stable cannot use `#[feature(abi_unadjusted)]`
--> $DIR/const-fn-lang-feature-inline-const.rs:26:9
|
LL | my_fun()
| ^^^^^^^^
|
= help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features
help: if the caller is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]`
|
LL | const #[rustc_const_unstable(feature = "...", issue = "...")]
| +++++++++++++++++++++++++++++++++++++++++++++++++++++++

error: const function that might be (indirectly) exposed to stable cannot use `#[feature(abi_unadjusted)]`
--> $DIR/const-fn-lang-feature-inline-const.rs:36:9
|
LL | my_fun()
| ^^^^^^^^
|
= help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features
help: if the caller is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]`
|
LL | const #[rustc_const_unstable(feature = "...", issue = "...")]
| +++++++++++++++++++++++++++++++++++++++++++++++++++++++

error: aborting due to 4 previous errors

37 changes: 35 additions & 2 deletions tests/ui/consts/min_const_fn/const-fn-lang-feature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//! enabling the feature gate actually lets us call the function.
//@ check-pass

#![feature(staged_api, abi_unadjusted)]
#![feature(staged_api, abi_unadjusted, rustc_allow_const_fn_unstable)]
#![stable(feature = "rust_test", since = "1.0.0")]

#[unstable(feature = "abi_unadjusted", issue = "42")]
Expand All @@ -15,6 +15,39 @@ const fn my_fun2() {
my_fun()
}

// Check that we can call unstable things in unstable const blocks
// in unstable fns.
#[unstable(feature = "abi_unadjusted", issue = "42")]
#[rustc_const_unstable(feature = "abi_unadjusted", issue = "42")]
const fn my_fun3() {
#[rustc_const_unstable(feature = "abi_unadjusted", issue = "42")]
const {
my_fun()
}
}

#[stable(feature = "asdf", since = "99.0.0")]
#[rustc_const_stable(feature = "asdf", since = "99.0.0")]
const fn stable_thing() {}

#[stable(feature = "asdf", since = "99.0.0")]
#[rustc_const_stable(feature = "asdf", since = "99.0.0")]
const fn my_fun4() {
#[rustc_const_stable(feature = "asdf", since = "99.0.0")]
const {
stable_thing()
}
}

#[stable(feature = "asdf", since = "99.0.0")]
#[rustc_const_stable(feature = "asdf", since = "99.0.0")]
const fn my_fun5() {
const { stable_thing() }
}

fn main() {
const { my_fun2() };
#[rustc_allow_const_fn_unstable(abi_unadjusted)]
const {
my_fun2()
};
}
Loading
Loading