summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEduard-Mihai Burtescu <edy.burt@gmail.com>2017-04-19 15:16:19 +0300
committerEduard-Mihai Burtescu <edy.burt@gmail.com>2017-04-23 11:11:57 +0300
commit8054377f8f4dfaf766bcff40e7a720c90c5e33be (patch)
tree9b91c1c746a4f520ae69502e0dde070ba23fd9f5
parent0ff828baa06504c91e38dfda53ead61cc44ad171 (diff)
downloadrust-8054377f8f4dfaf766bcff40e7a720c90c5e33be.tar.gz
rustc_const_eval: support all unit enum variants.
-rw-r--r--src/librustc/ich/impls_ty.rs9
-rw-r--r--src/librustc/middle/const_val.rs6
-rw-r--r--src/librustc/mir/mod.rs3
-rw-r--r--src/librustc/ty/mod.rs19
-rw-r--r--src/librustc_const_eval/eval.rs77
-rw-r--r--src/librustc_const_eval/pattern.rs8
-rw-r--r--src/librustc_trans/mir/constant.rs8
-rw-r--r--src/test/compile-fail/const-pattern-not-const-evaluable.rs11
-rw-r--r--src/test/compile-fail/issue-41394.rs20
-rw-r--r--src/test/run-pass/auxiliary/issue-41394.rs26
-rw-r--r--src/test/run-pass/const-pattern-variant.rs38
-rw-r--r--src/test/run-pass/issue-23898.rs (renamed from src/test/compile-fail/non-constant-enum-for-vec-repeat.rs)5
-rw-r--r--src/test/run-pass/issue-41394.rs17
13 files changed, 180 insertions, 67 deletions
diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
index f55462fb5de..16af98c2035 100644
--- a/src/librustc/ich/impls_ty.rs
+++ b/src/librustc/ich/impls_ty.rs
@@ -273,6 +273,12 @@ for ::middle::const_val::ConstVal<'tcx> {
ConstVal::Bool(value) => {
value.hash_stable(hcx, hasher);
}
+ ConstVal::Char(value) => {
+ value.hash_stable(hcx, hasher);
+ }
+ ConstVal::Variant(def_id) => {
+ def_id.hash_stable(hcx, hasher);
+ }
ConstVal::Function(def_id, substs) => {
def_id.hash_stable(hcx, hasher);
substs.hash_stable(hcx, hasher);
@@ -296,9 +302,6 @@ for ::middle::const_val::ConstVal<'tcx> {
value.hash_stable(hcx, hasher);
times.hash_stable(hcx, hasher);
}
- ConstVal::Char(value) => {
- value.hash_stable(hcx, hasher);
- }
}
}
}
diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs
index b65dbdbbcc2..ec7b3c4dd8d 100644
--- a/src/librustc/middle/const_val.rs
+++ b/src/librustc/middle/const_val.rs
@@ -38,12 +38,13 @@ pub enum ConstVal<'tcx> {
Str(InternedString),
ByteStr(Rc<Vec<u8>>),
Bool(bool),
+ Char(char),
+ Variant(DefId),
Function(DefId, &'tcx Substs<'tcx>),
Struct(BTreeMap<ast::Name, ConstVal<'tcx>>),
Tuple(Vec<ConstVal<'tcx>>),
Array(Vec<ConstVal<'tcx>>),
Repeat(Box<ConstVal<'tcx>>, u64),
- Char(char),
}
impl<'tcx> ConstVal<'tcx> {
@@ -54,12 +55,13 @@ impl<'tcx> ConstVal<'tcx> {
Str(_) => "string literal",
ByteStr(_) => "byte string literal",
Bool(_) => "boolean",
+ Char(..) => "char",
+ Variant(_) => "enum variant",
Struct(_) => "struct",
Tuple(_) => "tuple",
Function(..) => "function definition",
Array(..) => "array",
Repeat(..) => "repeat",
- Char(..) => "char",
}
}
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 9ff64b295b7..bfb72b5df7b 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -1307,10 +1307,11 @@ fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ConstVal) -> fmt::Result {
write!(fmt, "b\"{}\"", escaped)
}
Bool(b) => write!(fmt, "{:?}", b),
+ Char(c) => write!(fmt, "{:?}", c),
+ Variant(def_id) |
Function(def_id, _) => write!(fmt, "{}", item_path_str(def_id)),
Struct(_) | Tuple(_) | Array(_) | Repeat(..) =>
bug!("ConstVal `{:?}` should not be in MIR", const_val),
- Char(c) => write!(fmt, "{:?}", c),
}
}
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 1588773479c..cc5eb768d9b 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -1693,6 +1693,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
}
}
+ #[inline]
pub fn discriminants(&'a self, tcx: TyCtxt<'a, 'gcx, 'tcx>)
-> impl Iterator<Item=ConstInt> + 'a {
let repr_type = self.repr.discr_type();
@@ -1706,7 +1707,13 @@ impl<'a, 'gcx, 'tcx> AdtDef {
Ok(ConstVal::Integral(v)) => {
discr = v;
}
- _ => {}
+ err => {
+ if !expr_did.is_local() {
+ span_bug!(tcx.def_span(expr_did),
+ "variant discriminant evaluation succeeded \
+ in its crate but failed locally: {:?}", err);
+ }
+ }
}
}
prev_discr = Some(discr);
@@ -1740,7 +1747,15 @@ impl<'a, 'gcx, 'tcx> AdtDef {
explicit_value = v;
break;
}
- _ => {
+ err => {
+ if !expr_did.is_local() {
+ span_bug!(tcx.def_span(expr_did),
+ "variant discriminant evaluation succeeded \
+ in its crate but failed locally: {:?}", err);
+ }
+ if explicit_index == 0 {
+ break;
+ }
explicit_index -= 1;
}
}
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index 5c421df92c7..e9352f53c92 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -15,7 +15,7 @@ use rustc::middle::const_val::{ConstVal, ConstEvalErr, EvalResult, ErrKind};
use rustc::hir::map as hir_map;
use rustc::hir::map::blocks::FnLikeNode;
use rustc::traits;
-use rustc::hir::def::Def;
+use rustc::hir::def::{Def, CtorKind};
use rustc::hir::def_id::DefId;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::maps::Providers;
@@ -48,28 +48,6 @@ macro_rules! math {
}
}
-fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- variant_def: DefId)
- -> Option<(&'tcx Expr, &'a ty::TypeckTables<'tcx>)> {
- if let Some(variant_node_id) = tcx.hir.as_local_node_id(variant_def) {
- let enum_node_id = tcx.hir.get_parent(variant_node_id);
- if let Some(hir_map::NodeItem(it)) = tcx.hir.find(enum_node_id) {
- if let hir::ItemEnum(ref edef, _) = it.node {
- for variant in &edef.variants {
- if variant.node.data.id() == variant_node_id {
- return variant.node.disr_expr.map(|e| {
- let def_id = tcx.hir.body_owner_def_id(e);
- (&tcx.hir.body(e).value,
- tcx.item_tables(def_id))
- });
- }
- }
- }
- }
- }
- None
-}
-
/// * `def_id` is the id of the constant.
/// * `substs` is the monomorphized substitutions for the expression.
///
@@ -289,9 +267,22 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
}
}
hir::ExprCast(ref base, _) => {
- match cast_const(tcx, cx.eval(base)?, ety) {
- Ok(val) => val,
- Err(kind) => return Err(ConstEvalErr { span: e.span, kind: kind }),
+ let base_val = cx.eval(base)?;
+ let base_ty = cx.tables.expr_ty(base);
+
+ // Avoid applying substitutions if they're empty, that'd ICE.
+ let base_ty = if cx.substs.is_empty() {
+ base_ty
+ } else {
+ base_ty.subst(tcx, cx.substs)
+ };
+ if ety == base_ty {
+ base_val
+ } else {
+ match cast_const(tcx, base_val, ety) {
+ Ok(val) => val,
+ Err(kind) => signal!(e, kind),
+ }
}
}
hir::ExprPath(ref qpath) => {
@@ -317,27 +308,20 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
debug!("bad reference: {:?}, {:?}", err.description(), err.span);
signal!(e, ErroneousReferencedConstant(box err))
},
+ }
},
- Def::VariantCtor(variant_def, ..) => {
- if let Some((expr, tables)) = lookup_variant_by_id(tcx, variant_def) {
- let cx = ConstContext::with_tables(tcx, tables);
- match cx.eval(expr) {
- Ok(val) => val,
- Err(ConstEvalErr { kind: TypeckError, .. }) => {
- signal!(e, TypeckError);
- }
- Err(err) => {
- debug!("bad reference: {:?}, {:?}", err.description(), err.span);
- signal!(e, ErroneousReferencedConstant(box err))
- },
- }
- } else {
- signal!(e, UnimplementedConstVal("enum variants"));
- }
+ Def::VariantCtor(variant_def, CtorKind::Const) => {
+ Variant(variant_def)
+ }
+ Def::VariantCtor(_, CtorKind::Fn) => {
+ signal!(e, UnimplementedConstVal("enum variants"));
}
- Def::StructCtor(..) => {
+ Def::StructCtor(_, CtorKind::Const) => {
ConstVal::Struct(Default::default())
}
+ Def::StructCtor(_, CtorKind::Fn) => {
+ signal!(e, UnimplementedConstVal("tuple struct constructors"))
+ }
Def::Local(def_id) => {
debug!("Def::Local({:?}): {:?}", def_id, cx.fn_args);
if let Some(val) = cx.fn_args.as_ref().and_then(|args| args.get(&def_id)) {
@@ -578,7 +562,7 @@ fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
U8(u) => Ok(Char(u as char)),
_ => bug!(),
},
- _ => bug!(),
+ _ => Err(CannotCast),
}
}
@@ -622,6 +606,11 @@ fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
Bool(b) => cast_const_int(tcx, U8(b as u8), ty),
Float(f) => cast_const_float(tcx, f, ty),
Char(c) => cast_const_int(tcx, U32(c as u32), ty),
+ Variant(v) => {
+ let adt = tcx.lookup_adt_def(tcx.parent_def_id(v).unwrap());
+ let idx = adt.variant_index_with_id(v);
+ cast_const_int(tcx, adt.discriminant_for_variant(tcx, idx), ty)
+ }
Function(..) => Err(UnimplementedConstVal("casting fn pointers")),
ByteStr(b) => match ty.sty {
ty::TyRawPtr(_) => {
diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs
index a470d549d05..0dfafeb6fb8 100644
--- a/src/librustc_const_eval/pattern.rs
+++ b/src/librustc_const_eval/pattern.rs
@@ -116,6 +116,7 @@ fn print_const_val(value: &ConstVal, f: &mut fmt::Formatter) -> fmt::Result {
ConstVal::ByteStr(ref b) => write!(f, "{:?}", &b[..]),
ConstVal::Bool(b) => write!(f, "{:?}", b),
ConstVal::Char(c) => write!(f, "{:?}", c),
+ ConstVal::Variant(_) |
ConstVal::Struct(_) |
ConstVal::Tuple(_) |
ConstVal::Function(..) |
@@ -620,7 +621,12 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
let const_cx = eval::ConstContext::with_tables(self.tcx.global_tcx(), self.tables);
match const_cx.eval(expr) {
Ok(value) => {
- PatternKind::Constant { value: value }
+ if let ConstVal::Variant(def_id) = value {
+ let ty = self.tables.expr_ty(expr);
+ self.lower_variant_or_leaf(Def::Variant(def_id), ty, vec![])
+ } else {
+ PatternKind::Constant { value: value }
+ }
}
Err(e) => {
self.errors.push(PatternError::ConstEval(e));
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index e938913a3f1..040194e63d0 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -100,15 +100,13 @@ impl<'tcx> Const<'tcx> {
ConstVal::Integral(ref i) => return Const::from_constint(ccx, i),
ConstVal::Str(ref v) => C_str_slice(ccx, v.clone()),
ConstVal::ByteStr(ref v) => consts::addr_of(ccx, C_bytes(ccx, v), 1, "byte_str"),
+ ConstVal::Char(c) => C_integral(Type::char(ccx), c as u64, false),
+ ConstVal::Function(..) => C_null(type_of::type_of(ccx, ty)),
+ ConstVal::Variant(_) |
ConstVal::Struct(_) | ConstVal::Tuple(_) |
ConstVal::Array(..) | ConstVal::Repeat(..) => {
bug!("MIR must not use `{:?}` (aggregates are expanded to MIR rvalues)", cv)
}
- ConstVal::Function(..) => {
- let llty = type_of::type_of(ccx, ty);
- return Const::new(C_null(llty), ty);
- }
- ConstVal::Char(c) => C_integral(Type::char(ccx), c as u64, false),
};
assert!(!ty.has_erasable_regions());
diff --git a/src/test/compile-fail/const-pattern-not-const-evaluable.rs b/src/test/compile-fail/const-pattern-not-const-evaluable.rs
index b40aa2a8e27..71cac3edbc1 100644
--- a/src/test/compile-fail/const-pattern-not-const-evaluable.rs
+++ b/src/test/compile-fail/const-pattern-not-const-evaluable.rs
@@ -10,21 +10,22 @@
#![feature(const_fn)]
+#[derive(PartialEq, Eq)]
enum Cake {
BlackForest,
Marmor,
}
use Cake::*;
-const BOO: (Cake, Cake) = (Marmor, BlackForest);
+struct Pair<A, B>(A, B);
+
+const BOO: Pair<Cake, Cake> = Pair(Marmor, BlackForest);
//~^ ERROR: constant evaluation error [E0080]
-//~| unimplemented constant expression: enum variants
+//~| unimplemented constant expression: tuple struct constructors
const FOO: Cake = BOO.1;
const fn foo() -> Cake {
Marmor
- //~^ ERROR: constant evaluation error [E0080]
- //~| unimplemented constant expression: enum variants
}
const WORKS: Cake = Marmor;
@@ -34,7 +35,7 @@ const GOO: Cake = foo();
fn main() {
match BlackForest {
FOO => println!("hi"), //~ NOTE: for pattern here
- GOO => println!("meh"), //~ NOTE: for pattern here
+ GOO => println!("meh"),
WORKS => println!("möp"),
_ => println!("bye"),
}
diff --git a/src/test/compile-fail/issue-41394.rs b/src/test/compile-fail/issue-41394.rs
new file mode 100644
index 00000000000..1fb3b7c4ee1
--- /dev/null
+++ b/src/test/compile-fail/issue-41394.rs
@@ -0,0 +1,20 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// 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.
+
+enum Foo {
+ A = "" + 1
+ //~^ ERROR binary operation `+` cannot be applied to type `&'static str`
+}
+
+enum Bar {
+ A = Foo::A as isize
+}
+
+fn main() {}
diff --git a/src/test/run-pass/auxiliary/issue-41394.rs b/src/test/run-pass/auxiliary/issue-41394.rs
new file mode 100644
index 00000000000..f06b81279ac
--- /dev/null
+++ b/src/test/run-pass/auxiliary/issue-41394.rs
@@ -0,0 +1,26 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// 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.
+
+#![crate_type = "lib"]
+
+#[repr(u32)]
+pub enum Foo {
+ Foo = Private::Variant as u32
+}
+
+#[repr(u8)]
+enum Private {
+ Variant = 42
+}
+
+#[inline(always)]
+pub fn foo() -> Foo {
+ Foo::Foo
+}
diff --git a/src/test/run-pass/const-pattern-variant.rs b/src/test/run-pass/const-pattern-variant.rs
new file mode 100644
index 00000000000..104ab6e19db
--- /dev/null
+++ b/src/test/run-pass/const-pattern-variant.rs
@@ -0,0 +1,38 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// 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.
+
+#![feature(const_fn)]
+
+#[derive(PartialEq, Eq)]
+enum Cake {
+ BlackForest,
+ Marmor,
+}
+use Cake::*;
+
+const BOO: (Cake, Cake) = (Marmor, BlackForest);
+const FOO: Cake = BOO.1;
+
+const fn foo() -> Cake {
+ Marmor
+}
+
+const WORKS: Cake = Marmor;
+
+const GOO: Cake = foo();
+
+fn main() {
+ match BlackForest {
+ FOO => println!("hi"),
+ GOO => println!("meh"),
+ WORKS => println!("möp"),
+ _ => println!("bye"),
+ }
+}
diff --git a/src/test/compile-fail/non-constant-enum-for-vec-repeat.rs b/src/test/run-pass/issue-23898.rs
index cadfec5a38d..3f5546ce83d 100644
--- a/src/test/compile-fail/non-constant-enum-for-vec-repeat.rs
+++ b/src/test/run-pass/issue-23898.rs
@@ -8,13 +8,10 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// Note: This test is checking that we forbid a coding pattern that
-// Issue #5873 explicitly wants to allow.
+// Note: This test was used to demonstrate #5873 (now #23898).
enum State { ST_NULL, ST_WHITESPACE }
fn main() {
[State::ST_NULL; (State::ST_WHITESPACE as usize)];
- //~^ ERROR constant evaluation error
- //~| unimplemented constant expression: enum variants
}
diff --git a/src/test/run-pass/issue-41394.rs b/src/test/run-pass/issue-41394.rs
new file mode 100644
index 00000000000..798905599a8
--- /dev/null
+++ b/src/test/run-pass/issue-41394.rs
@@ -0,0 +1,17 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// 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.
+
+// aux-build:issue-41394.rs
+
+extern crate issue_41394 as lib;
+
+fn main() {
+ assert_eq!(lib::foo() as u32, 42);
+}