eval.rs 26.3 KB
Newer Older
1
// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
2 3 4 5 6 7 8 9 10
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

11
use rustc::middle::const_val::ConstVal::*;
12
use rustc::middle::const_val::ConstAggregate::*;
13
use rustc::middle::const_val::ErrKind::*;
14
use rustc::middle::const_val::{ByteArray, ConstVal, ConstEvalErr, EvalResult, ErrKind};
15

16
use rustc::hir::map::blocks::FnLikeNode;
17
use rustc::hir::def::{Def, CtorKind};
18
use rustc::hir::def_id::DefId;
19
use rustc::ty::{self, Ty, TyCtxt};
O
Oliver Schneider 已提交
20
use rustc::ty::layout::LayoutOf;
21
use rustc::ty::util::IntTypeExt;
22
use rustc::ty::subst::{Substs, Subst};
23
use rustc::util::common::ErrorReported;
24
use rustc::util::nodemap::NodeMap;
25

26
use syntax::abi::Abi;
27
use syntax::ast;
28
use syntax::attr;
29
use rustc::hir::{self, Expr};
30
use syntax_pos::Span;
31

32
use std::cmp::Ordering;
33

34
use rustc_const_math::*;
35 36 37 38 39 40
macro_rules! signal {
    ($e:expr, $exn:expr) => {
        return Err(ConstEvalErr { span: $e.span, kind: $exn })
    }
}

O
Oliver Schneider 已提交
41 42 43 44
macro_rules! math {
    ($e:expr, $op:expr) => {
        match $op {
            Ok(val) => val,
45
            Err(e) => signal!($e, ErrKind::from(e)),
O
Oliver Schneider 已提交
46 47 48 49
        }
    }
}

50 51
/// * `DefId` is the id of the constant.
/// * `Substs` is the monomorphized substitutions for the expression.
52
pub fn lookup_const_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
53
                                    key: ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>)
54
                                    -> Option<(DefId, &'tcx Substs<'tcx>)> {
O
Oliver Schneider 已提交
55 56 57 58 59 60
    ty::Instance::resolve(
        tcx,
        key.param_env,
        key.value.0,
        key.value.1,
    ).map(|instance| (instance.def_id(), instance.substs))
61 62
}

63 64
pub struct ConstContext<'a, 'tcx: 'a> {
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
65
    tables: &'a ty::TypeckTables<'tcx>,
66
    param_env: ty::ParamEnv<'tcx>,
67
    substs: &'tcx Substs<'tcx>,
68
    fn_args: Option<NodeMap<&'tcx ty::Const<'tcx>>>
69 70
}

71
impl<'a, 'tcx> ConstContext<'a, 'tcx> {
72
    pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
73 74 75
               param_env_and_substs: ty::ParamEnvAnd<'tcx, &'tcx Substs<'tcx>>,
               tables: &'a ty::TypeckTables<'tcx>)
               -> Self {
76
        ConstContext {
77
            tcx,
78
            param_env: param_env_and_substs.param_env,
79
            tables,
80
            substs: param_env_and_substs.value,
81 82 83
            fn_args: None
        }
    }
84

85
    /// Evaluate a constant expression in a context where the expression isn't
B
Bastien Orivel 已提交
86
    /// guaranteed to be evaluable.
87
    pub fn eval(&self, e: &'tcx Expr) -> EvalResult<'tcx> {
88 89 90 91
        if self.tables.tainted_by_errors {
            signal!(e, TypeckError);
        }
        eval_const_expr_partial(self, e)
92 93
    }
}
94

95
type CastResult<'tcx> = Result<ConstVal<'tcx>, ErrKind<'tcx>>;
96

97
fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
98
                                     e: &'tcx Expr) -> EvalResult<'tcx> {
O
Oliver Schneider 已提交
99
    trace!("eval_const_expr_partial: {:?}", e);
100
    let tcx = cx.tcx;
101 102
    let ty = cx.tables.expr_ty(e).subst(tcx, cx.substs);
    let mk_const = |val| tcx.mk_const(ty::Const { val, ty });
103

104
    let result = match e.node {
105
      hir::ExprUnary(hir::UnNeg, ref inner) => {
O
Oliver Schneider 已提交
106
        // unary neg literals already got their sign during creation
107 108 109
        if let hir::ExprLit(ref lit) = inner.node {
            use syntax::ast::*;
            use syntax::ast::LitIntType::*;
110 111 112 113 114
            const I8_OVERFLOW: u128 = i8::min_value() as u8 as u128;
            const I16_OVERFLOW: u128 = i16::min_value() as u16 as u128;
            const I32_OVERFLOW: u128 = i32::min_value() as u32 as u128;
            const I64_OVERFLOW: u128 = i64::min_value() as u64 as u128;
            const I128_OVERFLOW: u128 = i128::min_value() as u128;
115
            let negated = match (&lit.node, &ty.sty) {
116
                (&LitKind::Int(I8_OVERFLOW, _), &ty::TyInt(IntTy::I8)) |
117
                (&LitKind::Int(I8_OVERFLOW, Signed(IntTy::I8)), _) => {
118
                    Some(I8(i8::min_value()))
119
                },
120
                (&LitKind::Int(I16_OVERFLOW, _), &ty::TyInt(IntTy::I16)) |
121
                (&LitKind::Int(I16_OVERFLOW, Signed(IntTy::I16)), _) => {
122
                    Some(I16(i16::min_value()))
123
                },
124
                (&LitKind::Int(I32_OVERFLOW, _), &ty::TyInt(IntTy::I32)) |
125
                (&LitKind::Int(I32_OVERFLOW, Signed(IntTy::I32)), _) => {
126
                    Some(I32(i32::min_value()))
127
                },
128
                (&LitKind::Int(I64_OVERFLOW, _), &ty::TyInt(IntTy::I64)) |
129
                (&LitKind::Int(I64_OVERFLOW, Signed(IntTy::I64)), _) => {
130
                    Some(I64(i64::min_value()))
131
                },
132
                (&LitKind::Int(I128_OVERFLOW, _), &ty::TyInt(IntTy::I128)) |
S
Simonas Kazlauskas 已提交
133
                (&LitKind::Int(I128_OVERFLOW, Signed(IntTy::I128)), _) => {
134
                    Some(I128(i128::min_value()))
135
                },
136 137
                (&LitKind::Int(n, _), &ty::TyInt(IntTy::Isize)) |
                (&LitKind::Int(n, Signed(IntTy::Isize)), _) => {
138
                    match tcx.sess.target.isize_ty {
139
                        IntTy::I16 => if n == I16_OVERFLOW {
140 141 142
                            Some(Isize(Is16(i16::min_value())))
                        } else {
                            None
143 144
                        },
                        IntTy::I32 => if n == I32_OVERFLOW {
145 146 147
                            Some(Isize(Is32(i32::min_value())))
                        } else {
                            None
148 149
                        },
                        IntTy::I64 => if n == I64_OVERFLOW {
150 151 152
                            Some(Isize(Is64(i64::min_value())))
                        } else {
                            None
153
                        },
154
                        _ => span_bug!(e.span, "typeck error")
155 156
                    }
                },
157 158 159
                _ => None
            };
            if let Some(i) = negated {
160
                return Ok(mk_const(Integral(i)));
161
            }
O
Oliver Schneider 已提交
162
        }
163
        mk_const(match cx.eval(inner)?.val {
164
          Float(f) => Float(-f),
O
Oliver Schneider 已提交
165
          Integral(i) => Integral(math!(e, -i)),
166
          _ => signal!(e, TypeckError)
167
        })
168
      }
169
      hir::ExprUnary(hir::UnNot, ref inner) => {
170
        mk_const(match cx.eval(inner)?.val {
O
Oliver Schneider 已提交
171
          Integral(i) => Integral(math!(e, !i)),
172
          Bool(b) => Bool(!b),
173
          _ => signal!(e, TypeckError)
174
        })
175
      }
176
      hir::ExprUnary(hir::UnDeref, _) => signal!(e, UnimplementedConstVal("deref operation")),
177
      hir::ExprBinary(op, ref a, ref b) => {
O
Oliver Schneider 已提交
178 179 180 181
        // technically, if we don't have type hints, but integral eval
        // gives us a type through a type-suffix, cast or const def type
        // we need to re-eval the other value of the BinOp if it was
        // not inferred
182
        mk_const(match (cx.eval(a)?.val, cx.eval(b)?.val) {
183
          (Float(a), Float(b)) => {
184
            use std::cmp::Ordering::*;
185
            match op.node {
186 187 188 189 190 191 192 193 194 195 196
              hir::BiAdd => Float(math!(e, a + b)),
              hir::BiSub => Float(math!(e, a - b)),
              hir::BiMul => Float(math!(e, a * b)),
              hir::BiDiv => Float(math!(e, a / b)),
              hir::BiRem => Float(math!(e, a % b)),
              hir::BiEq => Bool(math!(e, a.try_cmp(b)) == Equal),
              hir::BiLt => Bool(math!(e, a.try_cmp(b)) == Less),
              hir::BiLe => Bool(math!(e, a.try_cmp(b)) != Greater),
              hir::BiNe => Bool(math!(e, a.try_cmp(b)) != Equal),
              hir::BiGe => Bool(math!(e, a.try_cmp(b)) != Less),
              hir::BiGt => Bool(math!(e, a.try_cmp(b)) == Greater),
197
              _ => span_bug!(e.span, "typeck error"),
198 199
            }
          }
O
Oliver Schneider 已提交
200 201
          (Integral(a), Integral(b)) => {
            use std::cmp::Ordering::*;
202
            match op.node {
O
Oliver Schneider 已提交
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
              hir::BiAdd => Integral(math!(e, a + b)),
              hir::BiSub => Integral(math!(e, a - b)),
              hir::BiMul => Integral(math!(e, a * b)),
              hir::BiDiv => Integral(math!(e, a / b)),
              hir::BiRem => Integral(math!(e, a % b)),
              hir::BiBitAnd => Integral(math!(e, a & b)),
              hir::BiBitOr => Integral(math!(e, a | b)),
              hir::BiBitXor => Integral(math!(e, a ^ b)),
              hir::BiShl => Integral(math!(e, a << b)),
              hir::BiShr => Integral(math!(e, a >> b)),
              hir::BiEq => Bool(math!(e, a.try_cmp(b)) == Equal),
              hir::BiLt => Bool(math!(e, a.try_cmp(b)) == Less),
              hir::BiLe => Bool(math!(e, a.try_cmp(b)) != Greater),
              hir::BiNe => Bool(math!(e, a.try_cmp(b)) != Equal),
              hir::BiGe => Bool(math!(e, a.try_cmp(b)) != Less),
              hir::BiGt => Bool(math!(e, a.try_cmp(b)) == Greater),
219
              _ => span_bug!(e.span, "typeck error"),
220 221
            }
          }
222 223
          (Bool(a), Bool(b)) => {
            Bool(match op.node {
224 225 226 227 228 229 230
              hir::BiAnd => a && b,
              hir::BiOr => a || b,
              hir::BiBitXor => a ^ b,
              hir::BiBitAnd => a & b,
              hir::BiBitOr => a | b,
              hir::BiEq => a == b,
              hir::BiNe => a != b,
231 232 233 234
              hir::BiLt => a < b,
              hir::BiLe => a <= b,
              hir::BiGe => a >= b,
              hir::BiGt => a > b,
235
              _ => span_bug!(e.span, "typeck error"),
236
             })
237
          }
238 239 240 241 242 243 244 245 246 247 248
          (Char(a), Char(b)) => {
            Bool(match op.node {
              hir::BiEq => a == b,
              hir::BiNe => a != b,
              hir::BiLt => a < b,
              hir::BiLe => a <= b,
              hir::BiGe => a >= b,
              hir::BiGt => a > b,
              _ => span_bug!(e.span, "typeck error"),
             })
          }
249

250
          _ => signal!(e, MiscBinaryOp),
251
        })
252
      }
253
      hir::ExprCast(ref base, _) => {
254
        let base_val = cx.eval(base)?;
255
        let base_ty = cx.tables.expr_ty(base).subst(tcx, cx.substs);
256
        if ty == base_ty {
257 258
            base_val
        } else {
259 260
            match cast_const(tcx, base_val.val, ty) {
                Ok(val) => mk_const(val),
261 262
                Err(kind) => signal!(e, kind),
            }
263
        }
264
      }
265
      hir::ExprPath(ref qpath) => {
266
        let substs = cx.tables.node_substs(e.hir_id).subst(tcx, cx.substs);
267
          match cx.tables.qpath_def(qpath, e.hir_id) {
268 269
              Def::Const(def_id) |
              Def::AssociatedConst(def_id) => {
O
Oliver Schneider 已提交
270
                    let substs = tcx.normalize_associated_type_in_env(&substs, cx.param_env);
271
                    match tcx.at(e.span).const_eval(cx.param_env.and((def_id, substs))) {
272 273 274 275 276 277 278 279
                        Ok(val) => val,
                        Err(ConstEvalErr { kind: TypeckError, .. }) => {
                            signal!(e, TypeckError);
                        }
                        Err(err) => {
                            debug!("bad reference: {:?}, {:?}", err.description(), err.span);
                            signal!(e, ErroneousReferencedConstant(box err))
                        },
280
                    }
281
              },
282
              Def::VariantCtor(variant_def, CtorKind::Const) => {
283
                mk_const(Variant(variant_def))
284 285 286
              }
              Def::VariantCtor(_, CtorKind::Fn) => {
                  signal!(e, UnimplementedConstVal("enum variants"));
287
              }
288
              Def::StructCtor(_, CtorKind::Const) => {
289
                  mk_const(Aggregate(Struct(&[])))
290
              }
291 292 293
              Def::StructCtor(_, CtorKind::Fn) => {
                  signal!(e, UnimplementedConstVal("tuple struct constructors"))
              }
294 295
              Def::Local(id) => {
                  debug!("Def::Local({:?}): {:?}", id, cx.fn_args);
296 297
                  if let Some(&val) = cx.fn_args.as_ref().and_then(|args| args.get(&id)) {
                      val
298
                  } else {
299
                      signal!(e, NonConstPath);
300 301
                  }
              },
302
              Def::Method(id) | Def::Fn(id) => mk_const(Function(id, substs)),
303
              Def::Err => span_bug!(e.span, "typeck error"),
304 305
              _ => signal!(e, NonConstPath),
          }
306
      }
307
      hir::ExprCall(ref callee, ref args) => {
308
          let (def_id, substs) = match cx.eval(callee)?.val {
309
              Function(def_id, substs) => (def_id, substs),
310
              _ => signal!(e, TypeckError),
311
          };
312

313 314
          if tcx.fn_sig(def_id).abi() == Abi::RustIntrinsic {
            let layout_of = |ty: Ty<'tcx>| {
315
                let ty = tcx.erase_regions(&ty);
O
Oliver Schneider 已提交
316
                (tcx.at(e.span), cx.param_env).layout_of(ty).map_err(|err| {
317 318
                    ConstEvalErr { span: e.span, kind: LayoutError(err) }
                })
319
            };
320
            match &tcx.item_name(def_id)[..] {
321
                "size_of" => {
O
Oliver Schneider 已提交
322
                    let size = layout_of(substs.type_at(0))?.size.bytes();
323
                    return Ok(mk_const(Integral(Usize(ConstUsize::new(size,
324
                        tcx.sess.target.usize_ty).unwrap()))));
325 326
                }
                "min_align_of" => {
O
Oliver Schneider 已提交
327
                    let align = layout_of(substs.type_at(0))?.align.abi();
328
                    return Ok(mk_const(Integral(Usize(ConstUsize::new(align,
329
                        tcx.sess.target.usize_ty).unwrap()))));
330
                }
331 332 333 334
                "type_id" => {
                    let type_id = tcx.type_id_hash(substs.type_at(0));
                    return Ok(mk_const(Integral(U64(type_id))));
                }
335 336 337 338
                _ => signal!(e, TypeckError)
            }
          }

339 340 341 342 343 344 345 346 347 348 349
          let body = if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
            if let Some(fn_like) = FnLikeNode::from_node(tcx.hir.get(node_id)) {
                if fn_like.constness() == hir::Constness::Const {
                    tcx.hir.body(fn_like.body())
                } else {
                    signal!(e, TypeckError)
                }
            } else {
                signal!(e, TypeckError)
            }
          } else {
T
Taylor Cramer 已提交
350
            if tcx.is_const_fn(def_id) {
351
                tcx.extern_const_body(def_id).body
352 353 354
            } else {
                signal!(e, TypeckError)
            }
355
          };
356

357 358
          let arg_ids = body.arguments.iter().map(|arg| match arg.pat.node {
               hir::PatKind::Binding(_, canonical_id, _, _) => Some(canonical_id),
359 360
               _ => None
           }).collect::<Vec<_>>();
361
          assert_eq!(arg_ids.len(), args.len());
362

363 364
          let mut call_args = NodeMap();
          for (arg, arg_expr) in arg_ids.into_iter().zip(args.iter()) {
365
              let arg_val = cx.eval(arg_expr)?;
366
              debug!("const call arg: {:?}", arg);
367 368
              if let Some(id) = arg {
                assert!(call_args.insert(id, arg_val).is_none());
369
              }
370 371
          }
          debug!("const call({:?})", call_args);
372
          let callee_cx = ConstContext {
373 374
            tcx,
            param_env: cx.param_env,
375
            tables: tcx.typeck_tables_of(def_id),
376
            substs,
377 378
            fn_args: Some(call_args)
          };
379
          callee_cx.eval(&body.value)?
380
      },
381 382
      hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ty) {
          Ok(val) => mk_const(val),
O
Oliver Schneider 已提交
383 384
          Err(err) => signal!(e, err),
      },
385
      hir::ExprBlock(ref block) => {
386
        match block.expr {
387
            Some(ref expr) => cx.eval(expr)?,
388
            None => mk_const(Aggregate(Tuple(&[]))),
389 390
        }
      }
391
      hir::ExprType(ref e, _) => cx.eval(e)?,
392
      hir::ExprTup(ref fields) => {
393
        let values = fields.iter().map(|e| cx.eval(e)).collect::<Result<Vec<_>, _>>()?;
394
        mk_const(Aggregate(Tuple(tcx.alloc_const_slice(&values))))
395 396
      }
      hir::ExprStruct(_, ref fields, _) => {
397
        mk_const(Aggregate(Struct(tcx.alloc_name_const_slice(&fields.iter().map(|f| {
398
            cx.eval(&f.expr).map(|v| (f.name.node, v))
399
        }).collect::<Result<Vec<_>, _>>()?))))
400
      }
401
      hir::ExprIndex(ref arr, ref idx) => {
402
        if !tcx.sess.features.borrow().const_indexing {
403
            signal!(e, IndexOpFeatureGated);
404
        }
405
        let arr = cx.eval(arr)?;
406
        let idx = match cx.eval(idx)?.val {
407
            Integral(Usize(i)) => i.as_u64(),
408
            _ => signal!(idx, IndexNotUsize),
409
        };
O
Oliver Schneider 已提交
410
        assert_eq!(idx as usize as u64, idx);
411
        match arr.val {
412 413 414
            Aggregate(Array(v)) => {
                if let Some(&elem) = v.get(idx as usize) {
                    elem
415 416 417 418
                } else {
                    let n = v.len() as u64;
                    signal!(e, IndexOutOfBounds { len: n, index: idx })
                }
419
            }
420

421
            Aggregate(Repeat(.., n)) if idx >= n => {
422 423
                signal!(e, IndexOutOfBounds { len: n, index: idx })
            }
424
            Aggregate(Repeat(elem, _)) => elem,
425

426 427
            ByteStr(b) if idx >= b.data.len() as u64 => {
                signal!(e, IndexOutOfBounds { len: b.data.len() as u64, index: idx })
428
            }
429
            ByteStr(b) => {
430
                mk_const(Integral(U8(b.data[idx as usize])))
O
Oliver Schneider 已提交
431
            },
432 433 434 435

            _ => signal!(e, IndexedNonVec),
        }
      }
436
      hir::ExprArray(ref v) => {
437
        let values = v.iter().map(|e| cx.eval(e)).collect::<Result<Vec<_>, _>>()?;
438
        mk_const(Aggregate(Array(tcx.alloc_const_slice(&values))))
439
      }
440
      hir::ExprRepeat(ref elem, _) => {
441
          let n = match ty.sty {
442
            ty::TyArray(_, n) => n.val.to_const_int().unwrap().to_u64().unwrap(),
443
            _ => span_bug!(e.span, "typeck error")
444
          };
445
          mk_const(Aggregate(Repeat(cx.eval(elem)?, n)))
446
      },
447
      hir::ExprTupField(ref base, index) => {
448
        if let Aggregate(Tuple(fields)) = cx.eval(base)?.val {
449
            fields[index.node]
450
        } else {
451
            signal!(base, ExpectedConstTuple);
452 453
        }
      }
454
      hir::ExprField(ref base, field_name) => {
455
        if let Aggregate(Struct(fields)) = cx.eval(base)?.val {
456 457
            if let Some(&(_, f)) = fields.iter().find(|&&(name, _)| name == field_name.node) {
                f
458
            } else {
459
                signal!(e, MissingStructField);
460
            }
461
        } else {
462
            signal!(base, ExpectedConstStruct);
463 464
        }
      }
465
      hir::ExprAddrOf(..) => signal!(e, UnimplementedConstVal("address operator")),
466
      _ => signal!(e, MiscCatchAll)
467 468
    };

469
    Ok(result)
470 471
}

472 473 474 475
fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                            val: ConstInt,
                            ty: Ty<'tcx>)
                            -> CastResult<'tcx> {
476
    let v = val.to_u128_unchecked();
O
Oliver Schneider 已提交
477 478 479
    match ty.sty {
        ty::TyBool if v == 0 => Ok(Bool(false)),
        ty::TyBool if v == 1 => Ok(Bool(true)),
480 481 482 483 484
        ty::TyInt(ast::IntTy::I8) => Ok(Integral(I8(v as i128 as i8))),
        ty::TyInt(ast::IntTy::I16) => Ok(Integral(I16(v as i128 as i16))),
        ty::TyInt(ast::IntTy::I32) => Ok(Integral(I32(v as i128 as i32))),
        ty::TyInt(ast::IntTy::I64) => Ok(Integral(I64(v as i128 as i64))),
        ty::TyInt(ast::IntTy::I128) => Ok(Integral(I128(v as i128))),
485
        ty::TyInt(ast::IntTy::Isize) => {
486
            Ok(Integral(Isize(ConstIsize::new_truncating(v as i128, tcx.sess.target.isize_ty))))
O
Oliver Schneider 已提交
487 488 489 490
        },
        ty::TyUint(ast::UintTy::U8) => Ok(Integral(U8(v as u8))),
        ty::TyUint(ast::UintTy::U16) => Ok(Integral(U16(v as u16))),
        ty::TyUint(ast::UintTy::U32) => Ok(Integral(U32(v as u32))),
491 492
        ty::TyUint(ast::UintTy::U64) => Ok(Integral(U64(v as u64))),
        ty::TyUint(ast::UintTy::U128) => Ok(Integral(U128(v as u128))),
493
        ty::TyUint(ast::UintTy::Usize) => {
494
            Ok(Integral(Usize(ConstUsize::new_truncating(v, tcx.sess.target.usize_ty))))
O
Oliver Schneider 已提交
495
        },
496 497 498 499 500 501 502 503 504
        ty::TyFloat(fty) => {
            if let Some(i) = val.to_u128() {
                Ok(Float(ConstFloat::from_u128(i, fty)))
            } else {
                // The value must be negative, go through signed integers.
                let i = val.to_u128_unchecked() as i128;
                Ok(Float(ConstFloat::from_i128(i, fty)))
            }
        }
505
        ty::TyRawPtr(_) => Err(ErrKind::UnimplementedConstVal("casting an address to a raw ptr")),
506 507 508
        ty::TyChar => match val {
            U8(u) => Ok(Char(u as char)),
            _ => bug!(),
509
        },
510
        _ => Err(CannotCast),
511
    }
O
Oliver Schneider 已提交
512
}
513

514 515
fn cast_const_float<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              val: ConstFloat,
516
                              ty: Ty<'tcx>) -> CastResult<'tcx> {
517 518 519
    let int_width = |ty| {
        ty::layout::Integer::from_attr(tcx, ty).size().bits() as usize
    };
O
Oliver Schneider 已提交
520
    match ty.sty {
521 522 523 524 525 526 527 528 529 530 531 532
        ty::TyInt(ity) => {
            if let Some(i) = val.to_i128(int_width(attr::SignedInt(ity))) {
                cast_const_int(tcx, I128(i), ty)
            } else {
                Err(CannotCast)
            }
        }
        ty::TyUint(uty) => {
            if let Some(i) = val.to_u128(int_width(attr::UnsignedInt(uty))) {
                cast_const_int(tcx, U128(i), ty)
            } else {
                Err(CannotCast)
533 534
            }
        }
535
        ty::TyFloat(fty) => Ok(Float(val.convert(fty))),
O
Oliver Schneider 已提交
536
        _ => Err(CannotCast),
537
    }
O
Oliver Schneider 已提交
538
}
539

540 541 542 543
fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                        val: ConstVal<'tcx>,
                        ty: Ty<'tcx>)
                        -> CastResult<'tcx> {
O
Oliver Schneider 已提交
544 545
    match val {
        Integral(i) => cast_const_int(tcx, i, ty),
546
        Bool(b) => cast_const_int(tcx, U8(b as u8), ty),
O
Oliver Schneider 已提交
547
        Float(f) => cast_const_float(tcx, f, ty),
548
        Char(c) => cast_const_int(tcx, U32(c as u32), ty),
549
        Variant(v) => {
550
            let adt = tcx.adt_def(tcx.parent_def_id(v).unwrap());
551 552 553
            let idx = adt.variant_index_with_id(v);
            cast_const_int(tcx, adt.discriminant_for_variant(tcx, idx), ty)
        }
554
        Function(..) => Err(UnimplementedConstVal("casting fn pointers")),
555
        ByteStr(b) => match ty.sty {
556 557 558
            ty::TyRawPtr(_) => {
                Err(ErrKind::UnimplementedConstVal("casting a bytestr to a raw ptr"))
            },
559
            ty::TyRef(_, ty::TypeAndMut { ref ty, mutbl: hir::MutImmutable }) => match ty.sty {
560 561 562 563 564 565 566
                ty::TyArray(ty, n) => {
                    let n = n.val.to_const_int().unwrap().to_u64().unwrap();
                    if ty == tcx.types.u8 && n == b.data.len() as u64 {
                        Ok(val)
                    } else {
                        Err(CannotCast)
                    }
567
                }
568 569 570 571 572 573 574 575 576 577 578 579 580
                ty::TySlice(_) => {
                    Err(ErrKind::UnimplementedConstVal("casting a bytestr to slice"))
                },
                _ => Err(CannotCast),
            },
            _ => Err(CannotCast),
        },
        Str(s) => match ty.sty {
            ty::TyRawPtr(_) => Err(ErrKind::UnimplementedConstVal("casting a str to a raw ptr")),
            ty::TyRef(_, ty::TypeAndMut { ref ty, mutbl: hir::MutImmutable }) => match ty.sty {
                ty::TyStr => Ok(Str(s)),
                _ => Err(CannotCast),
            },
581 582
            _ => Err(CannotCast),
        },
O
Oliver Schneider 已提交
583
        _ => Err(CannotCast),
584 585 586
    }
}

587
fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
588
                          tcx: TyCtxt<'a, 'tcx, 'tcx>,
589 590
                          mut ty: Ty<'tcx>)
                          -> Result<ConstVal<'tcx>, ErrKind<'tcx>> {
O
Oliver Schneider 已提交
591 592
    use syntax::ast::*;
    use syntax::ast::LitIntType::*;
593 594 595 596 597 598 599

    if let ty::TyAdt(adt, _) = ty.sty {
        if adt.is_enum() {
            ty = adt.repr.discr_type().to_ty(tcx)
        }
    }

O
Oliver Schneider 已提交
600
    match *lit {
601
        LitKind::Str(ref s, _) => Ok(Str(s.as_str())),
602
        LitKind::ByteStr(ref data) => Ok(ByteStr(ByteArray { data })),
O
Oliver Schneider 已提交
603
        LitKind::Byte(n) => Ok(Integral(U8(n))),
604 605 606 607 608
        LitKind::Int(n, hint) => {
            match (&ty.sty, hint) {
                (&ty::TyInt(ity), _) |
                (_, Signed(ity)) => {
                    Ok(Integral(ConstInt::new_signed_truncating(n as i128,
609
                        ity, tcx.sess.target.isize_ty)))
610 611 612 613
                }
                (&ty::TyUint(uty), _) |
                (_, Unsigned(uty)) => {
                    Ok(Integral(ConstInt::new_unsigned_truncating(n as u128,
614
                        uty, tcx.sess.target.usize_ty)))
615 616
                }
                _ => bug!()
617
            }
618
        }
619
        LitKind::Float(n, fty) => {
620
            parse_float(&n.as_str(), fty).map(Float)
621
        }
622
        LitKind::FloatUnsuffixed(n) => {
623 624 625
            let fty = match ty.sty {
                ty::TyFloat(fty) => fty,
                _ => bug!()
626
            };
627
            parse_float(&n.as_str(), fty).map(Float)
628
        }
O
Oliver Schneider 已提交
629 630
        LitKind::Bool(b) => Ok(Bool(b)),
        LitKind::Char(c) => Ok(Char(c)),
631 632 633
    }
}

634 635
fn parse_float<'tcx>(num: &str, fty: ast::FloatTy)
                     -> Result<ConstFloat, ErrKind<'tcx>> {
636
    ConstFloat::from_str(num, fty).map_err(|_| {
637
        // FIXME(#31407) this is only necessary because float parsing is buggy
M
mcarton 已提交
638
        UnimplementedConstVal("could not evaluate float literal (see issue #31407)")
639 640 641
    })
}

642 643 644 645
pub fn compare_const_vals(tcx: TyCtxt, span: Span, a: &ConstVal, b: &ConstVal)
                          -> Result<Ordering, ErrorReported>
{
    let result = match (a, b) {
O
Oliver Schneider 已提交
646
        (&Integral(a), &Integral(b)) => a.try_cmp(b).ok(),
647
        (&Float(a), &Float(b)) => a.try_cmp(b).ok(),
O
Oliver Schneider 已提交
648 649
        (&Str(ref a), &Str(ref b)) => Some(a.cmp(b)),
        (&Bool(a), &Bool(b)) => Some(a.cmp(&b)),
650 651
        (&ByteStr(a), &ByteStr(b)) => Some(a.data.cmp(b.data)),
        (&Char(a), &Char(b)) => Some(a.cmp(&b)),
O
Oliver Schneider 已提交
652
        _ => None,
653 654 655 656 657 658
    };

    match result {
        Some(result) => Ok(result),
        None => {
            // FIXME: can this ever be reached?
659 660
            tcx.sess.delay_span_bug(span,
                &format!("type mismatch comparing {:?} and {:?}", a, b));
661 662
            Err(ErrorReported)
        }
O
Oliver Schneider 已提交
663
    }
664 665
}

666 667 668
impl<'a, 'tcx> ConstContext<'a, 'tcx> {
    pub fn compare_lit_exprs(&self,
                             span: Span,
669 670
                             a: &'tcx Expr,
                             b: &'tcx Expr) -> Result<Ordering, ErrorReported> {
671
        let tcx = self.tcx;
672
        let a = match self.eval(a) {
673 674
            Ok(a) => a,
            Err(e) => {
675
                e.report(tcx, a.span, "expression");
676 677 678
                return Err(ErrorReported);
            }
        };
679
        let b = match self.eval(b) {
680 681
            Ok(b) => b,
            Err(e) => {
682
                e.report(tcx, b.span, "expression");
683 684 685
                return Err(ErrorReported);
            }
        };
686
        compare_const_vals(tcx, span, &a.val, &b.val)
687
    }
688
}