Skip to content

Commit

Permalink
Start implementing #[type_const]
Browse files Browse the repository at this point in the history
  • Loading branch information
camelid committed Jan 20, 2025
1 parent eadca84 commit a296ff8
Show file tree
Hide file tree
Showing 12 changed files with 157 additions and 5 deletions.
7 changes: 7 additions & 0 deletions compiler/rustc_feature/src/builtin_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,13 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
EncodeCrossCrate::Yes, experimental!(patchable_function_entry)
),

// Probably temporary component of min_generic_const_args.
// `#[type_const] const ASSOC: usize;`
gated!(
type_const, Normal, template!(Word), ErrorFollowing,
EncodeCrossCrate::Yes, min_generic_const_args, experimental!(type_const),
),

// ==========================================================================
// Internal attributes: Stability, deprecation, and unsafe:
// ==========================================================================
Expand Down
10 changes: 9 additions & 1 deletion compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2337,7 +2337,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let assoc_const = self
.probe_assoc_item(assoc_ident, ty::AssocKind::Const, hir_ref_id, span, trait_did)
.expect("failed to find associated const");
self.lower_assoc_const(span, assoc_const.def_id, assoc_segment, bound)
if assoc_const.has_type_const_attr(tcx) {
self.lower_assoc_const(span, assoc_const.def_id, assoc_segment, bound)
} else {
let mut err = tcx
.dcx()
.struct_span_err(span, "use of trait associated const without `#[type_const]`");
err.note("the declaration in the trait must be marked with `#[type_const]`");
Const::new_error(tcx, err.emit())
}
}

/// Literals are eagerly converted to a constant, everything else becomes `Unevaluated`.
Expand Down
19 changes: 18 additions & 1 deletion compiler/rustc_middle/src/ty/assoc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use rustc_hir as hir;
use rustc_hir::def::{DefKind, Namespace};
use rustc_hir::def_id::DefId;
use rustc_macros::{Decodable, Encodable, HashStable};
use rustc_span::{Ident, Symbol};
use rustc_span::{Ident, Symbol, sym};

use super::{TyCtxt, Visibility};
use crate::ty;
Expand Down Expand Up @@ -108,6 +108,23 @@ impl AssocItem {
pub fn is_impl_trait_in_trait(&self) -> bool {
self.opt_rpitit_info.is_some()
}

/// Does this associated item have the `#[type_const]` attribute,
/// or (if it is in a trait impl), does the item from the original
/// trait have this attribute?
pub fn has_type_const_attr(&self, tcx: TyCtxt<'_>) -> bool {
if self.kind != ty::AssocKind::Const {
return false;
}

let def_id = match (self.container, self.trait_item_def_id) {
(AssocItemContainer::Trait, _) => self.def_id,
(AssocItemContainer::Impl, Some(trait_item_did)) => trait_item_did,
// Inherent impl but this attr is only applied to trait assoc items.
(AssocItemContainer::Impl, None) => return false,
};
tcx.has_attr(def_id, sym::type_const)
}
}

#[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash, Encodable, Decodable)]
Expand Down
21 changes: 21 additions & 0 deletions compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use rustc_ast::{AttrStyle, LitKind, MetaItemInner, MetaItemKind, MetaItemLit, as
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{Applicability, DiagCtxtHandle, IntoDiagArg, MultiSpan, StashKey};
use rustc_feature::{AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute};
use rustc_hir::def::DefKind;
use rustc_hir::def_id::LocalModDefId;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{
Expand Down Expand Up @@ -246,6 +247,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
[sym::coroutine, ..] => {
self.check_coroutine(attr, target);
}
[sym::type_const, ..] => {
self.check_type_const(hir_id,attr, target);
}
[sym::linkage, ..] => self.check_linkage(attr, span, target),
[sym::rustc_pub_transparent, ..] => self.check_rustc_pub_transparent(attr.span, span, attrs),
[
Expand Down Expand Up @@ -2456,6 +2460,23 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
}
}

fn check_type_const(&self, hir_id: HirId, attr: &Attribute, target: Target) {
let tcx = self.tcx;
if target == Target::AssocConst
&& let parent = tcx.parent(hir_id.expect_owner().to_def_id())
&& self.tcx.def_kind(parent) == DefKind::Trait
{
return;
} else {
self.dcx()
.struct_span_err(
attr.span,
"`#[type_const]` must only be applied to trait associated constants",
)
.emit();
}
}

fn check_linkage(&self, attr: &Attribute, span: Span, target: Target) {
match target {
Target::Fn
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2058,6 +2058,7 @@ symbols! {
type_ascribe,
type_ascription,
type_changing_struct_update,
type_const,
type_id,
type_ir_inherent,
type_length_limit,
Expand Down
14 changes: 14 additions & 0 deletions tests/ui/const-generics/mgca/assoc-const-without-type_const.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#![feature(min_generic_const_args)]
#![allow(incomplete_features)]

pub trait Tr {
const SIZE: usize;
}

fn mk_array<T: Tr>(_x: T) -> [(); T::SIZE] {
//~^ ERROR type_const
[(); T::SIZE]
//~^ ERROR type_const
}

fn main() {}
18 changes: 18 additions & 0 deletions tests/ui/const-generics/mgca/assoc-const-without-type_const.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
error: use of trait associated const without `#[type_const]`
--> $DIR/assoc-const-without-type_const.rs:8:35
|
LL | fn mk_array<T: Tr>(_x: T) -> [(); T::SIZE] {
| ^^^^^^^
|
= note: the declaration in the trait must be marked with `#[type_const]`

error: use of trait associated const without `#[type_const]`
--> $DIR/assoc-const-without-type_const.rs:10:10
|
LL | [(); T::SIZE]
| ^^^^^^^
|
= note: the declaration in the trait must be marked with `#[type_const]`

error: aborting due to 2 previous errors

1 change: 1 addition & 0 deletions tests/ui/const-generics/mgca/assoc-const.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#![allow(incomplete_features)]

pub trait Tr {
#[type_const]
const SIZE: usize;
}

Expand Down
17 changes: 17 additions & 0 deletions tests/ui/const-generics/mgca/bad-type_const-syntax.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
trait Tr {
#[type_const()]
//~^ ERROR malformed
//~| ERROR experimental
const N: usize;
}

struct S;

impl Tr for S {
#[type_const]
//~^ ERROR must only be applied to trait associated constants
//~| ERROR experimental
const N: usize = 0;
}

fn main() {}
35 changes: 35 additions & 0 deletions tests/ui/const-generics/mgca/bad-type_const-syntax.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
error: malformed `type_const` attribute input
--> $DIR/bad-type_const-syntax.rs:2:5
|
LL | #[type_const()]
| ^^^^^^^^^^^^^^^ help: must be of the form: `#[type_const]`

error[E0658]: the `#[type_const]` attribute is an experimental feature
--> $DIR/bad-type_const-syntax.rs:2:5
|
LL | #[type_const()]
| ^^^^^^^^^^^^^^^
|
= note: see issue #132980 <https://github.com/rust-lang/rust/issues/132980> for more information
= help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error[E0658]: the `#[type_const]` attribute is an experimental feature
--> $DIR/bad-type_const-syntax.rs:11:5
|
LL | #[type_const]
| ^^^^^^^^^^^^^
|
= note: see issue #132980 <https://github.com/rust-lang/rust/issues/132980> for more information
= help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error: `#[type_const]` must only be applied to trait associated constants
--> $DIR/bad-type_const-syntax.rs:11:5
|
LL | #[type_const]
| ^^^^^^^^^^^^^

error: aborting due to 4 previous errors

For more information about this error, try `rustc --explain E0658`.
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
trait Trait {
#[type_const]
//~^ ERROR experimental
const ASSOC: usize;
}

// FIXME(min_generic_const_args): implement support for this, behind the feature gate
// FIXME(min_generic_const_args): add suggestion for mgca to this error
fn foo<T: Trait>() -> [u8; <T as Trait>::ASSOC] {
//~^ ERROR generic parameters may not be used in const operations
loop {}
Expand Down
15 changes: 13 additions & 2 deletions tests/ui/feature-gates/feature-gate-min-generic-const-args.stderr
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
error: generic parameters may not be used in const operations
--> $DIR/feature-gate-min-generic-const-args.rs:6:29
--> $DIR/feature-gate-min-generic-const-args.rs:8:29
|
LL | fn foo<T: Trait>() -> [u8; <T as Trait>::ASSOC] {
| ^ cannot perform const operation using `T`
|
= note: type parameters may not be used in const expressions
= help: add `#![feature(generic_const_exprs)]` to allow generic const expressions

error: aborting due to 1 previous error
error[E0658]: the `#[type_const]` attribute is an experimental feature
--> $DIR/feature-gate-min-generic-const-args.rs:2:5
|
LL | #[type_const]
| ^^^^^^^^^^^^^
|
= note: see issue #132980 <https://github.com/rust-lang/rust/issues/132980> for more information
= help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0658`.

0 comments on commit a296ff8

Please sign in to comment.