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
13 changes: 10 additions & 3 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2874,6 +2874,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
span: Span,
) -> Const<'tcx> {
let tcx = self.tcx();

let ty = if !ty.has_infer() { Some(ty) } else { None };

if let LitKind::Err(guar) = *kind {
return ty::Const::new_error(tcx, guar);
}
Expand Down Expand Up @@ -2905,16 +2908,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
};

let lit_input = match expr.kind {
hir::ExprKind::Lit(lit) => Some(LitToConstInput { lit: lit.node, ty, neg: false }),
hir::ExprKind::Lit(lit) => {
Some(LitToConstInput { lit: lit.node, ty: Some(ty), neg: false })
}
hir::ExprKind::Unary(hir::UnOp::Neg, expr) => match expr.kind {
hir::ExprKind::Lit(lit) => Some(LitToConstInput { lit: lit.node, ty, neg: true }),
hir::ExprKind::Lit(lit) => {
Some(LitToConstInput { lit: lit.node, ty: Some(ty), neg: true })
}
_ => None,
},
_ => None,
};

lit_input.and_then(|l| {
if const_lit_matches_ty(tcx, &l.lit, l.ty, l.neg) {
if const_lit_matches_ty(tcx, &l.lit, ty, l.neg) {
tcx.at(expr.span)
.lit_to_const(l)
.map(|value| ty::Const::new_value(tcx, value.valtree, value.ty))
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_middle/src/ty/consts/lit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ pub struct LitToConstInput<'tcx> {
/// The absolute value of the resultant constant.
pub lit: LitKind,
/// The type of the constant.
pub ty: Ty<'tcx>,
///
/// `None` is used by const generics when the type of the constant is unknown, e.g.
/// if there are inference variables
pub ty: Option<Ty<'tcx>>,
/// If the constant is negative.
pub neg: bool,
}
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_mir_build/src/builder/expr/as_constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ pub(crate) fn as_constant_inner<'tcx>(

match *kind {
ExprKind::Literal { lit, neg } => {
let const_ = lit_to_mir_constant(tcx, LitToConstInput { lit: lit.node, ty, neg });
let const_ =
lit_to_mir_constant(tcx, LitToConstInput { lit: lit.node, ty: Some(ty), neg });

ConstOperand { span, user_ty: None, const_ }
}
Expand Down Expand Up @@ -109,6 +110,8 @@ pub(crate) fn as_constant_inner<'tcx>(
fn lit_to_mir_constant<'tcx>(tcx: TyCtxt<'tcx>, lit_input: LitToConstInput<'tcx>) -> Const<'tcx> {
let LitToConstInput { lit, ty, neg } = lit_input;

let ty = ty.expect("type of literal must be known at this point");

if let Err(guar) = ty.error_reported() {
return Const::Ty(Ty::new_error(tcx, guar), ty::Const::new_error(tcx, guar));
}
Expand Down
22 changes: 12 additions & 10 deletions compiler/rustc_mir_build/src/thir/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,25 +31,27 @@ pub(crate) fn lit_to_const<'tcx>(
.unwrap_or_else(|| bug!("expected to create ScalarInt from uint {:?}", result))
};

let (valtree, valtree_ty) = match (lit, expected_ty.kind()) {
let (valtree, valtree_ty) = match (lit, expected_ty.map(|ty| ty.kind())) {
(ast::LitKind::Str(s, _), _) => {
let str_bytes = s.as_str().as_bytes();
let valtree_ty = Ty::new_imm_ref(tcx, tcx.lifetimes.re_static, tcx.types.str_);
(ty::ValTree::from_raw_bytes(tcx, str_bytes), valtree_ty)
}
(ast::LitKind::ByteStr(byte_sym, _), ty::Ref(_, inner_ty, _))
(ast::LitKind::ByteStr(byte_sym, _), Some(ty::Ref(_, inner_ty, _)))
if let ty::Slice(ty) | ty::Array(ty, _) = inner_ty.kind()
&& let ty::Uint(UintTy::U8) = ty.kind() =>
{
(ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()), expected_ty)
(ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()), expected_ty.unwrap())
}
(ast::LitKind::ByteStr(byte_sym, _), ty::Slice(inner_ty) | ty::Array(inner_ty, _))
if tcx.features().deref_patterns()
&& let ty::Uint(UintTy::U8) = inner_ty.kind() =>
(
ast::LitKind::ByteStr(byte_sym, _),
Some(ty::Slice(inner_ty) | ty::Array(inner_ty, _)),
) if tcx.features().deref_patterns()
&& let ty::Uint(UintTy::U8) = inner_ty.kind() =>
{
// Byte string literal patterns may have type `[u8]` or `[u8; N]` if `deref_patterns` is
// enabled, in order to allow, e.g., `deref!(b"..."): Vec<u8>`.
(ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()), expected_ty)
(ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()), expected_ty.unwrap())
}
(ast::LitKind::ByteStr(byte_sym, _), _) => {
let valtree = ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str());
Expand Down Expand Up @@ -79,11 +81,11 @@ pub(crate) fn lit_to_const<'tcx>(
trunc(if neg { u128::wrapping_neg(n.get()) } else { n.get() }, i.to_unsigned());
(ty::ValTree::from_scalar_int(tcx, scalar_int), Ty::new_int(tcx, i))
}
(ast::LitKind::Int(n, ast::LitIntType::Unsuffixed), ty::Uint(ui)) if !neg => {
(ast::LitKind::Int(n, ast::LitIntType::Unsuffixed), Some(ty::Uint(ui))) if !neg => {
let scalar_int = trunc(n.get(), *ui);
(ty::ValTree::from_scalar_int(tcx, scalar_int), Ty::new_uint(tcx, *ui))
}
(ast::LitKind::Int(n, ast::LitIntType::Unsuffixed), ty::Int(i)) => {
(ast::LitKind::Int(n, ast::LitIntType::Unsuffixed), Some(ty::Int(i))) => {
// Unsigned "negation" has the same bitwise effect as signed negation,
// which gets the result we want without additional casts.
let scalar_int =
Expand All @@ -101,7 +103,7 @@ pub(crate) fn lit_to_const<'tcx>(
let bits = parse_float_into_scalar(n, fty, neg)?;
(ty::ValTree::from_scalar_int(tcx, bits), Ty::new_float(tcx, fty))
}
(ast::LitKind::Float(n, ast::LitFloatType::Unsuffixed), ty::Float(fty)) => {
(ast::LitKind::Float(n, ast::LitFloatType::Unsuffixed), Some(ty::Float(fty))) => {
let bits = parse_float_into_scalar(n, *fty, neg)?;
(ty::ValTree::from_scalar_int(tcx, bits), Ty::new_float(tcx, *fty))
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_build/src/thir/pattern/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -696,7 +696,7 @@ impl<'tcx> PatCtxt<'tcx> {
// patterns to `str`, and byte-string literal patterns to `[u8; N]` or `[u8]`.

let pat_ty = self.typeck_results.node_type(pat.hir_id);
let lit_input = LitToConstInput { lit: lit.node, ty: pat_ty, neg: *negated };
let lit_input = LitToConstInput { lit: lit.node, ty: Some(pat_ty), neg: *negated };
let constant = const_lit_matches_ty(self.tcx, &lit.node, pat_ty, *negated)
.then(|| self.tcx.at(expr.span).lit_to_const(lit_input))
.flatten()
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_ty_utils/src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ fn recurse_build<'tcx>(
}
&ExprKind::Literal { lit, neg } => {
let sp = node.span;
match tcx.at(sp).lit_to_const(LitToConstInput { lit: lit.node, ty: node.ty, neg }) {
match tcx.at(sp).lit_to_const(LitToConstInput { lit: lit.node, ty: Some(node.ty), neg })
{
Some(value) => ty::Const::new_value(tcx, value.valtree, value.ty),
None => ty::Const::new_misc_error(tcx),
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//! This test ensures compilation failure when trying to pass literals
//! without explicitly stated type as inference variables in generic arguments.
//!
//! See https://github.com/rust-lang/rust/pull/153557

#![allow(incomplete_features)]
#![feature(adt_const_params, min_generic_const_args, generic_const_parameter_types)]

fn main() {
foo::<_, { 2 }>();
//~^ ERROR: type annotations needed for the literal
let _: PC<_, { 42 }> = PC { a: 1, b: 1 };
//~^ ERROR: type annotations needed for the literal
}

struct PC<T, const N: T> {
//~^ ERROR: `T` can't be used as a const parameter type [E0741]
a: T,
}

fn foo<const N: usize, const A: [u8; N]>() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
error[E0741]: `T` can't be used as a const parameter type
--> $DIR/infer-vars-in-const-args-conflicting.rs:16:23
|
LL | struct PC<T, const N: T> {
| ^

error: type annotations needed for the literal
--> $DIR/infer-vars-in-const-args-conflicting.rs:10:16
|
LL | foo::<_, { 2 }>();
| ^

error: type annotations needed for the literal
--> $DIR/infer-vars-in-const-args-conflicting.rs:12:20
|
LL | let _: PC<_, { 42 }> = PC { a: 1, b: 1 };
| ^^

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0741`.
22 changes: 22 additions & 0 deletions tests/ui/const-generics/mgca/infer-vars-in-const-args-correct.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//! This test ensures no errors are emitted when lowering literals with
//! explicitly stated types and inference variables in the type of the const
//! generic parameter.
//!
//! See https://github.com/rust-lang/rust/pull/153557

//@check-pass

#![allow(incomplete_features)]
#![feature(adt_const_params,
min_generic_const_args,
generic_const_parameter_types,
unsized_const_params
)]

use std::marker::ConstParamTy_;

fn main() {
foo::<_, 2_i32>();
}

fn foo<T: ConstParamTy_, const N: T>() {}
Loading