Skip to content
Merged
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
12 changes: 3 additions & 9 deletions compiler/rustc_const_eval/src/check_consts/qualifs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@
// having basically only two use-cases that act in different ways.

use rustc_errors::ErrorGuaranteed;
use rustc_hir::attrs::AttributeKind;
use rustc_hir::def::DefKind;
use rustc_hir::{LangItem, find_attr};
use rustc_hir::LangItem;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::mir::*;
use rustc_middle::ty::{self, AdtDef, Ty};
Expand Down Expand Up @@ -366,14 +364,10 @@ where
// check performed after the promotion. Verify that with an assertion.
assert!(promoted.is_none() || Q::ALLOW_PROMOTED);

// Avoid looking at attrs of anon consts as that will ICE
let is_type_const_item =
matches!(cx.tcx.def_kind(def), DefKind::Const | DefKind::AssocConst)
&& find_attr!(cx.tcx.get_all_attrs(def), AttributeKind::TypeConst(_));

// Don't peak inside trait associated constants, also `#[type_const] const` items
// don't have bodies so there's nothing to look at
if promoted.is_none() && cx.tcx.trait_of_assoc(def).is_none() && !is_type_const_item {
if promoted.is_none() && cx.tcx.trait_of_assoc(def).is_none() && !cx.tcx.is_type_const(def)
{
let qualifs = cx.tcx.at(constant.span).mir_const_qualif(def);

if !Q::in_qualifs(&qualifs) {
Expand Down
17 changes: 16 additions & 1 deletion compiler/rustc_hir_analysis/src/collect/type_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,22 @@ fn infer_placeholder_type<'tcx>(
kind: &'static str,
) -> Ty<'tcx> {
let tcx = cx.tcx();
let ty = tcx.typeck(def_id).node_type(hir_id);
// If the type is omitted on a #[type_const] we can't run
// type check on since that requires the const have a body
// which type_consts don't.
let ty = if tcx.is_type_const(def_id.to_def_id()) {
if let Some(trait_item_def_id) = tcx.trait_item_of(def_id.to_def_id()) {
tcx.type_of(trait_item_def_id).instantiate_identity()
} else {
Ty::new_error_with_message(
tcx,
ty_span,
"constant with #[type_const] requires an explicit type",
)
}
} else {
tcx.typeck(def_id).node_type(hir_id)
};

// If this came from a free `const` or `static mut?` item,
// then the user may have written e.g. `const A = 42;`.
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1891,6 +1891,12 @@ impl<'tcx> TyCtxt<'tcx> {
self.is_lang_item(self.parent(def_id), LangItem::AsyncDropInPlace)
}

/// Check if the given `def_id` is a const with the `#[type_const]` attribute.
pub fn is_type_const(self, def_id: DefId) -> bool {
matches!(self.def_kind(def_id), DefKind::Const | DefKind::AssocConst)
&& find_attr!(self.get_all_attrs(def_id), AttributeKind::TypeConst(_))
}

/// Returns the movability of the coroutine of `def_id`, or panics
/// if given a `def_id` that is not a coroutine.
pub fn coroutine_movability(self, def_id: DefId) -> hir::Movability {
Expand Down
10 changes: 9 additions & 1 deletion compiler/rustc_mir_build/src/builder/expr/as_constant.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! See docs in build/expr/mod.rs

use rustc_abi::Size;
use rustc_ast as ast;
use rustc_ast::{self as ast};
use rustc_hir::LangItem;
use rustc_middle::mir::interpret::{CTFE_ALLOC_SALT, LitToConstInput, Scalar};
use rustc_middle::mir::*;
Expand Down Expand Up @@ -47,6 +47,7 @@ pub(crate) fn as_constant_inner<'tcx>(
tcx: TyCtxt<'tcx>,
) -> ConstOperand<'tcx> {
let Expr { ty, temp_scope_id: _, span, ref kind } = *expr;

match *kind {
ExprKind::Literal { lit, neg } => {
let const_ = lit_to_mir_constant(tcx, LitToConstInput { lit: lit.node, ty, neg });
Expand All @@ -69,6 +70,13 @@ pub(crate) fn as_constant_inner<'tcx>(
}
ExprKind::NamedConst { def_id, args, ref user_ty } => {
let user_ty = user_ty.as_ref().and_then(push_cuta);
if tcx.is_type_const(def_id) {
let uneval = ty::UnevaluatedConst::new(def_id, args);
let ct = ty::Const::new_unevaluated(tcx, uneval);

let const_ = Const::Ty(ty, ct);
return ConstOperand { span, user_ty, const_ };
}

let uneval = mir::UnevaluatedConst::new(def_id, args);
let const_ = Const::Unevaluated(uneval, ty);
Expand Down
26 changes: 26 additions & 0 deletions tests/ui/const-generics/mgca/type_const-array-return.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//@ check-pass
// This test should compile without an ICE.
#![expect(incomplete_features)]
#![feature(min_generic_const_args)]

pub struct A;

pub trait Array {
#[type_const]
const LEN: usize;
fn arr() -> [u8; Self::LEN];
}

impl Array for A {
#[type_const]
const LEN: usize = 4;

#[allow(unused_braces)]
fn arr() -> [u8; const { Self::LEN }] {
return [0u8; const { Self::LEN }];
}
}

fn main() {
let _ = A::arr();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#![expect(incomplete_features)]
#![feature(min_generic_const_args)]

struct A;

impl A {
#[type_const]
const B = 4;
//~^ ERROR: missing type for `const` item
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
error: missing type for `const` item
--> $DIR/type_const-inherent-const-omitted-type.rs:8:12
|
LL | const B = 4;
| ^
|
help: provide a type for the item
|
LL | const B: <type> = 4;
| ++++++++

error: aborting due to 1 previous error

Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#![expect(incomplete_features)]
#![feature(min_generic_const_args)]

trait BadTr {
const NUM: usize;
}

struct GoodS;

impl BadTr for GoodS {
#[type_const]
const NUM: = 84;
//~^ ERROR: missing type for `const` item

}

fn accept_bad_tr<const N: usize, T: BadTr<NUM = { N }>>(_x: &T) {}
//~^ ERROR use of trait associated const without `#[type_const]`

fn main() {
accept_bad_tr::<84, _>(&GoodS);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
error: missing type for `const` item
--> $DIR/type_const-only-in-impl-omitted-type.rs:12:15
|
LL | const NUM: = 84;
| ^ help: provide a type for the associated constant: `usize`

error: use of trait associated const without `#[type_const]`
--> $DIR/type_const-only-in-impl-omitted-type.rs:17:43
|
LL | fn accept_bad_tr<const N: usize, T: BadTr<NUM = { N }>>(_x: &T) {}
| ^^^^^^^^^^^
|
= note: the declaration in the trait must be marked with `#[type_const]`

error: aborting due to 2 previous errors

8 changes: 8 additions & 0 deletions tests/ui/const-generics/mgca/type_const-recursive.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#![expect(incomplete_features)]
#![feature(min_generic_const_args)]

#[type_const]
const A: u8 = A;
//~^ ERROR: overflow normalizing the unevaluated constant `A` [E0275]

fn main() {}
11 changes: 11 additions & 0 deletions tests/ui/const-generics/mgca/type_const-recursive.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error[E0275]: overflow normalizing the unevaluated constant `A`
--> $DIR/type_const-recursive.rs:5:1
|
LL | const A: u8 = A;
| ^^^^^^^^^^^
|
= note: in case this is a recursive type alias, consider using a struct, enum, or union instead

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0275`.
13 changes: 13 additions & 0 deletions tests/ui/const-generics/mgca/type_const-use.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//@ check-pass
// This test should compile without an ICE.
#![expect(incomplete_features)]
#![feature(min_generic_const_args)]

#[type_const]
const CONST: usize = 1;

fn uses_const() {
CONST;
}

fn main() {}
Loading