Skip to content

Commit cc6ef80

Browse files
committed
Rollup merge of rust-lang#23275 - aochagavia:constants, r=eddyb
Fixes rust-lang#23260 r? @eddyb
2 parents e4e5640 + a83db81 commit cc6ef80

File tree

4 files changed

+90
-39
lines changed

4 files changed

+90
-39
lines changed

src/librustc/middle/const_eval.rs

Lines changed: 57 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use metadata::csearch;
1717
use middle::{astencode, def};
1818
use middle::pat_util::def_to_path;
1919
use middle::ty::{self, Ty};
20-
use middle::astconv_util::{ast_ty_to_prim_ty};
20+
use middle::astconv_util::ast_ty_to_prim_ty;
2121

2222
use syntax::ast::{self, Expr};
2323
use syntax::codemap::Span;
@@ -132,16 +132,16 @@ pub fn lookup_const_by_id<'a>(tcx: &'a ty::ctxt, def_id: ast::DefId)
132132
}
133133
}
134134

135-
// FIXME (#33): this doesn't handle big integer/float literals correctly
136-
// (nor does the rest of our literal handling).
137135
#[derive(Clone, PartialEq)]
138136
pub enum const_val {
139137
const_float(f64),
140138
const_int(i64),
141139
const_uint(u64),
142140
const_str(InternedString),
143-
const_binary(Rc<Vec<u8> >),
144-
const_bool(bool)
141+
const_binary(Rc<Vec<u8>>),
142+
const_bool(bool),
143+
Struct(ast::NodeId),
144+
Tuple(ast::NodeId)
145145
}
146146

147147
pub fn const_expr_to_pat(tcx: &ty::ctxt, expr: &Expr, span: Span) -> P<ast::Pat> {
@@ -226,9 +226,13 @@ pub enum ErrKind {
226226
NegateOnString,
227227
NegateOnBoolean,
228228
NegateOnBinary,
229+
NegateOnStruct,
230+
NegateOnTuple,
229231
NotOnFloat,
230232
NotOnString,
231233
NotOnBinary,
234+
NotOnStruct,
235+
NotOnTuple,
232236

233237
AddiWithOverflow(i64, i64),
234238
SubiWithOverflow(i64, i64),
@@ -242,7 +246,8 @@ pub enum ErrKind {
242246
ModuloWithOverflow,
243247
MissingStructField,
244248
NonConstPath,
245-
NonConstStruct,
249+
ExpectedConstTuple,
250+
ExpectedConstStruct,
246251
TupleIndexOutOfBounds,
247252

248253
MiscBinaryOp,
@@ -262,9 +267,13 @@ impl ConstEvalErr {
262267
NegateOnString => "negate on string".into_cow(),
263268
NegateOnBoolean => "negate on boolean".into_cow(),
264269
NegateOnBinary => "negate on binary literal".into_cow(),
270+
NegateOnStruct => "negate on struct".into_cow(),
271+
NegateOnTuple => "negate on tuple".into_cow(),
265272
NotOnFloat => "not on float or string".into_cow(),
266273
NotOnString => "not on float or string".into_cow(),
267274
NotOnBinary => "not on binary literal".into_cow(),
275+
NotOnStruct => "not on struct".into_cow(),
276+
NotOnTuple => "not on tuple".into_cow(),
268277

269278
AddiWithOverflow(..) => "attempted to add with overflow".into_cow(),
270279
SubiWithOverflow(..) => "attempted to sub with overflow".into_cow(),
@@ -278,7 +287,8 @@ impl ConstEvalErr {
278287
ModuloWithOverflow => "attempted remainder with overflow".into_cow(),
279288
MissingStructField => "nonexistent struct field".into_cow(),
280289
NonConstPath => "non-constant path in constant expr".into_cow(),
281-
NonConstStruct => "non-constant struct in constant expr".into_cow(),
290+
ExpectedConstTuple => "expected constant tuple".into_cow(),
291+
ExpectedConstStruct => "expected constant struct".into_cow(),
282292
TupleIndexOutOfBounds => "tuple index out of bounds".into_cow(),
283293

284294
MiscBinaryOp => "bad operands for binary".into_cow(),
@@ -341,6 +351,8 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
341351
const_str(_) => signal!(e, NegateOnString),
342352
const_bool(_) => signal!(e, NegateOnBoolean),
343353
const_binary(_) => signal!(e, NegateOnBinary),
354+
const_val::Tuple(_) => signal!(e, NegateOnTuple),
355+
const_val::Struct(..) => signal!(e, NegateOnStruct),
344356
}
345357
}
346358
ast::ExprUnary(ast::UnNot, ref inner) => {
@@ -351,6 +363,8 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
351363
const_str(_) => signal!(e, NotOnString),
352364
const_float(_) => signal!(e, NotOnFloat),
353365
const_binary(_) => signal!(e, NotOnBinary),
366+
const_val::Tuple(_) => signal!(e, NotOnTuple),
367+
const_val::Struct(..) => signal!(e, NotOnStruct),
354368
}
355369
}
356370
ast::ExprBinary(op, ref a, ref b) => {
@@ -540,33 +554,52 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
540554
None => const_int(0)
541555
}
542556
}
557+
ast::ExprTup(_) => {
558+
const_val::Tuple(e.id)
559+
}
560+
ast::ExprStruct(..) => {
561+
const_val::Struct(e.id)
562+
}
543563
ast::ExprTupField(ref base, index) => {
544-
// Get the base tuple if it is constant
545-
if let Some(&ast::ExprTup(ref fields)) = lookup_const(tcx, &**base).map(|s| &s.node) {
546-
// Check that the given index is within bounds and evaluate its value
547-
if fields.len() > index.node {
548-
return eval_const_expr_partial(tcx, &*fields[index.node], None);
564+
if let Ok(c) = eval_const_expr_partial(tcx, base, None) {
565+
if let const_val::Tuple(tup_id) = c {
566+
if let ast::ExprTup(ref fields) = tcx.map.expect_expr(tup_id).node {
567+
if index.node < fields.len() {
568+
return eval_const_expr_partial(tcx, &fields[index.node], None)
569+
} else {
570+
signal!(e, TupleIndexOutOfBounds);
571+
}
572+
} else {
573+
unreachable!()
574+
}
549575
} else {
550-
signal!(e, TupleIndexOutOfBounds);
576+
signal!(base, ExpectedConstTuple);
551577
}
578+
} else {
579+
signal!(base, NonConstPath)
552580
}
553-
554-
signal!(e, NonConstStruct);
555581
}
556582
ast::ExprField(ref base, field_name) => {
557583
// Get the base expression if it is a struct and it is constant
558-
if let Some(&ast::ExprStruct(_, ref fields, _)) = lookup_const(tcx, &**base)
559-
.map(|s| &s.node) {
560-
// Check that the given field exists and evaluate it
561-
if let Some(f) = fields.iter().find(|f|
562-
f.ident.node.as_str() == field_name.node.as_str()) {
563-
return eval_const_expr_partial(tcx, &*f.expr, None);
584+
if let Ok(c) = eval_const_expr_partial(tcx, base, None) {
585+
if let const_val::Struct(struct_id) = c {
586+
if let ast::ExprStruct(_, ref fields, _) = tcx.map.expect_expr(struct_id).node {
587+
// Check that the given field exists and evaluate it
588+
if let Some(f) = fields.iter().find(|f| f.ident.node.as_str()
589+
== field_name.node.as_str()) {
590+
return eval_const_expr_partial(tcx, &*f.expr, None)
591+
} else {
592+
signal!(e, MissingStructField);
593+
}
594+
} else {
595+
unreachable!()
596+
}
564597
} else {
565-
signal!(e, MissingStructField);
598+
signal!(base, ExpectedConstStruct);
566599
}
600+
} else {
601+
signal!(base, NonConstPath);
567602
}
568-
569-
signal!(e, NonConstStruct);
570603
}
571604
_ => signal!(e, MiscCatchAll)
572605
};

src/librustc/middle/ty.rs

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5853,16 +5853,13 @@ pub fn eval_repeat_count(tcx: &ctxt, count_expr: &ast::Expr) -> uint {
58535853
let found = match val {
58545854
const_eval::const_uint(count) => return count as uint,
58555855
const_eval::const_int(count) if count >= 0 => return count as uint,
5856-
const_eval::const_int(_) =>
5857-
"negative integer",
5858-
const_eval::const_float(_) =>
5859-
"float",
5860-
const_eval::const_str(_) =>
5861-
"string",
5862-
const_eval::const_bool(_) =>
5863-
"boolean",
5864-
const_eval::const_binary(_) =>
5865-
"binary array"
5856+
const_eval::const_int(_) => "negative integer",
5857+
const_eval::const_float(_) => "float",
5858+
const_eval::const_str(_) => "string",
5859+
const_eval::const_bool(_) => "boolean",
5860+
const_eval::const_binary(_) => "binary array",
5861+
const_eval::Struct(..) => "struct",
5862+
const_eval::Tuple(_) => "tuple"
58665863
};
58675864
span_err!(tcx.sess, count_expr.span, E0306,
58685865
"expected positive integer for repeat count, found {}",

src/test/compile-fail/repeat_count.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ fn main() {
1919
//~| found `()`
2020
//~| expected usize
2121
//~| found ()
22-
//~| ERROR expected constant integer for repeat count, found non-constant expression
22+
//~| ERROR expected positive integer for repeat count, found tuple
2323
let c = [0; true];
2424
//~^ ERROR mismatched types
2525
//~| expected `usize`

src/test/run-pass/issue-19244.rs

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,35 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
struct MyStruct { field: uint }
11+
struct MyStruct { field: usize }
12+
struct Nested { nested: MyStruct }
13+
struct Mix2 { nested: ((usize,),) }
14+
1215
const STRUCT: MyStruct = MyStruct { field: 42 };
13-
const TUP: (uint,) = (43,);
16+
const TUP: (usize,) = (43,);
17+
const NESTED_S: Nested = Nested { nested: MyStruct { field: 5 } };
18+
const NESTED_T: ((usize,),) = ((4,),);
19+
const MIX_1: ((Nested,),) = ((Nested { nested: MyStruct { field: 3 } },),);
20+
const MIX_2: Mix2 = Mix2 { nested: ((2,),) };
21+
const INSTANT_1: usize = (MyStruct { field: 1 }).field;
22+
const INSTANT_2: usize = (0,).0;
1423

1524
fn main() {
1625
let a = [0; STRUCT.field];
1726
let b = [0; TUP.0];
27+
let c = [0; NESTED_S.nested.field];
28+
let d = [0; (NESTED_T.0).0];
29+
let e = [0; (MIX_1.0).0.nested.field];
30+
let f = [0; (MIX_2.nested.0).0];
31+
let g = [0; INSTANT_1];
32+
let h = [0; INSTANT_2];
1833

19-
assert!(a.len() == 42);
20-
assert!(b.len() == 43);
34+
assert_eq!(a.len(), 42);
35+
assert_eq!(b.len(), 43);
36+
assert_eq!(c.len(), 5);
37+
assert_eq!(d.len(), 4);
38+
assert_eq!(e.len(), 3);
39+
assert_eq!(f.len(), 2);
40+
assert_eq!(g.len(), 1);
41+
assert_eq!(h.len(), 0);
2142
}

0 commit comments

Comments
 (0)