Skip to content

Commit 9ed4674

Browse files
committed
typeck: Fix const generic in repeat param ICE.
This commit fixes an ICE that occured when a const generic was used in a repeat expression. This was due to the code expecting the length of the repeat expression to be const evaluatable to a constant, but a const generic parameter is not (however, it can be made into a constant).
1 parent d132f54 commit 9ed4674

File tree

6 files changed

+104
-25
lines changed

6 files changed

+104
-25
lines changed

src/librustc_typeck/astconv.rs

+22-13
Original file line numberDiff line numberDiff line change
@@ -2144,6 +2144,17 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
21442144
result_ty
21452145
}
21462146

2147+
/// Returns the `DefId` of the constant parameter that the provided expression is a path to.
2148+
pub fn const_param_def_id(&self, expr: &hir::Expr) -> Option<DefId> {
2149+
match &expr.node {
2150+
ExprKind::Path(hir::QPath::Resolved(_, path)) => match path.res {
2151+
Res::Def(DefKind::ConstParam, did) => Some(did),
2152+
_ => None,
2153+
},
2154+
_ => None,
2155+
}
2156+
}
2157+
21472158
pub fn ast_const_to_const(
21482159
&self,
21492160
ast_const: &hir::AnonConst,
@@ -2174,19 +2185,17 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
21742185
}
21752186
}
21762187

2177-
if let ExprKind::Path(ref qpath) = expr.node {
2178-
if let hir::QPath::Resolved(_, ref path) = qpath {
2179-
if let Res::Def(DefKind::ConstParam, def_id) = path.res {
2180-
let node_id = tcx.hir().as_local_node_id(def_id).unwrap();
2181-
let item_id = tcx.hir().get_parent_node(node_id);
2182-
let item_def_id = tcx.hir().local_def_id(item_id);
2183-
let generics = tcx.generics_of(item_def_id);
2184-
let index = generics.param_def_id_to_index[&tcx.hir().local_def_id(node_id)];
2185-
let name = tcx.hir().name(node_id).as_interned_str();
2186-
const_.val = ConstValue::Param(ty::ParamConst::new(index, name));
2187-
}
2188-
}
2189-
};
2188+
if let Some(def_id) = self.const_param_def_id(expr) {
2189+
// Find the name and index of the const parameter by indexing the generics of the
2190+
// parent item and construct a `ParamConst`.
2191+
let node_id = tcx.hir().as_local_node_id(def_id).unwrap();
2192+
let item_id = tcx.hir().get_parent_node(node_id);
2193+
let item_def_id = tcx.hir().local_def_id(item_id);
2194+
let generics = tcx.generics_of(item_def_id);
2195+
let index = generics.param_def_id_to_index[&tcx.hir().local_def_id(node_id)];
2196+
let name = tcx.hir().name(node_id).as_interned_str();
2197+
const_.val = ConstValue::Param(ty::ParamConst::new(index, name));
2198+
}
21902199

21912200
tcx.mk_const(const_)
21922201
}

src/librustc_typeck/check/mod.rs

+22-12
Original file line numberDiff line numberDiff line change
@@ -2439,6 +2439,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
24392439
ty
24402440
}
24412441

2442+
/// Returns the `DefId` of the constant parameter that the provided expression is a path to.
2443+
pub fn const_param_def_id(&self, hir_c: &hir::AnonConst) -> Option<DefId> {
2444+
AstConv::const_param_def_id(self, &self.tcx.hir().body(hir_c.body).value)
2445+
}
2446+
24422447
pub fn to_const(&self, ast_c: &hir::AnonConst, ty: Ty<'tcx>) -> &'tcx ty::Const<'tcx> {
24432448
AstConv::ast_const_to_const(self, ast_c, ty)
24442449
}
@@ -4414,19 +4419,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
44144419
}
44154420
ExprKind::Repeat(ref element, ref count) => {
44164421
let count_def_id = tcx.hir().local_def_id_from_hir_id(count.hir_id);
4417-
let param_env = ty::ParamEnv::empty();
4418-
let substs = InternalSubsts::identity_for_item(tcx.global_tcx(), count_def_id);
4419-
let instance = ty::Instance::resolve(
4420-
tcx.global_tcx(),
4421-
param_env,
4422-
count_def_id,
4423-
substs,
4424-
).unwrap();
4425-
let global_id = GlobalId {
4426-
instance,
4427-
promoted: None
4422+
let count = if self.const_param_def_id(count).is_some() {
4423+
Ok(self.to_const(count, self.tcx.type_of(count_def_id)))
4424+
} else {
4425+
let param_env = ty::ParamEnv::empty();
4426+
let substs = InternalSubsts::identity_for_item(tcx.global_tcx(), count_def_id);
4427+
let instance = ty::Instance::resolve(
4428+
tcx.global_tcx(),
4429+
param_env,
4430+
count_def_id,
4431+
substs,
4432+
).unwrap();
4433+
let global_id = GlobalId {
4434+
instance,
4435+
promoted: None
4436+
};
4437+
4438+
tcx.const_eval(param_env.and(global_id))
44284439
};
4429-
let count = tcx.const_eval(param_env.and(global_id));
44304440

44314441
let uty = match expected {
44324442
ExpectHasType(uty) => {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#![feature(const_generics)]
2+
//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
3+
4+
fn f<T: Copy, const N: usize>(x: T) -> [T; N] {
5+
[x; N]
6+
//~^ ERROR array lengths can't depend on generic parameters
7+
}
8+
9+
fn main() {
10+
let x: [u32; 5] = f::<u32, 5>(3);
11+
assert_eq!(x, [3u32; 5]);
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
warning: the feature `const_generics` is incomplete and may cause the compiler to crash
2+
--> $DIR/issue-61336-1.rs:1:12
3+
|
4+
LL | #![feature(const_generics)]
5+
| ^^^^^^^^^^^^^^
6+
7+
error: array lengths can't depend on generic parameters
8+
--> $DIR/issue-61336-1.rs:5:9
9+
|
10+
LL | [x; N]
11+
| ^
12+
13+
error: aborting due to previous error
14+
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#![feature(const_generics)]
2+
//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
3+
4+
fn f<T: Copy, const N: usize>(x: T) -> [T; N] {
5+
[x; N]
6+
}
7+
8+
fn g<T, const N: usize>(x: T) -> [T; N] {
9+
[x; N]
10+
//~^ ERROR the trait bound `T: std::marker::Copy` is not satisfied [E0277]
11+
}
12+
13+
fn main() {
14+
let x: [u32; 5] = f::<u32, 5>(3);
15+
assert_eq!(x, [3u32; 5]);
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
warning: the feature `const_generics` is incomplete and may cause the compiler to crash
2+
--> $DIR/issue-61336.rs:1:12
3+
|
4+
LL | #![feature(const_generics)]
5+
| ^^^^^^^^^^^^^^
6+
7+
error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
8+
--> $DIR/issue-61336.rs:9:5
9+
|
10+
LL | [x; N]
11+
| ^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
12+
|
13+
= help: consider adding a `where T: std::marker::Copy` bound
14+
= note: the `Copy` trait is required because the repeated element will be copied
15+
16+
error: aborting due to previous error
17+
18+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)