Skip to content

change hir::ExprLit to take a ConstVal instead of an ast::Lit #32793

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

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 1 addition & 1 deletion mk/crates.mk
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_bo
rustc_typeck rustc_mir rustc_resolve log syntax serialize rustc_llvm \
rustc_trans rustc_privacy rustc_lint rustc_plugin \
rustc_metadata syntax_ext rustc_passes rustc_save_analysis rustc_const_eval
DEPS_rustc_lint := rustc log syntax rustc_const_eval
DEPS_rustc_lint := rustc log syntax rustc_const_eval rustc_const_math
DEPS_rustc_llvm := native:rustllvm libc std rustc_bitflags
DEPS_rustc_metadata := rustc syntax rbml rustc_const_math
DEPS_rustc_passes := syntax rustc core rustc_const_eval
Expand Down
1 change: 0 additions & 1 deletion src/librustc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ pub mod lint;
pub mod middle {
pub mod astconv_util;
pub mod expr_use_visitor; // STAGE0: increase glitch immunity
pub mod const_val;
pub mod const_qualif;
pub mod cstore;
pub mod dataflow;
Expand Down
16 changes: 10 additions & 6 deletions src/librustc/mir/repr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@
// except according to those terms.

use graphviz::IntoCow;
use middle::const_val::ConstVal;
use rustc_const_math::{ConstUsize, ConstInt};
use hir::def_id::DefId;
use rustc_const_math::{ConstUsize, ConstInt, ConstVal};
use hir::def_id::{DefId, DefIndex};
use ty::subst::Substs;
use ty::{self, AdtDef, ClosureSubsts, FnOutput, Region, Ty};
use util::ppaux;
Expand Down Expand Up @@ -999,9 +998,11 @@ impl<'tcx> Debug for Literal<'tcx> {

/// Write a `ConstVal` in a way closer to the original source code than the `Debug` output.
fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ConstVal) -> fmt::Result {
use middle::const_val::ConstVal::*;
use rustc_const_math::ConstVal::*;
match *const_val {
Float(f) => write!(fmt, "{:?}", f),
Float(f, Some(ast::FloatTy::F32)) => write!(fmt, "{}_f32", f as f32),
Float(f, Some(ast::FloatTy::F64)) => write!(fmt, "{}_f64", f),
Float(f, None) => write!(fmt, "{}", f),
Integral(n) => write!(fmt, "{}", n),
Str(ref s) => write!(fmt, "{:?}", s),
ByteStr(ref bytes) => {
Expand All @@ -1012,7 +1013,10 @@ fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ConstVal) -> fmt::Result {
write!(fmt, "b\"{}\"", escaped)
}
Bool(b) => write!(fmt, "{:?}", b),
Function(def_id) => write!(fmt, "{}", item_path_str(def_id)),
Function { krate, index } => {
let path = item_path_str(DefId { krate: krate, index: DefIndex::from_u32(index) });
write!(fmt, "{}", path)
},
Struct(node_id) | Tuple(node_id) | Array(node_id, _) | Repeat(node_id, _) =>
write!(fmt, "{}", node_to_string(node_id)),
Char(c) => write!(fmt, "{:?}", c),
Expand Down
3 changes: 1 addition & 2 deletions src/librustc/mir/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,11 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use middle::const_val::ConstVal;
use hir::def_id::DefId;
use ty::subst::Substs;
use ty::{ClosureSubsts, FnOutput, Region, Ty};
use mir::repr::*;
use rustc_const_math::ConstUsize;
use rustc_const_math::{ConstUsize, ConstVal};
use rustc_data_structures::tuple_slice::TupleSlice;
use syntax::codemap::Span;

Expand Down
4 changes: 2 additions & 2 deletions src/librustc_const_eval/check_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use self::Usefulness::*;
use self::WitnessPreference::*;

use rustc::dep_graph::DepNode;
use rustc::middle::const_val::ConstVal;
use rustc_const_math::ConstVal;
use ::{eval_const_expr, eval_const_expr_partial, compare_const_vals};
use ::{const_expr_to_pat, lookup_const_by_id};
use ::EvalHint::ExprTypeChecked;
Expand Down Expand Up @@ -275,7 +275,7 @@ fn check_for_static_nan(cx: &MatchCheckCtxt, pat: &Pat) {
pat.walk(|p| {
if let PatKind::Lit(ref expr) = p.node {
match eval_const_expr_partial(cx.tcx, &expr, ExprTypeChecked, None) {
Ok(ConstVal::Float(f)) if f.is_nan() => {
Ok(ConstVal::Float(f, _)) if f.is_nan() => {
span_warn!(cx.tcx.sess, p.span, E0003,
"unmatchable NaN in pattern, \
use the is_nan method in a guard instead");
Expand Down
67 changes: 42 additions & 25 deletions src/librustc_const_eval/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@

//#![allow(non_camel_case_types)]

use rustc::middle::const_val::ConstVal::*;
use rustc::middle::const_val::ConstVal;
use rustc_const_math::ConstVal::*;
use self::ErrKind::*;
use self::EvalHint::*;

Expand All @@ -20,7 +19,7 @@ use rustc::hir::map::blocks::FnLikeNode;
use rustc::middle::cstore::{self, CrateStore, InlinedItem};
use rustc::{infer, traits};
use rustc::hir::def::Def;
use rustc::hir::def_id::DefId;
use rustc::hir::def_id::{DefId, DefIndex};
use rustc::hir::pat_util::def_to_path;
use rustc::ty::{self, Ty, TyCtxt, subst};
use rustc::ty::util::IntTypeExt;
Expand Down Expand Up @@ -413,6 +412,7 @@ pub enum ErrKind {
IntermediateUnsignedNegative,
/// Expected, Got
TypeMismatch(String, ConstInt),
FloatTypeMismatch,
BadType(ConstVal),
}

Expand Down Expand Up @@ -480,6 +480,8 @@ impl ConstEvalErr {
expected, got.description()).into_cow()
},
BadType(ref i) => format!("value of wrong type: {:?}", i).into_cow(),
FloatTypeMismatch => "tried to apply a binary operation to values of \
different float types".into_cow(),
}
}
}
Expand Down Expand Up @@ -600,7 +602,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
}
}
match eval_const_expr_partial(tcx, &inner, ty_hint, fn_args)? {
Float(f) => Float(-f),
Float(f, ft) => Float(-f, ft),
Integral(i) => Integral(math!(e, -i)),
const_val => signal!(e, NegateOn(const_val)),
}
Expand All @@ -624,13 +626,15 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
// not inferred
match (eval_const_expr_partial(tcx, &a, ty_hint, fn_args)?,
eval_const_expr_partial(tcx, &b, b_ty, fn_args)?) {
(Float(a), Float(b)) => {
(Float(_, Some(at)), Float(_, Some(bt))) if at != bt => signal!(e, FloatTypeMismatch),
(Float(a, at), Float(b, bt)) => {
let ft = at.or(bt);
match op.node {
hir::BiAdd => Float(a + b),
hir::BiSub => Float(a - b),
hir::BiMul => Float(a * b),
hir::BiDiv => Float(a / b),
hir::BiRem => Float(a % b),
hir::BiAdd => Float(a + b, ft),
hir::BiSub => Float(a - b, ft),
hir::BiMul => Float(a * b, ft),
hir::BiDiv => Float(a / b, ft),
hir::BiRem => Float(a % b, ft),
hir::BiEq => Bool(a == b),
hir::BiLt => Bool(a < b),
hir::BiLe => Bool(a <= b),
Expand Down Expand Up @@ -765,15 +769,16 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
signal!(e, NonConstPath);
}
},
Def::Method(id) | Def::Fn(id) => Function(id),
Def::Method(id) |
Def::Fn(id) => Function { krate: id.krate, index: id.index.as_u32() },
_ => signal!(e, NonConstPath),
}
}
hir::ExprCall(ref callee, ref args) => {
let sub_ty_hint = ty_hint.erase_hint();
let callee_val = eval_const_expr_partial(tcx, callee, sub_ty_hint, fn_args)?;
let did = match callee_val {
Function(did) => did,
Function { krate, index } => DefId { krate: krate, index: DefIndex::from_u32(index) },
Struct(_) => signal!(e, UnimplementedConstVal("tuple struct constructors")),
callee => signal!(e, CallOn(callee)),
};
Expand Down Expand Up @@ -1066,22 +1071,24 @@ fn cast_const_int<'tcx>(tcx: &TyCtxt<'tcx>, val: ConstInt, ty: ty::Ty) -> CastRe
Err(_) => Ok(Integral(Usize(ConstUsize::Us32(v as u32)))),
}
},
ty::TyFloat(ast::FloatTy::F64) if val.is_negative() => {
ty::TyFloat(ft @ ast::FloatTy::F64) if val.is_negative() => {
// FIXME: this could probably be prettier
// there's no easy way to turn an `Infer` into a f64
let val = (-val).map_err(Math)?;
let val = val.to_u64().unwrap() as f64;
let val = -val;
Ok(Float(val))
Ok(Float(val, Some(ft)))
},
ty::TyFloat(ast::FloatTy::F64) => Ok(Float(val.to_u64().unwrap() as f64)),
ty::TyFloat(ast::FloatTy::F32) if val.is_negative() => {
ty::TyFloat(ft @ ast::FloatTy::F64) => Ok(Float(val.to_u64().unwrap() as f64, Some(ft))),
ty::TyFloat(ft @ ast::FloatTy::F32) if val.is_negative() => {
let val = (-val).map_err(Math)?;
let val = val.to_u64().unwrap() as f32;
let val = -val;
Ok(Float(val as f64))
Ok(Float(val as f64, Some(ft)))
},
ty::TyFloat(ft @ ast::FloatTy::F32) => {
Ok(Float(val.to_u64().unwrap() as f32 as f64, Some(ft)))
},
ty::TyFloat(ast::FloatTy::F32) => Ok(Float(val.to_u64().unwrap() as f32 as f64)),
ty::TyRawPtr(_) => Err(ErrKind::UnimplementedConstVal("casting an address to a raw ptr")),
_ => Err(CannotCast),
}
Expand All @@ -1092,8 +1099,8 @@ fn cast_const_float<'tcx>(tcx: &TyCtxt<'tcx>, f: f64, ty: ty::Ty) -> CastResult
ty::TyInt(_) if f >= 0.0 => cast_const_int(tcx, Infer(f as u64), ty),
ty::TyInt(_) => cast_const_int(tcx, InferSigned(f as i64), ty),
ty::TyUint(_) if f >= 0.0 => cast_const_int(tcx, Infer(f as u64), ty),
ty::TyFloat(ast::FloatTy::F64) => Ok(Float(f)),
ty::TyFloat(ast::FloatTy::F32) => Ok(Float(f as f32 as f64)),
ty::TyFloat(ft @ ast::FloatTy::F64) => Ok(Float(f, Some(ft))),
ty::TyFloat(ft @ ast::FloatTy::F32) => Ok(Float(f as f32 as f64, Some(ft))),
_ => Err(CannotCast),
}
}
Expand All @@ -1102,9 +1109,9 @@ fn cast_const<'tcx>(tcx: &TyCtxt<'tcx>, val: ConstVal, ty: ty::Ty) -> CastResult
match val {
Integral(i) => cast_const_int(tcx, i, ty),
Bool(b) => cast_const_int(tcx, Infer(b as u64), ty),
Float(f) => cast_const_float(tcx, f, ty),
Float(f, _) => cast_const_float(tcx, f, ty),
Char(c) => cast_const_int(tcx, Infer(c as u64), ty),
Function(_) => Err(UnimplementedConstVal("casting fn pointers")),
Function { .. } => Err(UnimplementedConstVal("casting fn pointers")),
_ => Err(CannotCast),
}
}
Expand Down Expand Up @@ -1145,10 +1152,17 @@ fn lit_to_const<'tcx>(lit: &ast::LitKind,
infer(Infer(n), tcx, &ty::TyUint(ity), span).map(Integral)
},

LitKind::Float(ref n, _) |
LitKind::Float(ref n, fty) => {
if let Ok(x) = n.parse::<f64>() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this supposed to do a double-rounding?

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't know why anyone would want to do that, but ConstVal doesn't have separate variants for f64 and f32 so avoiding the double rounding doesn't seem possible without semi-large changes all throughout const eval. I've been meaning to find a short example program that demonstrates the double-rounding and file an issue. In any case, fixing this existing brokenness seems orthogonal to and out of scope for this PR.

Copy link
Contributor

Choose a reason for hiding this comment

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

There's #32805 which is vaguely relevant.

Ok(Float(x, Some(fty)))
} else {
// FIXME(#31407) this is only necessary because float parsing is buggy
span_bug!(span, "could not evaluate float literal (see issue #31407)");
}
}
LitKind::FloatUnsuffixed(ref n) => {
if let Ok(x) = n.parse::<f64>() {
Ok(Float(x))
Ok(Float(x, None))
} else {
// FIXME(#31407) this is only necessary because float parsing is buggy
span_bug!(span, "could not evaluate float literal (see issue #31407)");
Expand All @@ -1162,7 +1176,10 @@ fn lit_to_const<'tcx>(lit: &ast::LitKind,
pub fn compare_const_vals(a: &ConstVal, b: &ConstVal) -> Option<Ordering> {
match (a, b) {
(&Integral(a), &Integral(b)) => a.try_cmp(b).ok(),
(&Float(a), &Float(b)) => {
(&Float(a, at), &Float(b, bt)) => {
if at != bt {
return None;
}
// This is pretty bad but it is the existing behavior.
Some(if a == b {
Ordering::Equal
Expand Down
2 changes: 2 additions & 0 deletions src/librustc_const_math/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,10 @@ mod int;
mod us;
mod is;
mod err;
mod val;

pub use int::*;
pub use us::*;
pub use is::*;
pub use err::ConstMathErr;
pub use val::*;
24 changes: 14 additions & 10 deletions src/librustc/middle/const_val.rs → src/librustc_const_math/val.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,24 @@
use syntax::parse::token::InternedString;
use syntax::ast;
use std::rc::Rc;
use hir::def_id::DefId;
use std::hash;
use std::mem::transmute;
use rustc_const_math::*;
use self::ConstVal::*;
use ConstInt;

#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub enum ConstVal {
Float(f64),
Float(f64, Option<ast::FloatTy>),
Integral(ConstInt),
Str(InternedString),
ByteStr(Rc<Vec<u8>>),
Bool(bool),
Struct(ast::NodeId),
Tuple(ast::NodeId),
Function(DefId),
Function {
krate: ast::CrateNum,
index: u32,
},
Array(ast::NodeId, u64),
Repeat(ast::NodeId, u64),
Char(char),
Expand All @@ -39,14 +41,14 @@ pub enum ConstVal {
impl hash::Hash for ConstVal {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
match *self {
Float(a) => unsafe { transmute::<_,u64>(a) }.hash(state),
Float(a, _) => unsafe { transmute::<_,u64>(a) }.hash(state),
Integral(a) => a.hash(state),
Str(ref a) => a.hash(state),
ByteStr(ref a) => a.hash(state),
Bool(a) => a.hash(state),
Struct(a) => a.hash(state),
Tuple(a) => a.hash(state),
Function(a) => a.hash(state),
Function { krate, index } => { krate.hash(state); index.hash(state) },
Array(a, n) => { a.hash(state); n.hash(state) },
Repeat(a, n) => { a.hash(state); n.hash(state) },
Char(c) => c.hash(state),
Expand All @@ -62,14 +64,16 @@ impl hash::Hash for ConstVal {
impl PartialEq for ConstVal {
fn eq(&self, other: &ConstVal) -> bool {
match (self, other) {
(&Float(a), &Float(b)) => unsafe{transmute::<_,u64>(a) == transmute::<_,u64>(b)},
(&Float(a, _), &Float(b, _)) => unsafe{transmute::<_,u64>(a) == transmute::<_,u64>(b)},
(&Integral(a), &Integral(b)) => a == b,
(&Str(ref a), &Str(ref b)) => a == b,
(&ByteStr(ref a), &ByteStr(ref b)) => a == b,
(&Bool(a), &Bool(b)) => a == b,
(&Struct(a), &Struct(b)) => a == b,
(&Tuple(a), &Tuple(b)) => a == b,
(&Function(a), &Function(b)) => a == b,
(&Function { krate, index }, &Function{ krate: bk, index: bi }) => {
(krate == bk) && (index == bi)
},
(&Array(a, an), &Array(b, bn)) => (a == b) && (an == bn),
(&Repeat(a, an), &Repeat(b, bn)) => (a == b) && (an == bn),
(&Char(a), &Char(b)) => a == b,
Expand All @@ -84,14 +88,14 @@ impl Eq for ConstVal { }
impl ConstVal {
pub fn description(&self) -> &'static str {
match *self {
Float(_) => "float",
Float(_, _) => "float",
Integral(i) => i.description(),
Str(_) => "string literal",
ByteStr(_) => "byte string literal",
Bool(_) => "boolean",
Struct(_) => "struct",
Tuple(_) => "tuple",
Function(_) => "function definition",
Function {..} => "function definition",
Array(..) => "array",
Repeat(..) => "repeat",
Char(..) => "char",
Expand Down
1 change: 1 addition & 0 deletions src/librustc_lint/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ log = { path = "../liblog" }
rustc = { path = "../librustc" }
rustc_back = { path = "../librustc_back" }
rustc_const_eval = { path = "../librustc_const_eval" }
rustc_const_math = { path = "../librustc_const_math" }
syntax = { path = "../libsyntax" }
1 change: 1 addition & 0 deletions src/librustc_lint/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ extern crate rustc;
extern crate log;
extern crate rustc_back;
extern crate rustc_const_eval;
extern crate rustc_const_math;

pub use rustc::lint as lint;
pub use rustc::middle as middle;
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_lint/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use rustc::hir::def_id::DefId;
use rustc::infer;
use rustc::ty::subst::Substs;
use rustc::ty::{self, Ty, TyCtxt};
use middle::const_val::ConstVal;
use rustc_const_math::ConstVal;
use rustc_const_eval::eval_const_expr_partial;
use rustc_const_eval::EvalHint::ExprTypeChecked;
use util::nodemap::{FnvHashSet};
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir/build/matches/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

use build::{BlockAnd, BlockAndExtension, Builder};
use rustc_data_structures::fnv::FnvHashMap;
use rustc::middle::const_val::ConstVal;
use rustc_const_math::ConstVal;
use rustc::ty::{AdtDef, Ty};
use rustc::mir::repr::*;
use hair::*;
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir/build/matches/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use build::Builder;
use build::matches::{Candidate, MatchPair, Test, TestKind};
use hair::*;
use rustc_data_structures::fnv::FnvHashMap;
use rustc::middle::const_val::ConstVal;
use rustc_const_math::ConstVal;
use rustc::ty::{self, Ty};
use rustc::mir::repr::*;
use syntax::codemap::Span;
Expand Down
Loading