Skip to content

Make lit_to_mir_constant and lit_to_const infallible #135195

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jan 9, 2025
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
34 changes: 7 additions & 27 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ use rustc_hir::{self as hir, AnonConst, GenericArg, GenericArgs, HirId};
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::ObligationCause;
use rustc_middle::middle::stability::AllowUnstable;
use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
use rustc_middle::mir::interpret::LitToConstInput;
use rustc_middle::ty::fold::fold_regions;
use rustc_middle::ty::print::PrintPolyTraitRefExt as _;
use rustc_middle::ty::{
Expand Down Expand Up @@ -2262,25 +2262,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
_ => None,
};

if let Some(lit_input) = lit_input {
// If an error occurred, ignore that it's a literal and leave reporting the error up to
// mir.
match tcx.at(expr.span).lit_to_const(lit_input) {
Ok(c) => return Some(c),
Err(_) if lit_input.ty.has_aliases() => {
// allow the `ty` to be an alias type, though we cannot handle it here
return None;
}
Err(e) => {
tcx.dcx().span_delayed_bug(
expr.span,
format!("try_lower_anon_const_lit: couldn't lit_to_const {e:?}"),
);
}
}
}

None
lit_input
// Allow the `ty` to be an alias type, though we cannot handle it here, we just go through
// the more expensive anon const code path.
.filter(|l| !l.ty.has_aliases())
.map(|l| tcx.at(expr.span).lit_to_const(l))
}

fn lower_delegation_ty(&self, idx: hir::InferDelegationKind) -> Ty<'tcx> {
Expand Down Expand Up @@ -2454,13 +2440,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
hir::PatExprKind::Lit { lit, negated } => {
let lit_input =
LitToConstInput { lit: &lit.node, ty, neg: negated };
let ct = match tcx.lit_to_const(lit_input) {
Ok(c) => c,
Err(LitToConstError::Reported(err)) => {
ty::Const::new_error(tcx, err)
}
Err(LitToConstError::TypeError) => todo!(),
};
let ct = tcx.lit_to_const(lit_input);
(ct, ty)
}

Expand Down
11 changes: 0 additions & 11 deletions compiler/rustc_middle/src/mir/interpret/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ use rustc_abi::{AddressSpace, Align, Endian, HasDataLayout, Size};
use rustc_ast::{LitKind, Mutability};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::Lock;
use rustc_errors::ErrorGuaranteed;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
Expand Down Expand Up @@ -84,16 +83,6 @@ pub struct LitToConstInput<'tcx> {
pub neg: bool,
}

/// Error type for `tcx.lit_to_const`.
#[derive(Copy, Clone, Debug, Eq, PartialEq, HashStable)]
pub enum LitToConstError {
/// The literal's inferred type did not match the expected `ty` in the input.
/// This is used for graceful error handling (`span_delayed_bug`) in
/// type checking (`Const::from_anon_const`).
TypeError,
Reported(ErrorGuaranteed),
}

#[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct AllocId(pub NonZero<u64>);

Expand Down
9 changes: 0 additions & 9 deletions compiler/rustc_middle/src/query/erase.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,14 +141,6 @@ impl EraseType for Result<rustc_abi::TyAndLayout<'_, Ty<'_>>, &ty::layout::Layou
>()];
}

impl EraseType for Result<ty::Const<'_>, mir::interpret::LitToConstError> {
type Result = [u8; size_of::<Result<ty::Const<'static>, mir::interpret::LitToConstError>>()];
}

impl EraseType for Result<mir::Const<'_>, mir::interpret::LitToConstError> {
type Result = [u8; size_of::<Result<mir::Const<'static>, mir::interpret::LitToConstError>>()];
}

impl EraseType for Result<mir::ConstAlloc<'_>, mir::interpret::ErrorHandled> {
type Result = [u8; size_of::<Result<mir::ConstAlloc<'static>, mir::interpret::ErrorHandled>>()];
}
Expand Down Expand Up @@ -296,7 +288,6 @@ trivial! {
rustc_middle::mir::interpret::AllocId,
rustc_middle::mir::interpret::CtfeProvenance,
rustc_middle::mir::interpret::ErrorHandled,
rustc_middle::mir::interpret::LitToConstError,
rustc_middle::thir::ExprId,
rustc_middle::traits::CodegenObligationError,
rustc_middle::traits::EvaluationResult,
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ use crate::middle::resolve_bound_vars::{ObjectLifetimeDefault, ResolveBoundVars,
use crate::middle::stability::{self, DeprecationEntry};
use crate::mir::interpret::{
EvalStaticInitializerRawResult, EvalToAllocationRawResult, EvalToConstValueResult,
EvalToValTreeResult, GlobalId, LitToConstError, LitToConstInput,
EvalToValTreeResult, GlobalId, LitToConstInput,
};
use crate::mir::mono::{CodegenUnit, CollectionMode, MonoItem};
use crate::query::erase::{Erase, erase, restore};
Expand Down Expand Up @@ -1268,7 +1268,7 @@ rustc_queries! {
// FIXME get rid of this with valtrees
query lit_to_const(
key: LitToConstInput<'tcx>
) -> Result<ty::Const<'tcx>, LitToConstError> {
) -> ty::Const<'tcx> {
desc { "converting literal to const" }
}

Expand Down
52 changes: 21 additions & 31 deletions compiler/rustc_mir_build/src/builder/expr/as_constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@
use rustc_abi::Size;
use rustc_ast as ast;
use rustc_hir::LangItem;
use rustc_middle::mir::interpret::{
Allocation, CTFE_ALLOC_SALT, LitToConstError, LitToConstInput, Scalar,
};
use rustc_middle::mir::interpret::{Allocation, CTFE_ALLOC_SALT, LitToConstInput, Scalar};
use rustc_middle::mir::*;
use rustc_middle::thir::*;
use rustc_middle::ty::{
self, CanonicalUserType, CanonicalUserTypeAnnotation, Ty, TyCtxt, UserTypeAnnotationIndex,
self, CanonicalUserType, CanonicalUserTypeAnnotation, Ty, TyCtxt, TypeVisitableExt as _,
UserTypeAnnotationIndex,
};
use rustc_middle::{bug, mir, span_bug};
use tracing::{instrument, trace};
Expand Down Expand Up @@ -50,16 +49,7 @@ pub(crate) fn as_constant_inner<'tcx>(
let Expr { ty, temp_lifetime: _, span, ref kind } = *expr;
match *kind {
ExprKind::Literal { lit, neg } => {
let const_ = match lit_to_mir_constant(tcx, LitToConstInput { lit: &lit.node, ty, neg })
{
Ok(c) => c,
Err(LitToConstError::Reported(guar)) => {
Const::Ty(Ty::new_error(tcx, guar), ty::Const::new_error(tcx, guar))
}
Err(LitToConstError::TypeError) => {
bug!("encountered type error in `lit_to_mir_constant`")
}
};
let const_ = lit_to_mir_constant(tcx, LitToConstInput { lit: &lit.node, ty, neg });

ConstOperand { span, user_ty: None, const_ }
}
Expand Down Expand Up @@ -108,11 +98,13 @@ pub(crate) fn as_constant_inner<'tcx>(
}

#[instrument(skip(tcx, lit_input))]
fn lit_to_mir_constant<'tcx>(
tcx: TyCtxt<'tcx>,
lit_input: LitToConstInput<'tcx>,
) -> Result<Const<'tcx>, LitToConstError> {
fn lit_to_mir_constant<'tcx>(tcx: TyCtxt<'tcx>, lit_input: LitToConstInput<'tcx>) -> Const<'tcx> {
let LitToConstInput { lit, ty, neg } = lit_input;

if let Err(guar) = ty.error_reported() {
return Const::Ty(Ty::new_error(tcx, guar), ty::Const::new_error(tcx, guar));
}

let trunc = |n| {
let width = match tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)) {
Ok(layout) => layout.size,
Expand All @@ -123,7 +115,7 @@ fn lit_to_mir_constant<'tcx>(
trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits());
let result = width.truncate(n);
trace!("trunc result: {}", result);
Ok(ConstValue::Scalar(Scalar::from_uint(result, width)))
ConstValue::Scalar(Scalar::from_uint(result, width))
};

let value = match (lit, ty.kind()) {
Expand Down Expand Up @@ -154,20 +146,18 @@ fn lit_to_mir_constant<'tcx>(
ConstValue::Scalar(Scalar::from_uint(*n, Size::from_bytes(1)))
}
(ast::LitKind::Int(n, _), ty::Uint(_)) | (ast::LitKind::Int(n, _), ty::Int(_)) => {
trunc(if neg { (n.get() as i128).overflowing_neg().0 as u128 } else { n.get() })?
}
(ast::LitKind::Float(n, _), ty::Float(fty)) => parse_float_into_constval(*n, *fty, neg)
.ok_or_else(|| {
LitToConstError::Reported(
tcx.dcx()
.delayed_bug(format!("couldn't parse float literal: {:?}", lit_input.lit)),
)
})?,
trunc(if neg { (n.get() as i128).overflowing_neg().0 as u128 } else { n.get() })
}
(ast::LitKind::Float(n, _), ty::Float(fty)) => {
parse_float_into_constval(*n, *fty, neg).unwrap()
Copy link
Contributor

Choose a reason for hiding this comment

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

delayed_bug to bug, it's unreachable I guess? 😁 though given we've got no tests for that, I don't mind merging this and reacting to a fuzzer ICE if it's reachable

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 looked into this before the holidays and if memory serves right the parser ensures we don't get anything that could fail here.

}
(ast::LitKind::Bool(b), ty::Bool) => ConstValue::Scalar(Scalar::from_bool(*b)),
(ast::LitKind::Char(c), ty::Char) => ConstValue::Scalar(Scalar::from_char(*c)),
(ast::LitKind::Err(guar), _) => return Err(LitToConstError::Reported(*guar)),
_ => return Err(LitToConstError::TypeError),
(ast::LitKind::Err(guar), _) => {
return Const::Ty(Ty::new_error(tcx, *guar), ty::Const::new_error(tcx, *guar));
}
_ => bug!("invalid lit/ty combination in `lit_to_mir_constant`: {lit:?}: {ty:?}"),
};

Ok(Const::Val(value, ty))
Const::Val(value, ty)
}
22 changes: 11 additions & 11 deletions compiler/rustc_mir_build/src/thir/constant.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use rustc_ast as ast;
use rustc_hir::LangItem;
use rustc_middle::bug;
use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
use rustc_middle::mir::interpret::LitToConstInput;
use rustc_middle::ty::{self, ScalarInt, TyCtxt, TypeVisitableExt as _};
use tracing::trace;

Expand All @@ -10,11 +10,11 @@ use crate::builder::parse_float_into_scalar;
pub(crate) fn lit_to_const<'tcx>(
tcx: TyCtxt<'tcx>,
lit_input: LitToConstInput<'tcx>,
) -> Result<ty::Const<'tcx>, LitToConstError> {
) -> ty::Const<'tcx> {
let LitToConstInput { lit, ty, neg } = lit_input;

if let Err(guar) = ty.error_reported() {
return Ok(ty::Const::new_error(tcx, guar));
return ty::Const::new_error(tcx, guar);
}

let trunc = |n| {
Expand All @@ -28,8 +28,8 @@ pub(crate) fn lit_to_const<'tcx>(
let result = width.truncate(n);
trace!("trunc result: {}", result);

Ok(ScalarInt::try_from_uint(result, width)
.unwrap_or_else(|| bug!("expected to create ScalarInt from uint {:?}", result)))
ScalarInt::try_from_uint(result, width)
.unwrap_or_else(|| bug!("expected to create ScalarInt from uint {:?}", result))
};

let valtree = match (lit, ty.kind()) {
Expand Down Expand Up @@ -57,20 +57,20 @@ pub(crate) fn lit_to_const<'tcx>(
}
(ast::LitKind::Int(n, _), ty::Uint(_)) | (ast::LitKind::Int(n, _), ty::Int(_)) => {
let scalar_int =
trunc(if neg { (n.get() as i128).overflowing_neg().0 as u128 } else { n.get() })?;
trunc(if neg { (n.get() as i128).overflowing_neg().0 as u128 } else { n.get() });
ty::ValTree::from_scalar_int(scalar_int)
}
(ast::LitKind::Bool(b), ty::Bool) => ty::ValTree::from_scalar_int((*b).into()),
(ast::LitKind::Float(n, _), ty::Float(fty)) => {
let bits = parse_float_into_scalar(*n, *fty, neg).ok_or_else(|| {
let bits = parse_float_into_scalar(*n, *fty, neg).unwrap_or_else(|| {
tcx.dcx().bug(format!("couldn't parse float literal: {:?}", lit_input.lit))
})?;
});
ty::ValTree::from_scalar_int(bits)
}
(ast::LitKind::Char(c), ty::Char) => ty::ValTree::from_scalar_int((*c).into()),
(ast::LitKind::Err(guar), _) => return Err(LitToConstError::Reported(*guar)),
_ => return Err(LitToConstError::TypeError),
(ast::LitKind::Err(guar), _) => return ty::Const::new_error(tcx, *guar),
_ => return ty::Const::new_misc_error(tcx),
};

Ok(ty::Const::new_value(tcx, valtree, ty))
ty::Const::new_value(tcx, valtree, ty)
}
9 changes: 3 additions & 6 deletions compiler/rustc_mir_build/src/thir/pattern/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use rustc_hir::pat_util::EnumerateAndAdjustIterator;
use rustc_hir::{self as hir, ByRef, Mutability, RangeEnd};
use rustc_index::Idx;
use rustc_lint as lint;
use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
use rustc_middle::mir::interpret::LitToConstInput;
use rustc_middle::thir::{
Ascription, FieldPat, LocalVarId, Pat, PatKind, PatRange, PatRangeBoundary,
};
Expand Down Expand Up @@ -669,11 +669,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {

let ct_ty = self.typeck_results.node_type(expr.hir_id);
let lit_input = LitToConstInput { lit: &lit.node, ty: ct_ty, neg };
match self.tcx.at(expr.span).lit_to_const(lit_input) {
Ok(constant) => self.const_to_pat(constant, ct_ty, expr.hir_id, lit.span).kind,
Err(LitToConstError::Reported(e)) => PatKind::Error(e),
Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"),
}
let constant = self.tcx.at(expr.span).lit_to_const(lit_input);
self.const_to_pat(constant, ct_ty, expr.hir_id, lit.span).kind
}
}

Expand Down
10 changes: 2 additions & 8 deletions compiler/rustc_ty_utils/src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use rustc_abi::{FIRST_VARIANT, VariantIdx};
use rustc_errors::ErrorGuaranteed;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::LocalDefId;
use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
use rustc_middle::mir::interpret::LitToConstInput;
use rustc_middle::query::Providers;
use rustc_middle::thir::visit;
use rustc_middle::thir::visit::Visitor;
Expand Down Expand Up @@ -118,13 +118,7 @@ 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 }) {
Ok(c) => c,
Err(LitToConstError::Reported(guar)) => ty::Const::new_error(tcx, guar),
Err(LitToConstError::TypeError) => {
bug!("encountered type error in lit_to_const")
}
}
tcx.at(sp).lit_to_const(LitToConstInput { lit: &lit.node, ty: node.ty, neg })
}
&ExprKind::NonHirLiteral { lit, user_ty: _ } => {
let val = ty::ValTree::from_scalar_int(lit);
Expand Down
6 changes: 0 additions & 6 deletions tests/crashes/114317.rs

This file was deleted.

10 changes: 0 additions & 10 deletions tests/crashes/126182.rs

This file was deleted.

22 changes: 22 additions & 0 deletions tests/ui/const-generics/generic_const_exprs/lit_type_mismatch.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//! ICE regression test for #114317 and #126182
//! Type mismatches of literals cause errors int typeck,
//! but those errors cannot be propagated to the various
//! `lit_to_const` call sites. Now `lit_to_const` just delays
//! a bug and produces an error constant on its own.

#![feature(adt_const_params)]
#![feature(generic_const_exprs)]
#![allow(incomplete_features)]

struct A<const B: () = 1, C>(C);
//~^ ERROR: generic parameters with a default must be trailing
//~| ERROR: mismatched types

struct Cond<const B: bool>;

struct Thing<T = Cond<0>>(T);
//~^ ERROR: mismatched types

impl Thing {}

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
error: generic parameters with a default must be trailing
--> $DIR/lit_type_mismatch.rs:11:16
|
LL | struct A<const B: () = 1, C>(C);
| ^

error[E0308]: mismatched types
--> $DIR/lit_type_mismatch.rs:11:24
|
LL | struct A<const B: () = 1, C>(C);
| ^ expected `()`, found integer

error[E0308]: mismatched types
--> $DIR/lit_type_mismatch.rs:17:23
|
LL | struct Thing<T = Cond<0>>(T);
| ^ expected `bool`, found integer

error: aborting due to 3 previous errors

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